diff --git a/lib/puppet/type/yumrepo.rb b/lib/puppet/type/yumrepo.rb index 0922bbdcc..daa8d44ee 100644 --- a/lib/puppet/type/yumrepo.rb +++ b/lib/puppet/type/yumrepo.rb @@ -1,312 +1,360 @@ require 'uri' Puppet::Type.newtype(:yumrepo) do @doc = "The client-side description of a yum repository. Repository configurations are found by parsing `/etc/yum.conf` and the files indicated by the `reposdir` option in that file (see `yum.conf(5)` for details). Most parameters are identical to the ones documented in the `yum.conf(5)` man page. Continuation lines that yum supports (for the `baseurl`, for example) are not supported. This type does not attempt to read or verify the exinstence of files listed in the `include` attribute." # Ensure yumrepos can be removed too. ensurable # Doc string for properties that can be made 'absent' ABSENT_DOC="Set this to `absent` to remove it from the file completely." # False can be false/0/no and True can be true/1/yes in yum. YUM_BOOLEAN=/^(True|False|0|1|No|Yes)$/i YUM_BOOLEAN_DOC="Valid values are: False/0/No or True/1/Yes." VALID_SCHEMES = %w[file http https ftp] newparam(:name, :namevar => true) do desc "The name of the repository. This corresponds to the `repositoryid` parameter in `yum.conf(5)`." end newparam(:target) do desc "The filename to write the yum repository to." defaultto :absent end newproperty(:descr) do desc "A human-readable description of the repository. This corresponds to the name parameter in `yum.conf(5)`. #{ABSENT_DOC}" newvalues(/.*/, :absent) end newproperty(:mirrorlist) do desc "The URL that holds the list of mirrors for this repository. #{ABSENT_DOC}" newvalues(/.*/, :absent) validate do |value| next if value.to_s == 'absent' parsed = URI.parse(value) unless VALID_SCHEMES.include?(parsed.scheme) raise "Must be a valid URL" end end end newproperty(:baseurl) do desc "The URL for this repository. #{ABSENT_DOC}" newvalues(/.*/, :absent) validate do |value| next if value.to_s == 'absent' value.split(/\s+/).each do |uri| parsed = URI.parse(uri) unless VALID_SCHEMES.include?(parsed.scheme) raise "Must be a valid URL" end end end end newproperty(:enabled) do desc "Whether this repository is enabled. #{YUM_BOOLEAN_DOC} #{ABSENT_DOC}" newvalues(YUM_BOOLEAN, :absent) end newproperty(:gpgcheck) do desc "Whether to check the GPG signature on packages installed from this repository. #{YUM_BOOLEAN_DOC} #{ABSENT_DOC}" newvalues(YUM_BOOLEAN, :absent) end newproperty(:repo_gpgcheck) do desc "Whether to check the GPG signature on repodata. #{YUM_BOOLEAN_DOC} #{ABSENT_DOC}" newvalues(YUM_BOOLEAN, :absent) end newproperty(:gpgkey) do desc "The URL for the GPG key with which packages from this repository are signed. #{ABSENT_DOC}" newvalues(/.*/, :absent) validate do |value| next if value.to_s == 'absent' value.split(/\s+/).each do |uri| parsed = URI.parse(uri) unless VALID_SCHEMES.include?(parsed.scheme) raise "Must be a valid URL" end end end end + newproperty(:mirrorlist_expire) do + desc "Time (in seconds) after which the mirrorlist locally cached + will expire.\n#{ABSENT_DOC}" + + newvalues(/^[0-9]+$/, :absent) + end + newproperty(:include) do desc "The URL of a remote file containing additional yum configuration settings. Puppet does not check for this file's existence or validity. #{ABSENT_DOC}" newvalues(/.*/, :absent) validate do |value| next if value.to_s == 'absent' parsed = URI.parse(value) unless VALID_SCHEMES.include?(parsed.scheme) raise "Must be a valid URL" end end end newproperty(:exclude) do desc "List of shell globs. Matching packages will never be considered in updates or installs for this repo. #{ABSENT_DOC}" newvalues(/.*/, :absent) end + newproperty(:gpgcakey) do + desc "The URL for the GPG CA key for this repository. #{ABSENT_DOC}" + + newvalues(/.*/, :absent) + validate do |value| + next if value.to_s == 'absent' + parsed = URI.parse(value) + + unless VALID_SCHEMES.include?(parsed.scheme) + raise "Must be a valid URL" + end + end + end + newproperty(:includepkgs) do desc "List of shell globs. If this is set, only packages matching one of the globs will be considered for update or install from this repo. #{ABSENT_DOC}" newvalues(/.*/, :absent) end newproperty(:enablegroups) do desc "Whether yum will allow the use of package groups for this repository. #{YUM_BOOLEAN_DOC} #{ABSENT_DOC}" newvalues(YUM_BOOLEAN, :absent) end newproperty(:failovermethod) do desc "The failover method for this repository; should be either `roundrobin` or `priority`. #{ABSENT_DOC}" newvalues(/^roundrobin|priority$/, :absent) end newproperty(:keepalive) do desc "Whether HTTP/1.1 keepalive should be used with this repository. #{YUM_BOOLEAN_DOC} #{ABSENT_DOC}" newvalues(YUM_BOOLEAN, :absent) end + newproperty(:retries) do + desc "Set the number of times any attempt to retrieve a file should + retry before returning an error. Setting this to `0` makes yum + try forever.\n#{ABSENT_DOC}" + + newvalues(/^[0-9]+$/, :absent) + end + newproperty(:http_caching) do desc "What to cache from this repository. #{ABSENT_DOC}" newvalues(/^(packages|all|none)$/, :absent) end newproperty(:timeout) do desc "Number of seconds to wait for a connection before timing out. #{ABSENT_DOC}" newvalues(/^\d+$/, :absent) end newproperty(:metadata_expire) do desc "Number of seconds after which the metadata will expire. #{ABSENT_DOC}" - newvalues(/^\d+$/, :absent) + newvalues(/^([0-9]+[dhm]?|never)$/, :absent) end newproperty(:protect) do desc "Enable or disable protection for this repository. Requires that the `protectbase` plugin is installed and enabled. #{YUM_BOOLEAN_DOC} #{ABSENT_DOC}" newvalues(YUM_BOOLEAN, :absent) end newproperty(:priority) do desc "Priority of this repository from 1-99. Requires that the `priorities` plugin is installed and enabled. #{ABSENT_DOC}" newvalues(/.*/, :absent) validate do |value| next if value.to_s == 'absent' unless (1..99).include?(value.to_i) fail("Must be within range 1-99") end end end + newproperty(:throttle) do + desc "Enable bandwidth throttling for downloads. This option + can be expressed as a absolute data rate in bytes/sec or a + percentage `60%`. An SI prefix (k, M or G) may be appended + to the data rate values.\n#{ABSENT_DOC}" + + newvalues(/^\d+[kMG%]?$/, :absent) + end + + newproperty(:bandwidth) do + desc "Use to specify the maximum available network bandwidth + in bytes/second. Used with the `throttle` option. If `throttle` + is a percentage and `bandwidth` is `0` then bandwidth throttling + will be disabled. If `throttle` is expressed as a data rate then + this option is ignored.\n#{ABSENT_DOC}" + + newvalues(/^\d+[kMG]?$/, :absent) + end + newproperty(:cost) do desc "Cost of this repository. #{ABSENT_DOC}" newvalues(/^\d+$/, :absent) end newproperty(:proxy) do desc "URL to the proxy server for this repository. #{ABSENT_DOC}" newvalues(/.*/, :absent) validate do |value| next if value.to_s == 'absent' parsed = URI.parse(value) unless VALID_SCHEMES.include?(parsed.scheme) raise "Must be a valid URL" end end end newproperty(:proxy_username) do desc "Username for this proxy. #{ABSENT_DOC}" newvalues(/.*/, :absent) end newproperty(:proxy_password) do desc "Password for this proxy. #{ABSENT_DOC}" newvalues(/.*/, :absent) end newproperty(:s3_enabled) do desc "Access the repo via S3. #{YUM_BOOLEAN_DOC} #{ABSENT_DOC}" newvalues(YUM_BOOLEAN, :absent) end newproperty(:sslcacert) do desc "Path to the directory containing the databases of the certificate authorities yum should use to verify SSL certificates. #{ABSENT_DOC}" newvalues(/.*/, :absent) end newproperty(:sslverify) do desc "Should yum verify SSL certificates/hosts at all. #{YUM_BOOLEAN_DOC} #{ABSENT_DOC}" newvalues(YUM_BOOLEAN, :absent) end newproperty(:sslclientcert) do desc "Path to the SSL client certificate yum should use to connect to repos/remote sites. #{ABSENT_DOC}" newvalues(/.*/, :absent) end newproperty(:sslclientkey) do desc "Path to the SSL client key yum should use to connect to repos/remote sites. #{ABSENT_DOC}" newvalues(/.*/, :absent) end newproperty(:metalink) do desc "Metalink for mirrors. #{ABSENT_DOC}" newvalues(/.*/, :absent) validate do |value| next if value.to_s == 'absent' parsed = URI.parse(value) unless VALID_SCHEMES.include?(parsed.scheme) raise "Must be a valid URL" end end end newproperty(:skip_if_unavailable) do desc "Should yum skip this repository if unable to reach it. #{YUM_BOOLEAN_DOC} #{ABSENT_DOC}" newvalues(YUM_BOOLEAN, :absent) end end diff --git a/spec/unit/type/yumrepo_spec.rb b/spec/unit/type/yumrepo_spec.rb index a871217e8..543a0ce35 100644 --- a/spec/unit/type/yumrepo_spec.rb +++ b/spec/unit/type/yumrepo_spec.rb @@ -1,313 +1,381 @@ require 'spec_helper' require 'puppet' shared_examples_for "a yumrepo parameter that can be absent" do |param| it "can be set as :absent" do described_class.new(:name => 'puppetlabs', param => :absent) end it "can be set as \"absent\"" do described_class.new(:name => 'puppetlabs', param => 'absent') end end shared_examples_for "a yumrepo parameter that expects a natural value" do |param| it "accepts a valid positive integer" do instance = described_class.new(:name => 'puppetlabs', param => '12') expect(instance[param]).to eq '12' end it "rejects invalid negative integer" do expect { described_class.new( :name => 'puppetlabs', param => '-12' ) }.to raise_error(Puppet::ResourceError, /Parameter #{param} failed/) end it "rejects invalid non-integer" do expect { described_class.new( :name => 'puppetlabs', param => 'I\'m a six' ) }.to raise_error(Puppet::ResourceError, /Parameter #{param} failed/) end it "rejects invalid string with integers inside" do expect { described_class.new( :name => 'puppetlabs', param => 'I\'m a 6' ) }.to raise_error(Puppet::ResourceError, /Parameter #{param} failed/) end end shared_examples_for "a yumrepo parameter that expects a boolean parameter" do |param| valid_values = %w[True False 0 1 No Yes] valid_values.each do |value| it "accepts a valid value of #{value}" do instance = described_class.new(:name => 'puppetlabs', param => value) expect(instance[param]).to eq value end it "accepts #{value} downcased to #{value.downcase}" do instance = described_class.new(:name => 'puppetlabs', param => value.downcase) expect(instance[param]).to eq value.downcase end it "fails on valid value #{value} contained in another value" do expect { described_class.new( :name => 'puppetlabs', param => "bla#{value}bla" ) }.to raise_error(Puppet::ResourceError, /Parameter #{param} failed/) end end it "rejects invalid boolean values" do expect { described_class.new(:name => 'puppetlabs', param => 'flase') }.to raise_error(Puppet::ResourceError, /Parameter #{param} failed/) end end shared_examples_for "a yumrepo parameter that accepts a single URL" do |param| it "can accept a single URL" do described_class.new( :name => 'puppetlabs', param => 'http://localhost/yumrepos' ) end it "fails if an invalid URL is provided" do expect { described_class.new( :name => 'puppetlabs', param => "that's no URL!" ) }.to raise_error(Puppet::ResourceError, /Parameter #{param} failed/) end it "fails if a valid URL uses an invalid URI scheme" do expect { described_class.new( :name => 'puppetlabs', param => 'ldap://localhost/yumrepos' ) }.to raise_error(Puppet::ResourceError, /Parameter #{param} failed/) end end shared_examples_for "a yumrepo parameter that accepts multiple URLs" do |param| it "can accept multiple URLs" do described_class.new( :name => 'puppetlabs', param => 'http://localhost/yumrepos http://localhost/more-yumrepos' ) end it "fails if multiple URLs are given and one is invalid" do expect { described_class.new( :name => 'puppetlabs', param => "http://localhost/yumrepos That's no URL!" ) }.to raise_error(Puppet::ResourceError, /Parameter #{param} failed/) end end +shared_examples_for "a yumrepo parameter that accepts kMG units" do |param| + %w[k M G].each do |unit| + it "can accept an integer with #{unit} units" do + described_class.new( + :name => 'puppetlabs', + param => "123#{unit}" + ) + end + end + + it "fails if wrong unit passed" do + expect { + described_class.new( + :name => 'puppetlabs', + param => '123J' + ) + }.to raise_error(Puppet::ResourceError, /Parameter #{param} failed/) + end +end + describe Puppet::Type.type(:yumrepo) do it "has :name as its namevar" do expect(described_class.key_attributes).to eq [:name] end describe "validating" do describe "name" do it "is a valid parameter" do instance = described_class.new(:name => 'puppetlabs') expect(instance.name).to eq 'puppetlabs' end end describe "target" do it_behaves_like "a yumrepo parameter that can be absent", :target end describe "descr" do it_behaves_like "a yumrepo parameter that can be absent", :descr end describe "mirrorlist" do it_behaves_like "a yumrepo parameter that accepts a single URL", :mirrorlist it_behaves_like "a yumrepo parameter that can be absent", :mirrorlist end describe "baseurl" do it_behaves_like "a yumrepo parameter that can be absent", :baseurl it_behaves_like "a yumrepo parameter that accepts a single URL", :baseurl it_behaves_like "a yumrepo parameter that accepts multiple URLs", :baseurl end describe "enabled" do it_behaves_like "a yumrepo parameter that expects a boolean parameter", :enabled it_behaves_like "a yumrepo parameter that can be absent", :enabled end describe "gpgcheck" do it_behaves_like "a yumrepo parameter that expects a boolean parameter", :gpgcheck it_behaves_like "a yumrepo parameter that can be absent", :gpgcheck end describe "repo_gpgcheck" do it_behaves_like "a yumrepo parameter that expects a boolean parameter", :repo_gpgcheck it_behaves_like "a yumrepo parameter that can be absent", :repo_gpgcheck end describe "gpgkey" do it_behaves_like "a yumrepo parameter that can be absent", :gpgkey it_behaves_like "a yumrepo parameter that accepts a single URL", :gpgkey it_behaves_like "a yumrepo parameter that accepts multiple URLs", :gpgkey end describe "include" do it_behaves_like "a yumrepo parameter that can be absent", :include it_behaves_like "a yumrepo parameter that accepts a single URL", :include end describe "exclude" do it_behaves_like "a yumrepo parameter that can be absent", :exclude end describe "includepkgs" do it_behaves_like "a yumrepo parameter that can be absent", :includepkgs end describe "enablegroups" do it_behaves_like "a yumrepo parameter that expects a boolean parameter", :enablegroups it_behaves_like "a yumrepo parameter that can be absent", :enablegroups end describe "failovermethod" do %w[roundrobin priority].each do |value| it "accepts a value of #{value}" do described_class.new(:name => "puppetlabs", :failovermethod => value) end it "fails on valid value #{value} contained in another value" do expect { described_class.new( :name => 'puppetlabs', :failovermethod => "bla#{value}bla" ) }.to raise_error(Puppet::ResourceError, /Parameter failovermethod failed/) end end it "raises an error if an invalid value is given" do expect { described_class.new(:name => "puppetlabs", :failovermethod => "notavalidvalue") }.to raise_error(Puppet::ResourceError, /Parameter failovermethod failed/) end it_behaves_like "a yumrepo parameter that can be absent", :failovermethod end describe "keepalive" do it_behaves_like "a yumrepo parameter that expects a boolean parameter", :keepalive it_behaves_like "a yumrepo parameter that can be absent", :keepalive end describe "http_caching" do %w[packages all none].each do |value| it "accepts a valid value of #{value}" do described_class.new(:name => 'puppetlabs', :http_caching => value) end it "fails on valid value #{value} contained in another value" do expect { described_class.new( :name => 'puppetlabs', :http_caching => "bla#{value}bla" ) }.to raise_error(Puppet::ResourceError, /Parameter http_caching failed/) end end it "rejects invalid values" do expect { described_class.new(:name => 'puppetlabs', :http_caching => 'yes') }.to raise_error(Puppet::ResourceError, /Parameter http_caching failed/) end it_behaves_like "a yumrepo parameter that can be absent", :http_caching end describe "timeout" do it_behaves_like "a yumrepo parameter that can be absent", :timeout it_behaves_like "a yumrepo parameter that expects a natural value", :timeout end describe "metadata_expire" do it_behaves_like "a yumrepo parameter that can be absent", :metadata_expire it_behaves_like "a yumrepo parameter that expects a natural value", :metadata_expire + + it "accepts dhm units" do + %W[d h m].each do |unit| + described_class.new( + :name => 'puppetlabs', + :metadata_expire => "123#{unit}" + ) + end + end + + it "accepts never as value" do + described_class.new(:name => 'puppetlabs', :metadata_expire => 'never') + end end describe "protect" do it_behaves_like "a yumrepo parameter that expects a boolean parameter", :protect it_behaves_like "a yumrepo parameter that can be absent", :protect end describe "priority" do it_behaves_like "a yumrepo parameter that can be absent", :priority end describe "proxy" do it_behaves_like "a yumrepo parameter that can be absent", :proxy it_behaves_like "a yumrepo parameter that accepts a single URL", :proxy end describe "proxy_username" do it_behaves_like "a yumrepo parameter that can be absent", :proxy_username end describe "proxy_password" do it_behaves_like "a yumrepo parameter that can be absent", :proxy_password end describe "s3_enabled" do it_behaves_like "a yumrepo parameter that expects a boolean parameter", :s3_enabled it_behaves_like "a yumrepo parameter that can be absent", :s3_enabled end describe "skip_if_unavailable" do it_behaves_like "a yumrepo parameter that expects a boolean parameter", :skip_if_unavailable it_behaves_like "a yumrepo parameter that can be absent", :skip_if_unavailable end describe "sslcacert" do it_behaves_like "a yumrepo parameter that can be absent", :sslcacert end describe "sslverify" do it_behaves_like "a yumrepo parameter that expects a boolean parameter", :sslverify it_behaves_like "a yumrepo parameter that can be absent", :sslverify end describe "sslclientcert" do it_behaves_like "a yumrepo parameter that can be absent", :sslclientcert end describe "sslclientkey" do it_behaves_like "a yumrepo parameter that can be absent", :sslclientkey end describe "metalink" do it_behaves_like "a yumrepo parameter that can be absent", :metalink it_behaves_like "a yumrepo parameter that accepts a single URL", :metalink end + describe "cost" do it_behaves_like "a yumrepo parameter that can be absent", :cost it_behaves_like "a yumrepo parameter that expects a natural value", :cost end + + describe "throttle" do + it_behaves_like "a yumrepo parameter that can be absent", :throttle + it_behaves_like "a yumrepo parameter that expects a natural value", :throttle + it_behaves_like "a yumrepo parameter that accepts kMG units", :throttle + + it "accepts percentage as unit" do + described_class.new( + :name => 'puppetlabs', + :throttle => '123%' + ) + end + end + + describe "bandwidth" do + it_behaves_like "a yumrepo parameter that can be absent", :bandwidth + it_behaves_like "a yumrepo parameter that expects a natural value", :bandwidth + it_behaves_like "a yumrepo parameter that accepts kMG units", :bandwidth + end + + describe "gpgcakey" do + it_behaves_like "a yumrepo parameter that can be absent", :gpgcakey + it_behaves_like "a yumrepo parameter that accepts a single URL", :gpgcakey + end + + describe "retries" do + it_behaves_like "a yumrepo parameter that can be absent", :retries + it_behaves_like "a yumrepo parameter that expects a natural value", :retries + end + + describe "mirrorlist_expire" do + it_behaves_like "a yumrepo parameter that can be absent", :mirrorlist_expire + it_behaves_like "a yumrepo parameter that expects a natural value", :mirrorlist_expire + end end end