Skip to content

Commit

Permalink
Merge pull request #17 from ferventcoder/ticket/master/MODULES-3035-c…
Browse files Browse the repository at this point in the history
…onfig

(MODULES-3035) Manage configuration settings
  • Loading branch information
jpogran authored Jun 29, 2016
2 parents 930c598 + 7631c06 commit 00f9044
Show file tree
Hide file tree
Showing 14 changed files with 951 additions and 3 deletions.
88 changes: 86 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Travis | AppVeyor
* [Package provider: Chocolatey](#package-provider-chocolatey)
* [Chocolatey source configuration](#chocolateysource)
* [Chocolatey feature configuration](#chocolateyfeature)
* [Chocolatey config configuration](#chocolateyconfig)
* [Class: chocolatey](#class-chocolatey)
6. [Limitations - OS compatibility, etc.](#limitations)
* [Known Issues](#known-issues)
Expand Down Expand Up @@ -366,6 +367,57 @@ chocolateyfeature {'usefipscompliantchecksums':
}
~~~

#### Config Configuration
You can configure config values that Chocolatey has available. Run
`choco config list` to see the config settings available (just the
config settings section).

Requires Chocolatey v0.9.10.0+.

##### Set Cache Location

Cache location defaults to the TEMP directory. Set an explicit directory
to cache downloads to instead of the default.

~~~puppet
chocolateyconfig {'cachelocation':
value => "c:\\downloads",
}
~~~

##### Unset Cache Location

Remove cache location setting to go back to default.

~~~puppet
chocolateyconfig {'cachelocation':
ensure => absent,
}
~~~

##### Use an Explicit Proxy

When using Chocolatey behind a proxy, set `proxy` and optionally
`proxyUser`/`proxyPassword` as well.

**NOTE:** `proxyPassword` value is not verifiable.

~~~puppet
chocolateyconfig {'proxy':
value => 'https://someproxy.com',
}
chocolateyconfig {'proxyUser':
value => 'bob',
}
# not verifiable
chocolateyconfig {'proxyPassword':
value => 'securepassword',
}
~~~


### Packages

#### With All Options
Expand Down Expand Up @@ -553,8 +605,8 @@ What state the package should be in. You can choose which package to retrieve by
specifying a version number or `latest` as the ensure value. This defaults to
`installed`.

Valid options: `present` (also called `installed`), `absent`, `latest` or a version
number.
Valid options: `present` (also called `installed`), `absent`, `latest`,
`held` or a version number.

##### `install_options`
An array of additional options to pass when installing a package. These options are
Expand Down Expand Up @@ -686,6 +738,38 @@ What state the feature should be in.
Valid options: `enabled` or `disabled`.


### ChocolateyConfig
Allows managing config settings for Chocolatey. Configuration values
provide settings for users to configure aspects of Chocolatey and the
way it functions. Similar to features, except allow for user configured
values. Learn more about config settings at
[Config](https://chocolatey.org/docs/commands-config). Requires
Chocolatey v0.9.9.9+.

#### Properties/Parameters

##### `name`
(**Namevar**: If ommitted, this attribute's value will default to the resource's
title.)

The name of the config setting. Used for uniqueness. Puppet is not able to
easily manage any values that include Password in the key name in them as they
will be encrypted in the configuration file.

##### `ensure`
(**Property**: This attribute represents concrete state on the target system.)

What state the config should be in. This defaults to `present`.

Valid options: `present` or `absent`.

##### `value`
(**Property**: This attribute represents concrete state on the target system.)

The value of the config setting. If the name includes "password", then the value
is not ensurable due to being encrypted in the configuration file.


### Class: chocolatey

Used for managing installation and configuration of Chocolatey itself.
Expand Down
140 changes: 140 additions & 0 deletions lib/puppet/provider/chocolateyconfig/windows.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
require 'puppet/type'
require 'pathname'
require 'rexml/document'

Puppet::Type.type(:chocolateyconfig).provide(:windows) do
confine :operatingsystem => :windows
defaultfor :operatingsystem => :windows

require Pathname.new(__FILE__).dirname + '../../../' + 'puppet_x/chocolatey/chocolatey_common'
include PuppetX::Chocolatey::ChocolateyCommon

CONFIG_MINIMUM_SUPPORTED_CHOCO_VERSION = '0.9.10.0'

commands :chocolatey => PuppetX::Chocolatey::ChocolateyCommon.chocolatey_command

def initialize(value={})
super(value)
@property_flush = {}
end

def properties
if @property_hash.empty?
@property_hash = query || { :ensure => ( :absent )}
@property_hash[:ensure] = :absent if @property_hash.empty?
end
@property_hash.dup
end

def query
self.class.configs.each do |config|
return config.properties if @resource[:name][/\A\S*/].downcase == config.name.downcase
end

return {}
end

def self.get_configs
PuppetX::Chocolatey::ChocolateyCommon.set_env_chocolateyinstall

choco_config = PuppetX::Chocolatey::ChocolateyCommon.choco_config_file
raise Puppet::ResourceError, "Config file not found for Chocolatey. Please make sure you have Chocolatey installed." if choco_config.nil?
raise Puppet::ResourceError, "An install was detected, but was unable to locate config file at #{choco_config}." unless PuppetX::Chocolatey::ChocolateyCommon.file_exists?(choco_config)

Puppet.debug("Gathering sources from '#{choco_config}'.")
config = REXML::Document.new File.new(choco_config, 'r')

config.elements.to_a( '//add' )
end

def self.get_config(element)
config = {}
return config if element.nil?

config[:name] = element.attributes['key'] if element.attributes['key']
config[:value] = element.attributes['value'] if element.attributes['value']
config[:description] = element.attributes['description'] if element.attributes['description']

config[:ensure] = :present

Puppet.debug("Loaded config '#{config.inspect}'.")

config
end

def self.configs
@configs ||= get_configs.collect do |item|
config = get_config(item)
new(config)
end
end

def self.refresh_configs
@configs = nil
self.configs
end

def self.instances
configs
end

def self.prefetch(resources)
instances.each do |provider|
if (resource = resources[provider.name])
resource.provider = provider
end
end
end

def create
@property_flush[:ensure] = :present
end

def exists?
@property_hash[:ensure] == :present
end

def destroy
@property_flush[:ensure] = :absent
end

def validate
choco_version = Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version)
if choco_version < Gem::Version.new(CONFIG_MINIMUM_SUPPORTED_CHOCO_VERSION)
raise Puppet::ResourceError, "Chocolatey version must be '#{CONFIG_MINIMUM_SUPPORTED_CHOCO_VERSION}' to manage configuration values. Detected '#{choco_version}' as your version. Please upgrade Chocolatey."
end
end

mk_resource_methods

def flush
choco_version = Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version)

args = []
args << 'config'

command = 'set'
command = 'unset' if @property_flush[:ensure] == :absent

args << command
args << '--name' << resource[:name]

if @property_flush[:ensure] != :absent
args << '--value' << resource[:value]
end

begin
Puppet::Util::Execution.execute([command(:chocolatey), *args])
rescue Puppet::ExecutionFailure => e
raise Puppet::Error, "An error occurred running choco. Unable to set Chocolateyconfig[#{self.name}]: #{e}"
end

@property_hash.clear
@property_hash = { :ensure => ( @property_flush[:ensure] )}

@property_flush.clear

self.class.refresh_configs
@property_hash = query
end
end
85 changes: 85 additions & 0 deletions lib/puppet/type/chocolateyconfig.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
require 'puppet/type'
require 'pathname'

Puppet::Type.newtype(:chocolateyconfig) do

@doc = <<-'EOT'
Allows managing config settings for Chocolatey.
Configuration values provide settings for users
to configure aspects of Chocolatey and the way it
functions. Similar to features, except allow for user
configured values. Requires 0.9.10+. Learn more about
config at https://chocolatey.org/docs/commands-config
EOT

ensurable do
newvalue(:present) { provider.create }
newvalue(:absent) { provider.destroy }
defaultto :present

def retrieve
provider.properties[:ensure]
end

end

newparam(:name) do
desc "The name of the config setting. Used for uniqueness.
Puppet is not able to easily manage any values that
include Password in the key name in them as they
will be encrypted in the configuration file."

validate do |value|
if value.nil? or value.empty?
raise ArgumentError, "A non-empty name must be specified."
end
end

isnamevar

munge do |value|
value.downcase
end

def insync?(is)
is.downcase == should.downcase
end
end

newproperty(:value) do
desc "The value of the config setting. If the
name includes 'password', then the value is
not ensurable due to being encrypted in the
configuration file."

validate do |value|
if value.nil? or value.empty?
raise ArgumentError, "A non-empty value must be specified. To unset value, use ensure => absent"
end
end

def insync?(is)
if (resource[:name] =~ /password/i)
# If name contains password, it is
# always in sync if there is a value
return (is.nil? || is.empty?) == (should.nil? || should.empty?)
else
return is.downcase == should.downcase
end
end
end

validate do
if self[:ensure] != :absent
raise ArgumentError, "Unless ensure => absent, value is required." if self[:value].nil? || self[:value].empty?
end

if provider.respond_to?(:validate)
provider.validate
end
end

autorequire(:exec) do
['install_chocolatey_official']
end
end
Loading

0 comments on commit 00f9044

Please sign in to comment.