diff --git a/lib/puppet/functions/archive/go_md5.rb b/lib/puppet/functions/archive/go_md5.rb new file mode 100644 index 0000000..017e421 --- /dev/null +++ b/lib/puppet/functions/archive/go_md5.rb @@ -0,0 +1,36 @@ +require_relative '../../../puppet_x/bodeco/util.rb' + +# @summary +# Retrieves and returns specific file's md5 from GoCD server md5 checksum file +# @api private +# @see http://www.thoughtworks.com/products/docs/go/12.4/help/Artifacts_API.html +Puppet::Functions.create_function(:'archive::go_md5') do + # @param username + # GoCD username + # @param password + # GoCD password + # @param file + # GoCD filename + # @param url + # The GoCD MD5 checkum URL + # @return [String] + # The MD5 string + dispatch :default_impl do + param 'String', :username + param 'String', :password + param 'String[1]', :file + param 'Stdlib::HTTPUrl', :url + return_type 'String' + end + + def default_impl(username, password, file, url) + uri = URI(url) + response = PuppetX::Bodeco::Util.content(uri, username: username, password: password) + + checksums = response.split("\n") + line = checksums.find { |x| x =~ %r{#{file}=} } + md5 = line.match(%r{\b[0-9a-f]{5,40}\b}) unless line.nil? + raise("Could not parse md5 from url #{url} response: #{response}") unless md5 + md5[0] + end +end diff --git a/lib/puppet/parser/functions/go_md5.rb b/lib/puppet/parser/functions/go_md5.rb deleted file mode 100644 index 668cf2d..0000000 --- a/lib/puppet/parser/functions/go_md5.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'puppet_x/bodeco/util' - -module Puppet::Parser::Functions - # Public: go file md5 checksum - # - # args[0] - username - # args[1] - password - # args[2] - file_name - # args[3] - go md5 checksum url - # - # http://www.thoughtworks.com/products/docs/go/12.4/help/Artifacts_API.html - # - # Returns specific file's md5 from go server md5 checksum file - newfunction(:go_md5, type: :rvalue) do |args| - raise(ArgumentError, "Invalid go md5 info url #{args}") unless args.size == 4 - - username, password, file, url = args - - uri = URI(url) - response = PuppetX::Bodeco::Util.content(uri, username: username, password: password) - - checksums = response.split("\n") - line = checksums.find { |x| x =~ %r{#{file}=} } - md5 = line.match(%r{\b[0-9a-f]{5,40}\b}) - raise("Could not parse md5 from url#{url} response: #{response.body}") unless md5 - md5[0] - end -end diff --git a/manifests/go.pp b/manifests/go.pp index 8fde0a7..f9a9285 100644 --- a/manifests/go.pp +++ b/manifests/go.pp @@ -1,61 +1,61 @@ # download from go define archive::go ( String $server, Integer $port, String $url_path, String $md5_url_path, String $username, String $password, Enum['present', 'absent'] $ensure = present, String $path = $name, Optional[String] $owner = undef, Optional[String] $group = undef, Optional[String] $mode = undef, Optional[Boolean] $extract = undef, Optional[String] $extract_path = undef, Optional[String] $creates = undef, Optional[Boolean] $cleanup = undef, Optional[Stdlib::Compat::Absolute_path] $archive_path = undef, ) { include archive::params if $archive_path { $file_path = "${archive_path}/${name}" } else { $file_path = $path } if $file_path !~ Stdlib::Compat::Absolute_path { fail("archive::go[${name}]: \$name or \$archive_path must be an absolute path!") # lint:ignore:trailing_comma } $go_url = "http://${server}:${port}" $file_url = "${go_url}/${url_path}" $md5_url = "${go_url}/${md5_url_path}" archive { $file_path: ensure => $ensure, path => $file_path, extract => $extract, extract_path => $extract_path, source => $file_url, - checksum => go_md5($username, $password, $name, $md5_url), + checksum => archive::go_md5($username, $password, $name, $md5_url), checksum_type => 'md5', creates => $creates, cleanup => $cleanup, username => $username, password => $password, } $file_owner = pick($owner, $archive::params::owner) $file_group = pick($group, $archive::params::group) $file_mode = pick($mode, $archive::params::mode) file { $file_path: owner => $file_owner, group => $file_group, mode => $file_mode, require => Archive[$file_path], } } diff --git a/spec/defines/go_spec.rb b/spec/defines/go_spec.rb index 2889fe8..7d34799 100644 --- a/spec/defines/go_spec.rb +++ b/spec/defines/go_spec.rb @@ -1,79 +1,82 @@ require 'spec_helper' describe 'archive::go' do let(:facts) { { os: { family: 'RedHat' }, puppetversion: '4.4.0' } } - before do - MockFunction.new('go_md5') do |f| - f.stub.returns('0d4f4b4b039c10917cfc49f6f6be71e4') - end + # Mock Puppet V4 API ruby function with a puppet language function equivalent + let(:pre_condition) do + <<-PUPPET + function archive::go_md5(String $username, String $password, String $file, Stdlib::HTTPUrl $url) { + return '0d4f4b4b039c10917cfc49f6f6be71e4' + } + PUPPET end context 'go archive with defaults' do let(:title) { '/opt/app/example.zip' } let(:params) do { server: 'home.lan', port: 8081, url_path: 'go/example.zip', md5_url_path: 'go/example.zip/checksum', username: 'username', password: 'password' } end it do is_expected.to contain_archive('/opt/app/example.zip').with( path: '/opt/app/example.zip', source: 'http://home.lan:8081/go/example.zip', checksum: '0d4f4b4b039c10917cfc49f6f6be71e4', checksum_type: 'md5' ) end it do is_expected.to contain_file('/opt/app/example.zip').with( owner: '0', group: '0', mode: '0640', require: 'Archive[/opt/app/example.zip]' ) end end context 'go archive with path' do let(:title) { 'example.zip' } let(:params) do { archive_path: '/opt/app', server: 'home.lan', port: 8081, url_path: 'go/example.zip', md5_url_path: 'go/example.zip/checksum', username: 'username', password: 'password', owner: 'app', group: 'app', mode: '0400' } end it do is_expected.to contain_archive('/opt/app/example.zip').with( path: '/opt/app/example.zip', source: 'http://home.lan:8081/go/example.zip', checksum: '0d4f4b4b039c10917cfc49f6f6be71e4', checksum_type: 'md5' ) end it do is_expected.to contain_file('/opt/app/example.zip').with( owner: 'app', group: 'app', mode: '0400', require: 'Archive[/opt/app/example.zip]' ) end end end diff --git a/spec/functions/archive_go_md5_spec.rb b/spec/functions/archive_go_md5_spec.rb new file mode 100644 index 0000000..d880bdb --- /dev/null +++ b/spec/functions/archive_go_md5_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe 'archive::go_md5' do + let(:example_md5) { File.read(fixtures('checksum', 'gocd.md5')) } + let(:url) { 'https://gocd.lan/path/file.md5' } + let(:uri) { URI(url) } + + it { is_expected.not_to eq(nil) } + + it 'retreives file md5' do + PuppetX::Bodeco::Util.stubs(:content).with(uri, username: 'user', password: 'pass').returns(example_md5) + is_expected.to run.with_params('user', 'pass', 'filea', url).and_return('283158c7da8c0ada74502794fa8745eb') + end + + context 'when file doesn\'t exist' do + it 'raises error' do + PuppetX::Bodeco::Util.stubs(:content).with(uri, username: 'user', password: 'pass').returns(example_md5) + is_expected.to run.with_params('user', 'pass', 'non-existent-file', url).and_raise_error(RuntimeError, "Could not parse md5 from url https://gocd\.lan/path/file\.md5 response: #{example_md5}") + end + end +end diff --git a/spec/unit/puppet/parser/functions/go_md5_spec.rb b/spec/unit/puppet/parser/functions/go_md5_spec.rb deleted file mode 100644 index 7dad352..0000000 --- a/spec/unit/puppet/parser/functions/go_md5_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'spec_helper' - -describe :go_md5 do # rubocop:disable RSpec/DescribeSymbol - before :all do # rubocop:disable RSpec/BeforeAfterAll - Puppet::Parser::Functions.autoloader.loadall - end - - let(:scope) { PuppetlabsSpec::PuppetInternals.scope } - - example_md5 = File.read(fixtures('checksum', 'gocd.md5')) - - it 'retreives file md5' do - url = 'https://gocd.lan/path/file.md5' - uri = URI(url) - PuppetX::Bodeco::Util.stubs(:content).with(uri, username: 'user', password: 'pass').returns(example_md5) - expect(scope.function_go_md5(['user', 'pass', 'filea', url])).to eq '283158c7da8c0ada74502794fa8745eb' - end -end