Merge branch 'master-forensics' into master-forensics-new

# Conflicts:
#	Gemfile
#	Gemfile.lock
This commit is contained in:
Jjk422
2017-04-13 17:01:16 +01:00
137 changed files with 8261 additions and 14 deletions

View File

@@ -11,6 +11,7 @@ gem 'rqrcode'
gem 'mini_exiftool_vendored'
gem 'rmagick'
gem 'sshkey'
gem 'sqlite3'
#development only gems go here
group :test, :development do

View File

@@ -56,6 +56,7 @@ GEM
spidr (0.6.0)
nokogiri (~> 1.3)
sshkey (1.9.0)
sqlite3 (1.3.13)
thor (0.19.1)
wordlist (0.1.1)
spidr (~> 0.2)
@@ -75,6 +76,7 @@ DEPENDENCIES
rake
rdoc
redcarpet
sqlite3
rmagick
rqrcode
sshkey
@@ -82,4 +84,4 @@ DEPENDENCIES
yard
BUNDLED WITH
1.14.3
1.14.5

View File

@@ -70,6 +70,14 @@ class XmlScenarioGenerator
xml.utility(selected_module.attributes_for_scenario_output) {
insert_inputs_and_values(selected_module,xml)
}
when 'forensic'
xml.forensic(selected_module.attributes_for_scenario_output) {
selected_module.received_inputs.each do |key,value|
xml.input({"into" => key}) {
xml.value value
}
end
}
when 'network'
xml.network(selected_module.attributes_for_scenario_output)
else

View File

@@ -31,6 +31,11 @@ class ModuleReader
return read_modules('utility', UTILITIES_DIR, UTILITY_SCHEMA_FILE, true)
end
# reads in all forensics
def self.read_forensics
return read_modules('forensic', FORENSICS_DIR, FORENSICS_SCHEMA_FILE, true)
end
# reads in all utilities
def self.read_generators
return read_modules('generator', GENERATORS_DIR, GENERATOR_SCHEMA_FILE, true)
@@ -147,7 +152,7 @@ class ModuleReader
# for each default input
doc.xpath("/#{module_type}/default_input").each do |inputs_doc|
inputs_doc.xpath('descendant::vulnerability | descendant::service | descendant::utility | descendant::network | descendant::base | descendant::encoder | descendant::generator').each do |module_node|
inputs_doc.xpath('descendant::vulnerability | descendant::service | descendant::utility | descendant::forensic | descendant::network | descendant::base | descendant::encoder | descendant::generator').each do |module_node|
# create a selector module, which is a regular module instance used as a placeholder for matching requirements
module_selector = Module.new(module_node.name)

View File

@@ -64,7 +64,7 @@ class SystemReader
end
# for each module selection
system_node.xpath('//vulnerability | //service | //utility | //build | //network | //base | //encoder | //generator').each do |module_node|
system_node.xpath('//vulnerability | //service | //utility | //forensic | //build | //network | //base | //encoder | //generator').each do |module_node|
# create a selector module, which is a regular module instance used as a placeholder for matching requirements
module_selector = Module.new(module_node.name)

View File

@@ -0,0 +1,30 @@
http://www.independent.co.uk/voices/aleppo-crisis-syrian-war-bashar-al-assad-isis-more-propaganda-than-news-a7479901.html
https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=14&ved=0ahUKEwj9ndTE0MHSAhUMmBoKHQrYB-4Q1ScIbjAN&url=http%3A%2F%2Fwww.independent.co.uk%2Fvoices%2Faleppo-crisis-syrian-war-bashar-al-assad-isis-more-propaganda-than-news-a7479901.html&usg=AFQjCNG6lQ4cMWcGWZ_m4rVrNbYp-mwoIg&bvm=bv.148747831,d.d2s&cad=rja
http://www.bbc.co.uk/news/uk-politics-32810887
https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=13&ved=0ahUKEwj9ndTE0MHSAhUMmBoKHQrYB-4Q1ScIbDAM&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews%2Fuk-politics-32810887&usg=AFQjCNEqQpbty5PU_3C4iiZw6AOoZP5rcQ&bvm=bv.148747831,d.d2s&cad=rja
https://www.theguardian.com/us-news/ng-interactive/2017/jan/20/donald-trump-first-100-days-president-daily-updates
http://www.express.co.uk/news
https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=11&ved=0ahUKEwj9ndTE0MHSAhUMmBoKHQrYB-4QFghjMAo&url=http%3A%2F%2Fwww.express.co.uk%2Fnews&usg=AFQjCNGiC2MV8fS-ERjk3lrYasD0xIDeWA&bvm=bv.148747831,d.d2s&cad=rja
https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=12&ved=0ahUKEwj9ndTE0MHSAhUMmBoKHQrYB-4Q1ScIajAL&url=https%3A%2F%2Fwww.theguardian.com%2Fus-news%2Fng-interactive%2F2017%2Fjan%2F20%2Fdonald-trump-first-100-days-president-daily-updates&usg=AFQjCNHand24H2PO66b0OFbQ-6ZYCOyqRA&bvm=bv.148747831,d.d2s&cad=rja
http://www.dailymail.co.uk/news/index.html
https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=10&ved=0ahUKEwj9ndTE0MHSAhUMmBoKHQrYB-4QFghdMAk&url=http%3A%2F%2Fwww.dailymail.co.uk%2Fnews%2Findex.html&usg=AFQjCNGeWFCOn7XJalTOjKGdVTeIQK_T8w&bvm=bv.148747831,d.d2s&cad=rja
https://www.google.co.uk/search?q=bbc+news&ie=utf-8&oe=utf-8&client=firefox-b-ab&gfe_rd=cr&ei=VDS9WKrJO9DCaOf6r5gI#q=news&*
http://www.bbc.co.uk/news/business-39175740
https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=8&ved=0ahUKEwjL95e-0MHSAhUJORoKHXXbCWcQqUMIPzAH&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews%2Fbusiness-39175740&usg=AFQjCNHTVX1eg93T6kfEoVO5WtqnB9ERGg&cad=rja
http://www.bbc.co.uk/news/uk-39176538
https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=7&ved=0ahUKEwjL95e-0MHSAhUJORoKHXXbCWcQqUMIOzAG&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews%2Fuk-39176538&usg=AFQjCNF1Lsgw73VzGWkAC9a-4t9fOHoB2A&cad=rja
http://www.bbc.co.uk/news/uk-39176110
http://www.bbc.co.uk/news/world
https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=6&ved=0ahUKEwjL95e-0MHSAhUJORoKHXXbCWcQqUMINzAF&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews%2Fuk-39176110&usg=AFQjCNH75QSNyOTErnsehKkHGwN5WxqgkA&cad=rja
https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=3&ved=0ahUKEwjL95e-0MHSAhUJORoKHXXbCWcQjBAILzAC&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews%2Fworld&usg=AFQjCNF5X_xXbi4RdS-n3YXetp2xyKOgZQ&cad=rja
http://www.bbc.co.uk/news/business
https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=5&ved=0ahUKEwjL95e-0MHSAhUJORoKHXXbCWcQjBAIMTAE&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews%2Fbusiness&usg=AFQjCNGbcH7S94Wc1xAlQpYi2mWNP2gLhg&cad=rja
http://www.bbc.co.uk/news/world/us_and_canada
https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=4&ved=0ahUKEwjL95e-0MHSAhUJORoKHXXbCWcQjBAILTAD&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews%2Fworld%2Fus_and_canada&usg=AFQjCNHfYWm_9x_ukbMz4b1vRFgm-PD5Pw&cad=rja
http://www.bbc.co.uk/news/uk
https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=2&ved=0ahUKEwjL95e-0MHSAhUJORoKHXXbCWcQjBAIKzAB&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews%2Fuk&usg=AFQjCNHuNSSR7R0oMF6unGocwTpv-iLAgQ&cad=rja
http://www.bbc.co.uk/news
https://www.google.co.uk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0ahUKEwjL95e-0MHSAhUJORoKHXXbCWcQFggjMAA&url=http%3A%2F%2Fwww.bbc.co.uk%2Fnews&usg=AFQjCNEonTvvrrbEptl1n_9nug5piXqeOQ&cad=rja
https://www.google.co.uk/search?q=bbc+news&ie=utf-8&oe=utf-8&client=firefox-b-ab&gfe_rd=cr&ei=VDS9WKrJO9DCaOf6r5gI
https://www.google.co.uk/?gws_rd=ssl
https://www.mozilla.org/en-US/firefox/51.0.1/firstrun/

View File

@@ -0,0 +1,168 @@
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.github/cliffe/SecGen/forensic"
xmlns="http://www.github/cliffe/SecGen/forensic"
elementFormDefault="qualified">
<xs:simpleType name="platformOptions">
<xs:restriction base="xs:string">
<xs:enumeration value="linux"/>
<xs:enumeration value="unix"/>
<xs:enumeration value="windows"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="forensic">
<xs:complexType>
<xs:sequence>
<!--required SecGen module details-->
<xs:element name="name" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="author" type="xs:string" minOccurs="1" maxOccurs="unbounded"/>
<xs:element name="module_license" minOccurs="1" maxOccurs="unbounded">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="MIT"/>
<xs:enumeration value="Apache v2"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="description" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="type" type="xs:string" minOccurs="1" maxOccurs="unbounded"/>
<xs:element name="platform" type="platformOptions" minOccurs="1" maxOccurs="1"/>
<!--optional details-->
<xs:element name="reference" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="software_name" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="software_license" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<!--I/O: a generator writes it's output to one fact & can also take inputs-->
<xs:element name="read_fact" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="default_input" type="InputElements" minOccurs="0" maxOccurs="unbounded" />
<!-- cannot co-exist with a system matching ALL of the optionally specified values (can be repeated for OR)-->
<xs:element name="conflict" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="module_path" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="name" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="author" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="module_license" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="type" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="platform" type="platformOptions" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="reference" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="software_name" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="software_license" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<!-- must co-exist with a system matching ALL of the optionally specified values (can be repeated for OR)-->
<!-- if a scenario does not include one already, the first match (randomly) found will be added before this module-->
<xs:element name="requires" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="module_path" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="name" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="author" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="module_license" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="description" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="type" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="platform" type="platformOptions" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="reference" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="software_name" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="software_license" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="InputElements">
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name='vulnerability' type='VulnerabilityType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='service' type='ServiceUtilityForensicEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='utility' type='ServiceUtilityForensicEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='network' type='NetworkType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='generator' type='ServiceUtilityForensicEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='encoder' type='ServiceUtilityForensicEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='value' type='xs:string' minOccurs='0' maxOccurs='unbounded' />
</xs:choice>
</xs:sequence>
<xs:attribute name='into' type='xs:string'/>
</xs:complexType>
<xs:complexType name="VulnerabilityType">
<xs:sequence>
<xs:element name="input" type="InputElements" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="module_path" type="xs:string"/>
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="author" type="xs:string"/>
<xs:attribute name="module_license" type="xs:string"/>
<xs:attribute name="description" type="xs:string"/>
<xs:attribute name="type" type="xs:string"/>
<xs:attribute name="privilege" type="xs:string"/>
<xs:attribute name="access" type="xs:string"/>
<xs:attribute name="platform" type="xs:string"/>
<!--optional vulnerability inputs-->
<xs:attribute name="read_fact" type="xs:string"/>
<!--optional vulnerability details-->
<xs:attribute name="difficulty" type="xs:string"/>
<xs:attribute name="cve" type="xs:string"/>
<xs:attribute name="cvss_base_score" type="xs:string"/>
<xs:attribute name="cvss_vector" type="xs:string"/>
<xs:attribute name="reference" type="xs:string"/>
<xs:attribute name="software_name" type="xs:string"/>
<xs:attribute name="software_license" type="xs:string"/>
<!--optional breadcrumb (info that is leaked and required to exploit)-->
<xs:attribute name="breadcrumb" type="xs:string"/>
<!--optional hints-->
<xs:attribute name="msf_module" type="xs:string"/>
<xs:attribute name="hint" type="xs:string"/>
<xs:attribute name="solution" type="xs:string"/>
</xs:complexType>
<xs:complexType name="ServiceUtilityForensicEncoderGeneratorType">
<xs:sequence>
<xs:element name="input" type="InputElements" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="module_path" type="xs:string"/>
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="author" type="xs:string"/>
<xs:attribute name="module_license" type="xs:string"/>
<xs:attribute name="description" type="xs:string"/>
<xs:attribute name="type" type="xs:string"/>
<xs:attribute name="platform" type="xs:string"/>
<xs:attribute name="reference" type="xs:string"/>
<xs:attribute name="software_name" type="xs:string"/>
<xs:attribute name="software_license" type="xs:string"/>
</xs:complexType>
<xs:complexType name="NetworkType">
<xs:attribute name="module_path" type="xs:string"/>
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="author" type="xs:string"/>
<xs:attribute name="module_license" type="xs:string"/>
<xs:attribute name="description" type="xs:string"/>
<xs:attribute name="type" type="xs:string"/>
<xs:attribute name='range' type='xs:string'/>
</xs:complexType>
</xs:schema>

View File

@@ -15,12 +15,13 @@
<xs:sequence>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name='vulnerability' type='VulnerabilityType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='service' type='ServiceUtilityBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='utility' type='ServiceUtilityBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='service' type='ServiceUtilityForensicBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='utility' type='ServiceUtilityForensicBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='forensic' type='ServiceUtilityForensicBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='network' type='NetworkType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='build' type='ServiceUtilityBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='generator' type='ServiceUtilityBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='encoder' type='ServiceUtilityBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='build' type='ServiceUtilityForensicBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='generator' type='ServiceUtilityForensicBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='encoder' type='ServiceUtilityForensicBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='value' type='xs:string' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='datastore' type='DatastoreType' minOccurs='0' maxOccurs='unbounded' />
</xs:choice>
@@ -43,9 +44,10 @@
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="input" type="InputElements" minOccurs="0" maxOccurs="unbounded" />
<xs:element name='vulnerability' type='VulnerabilityType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='service' type='ServiceUtilityBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='utility' type='ServiceUtilityBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='build' type='ServiceUtilityBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='service' type='ServiceUtilityForensicBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='utility' type='ServiceUtilityForensicBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='forensic' type='ServiceUtilityForensicBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='build' type='ServiceUtilityForensicBuildEncoderGeneratorType' minOccurs='0' maxOccurs='unbounded' />
<xs:element name='network' type='NetworkType' minOccurs='0' maxOccurs='unbounded' />
</xs:choice>
</xs:sequence>
@@ -104,7 +106,7 @@
<xs:attribute name="solution" type="xs:string"/>
</xs:complexType>
<xs:complexType name="ServiceUtilityBuildEncoderGeneratorType">
<xs:complexType name="ServiceUtilityForensicBuildEncoderGeneratorType">
<xs:sequence>
<xs:element name="input" type="InputElements" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>

View File

@@ -13,7 +13,7 @@ mod 'SecGen-secgen_functions', :path => '<%= SECGEN_FUNCTIONS_PUPPET_DIR %>'
<% @currently_processing_system.module_selections.each do |selected_module| -%>
<% case selected_module.module_type
when 'vulnerability', 'service', 'utility', 'build' -%>
when 'vulnerability', 'service', 'utility', 'build', 'forensic' -%>
mod 'SecGen-<%= selected_module.module_path_name %>/<%= selected_module.module_path_end %>', :path => '<%="#{ROOT_DIR}/#{selected_module.module_path}"%>'
<% end -%>
<% end -%>

View File

@@ -0,0 +1 @@
include internet_history_chrome::init

View File

@@ -0,0 +1,19 @@
class internet_history_chrome::init {
$user_account = 'vagrant'
$url_paths = ["https://www.offensive-security.com/backtrack/exploit-db-updates"]
# file { "C:\Users\{$user_account}\AppData\Roaming\Mozilla\Firefox\Profiles\{$mozilla_profile_number}.default\places.sqlite":
#
# }
# exec { "add-chrome-history":
# command => "",
# }
file { 'add-chrome-history':
ensure => 'present',
path => "C:/Users/$user_account/AppData/Local/Google/Chrome/User Data/Default/History",
content => template('evidence_windows_cybercrime_internet_history_chrome/insert_history.erb')
# content => inline_template('evidence_windows_cybercrime_internet_history_chrome/insert_history.erb')
}
}

View File

@@ -0,0 +1,41 @@
<?xml version="1.0"?>
<forensic xmlns="http://www.github/cliffe/SecGen/forensic"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.github/cliffe/SecGen/forensic">
<name>Internet history chrome</name>
<author>Jason Keighley</author>
<module_license>Apache v2</module_license>
<description>Create internet history for the Google Chrome browser</description>
<type>internet_artifacts</type>
<platform>windows</platform>
<!--optional details-->
<reference></reference>
<!--<read_fact>number_of_generic_urls</read_fact>-->
<!--<read_fact>number_of_cybercrime_urls</read_fact>-->
<read_fact>chrome_history_file</read_fact>
<default_input into="chrome_history_file">
<generator name="Chrome history file generator">
<input into="history_urls">
<generator name="Url generator"/>
</input>
</generator>
</default_input>
<!--<default_input into="number_of_generic_urls">-->
<!--<value>20</value>-->
<!--</default_input>-->
<!--<default_input into="number_of_cybercrime_urls">-->
<!--<value>1</value>-->
<!--</default_input>-->
<requires>
<name>Google Chrome install</name>
</requires>
</forensic>

View File

@@ -0,0 +1,28 @@
<% #require 'json'
#$secgen_parameters = JSON.parse(@json_inputs)
#$server_name = $secgen_parameters['server_name'].first
#$welcome_msg = $secgen_parameters['welcome_msg'].first
#
#if $secgen_parameters['url']
# $business_name = $secgen_parameters['business_name'].first
# $welcome_msg = "Welcome to the #{$business_name} FTP server!"
#end
require 'sqlite'
local_user = 'vagrant'
chrome_user = 'Default'
SQLite3::Database.new( "/media/user/3TB_internal_drive/Documents/SecGen/modules/forensics/windows/internet_artifacts/internet_history_chrome/files/History" ) do |db|
db.execute( "select * from urls" ) do |row|
puts row
end
db.execute(
"INSERT INTO urls(id, url, title, visit_count, typed_count, last_visit_time, hidden, favicon_id)
VALUES ('37', 'test_url', 'test_title', '1', '1', '1', '0', '0');"
)
db.execute( "select * from urls" ) do |row|
puts row
end
end
%>

View File

@@ -0,0 +1,17 @@
<% #puts "Hello World!" %>
<%
require 'sqlite3'
local_user = 'vagrant'
chrome_user = 'Default'
SQLite3::Database.new( "C:\\Users\\#{local_user}\\AppData\\Local\\Google\\Chrome\\User Data\\#{chrome_user}\\History" ) do |db|
db.execute( "select * from urls" ) do |row|
p row
end
db.execute(
"INSERT INTO urls(id, url, title, visit_count, typed_count, last_visit_time, hidden, favicon_id)
VALUES ('37', 'test_url', 'test_title', '1', '1', '1', '0', '0');"
)
end
%>

View File

@@ -0,0 +1,52 @@
#!/usr/bin/ruby
require_relative '../../../../../../lib/objects/local_string_generator.rb'
require 'date'
require 'sqlite3'
require 'fileutils'
# class ChromeHistoryFileGenerator < StringGenerator
# attr_accessor :history_urls
#
# def initialize
# super
# self.module_name = 'Chrome history file generator'
# self.history_urls = ''
# end
#
# def generate
local_user = 'vagrant'
chrome_user = 'Default'
history_urls = {
'url_test_1' => {:url => 'test1', :title => 'test1', :visit_count => '1', :typed_count => '1', :last_visit_time => 10, :hidden => '0', :favicon_id => '0'},
'url_test_2' => {:url => 'test2', :title => 'test2', :visit_count => '2', :typed_count => '2', :last_visit_time => 10, :hidden => '0', :favicon_id => '0'},
'url_test_3' => {:url => 'test3', :title => 'test3', :visit_count => '3', :typed_count => '3', :last_visit_time => 10, :hidden => '0', :favicon_id => '0'}
}
FileUtils.cp('../templates/History.source', '../templates/History')
database = SQLite3::Database.new( "../templates/History" ) do |db|
history_urls.each_value do |details|
db.execute(
"INSERT INTO urls(url, title, visit_count, typed_count, last_visit_time, hidden, favicon_id)
VALUES ('#{details[:url]}', '#{details[:title]}', '#{details[:visit_count]}', '#{details[:typed_count]}', '#{details[:last_visit_time]}', '#{details[:hidden]}', '#{details[:favicon_id]}');"
)
end
# db.execute( "select * from urls" ) do |row|
# puts row
# # p row
# end
# "INSERT INTO urls(url, title, visit_count, typed_count, last_visit_time, hidden, favicon_id)
# VALUES ('test_url', 'test_title', '1', '1', '1', '0', '0');"
end
# puts self.history_urls
#
# self.outputs << database
# end
# end
#
# ChromeHistoryFileGenerator.new.run

View File

@@ -0,0 +1,20 @@
<?xml version="1.0"?>
<generator xmlns="http://www.github/cliffe/SecGen/generator"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.github/cliffe/SecGen/generator">
<name>Chrome history file generator</name>
<author>Jason Keighley</author>
<module_license>Apache v2</module_license>
<description>Randomly selects urls from pool of crime urls dependent on inputted crime type.</description>
<type>internet_history_file_generator</type>
<platform>windows</platform>
<reference></reference>
<!-- Number of Urls of a given type. -->
<read_fact>history_urls</read_fact>
<output_type>urls</output_type>
</generator>

View File

@@ -0,0 +1,62 @@
#!/usr/bin/ruby
require_relative '../../../../../../lib/objects/local_string_generator.rb'
require 'date'
class UrlGenerator < StringGenerator
def initialize
super
self.module_name = 'Url generator'
self.number_of_generic_urls = '10'
self.generic_urls_start_time = '3rd july 2017'
self.number_of_cybercrime_urls = ''
self.cybercrime_urls_start_time = ''
end
def generate
urls = Hash.new
# number_of_generic_urls = 10
# generic_urls_start_time = '3rd july 2017 15:16:20'
# generic_urls_length_time = '2 days 1 hour 10 seconds'
# ROOT_DIR = File.expand_path('../../../../../../../',__FILE__)
# URLLISTS_DIR = "#{ROOT_DIR}/lib/resources/urllists"
# Generic filler urls
generic_urls = File.readlines("#{URLLISTS_DIR}/generic_urls").sample(self.number_of_generic_urls.to_int)
# Crime url start
# cybercrime_urls = File.readlines("#{URLLISTS_DIR}/cybercrime_urls").sample(self.number_of_cybercrime_urls).chomp
generic_urls.each do |url|
start_time = DateTime.parse(self.generic_urls_start_time)
# urls[url] = DateTime.new(
# rand(start_time.year..length_time.year + 1),
# rand(start_time.month..length_time.month + 1),
# rand(start_time.day..length_time.day + 1),
# rand(start_time.hour..length_time.hour + 1),
# rand(start_time.minute..length_time.minute + 1),
# rand(start_time.second..length_time.second + 1)
# )
# urls[url] = DateTime.new(
# rand(length_time.year - start_time.year),
# rand(length_time.month - start_time.month),
# rand(length_time.day - start_time.day),
# rand(length_time.hour - start_time.hour),
# rand(length_time.minute - start_time.minute),
# rand(length_time.second - start_time.second)
# )
urls[url] = { :url => url ,:title => 'test', :visit_count => '1', :typed_count => '1', :last_visit_time => start_time, :hidden => '0', :favicon_id => '0' }
end
puts urls
self.outputs << urls
end
end
UrlGenerator.new.run

View File

@@ -0,0 +1,21 @@
<?xml version="1.0"?>
<generator xmlns="http://www.github/cliffe/SecGen/generator"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.github/cliffe/SecGen/generator">
<name>Url generator</name>
<author>Jason Keighley</author>
<module_license>Apache v2</module_license>
<description>Randomly selects urls from pool of crime urls dependent on inputted crime type.</description>
<type>url_generator</type>
<platform>windows</platform>
<reference></reference>
<!-- Number of urls of a given type. -->
<read_fact>number_of_generic_urls</read_fact>
<read_fact>number_of_cybercrime_urls</read_fact>
<output_type>urls</output_type>
</generator>

View File

@@ -0,0 +1,10 @@
class python::install {
include chocolatey
notice('Installing python')
package { 'python':
ensure => installed,
provider => 'chocolatey',
}
}

View File

@@ -0,0 +1 @@
include python::install

View File

@@ -0,0 +1,20 @@
<?xml version="1.0"?>
<utility xmlns="http://www.github/cliffe/SecGen/utility"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.github/cliffe/SecGen/utility">
<name>Python programming language</name>
<author>Jason Keighley</author>
<module_license>Apache v2</module_license>
<description>A Python installation</description>
<type>languages</type>
<platform>windows</platform>
<!--optional details-->
<reference></reference>
<requires>
<name>Chocolatey install</name>
</requires>
</utility>

View File

@@ -0,0 +1,10 @@
class ruby::install {
include chocolatey
notice('Installing ruby')
package { 'ruby':
ensure => installed,
provider => 'chocolatey',
}
}

View File

@@ -0,0 +1 @@
include ruby::install

View File

@@ -0,0 +1,20 @@
<?xml version="1.0"?>
<utility xmlns="http://www.github/cliffe/SecGen/utility"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.github/cliffe/SecGen/utility">
<name>Ruby programming language</name>
<author>Jason Keighley</author>
<module_license>Apache v2</module_license>
<description>A Ruby installation</description>
<type>languages</type>
<platform>windows</platform>
<!--optional details-->
<reference></reference>
<requires>
<name>Chocolatey install</name>
</requires>
</utility>

View File

@@ -0,0 +1,172 @@
## 2016-12-30 Supported Release 2.0.1
### Summary
This is a bug fix release, correcting some issues in the original supported release and one that was introduced by the switchover to the puppetlabs-powershell v2 module.
### Bug Fixes
- Fix: ChocolateyInstall environment variable not set for alternate installation directory ([MODULES-4091](https://tickets.puppetlabs.com/browse/MODULES-4091))
- Fix: Unsuitable providers should not cause errors ([MODULES-4149](https://tickets.puppetlabs.com/browse/MODULES-4149))
- Fix: version is malformed with any extraneous messages ([MODULES-4135](https://tickets.puppetlabs.com/browse/MODULES-4135))
- Fix: module does not propagate null source error correctly ([MODULES-4056](https://tickets.puppetlabs.com/browse/MODULES-4056))
- Fix: install fails on Windows 10 when using built-in compression ([MODULES-4210](https://tickets.puppetlabs.com/browse/MODULES-4210))
### Improvements
- Set TLS 1.1+ when available
- Document considerations for install to "C:\Chocolatey" ([MODULES-4090](https://tickets.puppetlabs.com/browse/MODULES-4090))
## 2016-09-29 First Supported Release 2.0.0
### Summary
Puppetlabs-Chocolatey is now a supported module! This includes everything from the approved chocolatey-chocolatey module, plus the improvements in the unsupported releases 0.7.0 and 0.8.0. It also adds the following additional changes and fixes.
### Features
- `chocolateysource` - explicitly require location in ensure ([MODULES-3430](https://tickets.puppet.com/browse/MODULES-3430))
- set ignore package exit codes when Chocolatey is on version 0.9.10+ ([MODULES-3880](https://tickets.puppet.com/browse/MODULES-3880))
### Bug Fixes
- Fix: Ensure config file exists before `chocolateyfeature`, `chocolateyconfig`, or `chocolateysource` ([MODULES-3677](https://tickets.puppet.com/browse/MODULES-3677))
- Fix: `chocolateysource` - ensure flush when disabling source ([MODULES-3430](https://tickets.puppet.com/browse/MODULES-3430))
- Fix: `chocolateysource` - erroneous user sync messages ([MODULES-3758](https://tickets.puppet.com/browse/MODULES-3758))
## 2016-07-13 Unsupported Release 0.8.0
This brings the unsupported puppetlabs-chocolatey provider on par with the approved chocolatey-chocolatey at 1.2.6 and adds additional features.
* Includes community module releases up to 1.2.6 (changelog below).
* Manage features - `chocolateyfeature` - see [MODULES-3034](https://tickets.puppet.com/browse/MODULES-3034)
* Manage config settings - `chocolateyconfig` - see [MODULES-3035](https://tickets.puppet.com/browse/MODULES-3035)
## 2016-06-01 Unsupported Release 0.7.0
* Manage sources - `chocolateysource` - see [MODULES-3037](https://tickets.puppetlabs.com/browse/MODULES-3037)
* Includes community module releases up to 1.2.1 (changelog below up to 1.2.1), plus these additional fixes:
* $::chocolateyversion fact is optional - see [#110](https://github.com/chocolatey/puppet-chocolatey/issues/110)
* Fix: puppet apply works again - see [#105](https://github.com/chocolatey/puppet-chocolatey/issues/105)
# Approved Community Module Changelog - Chocolatey Team
The Chocolatey team has graciously agreed to allow Puppet to take this module
to the next level. Puppet will rerelease a supported module under the original
versioning scheme. For now we are using a number less than 1.0 to show that this
could have some technical issues and should be treated as a prerelease version.
## 2016-07-11 Release 1.2.6
- Fix - AutoUninstaller runs every time in 0.9.9.x [#134](https://github.com/chocolatey/puppet-chocolatey/issues/134)
## 2016-06-20 Release 1.2.5
- Support feature list changes in v0.9.10+ [#133](https://github.com/chocolatey/puppet-chocolatey/issues/133)
- Fix - Chocolatey fails to install in PowerShell v2 with PowerShell Module 1.x [#128](https://github.com/chocolatey/puppet-chocolatey/issues/128)
## 2016-06-04 Release 1.2.4
- Compatibility with puppetlabs-powershell 2.x [#125](https://github.com/chocolatey/puppet-chocolatey/issues/125).
## 2016-05-06 Release 1.2.3
- Do not call choco with --debug --verbose by default [#100](https://github.com/chocolatey/puppet-chocolatey/issues/100).
- Announce [Chocolatey for Business](https://chocolatey.org/compare) in ReadMe.
## 2016-05-06 Release 1.2.3
- Do not call choco with --debug --verbose by default [#100](https://github.com/chocolatey/puppet-chocolatey/issues/100).
- Announce Chocolatey for Business in ReadMe.
## 2016-04-06 Release 1.2.2
- Fix: puppet apply works again [#105](https://github.com/chocolatey/puppet-chocolatey/issues/105).
- `$::chocolateyversion` fact is optional - see [#110](https://github.com/chocolatey/puppet-chocolatey/issues/110)
- Fix: Implement PowerShell Redirection Fix for Windows 2008 / PowerShell v2 - see [#119](https://github.com/chocolatey/puppet-chocolatey/issues/119)
## 2015-12-08 Release 1.2.1
- Small release for support of newer PE versions.
##2015-11-03 Release 1.2.0
- Implement holdable ([#95](https://github.com/chocolatey/puppet-chocolatey/issues/95))
- Fix - Use install unless version specified in install ([#71](https://github.com/chocolatey/puppet-chocolatey/issues/71))
## 2015-10-02 Release 1.1.2
- Ensure 0.9.9.9 compatibility ([#94](https://github.com/chocolatey/puppet-chocolatey/issues/94))
- Fix - Mixed stale environment variables of existing choco install causing issues ([#86](https://github.com/chocolatey/puppet-chocolatey/issues/86))
- Upgrade From POSH Version of Chocolatey Fails from Puppet ([#60](https://github.com/chocolatey/puppet-chocolatey/issues/60))
## 2015-09-25 Release 1.1.1
- Add log_output for chocolatey bootstrap installer script
- Ensure bootstrap enforces chocolatey.nupkg in libs folder
- Allow file location for installing nupkg file.
## 2015-09-09 Release 1.1.0
- Install Chocolatey itself / ensure Chocolatey is installed (PUP-1691)
- Adds custom facts for chocolateyversion and choco_install_path
## 2015-07-23 Release 1.0.2
- Fixes [#71](https://github.com/chocolatey/puppet-chocolatey/issues/71) - Allow `ensure => $version` to work with already installed packages
## 2015-07-01 Release 1.0.1
- Fixes [#66](https://github.com/chocolatey/puppet-chocolatey/issues/66) - Check for choco existence more comprehensively
## 2015-06-08 Release 1.0.0
- No change, bumping to 1.0.0
## 2015-05-22 Release 0.5.3
- Fix manifest issue
- Fix choco path issue
- Update ReadMe - fix/clarify how options with quotes need to be passed.
## 2015-04-23 Release 0.5.2
- Update ReadMe
- Add support for Windows 10.
- Fixes [#56](https://github.com/chocolatey/puppet-chocolatey/pull/56) - Avoiding puppet returning 2 instead of 0 when there are no changes to be done.
## 2015-03-31 Release 0.5.1
- Fixes [#54](https://github.com/chocolatey/puppet-chocolatey/issues/54) - Blocking: Linux masters throw error if module is present
## 2015-03-30 Release 0.5.0
- Provider enhancements
- Better docs
- Works with both compiled and powershell Chocolatey clients
- Fixes #50 - work with newer compiled Chocolatey client (0.9.9+)
- Fixes #43 - check for installed packages is case sensitive
- Fixes #18 - The OS handle's position is not what FileStream expected.
- Fixes #52 - Document best way to pass options with spaces (#15 also related)
- Fixes #26 - Document Chocolatey needs to be installed by other means

View File

@@ -0,0 +1,219 @@
Checklist (and a short version for the impatient)
=================================================
* Commits:
- Make commits of logical units.
- Check for unnecessary whitespace with "git diff --check" before
committing.
- Commit using Unix line endings (check the settings around "crlf" in
git-config(1)).
- Do not check in commented out code or unneeded files.
- The first line of the commit message should be a short
description (50 characters is the soft limit, excluding ticket
number(s)), and should skip the full stop.
- Associate the issue in the message. The first line should include
the issue number in the form "(#XXXX) Rest of message".
- The body should provide a meaningful commit message, which:
- uses the imperative, present tense: "change", not "changed" or
"changes".
- includes motivation for the change, and contrasts its
implementation with the previous behavior.
- Make sure that you have tests for the bug you are fixing, or
feature you are adding.
- Make sure the test suites passes after your commit:
`bundle exec rspec spec/acceptance` More information on [testing](#Testing) below
- When introducing a new feature, make sure it is properly
documented in the README.md
* Submission:
* Pre-requisites:
- Make sure you have a [GitHub account](https://github.com/join)
- [Create a ticket](https://tickets.puppet.com/secure/CreateIssue!default.jspa), or [watch the ticket](https://tickets.puppet.com/browse/) you are patching for.
* Preferred method:
- Fork the repository on GitHub.
- Push your changes to a topic branch in your fork of the
repository. (the format ticket/1234-short_description_of_change is
usually preferred for this project).
- Submit a pull request to the repository in the puppetlabs
organization.
The long version
================
1. Make separate commits for logically separate changes.
Please break your commits down into logically consistent units
which include new or changed tests relevant to the rest of the
change. The goal of doing this is to make the diff easier to
read for whoever is reviewing your code. In general, the easier
your diff is to read, the more likely someone will be happy to
review it and get it into the code base.
If you are going to refactor a piece of code, please do so as a
separate commit from your feature or bug fix changes.
We also really appreciate changes that include tests to make
sure the bug is not re-introduced, and that the feature is not
accidentally broken.
Describe the technical detail of the change(s). If your
description starts to get too long, that is a good sign that you
probably need to split up your commit into more finely grained
pieces.
Commits which plainly describe the things which help
reviewers check the patch and future developers understand the
code are much more likely to be merged in with a minimum of
bike-shedding or requested changes. Ideally, the commit message
would include information, and be in a form suitable for
inclusion in the release notes for the version of Puppet that
includes them.
Please also check that you are not introducing any trailing
whitespace or other "whitespace errors". You can do this by
running "git diff --check" on your changes before you commit.
2. Sending your patches
To submit your changes via a GitHub pull request, we _highly_
recommend that you have them on a topic branch, instead of
directly on "master".
It makes things much easier to keep track of, especially if
you decide to work on another thing before your first change
is merged in.
GitHub has some pretty good
[general documentation](http://help.github.com/) on using
their site. They also have documentation on
[creating pull requests](http://help.github.com/send-pull-requests/).
In general, after pushing your topic branch up to your
repository on GitHub, you can switch to the branch in the
GitHub UI and click "Pull Request" towards the top of the page
in order to open a pull request.
3. Update the related GitHub issue.
If there is a GitHub issue associated with the change you
submitted, then you should update the ticket to include the
location of your branch, along with any other commentary you
may wish to make.
Testing
=======
Getting Started
---------------
Our puppet modules provide [`Gemfile`](./Gemfile)s which can tell a ruby
package manager such as [bundler](http://bundler.io/) what Ruby packages,
or Gems, are required to build, develop, and test this software.
Please make sure you have [bundler installed](http://bundler.io/#getting-started)
on your system, then use it to install all dependencies needed for this project,
by running
```shell
% bundle install
Fetching gem metadata from https://rubygems.org/........
Fetching gem metadata from https://rubygems.org/..
Using rake (10.1.0)
Using builder (3.2.2)
-- 8><-- many more --><8 --
Using rspec-system-puppet (2.2.0)
Using serverspec (0.6.3)
Using rspec-system-serverspec (1.0.0)
Using bundler (1.3.5)
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is installed.
```
NOTE some systems may require you to run this command with sudo.
If you already have those gems installed, make sure they are up-to-date:
```shell
% bundle update
```
With all dependencies in place and up-to-date we can now run the tests:
```shell
% rake spec
```
This will execute all the [rspec tests](http://rspec-puppet.com/) tests
under [spec/defines](./spec/defines), [spec/classes](./spec/classes),
and so on. rspec tests may have the same kind of dependencies as the
module they are testing. While the module defines in its [Modulefile](./Modulefile),
rspec tests define them in [.fixtures.yml](./fixtures.yml).
Some puppet modules also come with [beaker](https://github.com/puppetlabs/beaker)
tests. These tests spin up a virtual machine under
[VirtualBox](https://www.virtualbox.org/)) with, controlling it with
[Vagrant](http://www.vagrantup.com/) to actually simulate scripted test
scenarios. In order to run these, you will need both of those tools
installed on your system.
You can run them by issuing the following command
```shell
% rake spec_clean
% rspec spec/acceptance
```
This will now download a pre-fabricated image configured in the [default node-set](./spec/acceptance/nodesets/default.yml),
install puppet, copy this module and install its dependencies per [spec/spec_helper_acceptance.rb](./spec/spec_helper_acceptance.rb)
and then run all the tests under [spec/acceptance](./spec/acceptance).
Writing Tests
-------------
XXX getting started writing tests.
If you have commit access to the repository
===========================================
Even if you have commit access to the repository, you will still need to
go through the process above, and have someone else review and merge
in your changes. The rule is that all changes must be reviewed by a
developer on the project (that did not write the code) to ensure that
all changes go through a code review process.
Having someone other than the author of the topic branch recorded as
performing the merge is the record that they performed the code
review.
Additional Resources
====================
* [Getting additional help](http://puppet.com/community/get-help)
* [Writing tests](https://docs.puppet.com/guides/module_guides/bgtm.html#step-three-module-testing)
* [General GitHub documentation](http://help.github.com/)
* [GitHub pull request documentation](http://help.github.com/send-pull-requests/)

View File

@@ -0,0 +1,152 @@
#This file is generated by ModuleSync, do not edit.
source ENV['GEM_SOURCE'] || "https://rubygems.org"
# Determines what type of gem is requested based on place_or_version.
def gem_type(place_or_version)
if place_or_version =~ /^git:/
:git
elsif place_or_version =~ /^file:/
:file
else
:gem
end
end
# Find a location or specific version for a gem. place_or_version can be a
# version, which is most often used. It can also be git, which is specified as
# `git://somewhere.git#branch`. You can also use a file source location, which
# is specified as `file://some/location/on/disk`.
def location_for(place_or_version, fake_version = nil)
if place_or_version =~ /^(git[:@][^#]*)#(.*)/
[fake_version, { :git => $1, :branch => $2, :require => false }].compact
elsif place_or_version =~ /^file:\/\/(.*)/
['>= 0', { :path => File.expand_path($1), :require => false }]
else
[place_or_version, { :require => false }]
end
end
# Used for gem conditionals
supports_windows = true
# The following gems are not included by default as they require DevKit on Windows.
# You should probably include them in a Gemfile.local or a ~/.gemfile
#gem 'pry' #this may already be included in the gemfile
#gem 'pry-stack_explorer', :require => false
#if RUBY_VERSION =~ /^2/
# gem 'pry-byebug'
#else
# gem 'pry-debugger'
#end
group :development do
gem 'rake', :require => false
gem 'rspec', '~>3.0', :require => false
gem 'puppet-lint', :require => false
gem 'puppetlabs_spec_helper', '~>0.10.3', :require => false
gem 'puppet_facts', :require => false
gem 'mocha', '~>0.10.5', :require => false
gem 'pry', :require => false
gem 'json_pure', '<= 2.0.1', :require => false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0')
end
group :system_tests do
gem 'beaker', *location_for(ENV['BEAKER_VERSION'] || '~> 2.20')
gem 'master_manipulator', '~> 1.2', :require => false
gem 'beaker-windows', '~> 0.6', :require => false
gem 'beaker-hostgenerator', '~> 0.6', :require => false
end
gem 'puppet', *location_for(ENV['PUPPET_GEM_VERSION'])
# Only explicitly specify Facter/Hiera if a version has been specified.
# Otherwise it can lead to strange bundler behavior. If you are seeing weird
# gem resolution behavior, try setting `DEBUG_RESOLVER` environment variable
# to `1` and then run bundle install.
gem 'facter', *location_for(ENV['FACTER_GEM_VERSION']) if ENV['FACTER_GEM_VERSION']
gem 'hiera', *location_for(ENV['HIERA_GEM_VERSION']) if ENV['HIERA_GEM_VERSION']
# For Windows dependencies, these could be required based on the version of
# Puppet you are requiring. Anything greater than v3.5.0 is going to have
# Windows-specific dependencies dictated by the gem itself. The other scenario
# is when you are faking out Puppet to use a local file path / git path.
explicitly_require_windows_gems = false
puppet_gem_location = gem_type(ENV['PUPPET_GEM_VERSION'])
# This is not a perfect answer to the version check
if puppet_gem_location != :gem || (ENV['PUPPET_GEM_VERSION'] && Gem::Version.correct?(ENV['PUPPET_GEM_VERSION']) && Gem::Requirement.new('< 3.5.0').satisfied_by?(Gem::Version.new(ENV['PUPPET_GEM_VERSION'].dup)))
if Gem::Platform.local.os == 'mingw32'
explicitly_require_windows_gems = true
end
if puppet_gem_location == :gem
# If facterversion hasn't been specified and we are
# looking for a Puppet Gem version less than 3.5.0, we
# need to ensure we get a good Facter for specs.
gem "facter",">= 1.6.11","<= 1.7.5",:require => false unless ENV['FACTER_GEM_VERSION']
# If hieraversion hasn't been specified and we are
# looking for a Puppet Gem version less than 3.5.0, we
# need to ensure we get a good Hiera for specs.
gem "hiera",">= 1.0.0","<= 1.3.0",:require => false unless ENV['HIERA_GEM_VERSION']
end
end
if explicitly_require_windows_gems
# This also means Puppet Gem less than 3.5.0 - this has been tested back
# to 3.0.0. Any further back is likely not supported.
if puppet_gem_location == :gem
gem "ffi", "1.9.0", :require => false
gem "win32-eventlog", "0.5.3","<= 0.6.5", :require => false
gem "win32-process", "0.6.5","<= 0.7.5", :require => false
gem "win32-security", "~> 0.1.2","<= 0.2.5", :require => false
gem "win32-service", "0.7.2","<= 0.8.8", :require => false
gem "minitar", "0.5.4", :require => false
else
gem "ffi", "~> 1.9.0", :require => false
gem "win32-eventlog", "~> 0.5","<= 0.6.5", :require => false
gem "win32-process", "~> 0.6","<= 0.7.5", :require => false
gem "win32-security", "~> 0.1","<= 0.2.5", :require => false
gem "win32-service", "~> 0.7","<= 0.8.8", :require => false
gem "minitar", "~> 0.5.4", :require => false
end
gem "win32-dir", "~> 0.3","<= 0.4.9", :require => false
gem "win32console", "1.3.2", :require => false if RUBY_VERSION =~ /^1\./
# sys-admin was removed in Puppet 3.7.0+, and doesn't compile
# under Ruby 2.3 - so restrict it to Ruby 1.x
gem "sys-admin", "1.5.6", :require => false if RUBY_VERSION =~ /^1\./
# Puppet less than 3.7.0 requires these.
# Puppet 3.5.0+ will control the actual requirements.
# These are listed in formats that work with all versions of
# Puppet from 3.0.0 to 3.6.x. After that, these were no longer used.
# We do not want to allow newer versions than what came out after
# 3.6.x to be used as they constitute some risk in breaking older
# functionality. So we set these to exact versions.
gem "win32-api", "1.4.8", :require => false
gem "win32-taskscheduler", "0.2.2", :require => false
gem "windows-api", "0.4.3", :require => false
gem "windows-pr", "1.2.3", :require => false
else
if Gem::Platform.local.os == 'mingw32'
# If we're using a Puppet gem on windows, which handles its own win32-xxx gem dependencies (Pup 3.5.0 and above), set maximum versions
# Required due to PUP-6445
gem "win32-dir", "<= 0.4.9", :require => false
gem "win32-eventlog", "<= 0.6.5", :require => false
gem "win32-process", "<= 0.7.5", :require => false
gem "win32-security", "<= 0.2.5", :require => false
gem "win32-service", "<= 0.8.8", :require => false
end
end
# Evaluate Gemfile.local if it exists
if File.exists? "#{__FILE__}.local"
eval(File.read("#{__FILE__}.local"), binding)
end
# Evaluate ~/.gemfile if it exists
if File.exists?(File.join(Dir.home, '.gemfile'))
eval(File.read(File.join(Dir.home, '.gemfile')), binding)
end
# vim:ft=ruby

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,6 @@
## Maintenance
Maintainers:
- Puppet Windows Team `windows |at| puppet |dot| com`
Tickets: https://tickets.puppet.com/browse/MODULES. Make sure to set component to `chocolatey`.

View File

@@ -0,0 +1,783 @@
# Chocolatey Package Provider for Puppet
### Chocolatey for Business Now Available!
We're excited for you to learn more about what's available in the [Business editions](https://chocolatey.org/compare)!
## Build Status
Travis | AppVeyor
------------- | -------------
[![Build Status](https://api.travis-ci.org/puppetlabs/puppetlabs-chocolatey.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-chocolatey) | [![Build status](https://ci.appveyor.com/api/projects/status/uosorvcyhnayv70m/branch/master?svg=true)](https://ci.appveyor.com/project/puppetlabs/puppetlabs-chocolatey/branch/master)
#### Table of Contents
1. [Overview](#overview)
2. [Module Description - What the chocolatey module does and why it is useful](#module-description)
* [Why Chocolatey](#why-chocolatey)
3. [Setup - The basics of getting started with chocolatey](#setup)
* [What chocolatey affects](#what-chocolatey-affects)
* [Setup requirements](#setup-requirements)
* [Beginning with Chocolatey provider](#beginning-with-chocolatey-provider)
4. [Usage - Configuration options and additional functionality](#usage)
5. [Reference](#reference)
* [Classes](#public-classes)
* [Facts](#facts)
* [Types/Providers](#typesproviders)
* [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)
7. [Development - Guide for contributing to the module](#development)
8. [Attributions](#attributions)
## Overview
This is a [Puppet](http://docs.puppet.com/) package provider for
[Chocolatey](https://github.com/chocolatey/chocolatey), which is
like apt-get, but for Windows. Check the module's metadata.json for
compatible Puppet and Puppet Enterprise versions.
## Module Description
This is the official module for working with the [Chocolatey](https://chocolatey.org/about)
package manager.
This module supports all editions of Chocolatey, including FOSS, [Professional](https://chocolatey.org/compare) and [Chocolatey for Business](https://chocolatey.org/compare).
This module is able to:
* Install Chocolatey
* Work with custom location installations
* Configure Chocolatey
* Use Chocolatey as a package provider
### Why Chocolatey
Chocolatey closely mimics how package managers on other operating systems work. If you can imagine the built-in provider for
Windows versus Chocolatey, take a look at the use case of installing git:
~~~puppet
# Using built-in provider
package { "Git version 1.8.4-preview20130916":
ensure => installed,
source => 'C:\temp\Git-1.8.4-preview20130916.exe',
install_options => ['/VERYSILENT']
}
~~~
~~~puppet
# Using Chocolatey (set as default for Windows)
package { 'git':
ensure => latest,
}
~~~
With the built-in provider:
* The [package name must match ***exactly***](https://docs.puppet.com/puppet/latest/reference/resources_package_windows.html#package-name-must-be-the-displayname) the name from installed programs.
* The package name has issues with unicode characters.
* The [source must point to the location](https://docs.puppet.com/puppet/latest/reference/resources_package_windows.html#the-source-attribute-is-required) of the executable installer.
* It cannot `ensure => latest`. Read about [handling versions and upgrades](https://docs.puppet.com/puppet/latest/reference/resources_package_windows.html#handling-versions-and-upgrades) in the Puppet documentation.
With Chocolatey's provider:
* The package name only has to match the name of the package, which can be whatever you choose.
* The package knows how to install the software silently.
* The package knows where to get the executable installer.
* The source is able to specify different Chocolatey feeds.
* Chocolatey makes `package` more platform agnostic, because it looks exactly like other platforms.
For reference, read about the [provider features available](https://docs.puppet.com/references/latest/type.html#package-provider-features) from the built-in provider, compared to other package managers:
| Provider | holdable | install options | installable | package settings | purgeable | reinstallable | uninstall options | uninstallable | upgradeable | versionable | virtual packages |
|------------|----------|-----------------|-------------|------------------|-----------|---------------|-------------------|---------------|-------------|-------------|------------------|
| Windows | | x | x | | | | x | x | | x | |
| Chocolatey | x | x | x | | | | x | x | x | x | |
| apt | x | x | x | | x | | | x | x | x | |
| yum | | x | x | | x | | | x | x | x | x |
## Setup
### What Chocolatey affects
Chocolatey affects your system and what software is installed on it, ranging
from tools and portable software, to natively installed applications.
### Setup Requirements
Chocolatey requires the following components:
* Powershell v2+ (Installed on most systems by default)
* .NET Framework v4+
### Beginning with Chocolatey provider
Install this module via any of these approaches:
* [Puppet Forge](http://forge.puppet.com/chocolatey/chocolatey)
* git-submodule ([tutorial](http://goo.gl/e9aXh))
* [librarian-puppet](https://github.com/rodjek/librarian-puppet)
* [r10k](https://github.com/puppetlabs/r10k)
## Usage
### Manage Chocolatey installation
Ensure Chocolatey is installed and configured:
~~~puppet
include chocolatey
~~~
#### Override default Chocolatey install location
~~~puppet
class {'chocolatey':
choco_install_location => 'D:\secured\choco',
}
~~~
**NOTE:** This will affect suitability on first install. There are also
special considerations for `C:\Chocolatey` as an install location, see
[`choco_install_location`](#choco_install_location) for details.
#### Use an internal chocolatey.nupkg for Chocolatey installation
~~~puppet
class {'chocolatey':
chocolatey_download_url => 'https://internalurl/to/chocolatey.nupkg',
use_7zip => false,
choco_install_timeout_seconds => 2700,
}
~~~
#### Use a file chocolatey.0.9.9.9.nupkg for installation
~~~puppet
class {'chocolatey':
chocolatey_download_url => 'file:///c:/location/of/chocolatey.0.9.9.9.nupkg',
use_7zip => false,
choco_install_timeout_seconds => 2700,
}
~~~
#### Specify the version of chocolatey by class parameters
~~~puppet
class {'chocolatey':
chocolatey_download_url => 'file:///c:/location/of/chocolatey.0.9.9.9.nupkg',
use_7zip => false,
choco_install_timeout_seconds => 2700,
chocolatey_version => '0.9.9.9',
}
~~~
#### Log chocolatey bootstrap installer script output
~~~puppet
class {'chocolatey':
log_output => true,
}
~~~
### Configuration
If you have Chocolatey 0.9.9.x or above, you can take advantage of configuring different aspects of Chocolatey.
#### Sources Configuration
You can specify sources that Chocolatey uses by default, along with priority.
Requires Chocolatey v0.9.9.0+.
##### Disable the default community repository source
~~~puppet
chocolateysource {'chocolatey':
ensure => disabled,
}
~~~
##### Set a priority on a source
~~~puppet
chocolateysource {'chocolatey':
ensure => present,
location => 'https://chocolatey.org/api/v2',
priority => 1,
}
~~~
##### Add credentials to a source
~~~puppet
chocolateysource {'sourcename':
ensure => present,
location => 'https://internal/source',
user => 'username',
password => 'password',
}
~~~
**NOTE:** Chocolatey encrypts the password in a way that is not
verifiable. If you need to rotate passwords, you cannot use this
resource to do so unless you also change the location, user, or priority
(because those are ensurable properties).
#### Features Configuration
You can configure features that Chocolatey has available. Run
`choco feature list` to see the available configuration features.
Requires Chocolatey v0.9.9.0+.
##### Enable Auto Uninstaller
Uninstall from Programs and Features without requiring an explicit
uninstall script.
~~~puppet
chocolateyfeature {'autouninstaller':
ensure => enabled,
}
~~~
##### Disable Use Package Exit Codes
Requires 0.9.10+ for this feature.
**Use Package Exit Codes** - Allows package scripts to provide exit codes. With
this enabled, Chocolatey uses package exit codes for exit when
non-zero (this value can come from a dependency package). Chocolatey
defines valid exit codes as 0, 1605, 1614, 1641, 3010. With this feature
disabled, Chocolatey exits with a 0 or a 1 (matching previous behavior).
~~~puppet
chocolateyfeature {'usepackageexitcodes':
ensure => disabled,
}
~~~
##### Enable Virus Check
Requires 0.9.10+ and [Chocolatey Pro / Business](https://chocolatey.org/compare)
for this feature.
**Virus Check** - Performs virus checking on downloaded files. *(Licensed versions only.)*
~~~puppet
chocolateyfeature {'viruscheck':
ensure => enabled,
}
~~~
##### Enable FIPS Compliant Checksums
Requires 0.9.10+ for this feature.
**Use FIPS Compliant Checksums** - Ensures checksumming done by Chocolatey uses
FIPS compliant algorithms. *Not recommended unless required by FIPS Mode.*
Enabling on an existing installation could have unintended consequences
related to upgrades or uninstalls.
~~~puppet
chocolateyfeature {'usefipscompliantchecksums':
ensure => enabled,
}
~~~
#### 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
The cache location defaults to the TEMP directory. You can set an explicit directory
to cache downloads to instead of the default.
~~~puppet
chocolateyconfig {'cachelocation':
value => "c:\\downloads",
}
~~~
##### Unset cache location
Removes cache location setting, returning the setting to its default.
~~~puppet
chocolateyconfig {'cachelocation':
ensure => absent,
}
~~~
##### Use an explicit proxy
When using Chocolatey behind a proxy, set `proxy` and optionally
`proxyUser` and `proxyPassword`.
**NOTE:** The `proxyPassword` value is not verifiable.
~~~puppet
chocolateyconfig {'proxy':
value => 'https://someproxy.com',
}
chocolateyconfig {'proxyUser':
value => 'bob',
}
# not verifiable
chocolateyconfig {'proxyPassword':
value => 'securepassword',
}
~~~
#### Set Chocolatey as Default Windows Provider
If you want to set this provider as the site-wide default,
add to your `site.pp`:
~~~puppet
if $::kernel == 'windows' {
Package { provider => chocolatey, }
}
# OR
case $operatingsystem {
'windows': {
Package { provider => chocolatey, }
}
}
~~~
### Packages
#### With all options
~~~puppet
package { 'notepadplusplus':
ensure => installed|latest|'1.0.0'|absent,
provider => 'chocolatey',
install_options => ['-pre','-params','"','param1','param2','"'],
uninstall_options => ['-r'],
source => 'https://myfeed.example.com/api/v2',
}
~~~
* Supports `installable` and `uninstallable`.
* Supports `versionable` so that `ensure => '1.0'` works.
* Supports `upgradeable`.
* Supports `latest` (checks upstream), `absent` (uninstall).
* Supports `install_options` for pre-release, and other command-line options.
* Supports `uninstall_options` for pre-release, and other command-line options.
* Supports `holdable`, requires Chocolatey v0.9.9.0+.
#### Simple install
~~~puppet
package { 'notepadplusplus':
ensure => installed,
provider => 'chocolatey',
}
~~~
#### To always ensure using the newest version available
~~~puppet
package { 'notepadplusplus':
ensure => latest,
provider => 'chocolatey',
}
~~~
#### To ensure a specific version
~~~puppet
package { 'notepadplusplus':
ensure => '6.7.5',
provider => 'chocolatey',
}
~~~
#### To specify custom source
~~~puppet
package { 'notepadplusplus':
ensure => '6.7.5',
provider => 'chocolatey',
source => 'C:\local\folder\packages',
}
~~~
~~~puppet
package { 'notepadplusplus':
ensure => '6.7.5',
provider => 'chocolatey',
source => '\\unc\source\packages',
}
~~~
~~~puppet
package { 'notepadplusplus':
ensure => '6.7.5',
provider => 'chocolatey',
source => 'https://custom.nuget.odata.feed/api/v2/',
}
~~~
~~~puppet
package { 'notepadplusplus':
ensure => '6.7.5',
provider => 'chocolatey',
source => 'C:\local\folder\packages;https://chocolatey.org/api/v2/',
}
~~~
#### Install options with spaces
Spaces in arguments **must always** be covered with a separation. Shown
below is an example of how you configure `-installArgs "/VERYSILENT /NORESTART"`.
~~~puppet
package {'launchy':
ensure => installed,
provider => 'chocolatey',
install_options => ['-override', '-installArgs', '"', '/VERYSILENT', '/NORESTART', '"'],
}
~~~
#### Install options with quotes or spaces
The underlying installer may need quotes passed to it. This is possible, but not
as intuitive. The example below covers passing `/INSTALLDIR="C:\Program Files\somewhere"`.
For this to be passed through with Chocolatey, you need a set of double
quotes surrounding the argument and two sets of double quotes surrounding the
item that must be quoted (see [how to pass/options/switches](https://github.com/chocolatey/choco/wiki/CommandsReference#how-to-pass-options--switches)). This makes the
string look like `-installArgs "/INSTALLDIR=""C:\Program Files\somewhere"""` for
proper use with Chocolatey.
Then, for Puppet to handle that appropriately, you must split on ***every*** space.
Yes, on **every** space you must split the string or the result comes out
incorrectly. This means it will look like the following:
~~~puppet
install_options => ['-installArgs',
'"/INSTALLDIR=""C:\Program', 'Files\somewhere"""']
~~~
Make sure you have all of the right quotes - start it off with a single double
quote, then two double quotes, then close it all by closing the two double
quotes and then the single double quote or a possible three double quotes at
the end.
~~~puppet
package {'mysql':
ensure => latest,
provider => 'chocolatey',
install_options => ['-override', '-installArgs',
'"/INSTALLDIR=""C:\Program', 'Files\somewhere"""'],
}
~~~
You can split it up a bit for readability if it suits you:
~~~puppet
package {'mysql':
ensure => latest,
provider => 'chocolatey',
install_options => ['-override', '-installArgs', '"'
'/INSTALLDIR=""C:\Program', 'Files\somewhere""',
'"'],
}
~~~
**Note:** The above is for Chocolatey v0.9.9+. You may need to look for an
alternative method to pass args if you have 0.9.8.x and below.
## Reference
### Classes
#### Public classes
* [`chocolatey`](#class-chocolatey)
#### Private classes
* `chocolatey::install.pp`: Ensures Chocolatey is installed.
* `chocolatey::config.pp`: Ensures Chocolatey is configured.
### Facts
* `chocolateyversion` - The version of the installed Chocolatey client (could also be provided by class parameter `chocolatey_version`).
* `choco_install_path` - The location of the installed Chocolatey client (could also be provided by class parameter `choco_install_location`).
### Types/Providers
* [Chocolatey provider](#package-provider-chocolatey)
* [Chocolatey source configuration](#chocolateysource)
* [Chocolatey feature configuration](#chocolateyfeature)
### Package provider: Chocolatey
Chocolatey implements a [package type](http://docs.puppet.com/references/latest/type.html#package) with a resource provider, which is built into Puppet.
This provider supports the `install_options` and `uninstall_options` attributes,
which allow command-line options to be passed to the `choco` command. These options
should be specified as documented below.
* Required binaries: `choco.exe`, usually found in `C:\Program Data\chocolatey\bin\choco.exe`.
* The binary is searched for using the environment variable `ChocolateyInstall`, then by two known locations (`C:\Chocolatey\bin\choco.exe` and `C:\ProgramData\chocolatey\bin\choco.exe`).
* Supported features: `install_options`, `installable`, `uninstall_options`,
`uninstallable`, `upgradeable`, `versionable`.
**NOTE**: the root of `C:\` is not a secure location by default, so you may want to update the security on the folder.
#### Properties/Parameters
##### `ensure`
(**Property**: This attribute represents a concrete state on the target system.)
Specifies 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. Valid options: `present` (also called `installed`), `absent`, `latest`,
`held` or a version number. Default: `installed`.
##### `install_options`
Specifies an array of additional options to pass when installing a package. These options are
package-specific, and should be documented by the software vendor. One commonly
implemented option is `INSTALLDIR`:
~~~puppet
package {'launchy':
ensure => installed,
provider => 'chocolatey',
install_options => ['-installArgs', '"', '/VERYSILENT', '/NORESTART', '"'],
}
~~~
**NOTE:** The above method of single quotes in an array is the only method you should use
in passing `install_options` with the Chocolatey provider. There are other ways
to do it, but they are passed through to Chocolatey in ways that may not be
sufficient.
This is the **only** place in Puppet where backslash separators should be used.
Note that backslashes in double-quoted strings *must* be double-escaped and
backslashes in single-quoted strings *may* be double-escaped.
##### `name`
Specifies the package name. This is the name that the packaging system uses internally. Valid options: String. Default: The resource's title.
##### `provider`
**Required.** Sets the specific backend to use for the `package` resource. Chocolatey is not the
default provider for Windows, so it must be specified (or by using a resource
default, shown in the Usage section above). Valid options: `'chocolatey'`.
##### `source`
Specifies where to find the package file. Use this to override the default
source(s). Valid options: String of either an absolute path to a local
directory containing packages stored on the target system, a URL (to OData feeds), or a network
drive path. Chocolatey maintains default sources in its configuration file that it uses by default.
Puppet will not automatically retrieve source files for you, and
usually just passes the value of the source to the package installation command.
You can use a `file` resource if you need to manually copy package files to the
target system.
##### `uninstall_options`
Specifies an array of additional options to pass when uninstalling a package. These options
are package-specific, and should be documented by the software vendor.
~~~puppet
package {'launchy':
ensure => absent,
provider => 'chocolatey',
uninstall_options => ['-uninstallargs', '"', '/VERYSILENT', '/NORESTART', '"'],
}
~~~
The above method of single quotes in an array is the only method you should use
in passing `uninstall_options` with the Chocolatey provider. There are other ways
to do it, but they are passed to Chocolatey in ways that may not be
sufficient.
**NOTE:** This is the **only** place in Puppet where backslash separators should be used.
Backslashes in double-quoted strings *must* be double-escaped and
backslashes in single-quoted strings *may* be double-escaped.
### ChocolateySource
Allows managing default sources for Chocolatey. A source can be a folder, a CIFS share,
a NuGet Http OData feed, or a full Package Gallery. Learn more about sources at
[How To Host Feed](https://chocolatey.org/docs/how-to-host-feed). Requires
Chocolatey v0.9.9.0+.
#### Properties/Parameters
##### `name`
Specifies the name of the source. Used for uniqueness. Also sets the `location` to this value if `location` is unset. Valid options: String. Default: The resource's title.
##### `ensure`
(**Property**: This parameter represents a concrete state on the target system.)
Specifies what state the source should be in. Default: `present`. Valid options: `present`, `disabled`, or `absent`. `disabled` should only be used with existing sources.
##### `location`
(**Property**: This parameter represents a concrete state on the target system.)
Specifies the location of the source repository. Valid options: String of a URL pointing to an OData feed (such as chocolatey/chocolatey_server), a CIFS (UNC) share, or a local folder. Required when `ensure => present` (`present` is default value for `ensure`).
##### `user`
(**Property**: This parameter represents a concrete state on the target system.)
Specifies an optional user name for authenticated feeds. Requires at least Chocolatey v0.9.9.0. Default: `nil`. Specifying an empty value is the same as setting the value to `nil` or not specifying the property at all.
##### `password`
Specifies an optional user password for authenticated feeds. Not ensurable. Value cannot be checked with current value. If you need to update the password, update another setting as well to force the update. Requires at least Chocolatey v0.9.9.0. Default: `nil`. Specifying an empty value is the same as setting the value to `nil` or not specifying the property at all.
##### `priority`
(**Property**: This parameter represents a concrete state on the target system.)
Specifies an optional priority for explicit feed order when searching for packages across multiple feeds. The lower the number, the higher the priority. Sources with a 0 priority are considered no priority and are added after other sources with a priority number. Requires at least Chocolatey v0.9.9.9. Default: `0`.
### ChocolateyFeature
Allows managing features for Chocolatey. Features are configurations that
act as switches to turn on or off certain aspects of how
Chocolatey works. Learn more about features in the
[Chocolatey documentation](https://chocolatey.org/docs/commands-feature). Requires
Chocolatey v0.9.9.0+.
#### Properties/Parameters
##### `name`
Specifies the name of the feature. Used for uniqueness. Valid options: String. Default: The resource's title.
##### `ensure`
(**Property**: This parameter represents a concrete state on the target system.)
Specifies what state the feature should be in. Valid options: `enabled` or `disabled`. Default: `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 parameter's value will default to the resource's
title.)
Specifies 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 because they
will be encrypted in the configuration file.
##### `ensure`
(**Property**: This parameter represents a concrete state on the target system.)
Specifies what state the config should be in. Valid options: `present` or `absent`. Default: `present`.
##### `value`
(**Property**: This parameter represents a concrete state on the target system.)
Specifies 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
Manages installation and configuration of Chocolatey itself.
#### Parameters
##### `choco_install_location`
Specifies where Chocolatey install should be located. Valid options: Must be an absolute path starting with a drive letter, for example: `c:\`. Default: The currently detected install location based on the `ChocolateyInstall` environment variable. If not specified, falls back to `'C:\ProgramData\chocolatey'`.
**NOTE:** Puppet can install Chocolatey and configure Chocolatey install packages during the same run *UNLESS* you specify this setting. This is due to the way the providers search for suitability of the command, falling back to the default install for the executable when none is found. Because environment variables and commands do not refresh during the same Puppet run (due somewhat to a Windows limitation with updating environment information for currently running processes), installing to a directory that is not the default won't be detected until the next time Puppet runs. So unless you really want this installed elsewhere and don't have a current existing install in that non-default location, do not set this value.
Specifying `C:\Chocolatey` as the install directory will trigger Chocolatey to attempt to upgrade that directory. This is due to that location being the original install location for Chocolatey before it was moved to another directory and subsequently locked down. If you need this to be the installation directory, please define an environment variable `ChocolateyAllowInsecureRootDirectory` and set it to `'true'`. For more information, please see the [CHANGELOG for 0.9.9](https://github.com/chocolatey/choco/blob/master/CHANGELOG.md#099-march-3-2015).
If you override the default installation directory you need to set appropriate permissions on that install location, because Chocolatey does not restrict access to the custom directory to only Administrators. Chocolatey only restricts access to the directory in the default install location, to avoid permissions issues with custom locations, among other reasons. See ["Can I install Chocolatey to another location?"](https://chocolatey.org/install#can-i-install-chocolatey-to-another-location) for more information.
##### `use_7zip`
Specifies whether to use the built-in shell or allow the installer to download 7zip to extract `chocolatey.nupkg` during installation. Valid options: `true`, `false`. Default: `false`.
##### `choco_install_timeout_seconds`
Specifies how long in seconds should be allowed for the install of Chocolatey (including .NET Framework 4 if necessary). Valid options: Number. Default: `1500` (25 minutes).
##### `chocolatey_download_url`
Specifies the URL that returns `chocolatey.nupkg`. Valid options: String of URL, not necessarily from an OData feed. Any URL location will work, but it must result in the chocolatey nupkg file being downloaded. Default: `'https://chocolatey.org/api/v2/package/chocolatey/'`.
##### `enable_autouninstaller`
*Only for 0.9.9.x users. Chocolatey 0.9.10.x+ ignores this setting.* Specifies whether auto uninstaller is enabled. Auto uninstaller allows Chocolatey to automatically manage the uninstall of software from Programs and Features without necessarily requiring a `chocolateyUninstall.ps1` file in the package. Valid options: `true`, `false`. Default: `true`.
##### `log_output`
Specifies whether to log output from the installer. Valid options: `true`, `false`. Default: `false`.
## Limitations
1. Works with Windows only.
2. If you override an existing install location of Chocolatey using `choco_install_location =>` in the Chocolatey class, it does not bring any of the existing packages with it. You will need to handle that through some other means.
3. Overriding the install location will also not allow Chocolatey to be configured or install packages on the same run that it is installed on. See [`choco_install_location`](#choco_install_location) for details.
### Known Issues
1. This module doesn't support side by side scenarios.
2. This module may have issues upgrading Chocolatey itself using the package resource.
3. If .NET 4.0 is not installed, it may have trouble installing Chocolatey. Chocolatey version 0.9.9.9+ helps alleviate this issue.
4. If there is an error in the installer (`InstallChocolatey.ps1.erb`), it may not show as an error. This may be an issue with the PowerShell provider and is still under investigation.
## Development
Puppet Inc modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We cant access the huge number of platforms and myriad of hardware, software, and deployment configurations that Puppet is intended to serve.
We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things.
For more information, see our [module contribution guide.](https://docs.puppet.com/forge/contributing.html)
## Attributions
A special thanks goes out to [Rich Siegel](https://github.com/rismoney) and [Rob Reynolds](https://github.com/ferventcoder) who wrote the original
provider and continue to contribute to the development of this provider.

View File

@@ -0,0 +1,104 @@
require 'rake'
require 'rspec/core/rake_task'
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet'
begin
require 'beaker/tasks/test' unless RUBY_PLATFORM =~ /win32/
rescue LoadError
#Do nothing, only installed with system_tests group
end
# If puppet does not support symlinks (e.g., puppet <= 3.5) we cannot use
# puppetlabs_spec_helper's `rake spec` task because it requires symlink
# support. Redefine `rake spec` to avoid calling `rake spec_prep` (requires
# symlinks to place fixtures) and restrict the pattern match only files under
# the 'unit' directory (tests in other dirs require fixtures).
if Puppet::Util::Platform.windows? and !Puppet::FileSystem.respond_to?(:symlink)
ENV["SPEC"] = "./spec/{unit,integration}/**/*_spec.rb"
Rake::Task[:spec].clear if Rake::Task.task_defined?(:spec)
task :spec do
Rake::Task[:spec_standalone].invoke
Rake::Task[:spec_clean].invoke
end
end
# These lint exclusions are in puppetlabs_spec_helper but needs a version above 0.10.3
# Line length test is 80 chars in puppet-lint 1.1.0
PuppetLint.configuration.send('disable_80chars')
# Line length test is 140 chars in puppet-lint 2.x
PuppetLint.configuration.send('disable_140chars')
task :default => [:spec]
desc 'Generate code coverage'
RSpec::Core::RakeTask.new(:coverage) do |t|
t.rcov = true
t.rcov_opts = ['--exclude', 'spec']
end
platform = ENV["PLATFORM"]
# Create the directory, if it exists already you'll get an error, but this should not stop the execution
begin
sh 'mkdir tests/configs'
rescue => e
puts e.message
end
desc 'Executes reference tests (agent only) intended for use in CI'
task :reference_tests do
command = "bundle exec beaker-hostgenerator --global-config {masterless=true} #{platform} > tests/configs/#{platform}" # should we assume the "configs" directory is present?
sh command
command =<<-EOS
bundle exec beaker \
--debug \
--preserve-hosts never \
--config tests/configs/$PLATFORM \
--keyfile ~/.ssh/id_rsa-acceptance \
--load-path tests/lib \
--type aio \
--pre-suite tests/reference/pre-suite \
--tests tests/reference/tests
EOS
sh command
end
desc 'Executes acceptance tests (master and agent) intended for use in CI'
task :acceptance_tests do
command = "bundle exec beaker-hostgenerator #{platform} > tests/configs/#{platform}"
sh command
command =<<-EOS
bundle exec beaker \
--debug \
--preserve-hosts never \
--config tests/configs/$PLATFORM \
--keyfile ~/.ssh/id_rsa-acceptance \
--load-path tests/lib \
--pre-suite tests/acceptance/pre-suite \
--tests tests/acceptance/tests
EOS
sh command
end
task :acceptance_tests => [:basic_enviroment_variable_check, :acceptance_enviroment_varible_check]
task :reference_tests => [:basic_enviroment_variable_check]
task :basic_enviroment_variable_check do
abort('PLATFORM variable not present, aborting test.') unless ENV["PLATFORM"]
abort('MODULE_VERSION variable not present, aborting test.') unless ENV["MODULE_VERSION"]
end
task :acceptance_enviroment_varible_check do
if ENV["BEAKER_PE_DIR"] && ENV["PE_DIST_DIR"]
abort('Either BEAKER_PE_DIR or PE_DIST_DIR variable should be set but not both, aborting test.')
end
if !ENV["BEAKER_PE_DIR"] && !ENV["PE_DIST_DIR"]
abort('Neither BEAKER_PE_DIR or PE_DIST_DIR variable is set, aborting test.')
end
end

View File

@@ -0,0 +1,44 @@
version: 1.1.x.{build}
skip_commits:
message: /^\(?doc\)?.*/
clone_depth: 10
init:
- SET
- 'mkdir C:\ProgramData\PuppetLabs\code && exit 0'
- 'mkdir C:\ProgramData\PuppetLabs\facter && exit 0'
- 'mkdir C:\ProgramData\PuppetLabs\hiera && exit 0'
- 'mkdir C:\ProgramData\PuppetLabs\puppet\var && exit 0'
environment:
matrix:
- PUPPET_GEM_VERSION: ~> 3.0
RUBY_VER: 193
- PUPPET_GEM_VERSION: ~> 3.0
RUBY_VER: 200-x64
- PUPPET_GEM_VERSION: ~> 4.0
RUBY_VER: 21
- PUPPET_GEM_VERSION: ~> 4.0
RUBY_VER: 21-x64
- PUPPET_GEM_VERSION: ~> 4.0
RUBY_VER: 23
- PUPPET_GEM_VERSION: ~> 4.0
RUBY_VER: 23-x64
- PUPPET_GEM_VERSION: 3.0.0
RUBY_VER: 193
matrix:
fast_finish: true
install:
- SET PATH=C:\Ruby%RUBY_VER%\bin;%PATH%
- bundle install --jobs 4 --retry 2 --without system_tests
- type Gemfile.lock
build: off
test_script:
- bundle exec puppet -V
- ruby -v
- bundle exec rspec spec/unit -fd -b
notifications:
- provider: Email
to:
- nobody@nowhere.com
on_build_success: false
on_build_failure: false
on_build_status_changed: false

View File

@@ -0,0 +1,91 @@
{
"CHANGELOG.md": "ed75f911df877999ffe0b3d85c6d4c84",
"CONTRIBUTING.md": "2398672bb3e7c2a5ec11a9cea0f809e9",
"Gemfile": "e0713c9514c65b3bcce69e0b2bace8a7",
"LICENSE": "175792518e4ac015ab6696d16c4f607e",
"MAINTAINERS.md": "00d7777a4e0e4eed90437b4a972cdd6c",
"NOTICE": "267e1dc2b672516ff482a3fe8b857e2c",
"README.md": "a76ff6fb65c846cc273cb66333c2bbb5",
"Rakefile": "cde4be099ca764cc6bd7d706d2e37c90",
"appveyor.yml": "00752619ea15b8c6d287a7ae23a6c668",
"examples/init.pp": "1af719123c9af01ce6efd8de8465ad03",
"lib/facter/choco_install_path.rb": "36ece697e936cc950f8946ca2ac11729",
"lib/facter/chocolateyversion.rb": "ebbfc8535589aad01717852c93975ac3",
"lib/puppet/provider/chocolateyconfig/windows.rb": "048191d42df7e85cfc330569f500f88e",
"lib/puppet/provider/chocolateyfeature/windows.rb": "218b285cde1d86b2a530c194501de8d4",
"lib/puppet/provider/chocolateysource/windows.rb": "0d95da93a40c687a8a631d3c0c539609",
"lib/puppet/provider/package/chocolatey.rb": "80471c41d85faf45a521b5d8467fdd8b",
"lib/puppet/type/chocolateyconfig.rb": "1d86ef49b0faf6a321ea3ca24f9f39b1",
"lib/puppet/type/chocolateyfeature.rb": "1515df1d174d814ffc9bfff073a9051e",
"lib/puppet/type/chocolateysource.rb": "e2054da90dd124161fc64af9c11faf60",
"lib/puppet_x/chocolatey/chocolatey_common.rb": "03d3bf0cf1d2ef4a6843c3cd2e616c53",
"lib/puppet_x/chocolatey/chocolatey_install.rb": "e1e172d99659eb31882d64f88aacff60",
"lib/puppet_x/chocolatey/chocolatey_version.rb": "3155abe3c0a0b20770d322654c02e78d",
"manifests/config.pp": "307f680eb54988b9df8bd16e597a5843",
"manifests/init.pp": "984c562211c9bb0a7262531e1e5b2ef0",
"manifests/install.pp": "091c863df390704a9b01c2eb10c5b133",
"manifests/params.pp": "4a73fc3b0c6379551bdad6e5d3f357b4",
"metadata.json": "140403f7468691a05d49f54a52da9bc1",
"spec/classes/config_spec.rb": "8e6bb682200b29e2d622fa1d20e2a382",
"spec/classes/coverage_spec.rb": "5b6dfa0dd426aca0ccfae23c0a629f0b",
"spec/classes/init_spec.rb": "9d1316b761393c24fe7346aca679e69a",
"spec/classes/install_spec.rb": "76c2b4d46d8ddeac0d87ecb6612d58a4",
"spec/spec_helper.rb": "7adb146e2bdbb16f41786e325f33b1c5",
"spec/unit/facter/choco_install_path_spec.rb": "f23010110c2084aadc544b5c4d42c558",
"spec/unit/facter/chocolateyversion_spec.rb": "9ae92a85ed91c5f08edc7b8c4e8e53ac",
"spec/unit/puppet/provider/chocolateyconfig/windows_spec.rb": "ad562ea5608d75115d33111aca94b524",
"spec/unit/puppet/provider/chocolateyfeature/windows_spec.rb": "1e5bbb2cafae10e6a57b4c02f223ba80",
"spec/unit/puppet/provider/chocolateysource/windows_spec.rb": "1ad0760ce83a9590de51866f9f1de3d3",
"spec/unit/puppet/provider/package/chocolatey_spec.rb": "f6fdd633b4765f8ff0e0bc74bcd09769",
"spec/unit/puppet/type/chocolateyconfig_spec.rb": "b97b3604c59f9f8d011c4cd67cff4260",
"spec/unit/puppet/type/chocolateyfeature_spec.rb": "a2bf2e2fb8a45f8eefa43a0f289b0e40",
"spec/unit/puppet/type/chocolateysource_spec.rb": "1a71f966fac89b623decd08a401f08c6",
"spec/unit/puppet_x/chocolatey/chocolatey_common_spec.rb": "cb9087f4aa76641719bb5454fb474aa3",
"spec/unit/puppet_x/chocolatey/chocolatey_install_spec.rb": "5af79f6838ea628b1f55afcce1020279",
"spec/unit/puppet_x/chocolatey/chocolatey_version_spec.rb": "3f8e5abf71112d84a5be8ad096aad6ca",
"templates/InstallChocolatey.ps1.erb": "2adb1ce976d25907164b15cf1f16fd02",
"tests/acceptance/pre-suite/00_pe_install.rb": "cfe3fa761b0560792eacb872442dc9c7",
"tests/acceptance/pre-suite/01_chocolatey_module.install.rb": "9d11cc217d7f53ddffa36de7610c09b7",
"tests/acceptance/pre-suite/02_chocolatey_application_install.rb": "15205c3858c4d0a9c098541d9e0a7191",
"tests/acceptance/tests/hello.rb": "44c8a17a9a8ace86055fca4cf66d5a90",
"tests/lib/chocolatey_helper.rb": "c12b7e4bb5f06046bffc1031a866dd6b",
"tests/reference/pre-suite/00_install_certs.rb": "0814e2c5639947378749d0001ada530a",
"tests/reference/pre-suite/01_puppet_agent_install.rb": "34107ab52e53672aebe2f11b0759d9d3",
"tests/reference/pre-suite/02_chocolatey_module_install.rb": "515a96abf6a9660a113bcee882c7dd9c",
"tests/reference/pre-suite/03_chocolatey_application_install.rb": "33e65471ef20e5a34fdad72142c4a6b0",
"tests/reference/tests/chocolateyconfig/add_new_config_item.rb": "ca7e6cb60da8f6e41d1bb039a0f08af3",
"tests/reference/tests/chocolateyconfig/add_value_to_existing_config.rb": "407e1ea27b86a7e255f60330e7d3410e",
"tests/reference/tests/chocolateyconfig/change_config_value.rb": "3e6184e3a44a5ef3e82ac88e4c2da54b",
"tests/reference/tests/chocolateyconfig/ensure_config_value_with_password_in_name.rb": "c1171b2d053318df65af8fa7641b6334",
"tests/reference/tests/chocolateyconfig/fail_to_appy_bad_manifest.rb": "cc4261382302a4b18cbceedcb6bccdb1",
"tests/reference/tests/chocolateyconfig/fail_to_set_present_without_value.rb": "eb9093717f14d2102140d9a995321e60",
"tests/reference/tests/chocolateyconfig/remove_config_value_with_password_in_name.rb": "123e9d59bd3e1e449d0e9ec2eaae1f86",
"tests/reference/tests/chocolateyconfig/remove_value_from_config.rb": "1d4f7f8dc78e728b1d582e29845bc9d7",
"tests/reference/tests/chocolateyfeature/disable_disabled_feature.rb": "b0e6527d227f49b1baf67082891ab43e",
"tests/reference/tests/chocolateyfeature/disable_enabled_feature.rb": "201db0be084202704ec41967eda28865",
"tests/reference/tests/chocolateyfeature/enable_disabled_feature.rb": "87a8704e1c5b70bca03f1d2a715198b4",
"tests/reference/tests/chocolateyfeature/enable_enabled_feature.rb": "eedaf5068e428db99e409a3f912cae97",
"tests/reference/tests/chocolateyfeature/fail_to_enable_nonexistent_feature.rb": "8000a68d7ccb62e5f6b472facb7065a1",
"tests/reference/tests/chocolateyfeature/fail_to_remove_feature.rb": "aea6bb681d46924fe98d34295cf07807",
"tests/reference/tests/chocolateypackage/install_and_remove_good_package.rb": "b1a25035d4dad0ac42caeb1becfd56f1",
"tests/reference/tests/chocolateypackage/install_and_remove_good_package_utf-8.rb": "ea75ffbe326df41a35e4731fe08a3b61",
"tests/reference/tests/chocolateysource/add_priority_to_existing_source.rb": "c6788dd1224006c819549de936076be2",
"tests/reference/tests/chocolateysource/add_source_all_options.rb": "47c6aa9fc3f062e3fdc638b001051636",
"tests/reference/tests/chocolateysource/add_source_minimal.rb": "bbc7ed0b2d3faaae707872d6d73fdd09",
"tests/reference/tests/chocolateysource/add_source_normal.rb": "29fbe2335387aa97d54e994dffe26cae",
"tests/reference/tests/chocolateysource/add_user_pass_to_existing_source.rb": "e2cbd76cc086b16d1fde5a85ac7c1fb7",
"tests/reference/tests/chocolateysource/change_existing_priority.rb": "81f5bfe7f7f2d42ce0907abbf9513185",
"tests/reference/tests/chocolateysource/change_existing_source_location.rb": "afdadbae4c3373620eef0d23ff001716",
"tests/reference/tests/chocolateysource/change_user_pass.rb": "6e6af759af2de6429cd49d9c19564934",
"tests/reference/tests/chocolateysource/disable_existing_source.rb": "bf860a4876de665781735f370d23aa6f",
"tests/reference/tests/chocolateysource/disable_existing_source_two_runs.rb": "2ecb9c4b684ab92ba2af5ea8bdc3323d",
"tests/reference/tests/chocolateysource/fail_to_apply_source_without_location.rb": "7ebcb851a3402b93b8ca99dce2afacb6",
"tests/reference/tests/chocolateysource/fail_to_appy_bad_manifest.rb": "c81e640adf6b408db72dd2216819bfe9",
"tests/reference/tests/chocolateysource/fail_to_set_password_without_user.rb": "c27cbaadb8f2df3edebf4beca8aca73c",
"tests/reference/tests/chocolateysource/fail_to_set_user_without_password.rb": "2abfeb800092c7217d7e36dcbab75d78",
"tests/reference/tests/chocolateysource/remove_existing_source.rb": "e5fa96e486e522300e03270caf3bc613",
"tests/reference/tests/chocolateysource/remove_priority_from_existing_source.rb": "d49e25470cf51d9bc69d8670c0b600ad",
"tests/reference/tests/chocolateysource/remove_user_pass_from_existing_source.rb": "87920f736ad9958ce152944629292ffc",
"tests/test_run_scripts/acceptance_tests.sh": "d7bdd1185f73fd28389a6d60da0f0d69",
"tests/test_run_scripts/reference_tests.sh": "22220232bde40afa6c90fcdfc46943e0"
}

View File

@@ -0,0 +1 @@
include chocolatey

View File

@@ -0,0 +1,23 @@
# The baseline for module testing used by Puppet Labs is that each manifest
# should have a corresponding test manifest that declares that class or defined
# type.
#
# Tests are then run by using puppet apply --noop (to check for compilation errors
# and view a log of events) or by fully applying the test in a virtual environment
# (to compare the resulting system state to the desired state).
#
# Learn more about module testing here: http://docs.puppetlabs.com/guides/tests_smoke.html
#
# With symlinks on Windows, please run the following command an administrative command prompt (substituting the proper directories):
package { $pkg:
ensure => 'latest',
provider => 'chocolatey',
}
# mklink /D C:\ProgramData\PuppetLabs\puppet\etc\modules\chocolatey C:\code\puppetlabs\puppetlabs-chocolatey
# mklink /D C:\ProgramData\PuppetLabs\code\environments\production\modules\chocolatey C:\code\puppetlabs\puppetlabs-chocolatey
chocolateysource { 'local':
location => 'c:\packages',
}

View File

@@ -0,0 +1,9 @@
require 'pathname'
require Pathname.new(__FILE__).dirname + '../' + 'puppet_x/chocolatey/chocolatey_install'
Facter.add('choco_install_path') do
confine :osfamily => :windows
setcode do
PuppetX::Chocolatey::ChocolateyInstall.install_path || 'C:\ProgramData\chocolatey'
end
end

View File

@@ -0,0 +1,9 @@
require 'pathname'
require Pathname.new(__FILE__).dirname + '../' + 'puppet_x/chocolatey/chocolatey_version'
Facter.add('chocolateyversion') do
confine :osfamily => :windows
setcode do
PuppetX::Chocolatey::ChocolateyVersion.version || '0'
end
end

View File

@@ -0,0 +1,144 @@
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 PuppetX::Chocolatey::ChocolateyCommon.file_exists?(PuppetX::Chocolatey::ChocolateyCommon.chocolatey_command) && 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'
# look at the hash, then flush if present.
# If all else fails, looks at resource[:ensure]
property_ensure = @property_hash[:ensure]
property_ensure = @property_flush[:ensure] if @property_flush[:ensure]
property_ensure = resource[:ensure] if property_ensure.nil?
command = 'set'
command = 'unset' if property_ensure == :absent
args << command
args << '--name' << resource[:name]
if property_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_flush.clear
self.class.refresh_configs
@property_hash = query
end
end

View File

@@ -0,0 +1,126 @@
require 'puppet/type'
require 'pathname'
require 'rexml/document'
Puppet::Type.type(:chocolateyfeature).provide(:windows) do
confine :operatingsystem => :windows
defaultfor :operatingsystem => :windows
require Pathname.new(__FILE__).dirname + '../../../' + 'puppet_x/chocolatey/chocolatey_common'
include PuppetX::Chocolatey::ChocolateyCommon
FEATURE_MINIMUM_SUPPORTED_CHOCO_VERSION = '0.9.9.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
end
@property_hash.dup
end
def query
self.class.features.each do |feature|
return feature.properties if @resource[:name][/\A\S*/].downcase == feature.name.downcase
end
return {}
end
def self.get_features
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 features from '#{choco_config}'.")
config = REXML::Document.new File.new(choco_config, 'r')
config.elements.to_a( '//feature' )
end
def self.get_feature(element)
feature = {}
return feature if element.nil?
feature[:name] = element.attributes['name'].downcase if element.attributes['name']
feature[:description] = element.attributes['description'].downcase if element.attributes['description']
enabled = false
enabled = element.attributes['enabled'].downcase == 'true' if element.attributes['enabled']
feature[:ensure] = :disabled
feature[:ensure] = :enabled if enabled
Puppet.debug("Loaded feature '#{feature.inspect}'.")
feature
end
def self.features
get_features.collect do |item|
feature = get_feature(item)
new(feature)
end
end
def self.instances
features
end
def self.prefetch(resources)
instances.each do |provider|
if (resource = resources[provider.name])
resource.provider = provider
end
end
end
def enable
@property_flush[:ensure] = :enabled
end
def exists?
@property_hash[:ensure] == :enabled
end
def disable
@property_flush[:ensure] = :disabled
end
def validate
choco_version = Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version)
if PuppetX::Chocolatey::ChocolateyCommon.file_exists?(PuppetX::Chocolatey::ChocolateyCommon.chocolatey_command) && choco_version < Gem::Version.new(FEATURE_MINIMUM_SUPPORTED_CHOCO_VERSION)
raise Puppet::ResourceError, "Chocolatey version must be '#{FEATURE_MINIMUM_SUPPORTED_CHOCO_VERSION}' to manage configuration values with Puppet. Detected '#{choco_version}' as your version. Please upgrade Chocolatey to use this resource."
end
end
mk_resource_methods
def flush
args = []
args << 'feature'
command = 'enable'
command = 'disable' if @property_flush[:ensure] == :disabled
args << command
args << '--name' << resource[:name]
Puppet::Util::Execution.execute([command(:chocolatey), *args])
@property_hash.clear
@property_flush.clear
self.class.features
@property_hash = query
end
end

View File

@@ -0,0 +1,197 @@
require 'puppet/type'
require 'pathname'
require 'rexml/document'
Puppet::Type.type(:chocolateysource).provide(:windows) do
confine :operatingsystem => :windows
defaultfor :operatingsystem => :windows
require Pathname.new(__FILE__).dirname + '../../../' + 'puppet_x/chocolatey/chocolatey_common'
include PuppetX::Chocolatey::ChocolateyCommon
MINIMUM_SUPPORTED_CHOCO_VERSION = '0.9.9.0'
MINIMUM_SUPPORTED_CHOCO_VERSION_PRIORITY = '0.9.9.9'
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.sources.each do |source|
return source.properties if @resource[:name][/\A\S*/].downcase == source.name.downcase
end
return {}
end
def self.get_sources
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( '//source' )
end
def self.get_source(element)
source = {}
return source if element.nil?
source[:name] = element.attributes['id'].downcase if element.attributes['id']
source[:location] = element.attributes['value'].downcase if element.attributes['value']
disabled = false
disabled = element.attributes['disabled'].downcase == 'true' if element.attributes['disabled']
source[:ensure] = :present
source[:ensure] = :disabled if disabled
source[:priority] = 0
source[:priority] = element.attributes['priority'].downcase if element.attributes['priority']
source[:user] = ''
source[:user] = element.attributes['user'].downcase if element.attributes['user']
Puppet.debug("Loaded source '#{source.inspect}'.")
source
end
def self.sources
@sources ||= get_sources.collect do |item|
source = get_source(item)
new(source)
end
end
def self.refresh_sources
@sources = nil
self.sources
end
def self.instances
sources
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 disable
@property_flush[:ensure] = :disabled
end
def destroy
@property_flush[:ensure] = :absent
end
def validate
choco_version = Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version)
if PuppetX::Chocolatey::ChocolateyCommon.file_exists?(PuppetX::Chocolatey::ChocolateyCommon.chocolatey_command) && choco_version < Gem::Version.new(MINIMUM_SUPPORTED_CHOCO_VERSION)
raise Puppet::ResourceError, "Chocolatey version must be '#{MINIMUM_SUPPORTED_CHOCO_VERSION}' to manage configuration values with Puppet. Detected '#{choco_version}' as your version. Please upgrade Chocolatey to use this resource."
end
if choco_version < Gem::Version.new(MINIMUM_SUPPORTED_CHOCO_VERSION_PRIORITY) && resource[:priority] && resource[:priority] != 0
Puppet.warning("Chocolatey is unable to manage priority for sources when version is less than #{MINIMUM_SUPPORTED_CHOCO_VERSION_PRIORITY}. The value you set will be ignored.")
end
# location is always filled in with puppet resource, but
# resource[:location] is always empty (because it has a different
# code path where validation occurs before all properties/params
# have been set), resulting in errors
# location is always :absent when a manifest runs this with a missing
# `location => value`
location_check = location
# location could be :absent, which mk_resource_method will set it to
# resource[:location] is nil when running puppet resource
# if you remove `location => value`
location_check = resource[:location] if location_check == :absent
if (resource[:ensure] == :present && (location_check.nil? || location_check.strip == ''))
raise ArgumentError, "A non-empty location must be specified when ensure => present."
end
if resource[:password] && resource[:password] != ''
Puppet.debug("The password is not ensurable, so Puppet is unable to change the value using chocolateysource resource. As a workaround, a password change can be in the form of an exec. Reference Chocolateysource[#{resource[:name]}]")
end
end
mk_resource_methods
def flush
args = []
args << 'source'
# look at the hash, then flush if present.
# If all else fails, looks at resource[:ensure]
property_ensure = @property_hash[:ensure]
property_ensure = @property_flush[:ensure] if @property_flush[:ensure]
property_ensure = resource[:ensure] if property_ensure.nil?
command = 'add'
command = 'remove' if property_ensure == :absent
command = 'disable' if property_ensure == :disabled
args << command
args << '--name' << resource[:name]
if command == 'add'
args << '--source' << resource[:location]
if resource[:user] && resource[:user] != ''
args << '--user' << resource[:user]
args << '--password' << resource[:password]
end
choco_gem_version = Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version)
if choco_gem_version >= Gem::Version.new(MINIMUM_SUPPORTED_CHOCO_VERSION_PRIORITY)
args << '--priority' << resource[:priority]
end
end
begin
Puppet::Util::Execution.execute([command(:chocolatey), *args])
rescue Puppet::ExecutionFailure
raise Puppet::Error, "An error occurred running choco. Unable to set Chocolatey source configuration for #{self.inspect}"
end
if property_ensure == :present
begin
Puppet::Util::Execution.execute([command(:chocolatey), 'source', 'enable', '--name', resource[:name]])
rescue Puppet::ExecutionFailure
raise Puppet::Error, "An error occurred running choco. Unable to set Chocolatey source configuration for #{self.inspect}"
end
end
@property_hash.clear
@property_flush.clear
self.class.refresh_sources
@property_hash = query
end
end

View File

@@ -0,0 +1,280 @@
require 'puppet/provider/package'
require 'pathname'
require Pathname.new(__FILE__).dirname + '../../../' + 'puppet_x/chocolatey/chocolatey_install'
Puppet::Type.type(:package).provide(:chocolatey, :parent => Puppet::Provider::Package) do
desc "Manages packages using Chocolatey (Windows package manager).
The syntax for Chocolatey using the puppet provider is a much
closer match to *nix package managers, bringing a more agnostic
approach to package management across platforms. Chocolatey packages
usually contain all of the logic to install software silently on a
Windows machine, much like RPM (yum) or DPKG (apt).
Installs can be as simple as
package {'git':
ensure => latest,
}
See the ReadMe for more information."
confine :operatingsystem => :windows
has_feature :installable
has_feature :uninstallable
has_feature :upgradeable
has_feature :versionable
has_feature :install_options
has_feature :uninstall_options
has_feature :holdable
#has_feature :package_settings
require Pathname.new(__FILE__).dirname + '../../../' + 'puppet_x/chocolatey/chocolatey_common'
include PuppetX::Chocolatey::ChocolateyCommon
commands :chocolatey => PuppetX::Chocolatey::ChocolateyCommon.chocolatey_command
def initialize(value={})
super(value)
end
def print()
notice("The value is: '${name}'")
end
def self.is_compiled_choco?
Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version) >= Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon::FIRST_COMPILED_CHOCO_VERSION)
end
def is_compiled_choco?
self.class.is_compiled_choco?
end
def install
PuppetX::Chocolatey::ChocolateyCommon.set_env_chocolateyinstall
choco_exe = is_compiled_choco?
# always unhold on install
unhold if choco_exe
args = []
# also will need to address -sidebyside or -m in the install args to allow
# multiple versions to be installed.
args << 'install'
should = @resource.should(:ensure)
case should
when true, false, Symbol
args << @resource[:name][/\A\S*/]
else
args.clear
if choco_exe
args << 'upgrade'
else
args << 'update'
end
# Add the package version
args << @resource[:name][/\A\S*/] << '-version' << @resource[:ensure]
end
if choco_exe
args << '-y'
end
if @resource[:source]
args << '-source' << @resource[:source]
end
args << @resource[:install_options]
if Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version) >= Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon::MINIMUM_SUPPORTED_CHOCO_VERSION_EXIT_CODES)
args << '--ignore-package-exit-codes'
end
chocolatey(*args)
end
def uninstall
PuppetX::Chocolatey::ChocolateyCommon.set_env_chocolateyinstall
choco_exe = is_compiled_choco?
# always unhold on uninstall
unhold if choco_exe
args = 'uninstall', @resource[:name][/\A\S*/]
if choco_exe
args << '-fy'
end
choco_version = Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version)
if !choco_exe || choco_version >= Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon::MINIMUM_SUPPORTED_CHOCO_UNINSTALL_SOURCE)
if @resource[:source]
args << '-source' << @resource[:source]
end
end
args << @resource[:uninstall_options]
if Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version) >= Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon::MINIMUM_SUPPORTED_CHOCO_VERSION_EXIT_CODES)
args << '--ignore-package-exit-codes'
end
chocolatey(*args)
end
def update
PuppetX::Chocolatey::ChocolateyCommon.set_env_chocolateyinstall
choco_exe = is_compiled_choco?
# always unhold on upgrade
unhold if choco_exe
if choco_exe
args = 'upgrade', @resource[:name][/\A\S*/], '-y'
else
args = 'update', @resource[:name][/\A\S*/]
end
if @resource[:source]
args << '-source' << @resource[:source]
end
args << @resource[:install_options]
if Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon.choco_version) >= Gem::Version.new(PuppetX::Chocolatey::ChocolateyCommon::MINIMUM_SUPPORTED_CHOCO_VERSION_EXIT_CODES)
args << '--ignore-package-exit-codes'
end
if self.query
chocolatey(*args)
else
self.install
end
end
# from puppet-dev mailing list
# Puppet will call the query method on the instance of the package
# provider resource when checking if the package is installed already or
# not.
# It's a determination for one specific package, the package modeled by
# the resource the method is called on.
# Query provides the information for the single package identified by @Resource[:name].
def query
self.class.instances.each do |package|
return package.properties if @resource[:name][/\A\S*/].downcase == package.name.downcase
end
return nil
end
def self.listcmd
args = []
args << 'list'
args << '-lo'
if is_compiled_choco?
args << '-r'
end
[command(:chocolatey), *args]
end
def self.instances
packages = []
PuppetX::Chocolatey::ChocolateyCommon.set_env_chocolateyinstall
choco_exe = is_compiled_choco?
begin
pins = []
pin_output = nil unless choco_exe
#don't add -r yet, as there is an issue in 0.9.9.9/0.9.9.10 that returns full list plus pins
pin_output = Puppet::Util::Execution.execute([command(:chocolatey), 'pin', 'list']) if choco_exe
unless pin_output.nil?
pin_output.split("\n").each { |pin| pins << pin.split('|')[0] }
end
execpipe(listcmd) do |process|
process.each_line do |line|
line.chomp!
if line.empty? or line.match(/Reading environment variables.*/); next; end
raise Puppet::Error, "At least one source must be enabled." if line.match(/Unable to search for packages.*/)
if choco_exe
values = line.split('|')
else
values = line.split(' ')
end
values[1] = :held if pins.include? values[0]
packages << new({ :name => values[0].downcase, :ensure => values[1], :provider => self.name })
end
end
rescue Puppet::ExecutionFailure
return nil
end
packages
end
def latestcmd
choco_exe = is_compiled_choco?
if choco_exe
args = 'upgrade', '--noop', @resource[:name][/\A\S*/], '-r'
else
args = 'version', @resource[:name][/\A\S*/]
end
if @resource[:source]
args << '-source' << @resource[:source]
end
unless choco_exe
args << '| findstr /R "latest" | findstr /V "latestCompare"'
end
[command(:chocolatey), *args]
end
def latest
package_ver = ''
PuppetX::Chocolatey::ChocolateyCommon.set_env_chocolateyinstall
begin
execpipe(latestcmd) do |process|
process.each_line do |line|
line.chomp!
if line.empty?; next; end
if is_compiled_choco?
values = line.split('|')
package_ver = values[2]
else
# Example: ( latest : 2013.08.19.155043 )
values = line.split(':').collect(&:strip).delete_if(&:empty?)
package_ver = values[1]
end
end
end
rescue Puppet::ExecutionFailure
return nil
end
package_ver
end
def hold
raise ArgumentError, 'Only choco v0.9.9+ can use ensure => held' unless is_compiled_choco?
install
args = 'pin', 'add', '-n', @resource[:name][/\A\S*/]
chocolatey(*args)
end
def unhold
return unless is_compiled_choco?
Puppet::Util::Execution.execute([command(:chocolatey), 'pin','remove', '-n', @resource[:name][/\A\S*/]], :failonfail => false)
end
end

View File

@@ -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

View File

@@ -0,0 +1,57 @@
require 'puppet/type'
require 'pathname'
Puppet::Type.newtype(:chocolateyfeature) do
@doc = <<-'EOT'
Allows managing features for Chocolatey. Features are
configuration that act as feature flippers to turn on or
off certain aspects of how Chocolatey works.
Learn more about features at
https://chocolatey.org/docs/commands-feature
EOT
newparam(:name) do
desc "The name of the feature. Used for uniqueness."
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
ensurable do
newvalue(:enabled) { provider.enable }
newvalue(:disabled) { provider.disable }
def retrieve
provider.properties[:ensure]
end
end
validate do
if self[:ensure].nil? && provider.properties[:ensure].nil?
raise ArgumentError, "Invalid value for ensure. Valid values are enabled or disabled."
end
if provider.respond_to?(:validate)
provider.validate
end
end
autorequire(:exec) do
['install_chocolatey_official']
end
end

View File

@@ -0,0 +1,141 @@
require 'puppet/type'
require 'pathname'
Puppet::Type.newtype(:chocolateysource) do
@doc = <<-'EOT'
Allows managing sources for Chocolatey. A source can be a
folder, a CIFS share, a NuGet Http OData feed, or a full
Package Gallery. Learn more about sources at
https://chocolatey.org/docs/how-to-host-feed
EOT
ensurable do
newvalue(:present) { provider.create }
newvalue(:disabled) { provider.disable }
newvalue(:absent) { provider.destroy }
defaultto :present
def retrieve
provider.properties[:ensure]
end
end
newparam(:name) do
desc "The name of the source. Used for uniqueness."
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(:location) do
desc "The location of the source repository. Can be a url pointing to
an OData feed (like chocolatey/chocolatey_server), a CIFS (UNC) share,
or a local folder. Required when `ensure => present` (the default for
`ensure`)."
validate do |value|
if value.nil? or value.empty?
raise ArgumentError, "A non-empty location must be specified."
end
end
def insync?(is)
is.downcase == should.downcase
end
end
newproperty(:user) do
desc "Optional user name for authenticated feeds.
Requires at least Chocolatey v0.9.9.0.
Defaults to `nil`. Specifying an empty value is the
same as setting the value to nil or not specifying
the property at all."
def insync?(is)
is.downcase == should.downcase
end
defaultto ''
end
newparam(:password) do
desc "Optional user password for authenticated feeds.
Not ensurable. Value is not able to be checked
with current value. If you need to update the password,
update another setting as well.
Requires at least Chocolatey v0.9.9.0.
Defaults to `nil`. Specifying an empty value is the
same as setting the value to nil or not specifying
the property at all."
defaultto ''
end
newproperty(:priority) do
desc "Optional priority for explicit feed order when
searching for packages across multiple feeds.
The lower the number the higher the priority.
Sources with a 0 priority are considered no priority
and are added after other sources with a priority
number.
Requires at least Chocolatey v0.9.9.9.
Defaults to 0."
validate do |value|
if value.nil?
raise ArgumentError, "A non-empty priority must be specified."
end
raise ArgumentError, "An integer is necessary for priority. Specify 0 or remove for no priority." unless resource.is_numeric?(value)
end
defaultto(0)
end
validate do
if (!self[:user].nil? && self[:user].strip != '' && (self[:password].nil? || self[:password] == '')) || ((self[:user].nil? || self[:user].strip == '') && !self[:password].nil? && self[:password] != '')
raise ArgumentError, "If specifying user/password, you must specify both values."
end
if provider.respond_to?(:validate)
provider.validate
end
end
autorequire(:exec) do
['install_chocolatey_official']
end
def munge_boolean(value)
case value
when true, "true", :true
:true
when false, "false", :false
:false
else
fail("munge_boolean only takes booleans")
end
end
def is_numeric?(value)
# this is what stdlib does. Not sure if we want to emulate or not.
#numeric = %r{^-?(?:(?:[1-9]\d*)|0)$}
#if value.is_a? Integer or (value.is_a? String and value.match numeric)
Float(value) != nil rescue false
end
end

View File

@@ -0,0 +1,90 @@
require 'pathname'
require Pathname.new(__FILE__).dirname + 'chocolatey_version'
require Pathname.new(__FILE__).dirname + 'chocolatey_install'
module PuppetX
module Chocolatey
module ChocolateyCommon
## determines if C# version of choco
FIRST_COMPILED_CHOCO_VERSION = '0.9.9.0'
MINIMUM_SUPPORTED_CHOCO_VERSION_EXIT_CODES = '0.9.10.0'
MINIMUM_SUPPORTED_CHOCO_UNINSTALL_SOURCE = '0.9.10.0'
def file_exists?(path)
File.exist?(path)
end
module_function :file_exists?
def chocolatey_command
if Puppet::Util::Platform.windows?
# When attempting to find the choco command executable, the following
# paths are checked:
# - Start with the install_path. If choco is found with environment
# variables through the registry or a check on the
# ChocolateyInstall env var (first install of Choco may only have
# this), then use that path.
# - Next look to the most commonly used install location (ProgramData)
# - Fall back to the older install location for older installations
# - If all else fails, attempt to find Chocolatey in the default place
# it installs
chocoInstallPath = PuppetX::Chocolatey::ChocolateyInstall.install_path
chocopath = (chocoInstallPath if (chocoInstallPath && file_exists?("#{chocoInstallPath}\\bin\\choco.exe"))) ||
('C:\ProgramData\chocolatey' if file_exists?('C:\ProgramData\chocolatey\bin\choco.exe')) ||
('C:\Chocolatey' if file_exists?('C:\Chocolatey\bin\choco.exe')) ||
"#{ENV['ALLUSERSPROFILE']}\\chocolatey"
chocopath += '\bin\choco.exe'
else
chocopath = 'choco.exe'
end
chocopath
end
module_function :chocolatey_command
def set_env_chocolateyinstall
ENV['ChocolateyInstall'] = PuppetX::Chocolatey::ChocolateyInstall.install_path
end
module_function :set_env_chocolateyinstall
def choco_version
@chocoversion ||= self.strip_beta_from_version(PuppetX::Chocolatey::ChocolateyVersion.version)
end
module_function :choco_version
def self.strip_beta_from_version(value)
return nil if value.nil?
value.split(/-/)[0]
end
def choco_config_file
chocoInstallPath = PuppetX::Chocolatey::ChocolateyInstall.install_path
choco_config = "#{chocoInstallPath}\\config\\chocolatey.config"
# choco may be installed, but a config file doesn't exist until the
# first run of choco - trigger that by checking the version
choco_run_ensure_config = choco_version
return choco_config if file_exists?(choco_config)
old_choco_config = "#{chocoInstallPath}\\chocolateyinstall\\chocolatey.config"
return old_choco_config if file_exists?(old_choco_config)
return nil
end
module_function :choco_config_file
# clears the cached values
def clear_cached_values
@chocoversion = nil
@compiled_choco = nil
end
module_function :clear_cached_values
end
end
end

View File

@@ -0,0 +1,34 @@
module PuppetX
module Chocolatey
class ChocolateyInstall
def self.install_path
value = nil
if Puppet::Util::Platform.windows?
require 'win32/registry'
begin
hive = Win32::Registry::HKEY_LOCAL_MACHINE
hive.open('SYSTEM\CurrentControlSet\Control\Session Manager\Environment', Win32::Registry::KEY_READ | 0x100) do |reg|
value = reg['ChocolateyInstall']
end
rescue Win32::Registry::Error => e
value = nil
end
end
# If machine level is not set, use process or user as the intended
# location where Chocolatey would be installed.
# Since it is technically possible that Chocolatey could exist on
# non-Windows installations, we don't want to confine this
# to just Windows.
if value.nil?
value = ENV['ChocolateyInstall']
end
value
end
end
end
end

View File

@@ -0,0 +1,32 @@
require 'pathname'
require Pathname.new(__FILE__).dirname + 'chocolatey_install'
module PuppetX
module Chocolatey
class ChocolateyVersion
OLD_CHOCO_MESSAGE = "Please run chocolatey /? or chocolatey help - chocolatey v"
def self.version
version = nil
choco_path = "#{PuppetX::Chocolatey::ChocolateyInstall.install_path}\\bin\\choco.exe"
if Puppet::Util::Platform.windows? && File.exist?(choco_path)
begin
# call `choco -v`
# - new choco will output a single value e.g. `0.9.9`
# - old choco is going to return the default output e.g. `Please run chocolatey /?`
version = Puppet::Util::Execution.execute("#{choco_path} -v").gsub(OLD_CHOCO_MESSAGE,'')
# - other messages, such as upgrade warnings or warnings about
# installing the licensed extension once the license is installed
# may show up when running this comamnd. Remove those as well
version = version.split(/\r\n|\n|\r/).last.strip unless version.nil?
rescue StandardError => e
version = '0'
end
end
version
end
end
end
end

View File

@@ -0,0 +1,34 @@
# chocolatey::config - Private class used for configuration
class chocolatey::config {
assert_private()
# this will require a second converge when choco is not
# installed the first time through. This is on purpose
# as we don't want to try to set these values for a
# version less than 0.9.9 and we don't know what the
# user may link to - it could be an older version of
# Chocolatey
$_choco_version = $chocolatey::chocolatey_version ? {
undef => '0',
default => $chocolatey::chocolatey_version
}
# lint:ignore:80chars
if versioncmp($_choco_version, '0.9.9.0') >= 0 and versioncmp($_choco_version, '0.9.10.0') < 0 {
$_choco_exe_path = "${chocolatey::choco_install_location}\\bin\\choco.exe"
$_enable_autouninstaller = $chocolatey::enable_autouninstaller ? {
false => 'disable',
default => 'enable'
}
exec { "chocolatey_autouninstaller_${_enable_autouninstaller}":
path => $::path,
command => "${_choco_exe_path} feature -r ${_enable_autouninstaller} -n autoUninstaller",
unless => "cmd.exe /c ${_choco_exe_path} feature list -r | findstr /B /I /C:\"autoUninstaller - [${_enable_autouninstaller}d]\"",
environment => ["ChocolateyInstall=${::chocolatey::choco_install_location}"]
}
}
# lint:endignore
}

View File

@@ -0,0 +1,104 @@
# chocolatey - Used for managing installation and configuration
# of Chocolatey itself.
#
# @author Rob Reynolds, Rich Siegel, and puppet-chocolatey contributors
#
# @example Default - This will by default ensure Chocolatey is installed and ready for use.
# include chocolatey
#
# @example Override default install location
# class {'chocolatey':
# choco_install_location => 'D:\secured\choco',
# }
#
# @example Use an internal Chocolatey.nupkg for installation
# class {'chocolatey':
# chocolatey_download_url => 'https://internalurl/to/chocolatey.nupkg',
# use_7zip => false,
# choco_install_timeout_seconds => 2700,
# }
#
# @example Use a file chocolatey.0.9.9.9.nupkg for installation
# class {'chocolatey':
# chocolatey_download_url => 'file:///c:/location/of/chocolatey.0.9.9.9.nupkg',
# use_7zip => false,
# choco_install_timeout_seconds => 2700,
# }
#
# @example Log chocolatey bootstrap installer script output
# class {'chocolatey':
# log_output => true,
# }
#
# @example Disable autouninstaller (use when less than 0.9.9.8)
# class {'chocolatey':
# enable_autouninstaller => false,
# }
#
# @param [String] choco_install_location Where Chocolatey install should be
# located. This needs to be an absolute path starting with a drive letter
# e.g. `c:\`. Defaults to the currently detected install location based on
# the `ChocolateyInstall` environment variable, falls back to
# `'C:\ProgramData\chocolatey'`.
# @param [Boolean] use_7zip Whether to use built-in shell or allow installer
# to download 7zip to extract `chocolatey.nupkg` during installation.
# Defaults to `false`.
# @param [Integer] choco_install_timeout_seconds How long in seconds should
# be allowed for the install of Chocolatey (including .NET Framework 4 if
# necessary). Defaults to `1500` (25 minutes).
# @param [String] chocolatey_download_url A url that will return
# `chocolatey.nupkg`. This must be a url, but not necessarily an OData feed.
# Any old url location will work. Defaults to
# `'https://chocolatey.org/api/v2/package/chocolatey/'`.
# @param [Boolean] enable_autouninstaller [Deprecated] - Should auto
# uninstaller be turned on? Auto uninstaller is what allows Chocolatey to
# automatically manage the uninstall of software from Programs and Features
# without necessarily requiring a `chocolateyUninstall.ps1` file in the
# package. Defaults to `true`. Setting is ignored in Chocolatey v0.9.10+.
# @param [Boolean] log_output Log output from the installer. Defaults to
# `false`.
# @param [String] chocolatey_version chocolatey version, falls back to
# `$::chocolateyversion`.
class chocolatey (
$choco_install_location = $::chocolatey::params::install_location,
$use_7zip = $::chocolatey::params::use_7zip,
$choco_install_timeout_seconds = $::chocolatey::params::install_timeout_seconds,
$chocolatey_download_url = $::chocolatey::params::download_url,
$enable_autouninstaller = $::chocolatey::params::enable_autouninstaller,
$log_output = false,
$chocolatey_version = $::chocolatey::params::chocolatey_version
) inherits ::chocolatey::params {
validate_string($choco_install_location)
# lint:ignore:140chars
validate_re($choco_install_location, '^\w\:',
"Please use a full path for choco_install_location starting with a local drive. Reference choco_install_location => '${choco_install_location}'."
)
# lint:endignore
validate_bool($use_7zip)
validate_integer($choco_install_timeout_seconds)
validate_string($chocolatey_download_url)
# lint:ignore:140chars
validate_re($chocolatey_download_url,['^http\:\/\/','^https\:\/\/','file\:\/\/\/'],
"For chocolatey_download_url, if not using the default '${::chocolatey::params::download_url}', please use a Http/Https/File Url that downloads 'chocolatey.nupkg'."
)
# lint:endignore
validate_bool($enable_autouninstaller)
if ((versioncmp($::clientversion, '3.4.0') >= 0) and (!defined('$::serverversion') or versioncmp($::serverversion, '3.4.0') >= 0)) {
class { '::chocolatey::install': } ->
class { '::chocolatey::config': }
contain '::chocolatey::install'
contain '::chocolatey::config'
} else {
anchor {'before_chocolatey':} ->
class { '::chocolatey::install': } ->
class { '::chocolatey::config': } ->
anchor {'after_chocolatey':}
}
}

View File

@@ -0,0 +1,27 @@
# chocolatey::install - Private class used for install of Chocolatey
class chocolatey::install {
assert_private()
$download_url = $::chocolatey::chocolatey_download_url
$unzip_type = $::chocolatey::use_7zip ? {
true => '7zip',
default => 'windows'
}
registry_value { 'ChocolateyInstall environment value':
ensure => present,
path => 'HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\ChocolateyInstall',
type => 'string',
data => $chocolatey::choco_install_location,
}
exec { 'install_chocolatey_official':
command => template('chocolatey/InstallChocolatey.ps1.erb'),
creates => "${::chocolatey::choco_install_location}\\bin\\choco.exe",
provider => powershell,
timeout => $::chocolatey::choco_install_timeout_seconds,
logoutput => $::chocolatey::log_output,
environment => ["ChocolateyInstall=${::chocolatey::choco_install_location}"],
require => Registry_value['ChocolateyInstall environment value'],
}
}

View File

@@ -0,0 +1,9 @@
# chocolatey::params - Default parameters
class chocolatey::params {
$install_location = $::choco_install_path # default is C:\ProgramData\chocolatey
$download_url = 'https://chocolatey.org/api/v2/package/chocolatey/'
$use_7zip = false
$install_timeout_seconds = 1500
$enable_autouninstaller = true
$chocolatey_version = $::chocolateyversion
}

View File

@@ -0,0 +1,53 @@
{
"name": "puppetlabs-chocolatey",
"version": "2.0.1",
"author": "Puppet Inc",
"summary": "Chocolatey package provider for Puppet",
"license": "Apache-2.0",
"source": "https://github.com/puppetlabs/puppetlabs-chocolatey",
"project_page": "https://github.com/puppetlabs/puppetlabs-chocolatey",
"issues_url": "https://tickets.puppet.com/browse/MODULES",
"dependencies": [
{"name":"puppetlabs/stdlib","version_requirement":">= 4.6.0 < 5.0.0"},
{"name":"puppetlabs/powershell","version_requirement":">= 1.0.1 < 3.0.0"},
{"name":"puppetlabs/registry","version_requirement":">= 1.0.0 < 3.0.0"}
],
"data_provider": null,
"description": "Chocolatey package provider for Puppet",
"tags": [
"microsoft",
"powershell",
".NET Framework",
".Net",
"dot_net",
"chocolatey",
"package",
"package manager",
"chocolatey for business",
"chocolatey professional"
],
"requirements": [
{
"name": "pe",
"version_requirement": ">= 3.0.0 < 2016.4.0"
},
{
"name": "puppet",
"version_requirement": ">= 3.0.0 < 5.0.0"
}
],
"operatingsystem_support": [
{
"operatingsystem": "Windows",
"operatingsystemrelease": [
"Server 2008",
"Server 2008 R2",
"Server 2012",
"Server 2012 R2",
"7",
"8.1",
"10"
]
}
]
}

View File

@@ -0,0 +1,17 @@
<?xml version="1.0"?>
<utility xmlns="http://www.github/cliffe/SecGen/utility"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.github/cliffe/SecGen/utility">
<name>Chocolatey install</name>
<author>Jason Keighley</author>
<module_license>Apache v2</module_license>
<description>A Chocolatey installation</description>
<type>repository_managers</type>
<platform>windows</platform>
<!--optional details-->
<reference></reference>
</utility>

View File

@@ -0,0 +1,77 @@
require 'spec_helper'
RSpec.describe 'chocolatey' do
context 'contains config.pp' do
context 'with older choco installed' do
let(:facts) {
{
:chocolateyversion => '0.9.8.33',
:choco_install_path => 'C:\ProgramData\chocolatey',
}
}
[true, false].each do |param_value|
feature_enable = 'enable'
feature_enable = 'disable' if !param_value
context "enable_autouninstaller => #{param_value}" do
let(:params) {{ :enable_autouninstaller => param_value }}
it { is_expected.not_to contain_exec("chocolatey_autouninstaller_#{feature_enable}") }
it {
is_expected.not_to contain_exec("chocolatey_autouninstaller_#{feature_enable}").with_command("C:\\ProgramData\\chocolatey\\bin\\choco.exe feature -r #{feature_enable} -n autoUninstaller")
}
end
end
end
context 'without choco installed' do
let(:facts) {
{
:chocolateyversion => '0',
:choco_install_path => 'C:\ProgramData\chocolatey',
}
}
[true, false].each do |param_value|
feature_enable = 'enable'
feature_enable = 'disable' if !param_value
context "enable_autouninstaller => #{param_value}" do
let(:params) {{ :enable_autouninstaller => param_value }}
it { is_expected.not_to contain_exec("chocolatey_autouninstaller_#{feature_enable}") }
it {
is_expected.not_to contain_exec("chocolatey_autouninstaller_#{feature_enable}").with_command("C:\\ProgramData\\chocolatey\\bin\\choco.exe feature -r #{feature_enable} -n autoUninstaller")
}
end
end
end
context 'with choco.exe installed' do
let(:facts) {
{
:chocolateyversion => '0.9.9.8',
:choco_install_path => 'C:\ProgramData\chocolatey',
}
}
[true, false].each do |param_value|
feature_enable = 'enable'
feature_enable = 'disable' if !param_value
context "enable_autouninstaller => #{param_value}" do
let(:params) {{ :enable_autouninstaller => param_value }}
it { is_expected.to contain_exec("chocolatey_autouninstaller_#{feature_enable}") }
it {
is_expected.to contain_exec("chocolatey_autouninstaller_#{feature_enable}").with_command("C:\\ProgramData\\chocolatey\\bin\\choco.exe feature -r #{feature_enable} -n autoUninstaller")
}
end
end
end
end
end

View File

@@ -0,0 +1 @@
at_exit { RSpec::Puppet::Coverage.report! }

View File

@@ -0,0 +1,200 @@
require 'spec_helper'
describe 'chocolatey' do
let(:facts) {
{
:chocolateyversion => '0.9.9.8',
:choco_install_path => 'C:\ProgramData\chocolatey',
}
}
[{}].each do |params|
context "#{params}" do
let(:params) { params }
it 'should compile successfully' do
catalogue
end
#it { is_expected.to compile }
#it { is_expected.to compile.with_all_deps }
it { is_expected.to contain_class('chocolatey') }
it { is_expected.to contain_class('chocolatey::params') }
it { is_expected.to contain_class('chocolatey::install') }
it { is_expected.to contain_class('chocolatey::config') }
end
end
context "chocolatey_download_url =>" do
['https://chocolatey.org/api/v2/package/chocolatey/','http://location','file:///c:/somwhere/chocolatey.nupkg'].each do |param_value|
context "#{param_value}" do
let (:params) {{
:chocolatey_download_url => param_value
}}
it 'should compile successfully' do
catalogue
end
end
end
if Puppet.version < '4.0.0'
invalid_url_values = ['\\\\ciflocation\\share','bob',"4",'',3]
not_a_string_values = [false]
else
invalid_url_values = ['\\\\ciflocation\\share','bob',"4",'']
not_a_string_values = [false, 3]
end
invalid_url_values.each do |param_value|
context "#{param_value} (invalid scenario)" do
let (:params) {{
:chocolatey_download_url => param_value
}}
let(:error_message) { /use a Http\/Https\/File Url that downloads/ }
it {
expect { catalogue }.to raise_error(Puppet::Error, error_message)
}
end
end
not_a_string_values.each do |param_value|
context "#{param_value} (invalid scenario)" do
let (:params) {{
:chocolatey_download_url => param_value
}}
let(:error_message) { /is not a string/ }
it {
expect { catalogue }.to raise_error(Puppet::Error, error_message)
}
end
end
end
context "choco_install_location =>" do
['C:\\ProgramData\\chocolatey','D:\\somewhere'].each do |param_value|
context "#{param_value}" do
let (:params) {{
:choco_install_location => param_value
}}
it 'should compile successfully' do
catalogue
end
end
end
if Puppet.version < '4.0.0'
[false].each do |param_value|
context "#{param_value} (invalid scenario)" do
let (:params) {{
:choco_install_location => param_value
}}
let(:error_message) { /is not a string/ }
it {
expect { catalogue }.to raise_error(Puppet::Error, error_message)
}
end
end
#1 is actually a string before v4.
[1,'https://somewhere','\\\\overhere',''].each do |param_value|
context "#{param_value} (invalid scenario)" do
let (:params) {{
:choco_install_location => param_value
}}
let(:error_message) { /Please use a full path for choco_install_location/ }
it {
expect { catalogue }.to raise_error(Puppet::Error, error_message)
}
end
end
else
[1,false].each do |param_value|
context "#{param_value} (invalid scenario)" do
let (:params) {{
:choco_install_location => param_value
}}
let(:error_message) { /is not a string/ }
it {
expect { catalogue }.to raise_error(Puppet::Error, error_message)
}
end
end
['https://somewhere','\\\\overhere',''].each do |param_value|
context "#{param_value} (invalid scenario)" do
let (:params) {{
:choco_install_location => param_value
}}
let(:error_message) { /Please use a full path for choco_install_location/ }
it {
expect { catalogue }.to raise_error(Puppet::Error, error_message)
}
end
end
end
end
context "choco_install_timeout_seconds =>" do
[1500,8000,"1",'30'].each do |param_value|
context "#{param_value}" do
let (:params) {{
:choco_install_timeout_seconds => param_value
}}
it 'should compile successfully' do
catalogue
end
end
end
['string',false,''].each do |param_value|
context "#{param_value} (invalid scenario)" do
let (:params) {{
:choco_install_timeout_seconds => param_value
}}
let(:error_message) { /Expected first argument to be an Integer/ }
it {
expect { catalogue }.to raise_error(Puppet::Error, error_message)
}
end
end
end
['use_7zip','enable_autouninstaller'].each do |boolean_param|
context "#{boolean_param} =>" do
[true, false].each do |param_value|
context "#{param_value}" do
let (:params) {{
boolean_param.to_sym => param_value
}}
it 'should compile successfully' do
catalogue
end
end
end
['true','false','bob',3,"4",''].each do |param_value|
context "#{param_value} (invalid scenario)" do
let (:params) {{
boolean_param.to_sym => param_value
}}
let(:error_message) { /is not a boolean./ }
it {
expect { catalogue }.to raise_error(Puppet::Error, error_message)
}
end
end
end
end
end

View File

@@ -0,0 +1,30 @@
require 'spec_helper'
RSpec.describe 'chocolatey' do
let(:facts) {
{
:chocolateyversion => '0.9.9.8',
:choco_install_path => 'C:\ProgramData\chocolatey',
}
}
context 'contains install.pp' do
['c:\local_folder', "C:\\ProgramData\\chocolatey"].each do |param_value|
context "choco_install_location => #{param_value}" do
let(:params) {{ :choco_install_location => param_value }}
it { is_expected.to contain_exec('install_chocolatey_official').with_creates("#{param_value}\\bin\\choco.exe") }
end
end
[1500, 35].each do |param_value|
context "choco_install_timeout_seconds => #{param_value}" do
let(:params) {{ :choco_install_timeout_seconds => param_value }}
it { is_expected.to contain_exec('install_chocolatey_official').with_timeout("#{param_value}") }
end
end
end
end

View File

@@ -0,0 +1,64 @@
#require 'ruby-prof'
#RubyProf.start
IDEAL_CONSOLE_WIDTH = 72
def horizontal_rule(width = 5)
'=' * [width, IDEAL_CONSOLE_WIDTH].min
end
require 'puppetlabs_spec_helper/module_spec_helper'
# require dependencies
gems = [
#'minitest/autorun', # http://docs.seattlerb.org/minitest/
#'minitest/unit', # https://github.com/freerange/mocha#bundler
'mocha', # http://gofreerange.com/mocha/docs/Mocha/Configuration.html
'puppet',
]
begin
gems.each {|gem| require gem}
rescue => e
# http://goo.gl/r3nFG
# emphasize dependency failures in case a task spews lots of output
warn horizontal_rule(e.message.length)
warn e.class
warn e.message
warn horizontal_rule(e.message.length)
exit(1)
end
RSpec.configure do |c|
# set the environment variable before files are loaded, otherwise it is too late
ENV['ChocolateyInstall'] = 'c:\blah'
begin
Win32::Registry.any_instance.stubs(:[]).with('Bind')
Win32::Registry.any_instance.stubs(:[]).with('Domain')
Win32::Registry.any_instance.stubs(:[]).with('ChocolateyInstall').raises(Win32::Registry::Error.new(2), 'file not found yo')
rescue
# we don't care
end
# https://www.relishapp.com/rspec/rspec-core/v/2-12/docs/mock-framework-integration/mock-with-mocha!
c.mock_framework = :mocha
# see output for all failures
c.fail_fast = false
c.expect_with :rspec do |e|
e.syntax = [:should, :expect]
end
c.raise_errors_for_deprecations!
c.after :suite do
#result = RubyProf.stop
# Print a flat profile to text
#printer = RubyProf::FlatPrinter.new(result)
#printer.print(STDOUT)
end
end
# We need this because the RAL uses 'should' as a method. This
# allows us the same behaviour but with a different method name.
class Object
alias :must :should
alias :must_not :should_not
end

View File

@@ -0,0 +1,32 @@
require 'spec_helper'
require 'facter'
require 'puppet_x/chocolatey/chocolatey_install'
describe 'choco_install_path fact' do
subject(:fact) { Facter.fact(:choco_install_path) }
before :each do
Facter.clear
Facter.clear_messages
end
context "on Windows", :if => Puppet::Util::Platform.windows? do
it "should return the output of PuppetX::Chocolatey::ChocolateyInstall.install_path" do
expected_value = 'C:\somewhere'
PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns(expected_value)
subject.value.must == expected_value
end
it "should return the default path when PuppetX::Chocolatey::ChocolateyInstall.install_path is nil" do
PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns(nil)
subject.value.must == 'C:\ProgramData\chocolatey'
end
end
after :each do
Facter.clear
Facter.clear_messages
end
end

View File

@@ -0,0 +1,32 @@
require 'spec_helper'
require 'facter'
require 'puppet_x/chocolatey/chocolatey_version'
describe 'chocolateyversion fact' do
subject(:fact) { Facter.fact(:chocolateyversion) }
before :each do
Facter.clear
Facter.clear_messages
end
context "on Windows", :if => Puppet::Util::Platform.windows? do
it "should return the output of PuppetX::Chocolatey::ChocolateyVersion.version" do
expected_value = '1.2.3'
PuppetX::Chocolatey::ChocolateyVersion.expects(:version).returns(expected_value)
subject.value.must == expected_value
end
it "should return the default of 0 when PuppetX::Chocolatey::ChocolateyVersion.version is nil" do
PuppetX::Chocolatey::ChocolateyVersion.expects(:version).returns(nil)
subject.value.must == '0'
end
end
after :each do
Facter.clear
Facter.clear_messages
end
end

View File

@@ -0,0 +1,268 @@
require 'spec_helper'
require 'stringio'
require 'puppet/type/chocolateyconfig'
require 'puppet/provider/chocolateyconfig/windows'
require 'rexml/document'
provider = Puppet::Type.type(:chocolateyconfig).provider(:windows)
describe provider do
let (:name) { 'configItem' }
let (:resource) { Puppet::Type.type(:chocolateyconfig).new(:provider => :windows, :name => name, :value => "yes") }
let (:choco_config) { 'c:\choco.config' }
let (:choco_install_path) { 'c:\dude\bin\choco.exe' }
let (:choco_config_contents) { <<-'EOT'
<?xml version="1.0" encoding="utf-8"?>
<chocolatey xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<config>
<add key="cacheLocation" value="" description="Cache location if not TEMP folder." />
<add key="commandExecutionTimeoutSeconds" value="2700" description="Default timeout for command execution." />
<add key="containsLegacyPackageInstalls" value="true" description="Install has packages installed prior to 0.9.9 series." />
<add key="proxy" value="" description="Explicit proxy location." />
<add key="proxyUser" value="" description="Optional proxy user." />
<add key="proxyPassword" value="" description="Optional proxy password. Encrypted." />
<add key="virusCheckMinimumPositives" value="5" description="Minimum numer of scan result positives before flagging a binary as a possible virus. Available in 0.9.10+. Licensed versions only." />
<add key="virusScannerType" value="VirusTotal" description="Virus Scanner Type (Generic or VirusTotal). Defaults to VirusTotal for Pro. Available in 0.9.10+. Licensed versions only." />
<add key="genericVirusScannerPath" value="" description="The full path to the command line virus scanner executable. Used when virusScannerType is Generic. Available in 0.9.10+. Licensed versions only." />
<add key="genericVirusScannerArgs" value="[[File]]" description="The arguments to pass to the generic virus scanner. Use [[File]] for the file path placeholder. Used when virusScannerType is Generic. Available in 0.9.10+. Licensed versions only." />
<add key="genericVirusScannerValidExitCodes" value="0" description="The exit codes for the generic virus scanner when a file is not flagged. Separate with comma, defaults to 0. Used when virusScannerType is Generic. Available in 0.9.10+. Licensed versions only." />
</config>
<sources>
<source id="local" value="c:\packages" disabled="true" user="rob" password="bogus/encrypted+value=" priority="0" />
<source id="chocolatey" value="https://chocolatey.org/api/v2/" disabled="false" priority="0" />
<source id="chocolatey.licensed" value="https://licensedpackages.chocolatey.org/api/v2/" disabled="false" user="customer" password="bogus/encrypted+value=" priority="10" />
</sources>
<features>
<feature name="checksumFiles" enabled="true" setExplicitly="false" description="Checksum files when pulled in from internet (based on package)." />
<feature name="virusCheckFiles" enabled="false" setExplicitly="false" />
<feature name="autoUninstaller" enabled="true" setExplicitly="true" description="Uninstall from programs and features without requiring an explicit uninstall script." />
<feature name="allowGlobalConfirmation" enabled="false" setExplicitly="true" description="Prompt for confirmation in scripts or bypass." />
<feature name="allowInsecureConfirmation" enabled="false" setExplicitly="false" />
<feature name="failOnAutoUninstaller" enabled="false" setExplicitly="false" description="Fail if automatic uninstaller fails." />
<feature name="failOnStandardError" enabled="false" setExplicitly="false" description="Fail if install provider writes to stderr." />
<feature name="powershellHost" enabled="true" setExplicitly="false" description="Use Chocolatey''s built-in PowerShell host." />
<feature name="logEnvironmentValues" enabled="false" setExplicitly="false" description="Log Environment Values - will log values of environment before and after install (could disclose sensitive data)." />
<feature name="virusCheck" enabled="true" setExplicitly="true" description="Virus Check - perform virus checking on downloaded files. Available in 0.9.10+. Licensed versions only." />
<feature name="downloadCache" enabled="true" setExplicitly="false" description="Download Cache - use the private download cache if available for a package. Available in 0.9.10+. Licensed versions only." />
<feature name="failOnInvalidOrMissingLicense" enabled="false" setExplicitly="false" description="Fail On Invalid Or Missing License - allows knowing when a license is expired or not applied to a machine." />
<feature name="ignoreInvalidOptionsSwitches" enabled="true" setExplicitly="false" description="Ignore Invalid Options/Switches - If a switch or option is passed that is not recognized, should choco fail?" />
<feature name="usePackageExitCodes" enabled="true" setExplicitly="false" description="Use Package Exit Codes - Package scripts can provide exit codes. With this on, package exit codes will be what choco uses for exit when non-zero (this value can come from a dependency package). Chocolatey defines valid exit codes as 0, 1605, 1614, 1641, 3010. With this feature off, choco will exit with a 0 or a 1 (matching previous behavior). Available in 0.9.10+." />
</features>
<apiKeys>
<apiKeys source="https://chocolatey.org/" key="bogus/encrypted+value=" />
</apiKeys>
</chocolatey>
EOT
}
let (:minimum_supported_version) {'0.9.10.0'}
let (:last_unsupported_version) {'0.9.9.12'}
before :each do
PuppetX::Chocolatey::ChocolateyInstall.stubs(:install_path).returns('c:\dude')
PuppetX::Chocolatey::ChocolateyCommon.stubs(:choco_version).returns(minimum_supported_version)
@provider = provider.new(resource)
resource.provider = @provider
# Stub all file and config tests
provider.stubs(:healthcheck)
end
context "verify provider" do
it "should be an instance of Puppet::Type::Chocolateyconfig::ProviderWindows" do
@provider.must be_an_instance_of Puppet::Type::Chocolateyconfig::ProviderWindows
end
it "should have a create method" do
@provider.should respond_to(:create)
end
it "should have an exists? method" do
@provider.should respond_to(:exists?)
end
it "should have a destroy method" do
@provider.should respond_to(:destroy)
end
it "should have a properties method" do
@provider.should respond_to(:properties)
end
it "should have a query method" do
@provider.should respond_to(:query)
end
end
context "properties" do
context ":value" do
#it "should default to nil" do
# resource[:value].should be_nil
#end
it "should accept c:\\cache" do
resource[:value] = 'c:\cache'
end
it "should accept 2700" do
resource[:value] = '2700'
end
it "should accept 'value with spaces'" do
resource[:value] = 'value with spaces'
end
end
end
context "self.get_configs" do
before :each do
PuppetX::Chocolatey::ChocolateyCommon.expects(:set_env_chocolateyinstall)
end
it "should error when the config file location is null" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(nil)
expect {
provider.get_configs
}.to raise_error(Puppet::ResourceError, /Config file not found for Chocolatey/)
end
it "should error when the config file is not found" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(choco_config)
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_config).returns(false)
expect {
provider.get_configs
}.to raise_error(Puppet::ResourceError, /was unable to locate config file at/)
end
context "when getting configs from the config file" do
configs = []
before :each do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(choco_config)
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_config).returns(true)
File.expects(:new).with(choco_config,"r").returns choco_config_contents
configs = provider.get_configs
end
it "should match the count of configs in the config" do
configs.count.must eq 11
end
it "should contain xml elements" do
configs[0].must be_an_instance_of REXML::Element
end
end
end
context "self.get_config" do
let (:element) { REXML::Element.new('add') }
element_key = "cacheLocation"
element_value= "c:\\cache"
element_description = "Cache location if not TEMP folder."
before :each do
element.add_attributes( { "key" => element_key,
"value" => element_value,
"description" => element_description,
} )
end
it "should return nil config when element is nil" do
provider.get_config(nil).must be == {}
end
it "should convert an element to a config" do
config = provider.get_config(element)
config[:name].must eq element_key
config[:value].must eq element_value
config[:description].must eq element_description
config[:ensure].must eq :present
end
end
context ".validation" do
it "should not error when Chocolatey is not installed" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).returns(false).at_least(0)
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_install_path).returns(false).at_least(0)
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns('')
resource.provider.validate
end
it "should not error when the minimum version is met" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).returns(false).at_least(0)
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_install_path).returns(true).at_least(0)
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version)
resource.provider.validate
end
it "should error when the minimum version is not met" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).returns(true).at_least(0)
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(last_unsupported_version)
expect {
resource.provider.validate
}.to raise_error(Puppet::ResourceError, /Chocolatey version must be '0.9.10.0' to manage configuration values. Detected '#{last_unsupported_version}'/)
end
end
context ".flush" do
resource_name = "yup"
resource_value = "this"
resource_ensure = :present
before :each do
PuppetX::Chocolatey::ChocolateyCommon.expects(:set_env_chocolateyinstall).at_most_once
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(choco_config).at_most_once
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_config).returns(true).at_most_once
File.expects(:new).with(choco_config,"r").returns(choco_config_contents).at_most_once
resource[:name] = resource_name
resource[:value] = resource_value
resource[:ensure] = resource_ensure
end
it "should ensure a config setting is set" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version)
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'config', 'set',
'--name', resource_name,
'--value', resource_value
])
resource.flush
end
it "should ensure a config setting is removed" do
resource.provider.destroy
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version)
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'config', 'unset',
'--name', resource_name
])
resource.flush
end
it "should provide an error message when choco execution fails" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version)
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'config', 'set',
'--name', resource_name,
'--value', resource_value
]).raises(Puppet::ExecutionFailure, "Nooooo")
expect { resource.flush }.to raise_error(Puppet::Error, /Unable to set Chocolateyconfig/)
end
end
end

View File

@@ -0,0 +1,170 @@
require 'spec_helper'
require 'stringio'
require 'puppet/type/chocolateyfeature'
require 'puppet/provider/chocolateyfeature/windows'
require 'rexml/document'
provider = Puppet::Type.type(:chocolateyfeature).provider(:windows)
describe provider do
let (:name) { 'allowglobalconfirmation' }
let (:resource) { Puppet::Type.type(:chocolateyfeature).new(:provider => :windows, :name => name, :ensure => 'enabled' ) }
let (:choco_config) { 'c:\choco.config' }
let (:choco_install_path) { 'c:\dude\bin\choco.exe' }
let (:choco_config_contents) { <<-'EOT'
<?xml version="1.0" encoding="utf-8"?>
<chocolatey xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<config>
<add key="cacheLocation" value="" description="Cache location if not TEMP folder." />
<add key="commandExecutionTimeoutSeconds" value="2700" description="Default timeout for command execution." />
<add key="containsLegacyPackageInstalls" value="true" description="Install has packages installed prior to 0.9.9 series." />
<add key="proxy" value="" description="Explicit proxy location." />
<add key="proxyUser" value="" description="Optional proxy user." />
<add key="proxyPassword" value="" description="Optional proxy password. Encrypted." />
<add key="virusCheckMinimumPositives" value="5" description="Minimum numer of scan result positives before flagging a binary as a possible virus. Available in 0.9.10+. Licensed versions only." />
<add key="virusScannerType" value="VirusTotal" description="Virus Scanner Type (Generic or VirusTotal). Defaults to VirusTotal for Pro. Available in 0.9.10+. Licensed versions only." />
<add key="genericVirusScannerPath" value="" description="The full path to the command line virus scanner executable. Used when virusScannerType is Generic. Available in 0.9.10+. Licensed versions only." />
<add key="genericVirusScannerArgs" value="[[File]]" description="The arguments to pass to the generic virus scanner. Use [[File]] for the file path placeholder. Used when virusScannerType is Generic. Available in 0.9.10+. Licensed versions only." />
<add key="genericVirusScannerValidExitCodes" value="0" description="The exit codes for the generic virus scanner when a file is not flagged. Separate with comma, defaults to 0. Used when virusScannerType is Generic. Available in 0.9.10+. Licensed versions only." />
</config>
<sources>
<source id="local" value="c:\packages" disabled="true" user="rob" password="bogus\/encrypted+value=" priority="0" />
<source id="chocolatey" value="https://chocolatey.org/api/v2/" disabled="false" priority="0" />
<source id="chocolatey.licensed" value="https://licensedpackages.chocolatey.org/api/v2/" disabled="false" user="customer" password="bogus/encrypted+value=" priority="10" />
</sources>
<features>
<feature name="checksumFiles" enabled="true" setExplicitly="false" description="Checksum files when pulled in from internet (based on package)." />
<feature name="virusCheckFiles" enabled="false" setExplicitly="false" />
<feature name="autoUninstaller" enabled="true" setExplicitly="true" description="Uninstall from programs and features without requiring an explicit uninstall script." />
<feature name="allowGlobalConfirmation" enabled="false" setExplicitly="true" description="Prompt for confirmation in scripts or bypass." />
<feature name="allowInsecureConfirmation" enabled="false" setExplicitly="false" />
<feature name="failOnAutoUninstaller" enabled="false" setExplicitly="false" description="Fail if automatic uninstaller fails." />
<feature name="failOnStandardError" enabled="false" setExplicitly="false" description="Fail if install provider writes to stderr." />
<feature name="powershellHost" enabled="true" setExplicitly="false" description="Use Chocolatey''s built-in PowerShell host." />
<feature name="logEnvironmentValues" enabled="false" setExplicitly="false" description="Log Environment Values - will log values of environment before and after install (could disclose sensitive data)." />
<feature name="virusCheck" enabled="true" setExplicitly="true" description="Virus Check - perform virus checking on downloaded files. Available in 0.9.10+. Licensed versions only." />
<feature name="downloadCache" enabled="true" setExplicitly="false" description="Download Cache - use the private download cache if available for a package. Available in 0.9.10+. Licensed versions only." />
<feature name="failOnInvalidOrMissingLicense" enabled="false" setExplicitly="false" description="Fail On Invalid Or Missing License - allows knowing when a license is expired or not applied to a machine." />
<feature name="ignoreInvalidOptionsSwitches" enabled="true" setExplicitly="false" description="Ignore Invalid Options/Switches - If a switch or option is passed that is not recognized, should choco fail?" />
<feature name="usePackageExitCodes" enabled="true" setExplicitly="false" description="Use Package Exit Codes - Package scripts can provide exit codes. With this on, package exit codes will be what choco uses for exit when non-zero (this value can come from a dependency package). Chocolatey defines valid exit codes as 0, 1605, 1614, 1641, 3010. With this feature off, choco will exit with a 0 or a 1 (matching previous behavior). Available in 0.9.10+." />
</features>
<apiKeys>
<apiKeys source="https:\/\/chocolatey.org\/" key="bogus\/encrypted+value=" />
</apiKeys>
</chocolatey>
EOT
}
let (:minimum_supported_version) {'0.9.9.0'}
before :each do
PuppetX::Chocolatey::ChocolateyInstall.stubs(:install_path).returns('c:\dude')
PuppetX::Chocolatey::ChocolateyCommon.stubs(:choco_version).returns(minimum_supported_version)
@provider = provider.new(resource)
resource.provider = @provider
# Stub all file and config tests
provider.stubs(:healthcheck)
end
context "verify provider" do
it "should be an instance of Puppet::Type::Chocolateyfeature::ProviderWindows" do
@provider.must be_an_instance_of Puppet::Type::Chocolateyfeature::ProviderWindows
end
it "should have a enable method" do
@provider.should respond_to(:enable)
end
it "should have an exists? method" do
@provider.should respond_to(:exists?)
end
it "should have a disable method" do
@provider.should respond_to(:disable)
end
it "should have a properties method" do
@provider.should respond_to(:properties)
end
it "should have a query method" do
@provider.should respond_to(:query)
end
end
context "self.get_features" do
before :each do
PuppetX::Chocolatey::ChocolateyCommon.expects(:set_env_chocolateyinstall)
end
it "should error when the config file location is null" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(nil)
expect {
provider.get_features
}.to raise_error(Puppet::ResourceError, /Config file not found for Chocolatey/)
end
it "should error when the config file is not found" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(choco_config)
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_config).returns(false)
expect {
provider.get_features
}.to raise_error(Puppet::ResourceError, /was unable to locate config file at/)
end
context "when getting features from the config file" do
features = []
before :each do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(choco_config)
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_config).returns(true)
File.expects(:new).with(choco_config,"r").returns choco_config_contents
features = provider.get_features
end
it "should match the count of features in the config" do
features.count.must eq 14
end
it "should contain xml elements" do
features[0].must be_an_instance_of REXML::Element
end
end
end
context "self.get_feature" do
let (:element) { REXML::Element.new('feature') }
element_name = "default"
element_enabled = 'true'
before :each do
element.add_attributes( { "name" => element_name, "enabled" => element_enabled, } )
end
it "should return nil feature when element is nil" do
provider.get_feature(nil).must be == {}
end
it "should convert an element to a feature" do
feature = provider.get_feature(element)
feature[:name].must eq element_name
feature[:ensure].must eq :enabled
end
it "when feature is disabled" do
element.delete_attribute('enabled')
element.add_attribute('enabled', 'false')
feature = provider.get_feature(element)
feature[:ensure].must eq :disabled
end
end
end

View File

@@ -0,0 +1,607 @@
require 'spec_helper'
require 'stringio'
require 'puppet/type/chocolateysource'
require 'puppet/provider/chocolateysource/windows'
require 'rexml/document'
provider = Puppet::Type.type(:chocolateysource).provider(:windows)
describe provider do
let (:name) { 'sourcename' }
let (:location) { 'c:\packages' }
let (:resource) { Puppet::Type.type(:chocolateysource).new(:provider => :windows, :name => name, :location => location) }
let (:choco_config) { 'c:\choco.config' }
let (:choco_install_path) { 'c:\dude\bin\choco.exe' }
let (:choco_config_contents) { <<-'EOT'
<?xml version="1.0" encoding="utf-8"?>
<chocolatey xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<config>
<add key="cacheLocation" value="" description="Cache location if not TEMP folder." />
<add key="commandExecutionTimeoutSeconds" value="2700" description="Default timeout for command execution." />
<add key="containsLegacyPackageInstalls" value="true" description="Install has packages installed prior to 0.9.9 series." />
<add key="proxy" value="" description="Explicit proxy location." />
<add key="proxyUser" value="" description="Optional proxy user." />
<add key="proxyPassword" value="" description="Optional proxy password. Encrypted." />
<add key="virusCheckMinimumPositives" value="5" description="Minimum numer of scan result positives before flagging a binary as a possible virus. Available in 0.9.10+. Licensed versions only." />
<add key="virusScannerType" value="VirusTotal" description="Virus Scanner Type (Generic or VirusTotal). Defaults to VirusTotal for Pro. Available in 0.9.10+. Licensed versions only." />
<add key="genericVirusScannerPath" value="" description="The full path to the command line virus scanner executable. Used when virusScannerType is Generic. Available in 0.9.10+. Licensed versions only." />
<add key="genericVirusScannerArgs" value="[[File]]" description="The arguments to pass to the generic virus scanner. Use [[File]] for the file path placeholder. Used when virusScannerType is Generic. Available in 0.9.10+. Licensed versions only." />
<add key="genericVirusScannerValidExitCodes" value="0" description="The exit codes for the generic virus scanner when a file is not flagged. Separate with comma, defaults to 0. Used when virusScannerType is Generic. Available in 0.9.10+. Licensed versions only." />
</config>
<sources>
<source id="local" value="c:\packages" disabled="true" user="rob" password="bogus/encrypted+value=" priority="0" />
<source id="chocolatey" value="https://chocolatey.org/api/v2/" disabled="false" priority="0" />
<source id="chocolatey.licensed" value="https://licensedpackages.chocolatey.org/api/v2/" disabled="false" user="customer" password="bogus/encrypted+value=" priority="10" />
</sources>
<features>
<feature name="checksumFiles" enabled="true" setExplicitly="false" description="Checksum files when pulled in from internet (based on package)." />
<feature name="virusCheckFiles" enabled="false" setExplicitly="false" />
<feature name="autoUninstaller" enabled="true" setExplicitly="true" description="Uninstall from programs and features without requiring an explicit uninstall script." />
<feature name="allowGlobalConfirmation" enabled="false" setExplicitly="true" description="Prompt for confirmation in scripts or bypass." />
<feature name="allowInsecureConfirmation" enabled="false" setExplicitly="false" />
<feature name="failOnAutoUninstaller" enabled="false" setExplicitly="false" description="Fail if automatic uninstaller fails." />
<feature name="failOnStandardError" enabled="false" setExplicitly="false" description="Fail if install provider writes to stderr." />
<feature name="powershellHost" enabled="true" setExplicitly="false" description="Use Chocolatey''s built-in PowerShell host." />
<feature name="logEnvironmentValues" enabled="false" setExplicitly="false" description="Log Environment Values - will log values of environment before and after install (could disclose sensitive data)." />
<feature name="virusCheck" enabled="true" setExplicitly="true" description="Virus Check - perform virus checking on downloaded files. Available in 0.9.10+. Licensed versions only." />
<feature name="downloadCache" enabled="true" setExplicitly="false" description="Download Cache - use the private download cache if available for a package. Available in 0.9.10+. Licensed versions only." />
<feature name="failOnInvalidOrMissingLicense" enabled="false" setExplicitly="false" description="Fail On Invalid Or Missing License - allows knowing when a license is expired or not applied to a machine." />
<feature name="ignoreInvalidOptionsSwitches" enabled="true" setExplicitly="false" description="Ignore Invalid Options/Switches - If a switch or option is passed that is not recognized, should choco fail?" />
<feature name="usePackageExitCodes" enabled="true" setExplicitly="false" description="Use Package Exit Codes - Package scripts can provide exit codes. With this on, package exit codes will be what choco uses for exit when non-zero (this value can come from a dependency package). Chocolatey defines valid exit codes as 0, 1605, 1614, 1641, 3010. With this feature off, choco will exit with a 0 or a 1 (matching previous behavior). Available in 0.9.10+." />
</features>
<apiKeys>
<apiKeys source="https://chocolatey.org/" key="bogus/encrypted+value=" />
</apiKeys>
</chocolatey>
EOT
}
let (:newer_choco_version) {'0.9.10.0'}
let (:minimum_supported_version_priority) {'0.9.9.9'}
let (:last_unsupported_version_priority) {'0.9.9.8'}
let (:minimum_supported_version) {'0.9.9.0'}
let (:last_unsupported_version) {'0.9.8.33'}
before :each do
PuppetX::Chocolatey::ChocolateyInstall.stubs(:install_path).returns('c:\dude')
PuppetX::Chocolatey::ChocolateyCommon.stubs(:choco_version).returns(minimum_supported_version)
@provider = provider.new(resource)
resource.provider = @provider
# Stub all file and config tests
provider.stubs(:healthcheck)
end
context "verify provider" do
it "should be an instance of Puppet::Type::Chocolateysource::ProviderWindows" do
@provider.must be_an_instance_of Puppet::Type::Chocolateysource::ProviderWindows
end
it "should have a create method" do
@provider.should respond_to(:create)
end
it "should have an exists? method" do
@provider.should respond_to(:exists?)
end
it "should have a disable method" do
@provider.should respond_to(:disable)
end
it "should have a destroy method" do
@provider.should respond_to(:destroy)
end
it "should have a properties method" do
@provider.should respond_to(:properties)
end
it "should have a query method" do
@provider.should respond_to(:query)
end
end
context "properties" do
context ":location" do
it "should accept c:\\packages" do
resource[:location] = 'c:\packages'
end
it "should accept http://somelocation/packages" do
resource[:location] = 'http://somelocation/packages'
end
it "should accept \\\\unc\\share\\packages" do
resource[:location] = '\\unc\share\packages'
end
end
context ":user" do
it "should accept 'bob'" do
resource[:user] = 'bob'
end
it "should accept 'domain\\bob'" do
resource[:user] = 'domain\bob'
end
it "should accept api keys like 'api123-456-243 d123'" do
resource[:user] = 'api123-456-243 d123'
end
end
context ":password" do
it "should accept 'bob'" do
resource[:password] = 'bob'
end
it "should accept api keys like 'api123-456-243 d123'" do
resource[:password] = 'api123-456-243 d123'
end
end
end
context "self.get_sources" do
before :each do
PuppetX::Chocolatey::ChocolateyCommon.expects(:set_env_chocolateyinstall)
end
it "should error when the config file location is null" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(nil)
expect {
provider.get_sources
}.to raise_error(Puppet::ResourceError, /Config file not found for Chocolatey/)
end
it "should error when the config file is not found" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(choco_config)
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_config).returns(false)
expect {
provider.get_sources
}.to raise_error(Puppet::ResourceError, /was unable to locate config file at/)
end
context "when getting sources from the config file" do
sources = []
before :each do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(choco_config)
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_config).returns(true)
File.expects(:new).with(choco_config,"r").returns choco_config_contents
sources = provider.get_sources
end
it "should match the count of sources in the config" do
sources.count.must eq 3
end
it "should contain xml elements" do
sources[0].must be_an_instance_of REXML::Element
end
end
end
context "self.get_source" do
let (:element) { REXML::Element.new('source') }
element_id = "default"
element_value= "c:\\packages"
element_disabled = "false"
element_priority = "10"
element_user = "thisguy"
element_password = "super/encrypted+value=="
before :each do
element.add_attributes( { "id" => element_id,
"value" => element_value,
"disabled" => element_disabled,
"priority" => element_priority,
"user" => element_user,
"password" => element_password
} )
end
it "should return nil source when element it nil" do
provider.get_source(nil).must be == {}
end
it "should convert an element to a source" do
source = provider.get_source(element)
source[:name].must eq element_id
source[:location].must eq element_value
source[:priority].must eq element_priority
source[:user].must eq element_user
source[:ensure].must eq :present
end
it "should convert a bare bones element to a source" do
element.delete_attribute('disabled')
element.delete_attribute('priority')
element.delete_attribute('user')
element.delete_attribute('password')
source = provider.get_source(element)
source[:name].must eq element_id
source[:location].must eq element_value
source[:ensure].must eq :present
end
it "when source is disabled" do
element.delete_attribute('disabled')
element.add_attribute('disabled', 'true')
source = provider.get_source(element)
source[:ensure].must eq :disabled
end
end
context ".validation" do
before :each do
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).returns(true).at_least(0)
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_install_path).returns(true).at_least(0)
end
it "should not warn when both user/password are empty" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version)
Puppet.expects(:warning).never
Puppet.expects(:debug).never
resource.provider.validate
end
it "should throw when choco version is less than the minimum supported version" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(last_unsupported_version)
expect {
resource.provider.validate
}.to raise_error(Puppet::Error, /Chocolatey version must be '0.9.9.0' to manage configuration values with Puppet/)
end
it "should write a debug message on password when password is not empty" do
resource[:user] = 'tim'
resource[:password] = 'tim'
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version)
Puppet.expects(:warning).never
Puppet.expects(:debug).with("The password is not ensurable, so Puppet is unable to change the value using chocolateysource resource. As a workaround, a password change can be in the form of an exec. Reference Chocolateysource[#{name}]")
resource.provider.validate
end
it "should not warn on user/password on newer choco versions" do
resource[:user] = 'tim'
resource[:password] = 'tim'
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version)
Puppet.expects(:warning).never
resource.provider.validate
end
it "should not warn on user/password when choco version is the minimum supported version" do
resource[:user] = 'tim'
resource[:password] = 'tim'
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version)
Puppet.expects(:warning).never
resource.provider.validate
end
it "should not warn if priority is not set" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version)
Puppet.expects(:warning).never
resource.provider.validate
end
it "should not warn if priority is not set on older unsupported versions" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(last_unsupported_version_priority)
Puppet.expects(:warning).never
resource.provider.validate
end
it "should not warn if priority is 0 on unsupported versions" do
resource[:priority] = 0
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(last_unsupported_version_priority)
Puppet.expects(:warning).never
resource.provider.validate
end
it "should not warn on priority when choco version is newer than the minimum supported version" do
resource[:priority] = 10
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version)
Puppet.expects(:warning).never
resource.provider.validate
end
it "should not warn on priority when choco version is the minimum supported version" do
resource[:priority] = 10
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version_priority)
Puppet.expects(:warning).never
resource.provider.validate
end
it "should warn on priority when choco version is less than the minimum supported version" do
resource[:priority] = 10
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(last_unsupported_version_priority)
Puppet.expects(:warning).with("Chocolatey is unable to manage priority for sources when version is less than 0.9.9.9. The value you set will be ignored.")
resource.provider.validate
end
it "should pass when ensure is not present and location is empty" do
no_location_resource = Puppet::Type.type(:chocolateysource).new(:name => 'source', :ensure => :disabled )
no_location_resource.provider = provider.new(no_location_resource)
no_location_resource.provider.validate
end
it "should fail when ensure => present and location is empty" do
expect {
no_location_resource = Puppet::Type.type(:chocolateysource).new(:name => 'source')
no_location_resource.provider = provider.new(no_location_resource)
no_location_resource.provider.validate
}.to raise_error(Exception, /non-empty location/)
# check for just an exception here
# In some versions of Puppet, this comes back as ArgumentError
# In other versions of Puppet, this comes back as Puppet::Error
end
end
context ".flush" do
resource_name = "yup"
resource_location = "loc"
resource_ensure = :present
resource_priority = 10
resource_user = "thatguy"
resource_password = "secrets!"
before :each do
PuppetX::Chocolatey::ChocolateyCommon.expects(:set_env_chocolateyinstall).at_most_once
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_config_file).returns(choco_config).at_most_once
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(choco_config).returns(true).at_most_once
File.expects(:new).with(choco_config,"r").returns(choco_config_contents).at_most_once
resource[:name] = resource_name
resource[:location] = resource_location
resource[:ensure] = resource_ensure
end
it "should ensure a source is present with minimal values set" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version)
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'add',
'--name', resource_name,
'--source', resource_location,
'--priority', 0,
])
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'enable',
'--name', 'yup'
])
resource.flush
end
it "should ensure a source is present with all values set" do
resource[:priority] = resource_priority
resource[:user] = resource_user
resource[:password] = resource_password
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version)
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'add',
'--name', resource_name,
'--source', resource_location,
'--user', resource_user,
'--password', resource_password,
'--priority', resource_priority,
])
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'enable',
'--name', resource_name
])
resource.flush
end
it "should set priority when present" do
resource[:priority] = resource_priority
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version)
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'add',
'--name', resource_name,
'--source', resource_location,
'--priority', resource_priority,
])
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'enable',
'--name', resource_name
])
resource.flush
end
it "should set user and password when user is present" do
resource[:user] = resource_user
resource[:password] = resource_password
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version)
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'add',
'--name', resource_name,
'--source', resource_location,
'--user', resource_user,
'--password', resource_password,
'--priority', 0,
])
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'enable',
'--name', resource_name
])
resource.flush
end
it "should set user and password when choco version is newer than the minimum supported version" do
resource[:user] = resource_user
resource[:password] = resource_password
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version)
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'add',
'--name', resource_name,
'--source', resource_location,
'--user', resource_user,
'--password', resource_password,
'--priority', 0,
])
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'enable',
'--name', resource_name
])
resource.flush
end
it "should set user and password when choco version is the minimum supported version" do
resource[:user] = resource_user
resource[:password] = resource_password
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version)
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'add',
'--name', resource_name,
'--source', resource_location,
'--user', resource_user,
'--password', resource_password,
])
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'enable',
'--name', resource_name
])
resource.flush
end
it "should set priority when choco version is newer than the minimum supported version" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version)
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'add',
'--name', resource_name,
'--source', resource_location,
'--priority', 0,
])
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'enable',
'--name', resource_name,
])
resource.flush
end
it "should set priority when choco version is the minimum supported version" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_version_priority)
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'add',
'--name', resource_name,
'--source', resource_location,
'--priority', 0,
])
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'enable',
'--name', resource_name,
])
resource.flush
end
it "should not set priority when choco version is less than the minimum supported version" do
resource[:priority] = resource_priority
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(last_unsupported_version_priority)
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'add',
'--name', resource_name,
'--source', resource_location,
])
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'enable',
'--name', resource_name,
])
resource.flush
end
it "should disable a source when ensure => disabled" do
resource[:ensure] = :disabled
resource[:name] = 'chocolatey'
resource.provider.disable
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'disable',
'--name', 'chocolatey'
])
resource.flush
end
it "should remove a source when ensure => absent" do
resource[:ensure] = :absent
resource.provider.destroy
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).never
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'remove',
'--name', resource_name,
])
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'enable',
'--name', 'yup'
]).never
resource.flush
end
it "should provide an error message when choco execution fails" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(newer_choco_version)
Puppet::Util::Execution.expects(:execute).with([provider.command(:chocolatey),
'source', 'add',
'--name', resource_name,
'--source', resource_location,
'--priority', 0,
]).raises(Puppet::ExecutionFailure, "Nooooo")
expect { resource.flush }.to raise_error(Puppet::Error, /Unable to set Chocolatey source/)
end
end
end

View File

@@ -0,0 +1,514 @@
require 'spec_helper'
require 'stringio'
require 'puppet/type/package'
require 'puppet/provider/package/chocolatey'
provider = Puppet::Type.type(:package).provider(:chocolatey)
describe provider do
let (:resource) { Puppet::Type.type(:package).new(:provider => :chocolatey, :name => "chocolatey") }
let (:first_compiled_choco_version) {'0.9.9.0'}
let (:newer_choco_version) {'0.9.10.0'}
let (:last_posh_choco_version) {'0.9.8.33'}
let (:minimum_supported_choco_uninstall_source) {'0.9.10.0'}
let (:minimum_supported_choco_exit_codes) {'0.9.10.0'}
let (:choco_zero_ten_zero) {'0.10.0'}
before :each do
@provider = provider.new(resource)
resource.provider = @provider
# Stub all file and config tests
provider.stubs(:healthcheck)
Puppet::Util::Execution.stubs(:execute)
end
it "should be an instance of Puppet::Type::Package::ProviderChocolatey" do
@provider.must be_an_instance_of Puppet::Type::Package::ProviderChocolatey
end
it "should have an install method" do
@provider.should respond_to(:install)
end
it "should have a latest method" do
@provider.should respond_to(:uninstall)
end
it "should have an update method" do
@provider.should respond_to(:update)
end
it "should have a latest method" do
@provider.should respond_to(:latest)
end
context "parameter :source" do
it "should default to nil" do
resource[:source].should be_nil
end
it "should accept c:\\packages" do
resource[:source] = 'c:\packages'
end
it "should accept http://somelocation/packages" do
resource[:source] = 'http://somelocation/packages'
end
it "should accept \\\\unc\\share\\packages" do
resource[:source] = '\\unc\share\packages'
end
end
context "when installing" do
context "with compiled choco client" do
before :each do
@provider.class.stubs(:is_compiled_choco?).returns(true)
PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns('c:\dude')
PuppetX::Chocolatey::ChocolateyCommon.stubs(:file_exists?).with('c:\dude\bin\choco.exe').returns(true)
PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(first_compiled_choco_version)
# unhold is called in installs on compiled choco
Puppet::Util::Execution.stubs(:execute)
end
it "should use install command without versioned package" do
resource[:ensure] = :present
@provider.expects(:chocolatey).with('install', 'chocolatey','-y', nil)
@provider.install
end
it "should call with ignore package exit codes when = 0.9.10" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_choco_exit_codes).at_least_once
resource[:ensure] = :present
@provider.expects(:chocolatey).with('install', 'chocolatey','-y', nil, '--ignore-package-exit-codes')
@provider.install
end
it "should call with ignore package exit codes when > 0.9.10" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(choco_zero_ten_zero).at_least_once
resource[:ensure] = :present
@provider.expects(:chocolatey).with('install', 'chocolatey','-y', nil, '--ignore-package-exit-codes')
@provider.install
end
it "should use upgrade command with versioned package" do
resource[:ensure] = '1.2.3'
@provider.expects(:chocolatey).with('upgrade', 'chocolatey', '-version', '1.2.3', '-y', nil)
@provider.install
end
it "should call install instead of upgrade if package name ends with .config" do
resource[:name] = "packages.config"
resource[:ensure] = :present
@provider.expects(:chocolatey).with('install', 'packages.config','-y', nil)
@provider.install
end
it "should use source if it is specified" do
resource[:source] = 'c:\packages'
@provider.expects(:chocolatey).with('install','chocolatey','-y', '-source', 'c:\packages', nil)
@provider.install
end
end
context "with posh choco client" do
before :each do
@provider.class.stubs(:is_compiled_choco?).returns(false)
PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns('c:\dude')
PuppetX::Chocolatey::ChocolateyCommon.stubs(:file_exists?).with('c:\dude\bin\choco.exe').returns(true)
PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(last_posh_choco_version)
end
it "should use install command without versioned package" do
resource[:ensure] = :present
@provider.expects(:chocolatey).with('install', 'chocolatey', nil)
@provider.install
end
it "should use update command with versioned package" do
resource[:ensure] = '1.2.3'
@provider.expects(:chocolatey).with('update', 'chocolatey', '-version', '1.2.3', nil)
@provider.install
end
it "should use source if it is specified" do
resource[:source] = 'c:\packages'
@provider.expects(:chocolatey).with('install','chocolatey', '-source', 'c:\packages', nil)
@provider.install
end
end
end
context "when holding" do
context "with compiled choco client" do
before :each do
@provider.class.stubs(:is_compiled_choco?).returns(true)
PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns('c:\dude')
PuppetX::Chocolatey::ChocolateyCommon.stubs(:file_exists?).with('c:\dude\bin\choco.exe').returns(true)
PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(first_compiled_choco_version)
# unhold is called in installs on compiled choco
Puppet::Util::Execution.stubs(:execute)
end
it "should use install command with held package" do
resource[:ensure] = :held
@provider.expects(:chocolatey).with('install', 'chocolatey','-y', nil)
@provider.expects(:chocolatey).with('pin', 'add', '-n', 'chocolatey')
@provider.hold
end
end
context "with posh choco client" do
before :each do
@provider.class.stubs(:is_compiled_choco?).returns(false)
end
it "should throw an argument error with held package" do
resource[:ensure] = :held
expect { @provider.hold }.to raise_error(ArgumentError, "Only choco v0.9.9+ can use ensure => held")
end
end
end
context "when uninstalling" do
context "with compiled choco client" do
before :each do
@provider.class.stubs(:is_compiled_choco?).returns(true)
PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(first_compiled_choco_version)
# unhold is called in installs on compiled choco
Puppet::Util::Execution.stubs(:execute)
end
it "should call the remove operation" do
@provider.expects(:chocolatey).with('uninstall', 'chocolatey','-fy', nil)
@provider.uninstall
end
it "should call with ignore package exit codes when = 0.9.10" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_choco_exit_codes).at_least_once
@provider.expects(:chocolatey).with('uninstall', 'chocolatey','-fy', nil, '--ignore-package-exit-codes')
@provider.uninstall
end
it "should call with ignore package exit codes when > 0.9.10" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(choco_zero_ten_zero).at_least_once
@provider.expects(:chocolatey).with('uninstall', 'chocolatey','-fy', nil, '--ignore-package-exit-codes')
@provider.uninstall
end
it "should use ignore source if it is specified and the version is less than 0.9.10" do
resource[:source] = 'c:\packages'
@provider.expects(:chocolatey).with('uninstall','chocolatey','-fy', nil)
@provider.uninstall
end
it "should use source if it is specified and the version is at least 0.9.10" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_choco_uninstall_source).at_least_once
resource[:source] = 'c:\packages'
@provider.expects(:chocolatey).with('uninstall','chocolatey', '-fy', '-source', 'c:\packages', nil, '--ignore-package-exit-codes')
@provider.uninstall
end
it "should use source if it is specified and the version is greater than 0.9.10" do
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(choco_zero_ten_zero).at_least_once
resource[:source] = 'c:\packages'
@provider.expects(:chocolatey).with('uninstall','chocolatey', '-fy', '-source', 'c:\packages', nil, '--ignore-package-exit-codes')
@provider.uninstall
end
end
context "with posh choco client" do
before :each do
@provider.class.stubs(:is_compiled_choco?).returns(false)
PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(last_posh_choco_version)
end
it "should call the remove operation" do
@provider.expects(:chocolatey).with('uninstall', 'chocolatey', nil)
@provider.uninstall
end
it "should use source if it is specified" do
resource[:source] = 'c:\packages'
@provider.expects(:chocolatey).with('uninstall','chocolatey', '-source', 'c:\packages', nil)
@provider.uninstall
end
end
end
context "when updating" do
context "with compiled choco client" do
before :each do
@provider.class.stubs(:is_compiled_choco?).returns(true)
PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(first_compiled_choco_version)
# unhold is called in installs on compiled choco
Puppet::Util::Execution.stubs(:execute)
end
it "should use `chocolatey upgrade` when ensure latest and package present" do
provider.stubs(:instances).returns [provider.new({
:ensure => "1.2.3",
:name => "chocolatey",
:provider => :chocolatey,
})]
@provider.expects(:chocolatey).with('upgrade', 'chocolatey', '-y', nil)
@provider.update
end
it "should call with ignore package exit codes when = 0.9.10" do
provider.stubs(:instances).returns [provider.new({
:ensure => "1.2.3",
:name => "chocolatey",
:provider => :chocolatey,
})]
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(minimum_supported_choco_exit_codes).at_least_once
resource[:ensure] = :present
@provider.expects(:chocolatey).with('upgrade', 'chocolatey','-y', nil, '--ignore-package-exit-codes')
@provider.update
end
it "should call with ignore package exit codes when > 0.9.10" do
provider.stubs(:instances).returns [provider.new({
:ensure => "1.2.3",
:name => "chocolatey",
:provider => :chocolatey,
})]
PuppetX::Chocolatey::ChocolateyCommon.expects(:choco_version).returns(choco_zero_ten_zero).at_least_once
resource[:ensure] = :present
@provider.expects(:chocolatey).with('upgrade', 'chocolatey','-y', nil, '--ignore-package-exit-codes')
@provider.update
end
it "should use `chocolatey install` when ensure latest and package absent" do
provider.stubs(:instances).returns []
@provider.expects(:chocolatey).with('install', 'chocolatey', '-y', nil)
@provider.update
end
it "should use source if it is specified" do
provider.expects(:instances).returns [provider.new({
:ensure => "latest",
:name => "chocolatey",
:provider => :chocolatey,
})]
resource[:source] = 'c:\packages'
@provider.expects(:chocolatey).with('upgrade','chocolatey', '-y', '-source', 'c:\packages', nil)
@provider.update
end
end
context "with posh choco client" do
before :each do
@provider.class.stubs(:is_compiled_choco?).returns(false)
PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(last_posh_choco_version)
end
it "should use `chocolatey update` when ensure latest and package present" do
provider.stubs(:instances).returns [provider.new({
:ensure => "1.2.3",
:name => "chocolatey",
:provider => :chocolatey,
})]
@provider.expects(:chocolatey).with('update', 'chocolatey', nil)
@provider.update
end
it "should use `chocolatey install` when ensure latest and package absent" do
provider.stubs(:instances).returns []
@provider.expects(:chocolatey).with('install', 'chocolatey', nil)
@provider.update
end
it "should use source if it is specified" do
provider.expects(:instances).returns [provider.new({
:ensure => "latest",
:name => "chocolatey",
:provider => :chocolatey,
})]
resource[:source] = 'c:\packages'
@provider.expects(:chocolatey).with('update','chocolatey', '-source', 'c:\packages', nil)
@provider.update
end
end
end
context "when getting latest" do
context "with compiled choco client" do
before :each do
@provider.class.stubs(:is_compiled_choco?).returns(true)
PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(first_compiled_choco_version)
end
it "should use choco.exe arguments" do
# we don't care where choco is, we are concerned with the arguments that are passed to choco.
#
@provider.send(:latestcmd).drop(1).should == ['upgrade', '--noop', 'chocolatey','-r']
end
it "should use source if it is specified" do
resource[:source] = 'c:\packages'
@provider.send(:latestcmd).drop(1).should == ['upgrade', '--noop', 'chocolatey','-r', '-source', 'c:\packages']
#@provider.expects(:chocolatey).with('upgrade', '--noop', 'chocolatey','-r', '-source', 'c:\packages')
#@provider.latest
end
end
context "with posh choco client" do
before :each do
@provider.class.stubs(:is_compiled_choco?).returns(false)
PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(last_posh_choco_version)
end
it "should use posh arguments" do
@provider.send(:latestcmd).drop(1).should == ['version', 'chocolatey', '| findstr /R "latest" | findstr /V "latestCompare"']
end
it "should use source if it is specified" do
resource[:source] = 'c:\packages'
@provider.send(:latestcmd).drop(1).should == ['version', 'chocolatey', '-source', 'c:\packages', '| findstr /R "latest" | findstr /V "latestCompare"']
#@provider.expects(:chocolatey).with('version', 'chocolatey', '-source', 'c:\packages', '| findstr /R "latest" | findstr /V "latestCompare"')
#@provider.latest
end
end
end
context "query" do
it "should return a hash when chocolatey and the package are present" do
provider.expects(:instances).returns [provider.new({
:ensure => "1.2.5",
:name => "chocolatey",
:provider => :chocolatey,
})]
@provider.query.should == {
:ensure => "1.2.5",
:name => "chocolatey",
:provider => :chocolatey,
}
end
it "should return nil when the package is missing" do
provider.expects(:instances).returns []
@provider.query.should == nil
end
end
context "when fetching a package list" do
it "should invoke provider listcmd" do
provider.expects(:listcmd)
provider.instances
end
it "should query chocolatey" do
provider.expects(:execpipe).with() do |args|
args[1] =~ /list/
args[2] =~ /-lo/
end
provider.instances
end
context "self.instances" do
it "should return nil on error" do
provider.expects(:execpipe).raises(Puppet::ExecutionFailure.new("ERROR!"))
provider.instances.should be_nil
end
context "with compiled choco client" do
before :each do
@provider.class.stubs(:is_compiled_choco?).returns(true)
PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(first_compiled_choco_version)
end
it "should return installed packages with their versions" do
provider.expects(:execpipe).yields(StringIO.new(%Q(package1|1.23\n\package2|2.00\n)))
packages = (provider.instances)
packages.length.should == 2
packages[0].properties.should == {
:provider => :chocolatey,
:ensure => "1.23",
:name => 'package1'
}
packages[1].properties.should == {
:provider => :chocolatey,
:ensure => "2.00",
:name => 'package2'
}
end
it "should return nil on error" do
provider.expects(:execpipe).yields(StringIO.new(%Q(Unable to search for packages when there are no soures enabled for packages and none were passed as arguments.\n)))
expect {
provider.instances
}.to raise_error(Puppet::Error, /At least one source must be enabled./)
end
end
context "with posh choco client" do
before :each do
@provider.class.stubs(:is_compiled_choco?).returns(false)
PuppetX::Chocolatey::ChocolateyVersion.stubs(:version).returns(last_posh_choco_version)
end
it "should return installed packages with their versions" do
provider.expects(:execpipe).yields(StringIO.new(%Q(package1 1.23\n\package2 2.00\n)))
packages = (provider.instances)
packages.length.should == 2
packages[0].properties.should == {
:provider => :chocolatey,
:ensure => "1.23",
:name => 'package1'
}
packages[1].properties.should == {
:provider => :chocolatey,
:ensure => "2.00",
:name => 'package2'
}
end
end
end
end
end

View File

@@ -0,0 +1,103 @@
require 'spec_helper'
require 'puppet/type/chocolateyconfig'
describe Puppet::Type.type(:chocolateyconfig) do
let(:resource) { Puppet::Type.type(:chocolateyconfig).new(:name => "config", :ensure => :absent) }
let(:provider) { Puppet::Provider.new(resource) }
let(:catalog) { Puppet::Resource::Catalog.new }
let (:minimum_supported_version) {'0.9.10.0'}
before :each do
PuppetX::Chocolatey::ChocolateyCommon.stubs(:choco_version).returns(minimum_supported_version)
resource.provider = provider
end
it "should be an instance of Puppet::Type::Chocolateyconfig" do
resource.must be_an_instance_of Puppet::Type::Chocolateyconfig
end
it "parameter :name should be the name var" do
resource.parameters[:name].isnamevar?.should be_truthy
end
#string values
['name','value'].each do |param|
context "parameter :#{param}" do
let (:param_symbol) { param.to_sym }
it "should not allow nil" do
expect {
resource[param_symbol] = nil
}.to raise_error(Puppet::Error, /Got nil value for #{param}/)
end
it "should not allow empty" do
expect {
resource[param_symbol] = ''
}.to raise_error(Puppet::Error, /A non-empty #{param} must/)
end
it "should accept any string value" do
resource[param_symbol] = 'value'
resource[param_symbol] = "c:/thisstring-location/value/somefile.txt"
resource[param_symbol] = "c:\\thisstring-location\\value\\somefile.txt"
end
end
end
context "param :ensure" do
it "should accept 'present'" do
resource[:ensure] = 'present'
end
it "should accept present" do
resource[:ensure] = :present
end
it "should accept absent" do
resource[:ensure] = :absent
end
it "should reject any other value" do
expect {
resource[:ensure] = :whenever
}.to raise_error(Puppet::Error, /Invalid value :whenever. Valid values are/)
end
end
it "should autorequire Exec[install_chocolatey_official] when in the catalog" do
exec = Puppet::Type.type(:exec).new(:name => "install_chocolatey_official", :path => "nope")
catalog.add_resource resource
catalog.add_resource exec
reqs = resource.autorequire
reqs.count.must == 1
reqs[0].source.must == exec
reqs[0].target.must == resource
end
context ".validate" do
it "should pass when ensure => absent with no value" do
resource[:ensure] = :absent
resource.validate
end
it "should pass when ensure => present with a value" do
resource[:ensure] = :present
resource[:value] = 'yo'
resource.validate
end
it "should fail when ensure => present with no value" do
resource[:ensure] = :present
expect {
resource.validate
}.to raise_error(ArgumentError, /Unless ensure => absent, value is required/)
end
end
end

View File

@@ -0,0 +1,58 @@
require 'spec_helper'
require 'puppet/type/chocolateyfeature'
describe Puppet::Type.type(:chocolateyfeature) do
let(:resource) { Puppet::Type.type(:chocolateyfeature).new(:name => "chocolateyfeature", :ensure => "enabled" ) }
let(:provider) { Puppet::Provider.new(resource) }
let(:catalog) { Puppet::Resource::Catalog.new }
let (:minimum_supported_version) {'0.9.9.0'}
before :each do
PuppetX::Chocolatey::ChocolateyCommon.stubs(:choco_version).returns(minimum_supported_version)
resource.provider = provider
resource[:ensure] = 'enabled'
end
it "should be an instance of Puppet::Type::Chocolateyfeature" do
resource.must be_an_instance_of Puppet::Type::Chocolateyfeature
end
it "parameter :name should be the name var" do
resource.parameters[:name].isnamevar?.should be_truthy
end
context "parameter :name" do
let (:param_symbol) { :name }
it "should accept any string value" do
resource[param_symbol] = 'value'
resource[param_symbol] = "c:/thisstring-location/value/somefile.txt"
resource[param_symbol] = "c:\\thisstring-location\\value\\somefile.txt"
end
end
context "param :ensure" do
it "should accept 'enabled'" do
resource[:ensure] = 'enabled'
end
it "should accept enabled" do
resource[:ensure] = :enabled
end
it "should accept 'disabled'" do
resource[:ensure] = 'disabled'
end
it "should accept :disabled" do
resource[:ensure] = :disabled
end
it "should reject any other value" do
expect {
resource[:ensure] = :whenever
}.to raise_error(Puppet::Error, /Invalid value :whenever. Valid values are/)
end
end
end

View File

@@ -0,0 +1,129 @@
require 'spec_helper'
require 'puppet/type/chocolateysource'
describe Puppet::Type.type(:chocolateysource) do
let(:resource) { Puppet::Type.type(:chocolateysource).new(:name => 'source', :location => 'c:\packages') }
let(:provider) { Puppet::Provider.new(resource) }
let(:catalog) { Puppet::Resource::Catalog.new }
let (:minimum_supported_version) {'0.9.9.0'}
before :each do
PuppetX::Chocolatey::ChocolateyCommon.stubs(:choco_version).returns(minimum_supported_version)
resource.provider = provider
end
it "should be an instance of Puppet::Type::Chocolateysource" do
resource.must be_an_instance_of Puppet::Type::Chocolateysource
end
it "parameter :name should be the name var" do
resource.parameters[:name].isnamevar?.should be_truthy
end
#string values
['name','location','user','password'].each do |param|
context "parameter :#{param}" do
let (:param_symbol) { param.to_sym }
it "should accept any string value" do
resource[param_symbol] = 'value'
resource[param_symbol] = "c:/thisstring-location/value/somefile.txt"
resource[param_symbol] = "c:\\thisstring-location\\value\\somefile.txt"
end
end
end
#numeric values
['priority'].each do |param|
context "parameter :#{param}" do
let (:param_symbol) { param.to_sym }
it "should accept any numeric value" do
resource[param_symbol] = 0
resource[param_symbol] = 10
end
it "should accept any string that represents a numeric value" do
resource[param_symbol] = '1'
resource[param_symbol] = '0'
end
it "should not accept other string values" do
expect {
resource[param_symbol] = 'value'
}.to raise_error(Puppet::Error, /An integer is necessary for #{param}/)
end
it "should not accept symbol values" do
expect {
resource[param_symbol] = :whenever
}.to raise_error(Puppet::Error, /An integer is necessary for #{param}/)
end
end
end
context "param :ensure" do
it "should accept 'present'" do
resource[:ensure] = 'present'
end
it "should accept present" do
resource[:ensure] = :present
end
it "should accept :disabled" do
resource[:ensure] = :disabled
end
it "should accept absent" do
resource[:ensure] = :absent
end
it "should reject any other value" do
expect {
resource[:ensure] = :whenever
}.to raise_error(Puppet::Error, /Invalid value :whenever. Valid values are/)
end
end
it "should autorequire Exec[install_chocolatey_official] when in the catalog" do
exec = Puppet::Type.type(:exec).new(:name => "install_chocolatey_official", :path => "nope")
catalog.add_resource resource
catalog.add_resource exec
reqs = resource.autorequire
reqs.count.must == 1
reqs[0].source.must == exec
reqs[0].target.must == resource
end
context ".validate" do
it "should pass when both user/password are empty" do
resource.validate
end
it "should pass when both user/password have a value" do
resource[:user] = 'tim'
resource[:password] = 'tim'
resource.validate
end
it "should fail when user has a value but password does not" do
resource[:user] = 'tim'
expect {
resource.validate
}.to raise_error(ArgumentError, /you must specify both values/)
end
it "should fail when password has a value but user does not" do
resource[:password] = 'tim'
expect {
resource.validate
}.to raise_error(ArgumentError, /you must specify both values/)
end
end
end

View File

@@ -0,0 +1,71 @@
require 'spec_helper'
require 'puppet_x/chocolatey/chocolatey_install'
require 'puppet_x/chocolatey/chocolatey_common'
describe 'Chocolatey Common' do
let (:first_compiled_choco_version) {'0.9.9.0'}
let (:newer_choco_version) {'0.9.10.0'}
let (:last_posh_choco_version) {'0.9.8.33'}
before :each do
PuppetX::Chocolatey::ChocolateyCommon.stubs(:set_env_chocolateyinstall)
end
context ".chocolatey_command" do
it "should find chocolatey install location based on PuppetX::Chocolatey::ChocolateyInstall", :if => Puppet.features.microsoft_windows? do
PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns('c:\dude')
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with('c:\dude\bin\choco.exe').returns(true)
PuppetX::Chocolatey::ChocolateyCommon.chocolatey_command.should == 'c:\dude\bin\choco.exe'
end
it "should find chocolatey install location based on default location", :if => Puppet.features.microsoft_windows? do
PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns('c:\dude')
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with('c:\dude\bin\choco.exe').returns(false)
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with('C:\ProgramData\chocolatey\bin\choco.exe').returns(false)
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with('C:\Chocolatey\bin\choco.exe').returns(false)
PuppetX::Chocolatey::ChocolateyCommon.chocolatey_command.should == "#{ENV['ALLUSERSPROFILE']}\\chocolatey\\bin\\choco.exe"
end
end
context ".choco_version" do
it "should return PuppetX::Chocolatey::ChocolateyVersion.version" do
expected = '0.9.9.0.1'
PuppetX::Chocolatey::ChocolateyVersion.expects(:version).returns(expected)
PuppetX::Chocolatey::ChocolateyCommon.clear_cached_values
PuppetX::Chocolatey::ChocolateyCommon.choco_version.must eq expected
end
end
context ".choco_config_file" do
let (:choco_install_loc) { 'c:\dude' }
it "should return the normal config file location when found" do
expected = 'c:\dude\config\chocolatey.config'
PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns(choco_install_loc)
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(expected).returns(true)
PuppetX::Chocolatey::ChocolateyCommon.choco_config_file.must eq expected
end
it "should return the old config file location for older installs" do
expected = 'c:\dude\chocolateyinstall\chocolatey.config'
PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns(choco_install_loc)
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with('c:\dude\config\chocolatey.config').returns(false)
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with(expected).returns(true)
PuppetX::Chocolatey::ChocolateyCommon.choco_config_file.must eq expected
end
it "should return nil when the config cannot be found" do
PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns(choco_install_loc)
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with('c:\dude\config\chocolatey.config').returns(false)
PuppetX::Chocolatey::ChocolateyCommon.expects(:file_exists?).with('c:\dude\chocolateyinstall\chocolatey.config').returns(false)
PuppetX::Chocolatey::ChocolateyCommon.choco_config_file.must be_nil
end
end
end

View File

@@ -0,0 +1,52 @@
require 'spec_helper'
require 'puppet_x/chocolatey/chocolatey_install'
describe 'Chocolatey Install Location' do
context 'on Windows', :if => Puppet::Util::Platform.windows? do
it "should return install path from registry if it exists" do
expected_value = 'C:\somewhere'
Win32::Registry.any_instance.expects(:[]).with('ChocolateyInstall').returns(expected_value)
PuppetX::Chocolatey::ChocolateyInstall.install_path.must == expected_value
end
it "should return the environment variable ChocolateyInstall if it exists" do
Win32::Registry.any_instance.expects(:[]).with('ChocolateyInstall').raises(Win32::Registry::Error.new(2), 'file not found yo')
# this is a placeholder, it is already set in spec_helper
ENV['ChocolateyInstall'] = 'c:\blah'
PuppetX::Chocolatey::ChocolateyInstall.install_path.must == 'c:\blah'
end
it "should return nil if the environment variable does not exist" do
Win32::Registry.any_instance.expects(:[]).with('ChocolateyInstall').raises(Win32::Registry::Error.new(2), 'file not found yo')
ENV['ChocolateyInstall'] = nil
PuppetX::Chocolatey::ChocolateyInstall.install_path.must be_nil
end
end
context 'on Linux', :if => Puppet.features.posix? do
it "should return the environment variable ChocolateyInstall if it exists" do
# this is a placeholder, it is already set in spec_helper
ENV['ChocolateyInstall'] = 'c:\blah'
PuppetX::Chocolatey::ChocolateyInstall.install_path.must == 'c:\blah'
end
it "should return nil if the ChocolateyInstall variable does not exist" do
ENV['ChocolateyInstall'] = nil
PuppetX::Chocolatey::ChocolateyInstall.install_path.must be_nil
end
end
after :each do
# setting the values back
ENV['ChocolateyInstall'] = 'c:\blah'
end
end

View File

@@ -0,0 +1,81 @@
require 'spec_helper'
require 'puppet_x/chocolatey/chocolatey_version'
describe 'Chocolatey Version' do
context 'on Windows', :if => Puppet::Util::Platform.windows? do
context "when Chocolatey is installed" do
before :each do
PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns('c:\dude')
File.expects(:exist?).with('c:\dude\bin\choco.exe').returns(true)
end
it "should return the value from running choco -v" do
expected_value = '1.2.3'
Puppet::Util::Execution.expects(:execute).returns(expected_value)
PuppetX::Chocolatey::ChocolateyVersion.version.must == expected_value
end
it "should handle cleaning up spaces" do
expected_value = '1.2.3'
Puppet::Util::Execution.expects(:execute).returns(' ' + expected_value + ' ')
PuppetX::Chocolatey::ChocolateyVersion.version.must == expected_value
end
it "should handle older versions of choco" do
expected_value = '1.2.3'
Puppet::Util::Execution.expects(:execute).returns('Please run chocolatey /? or chocolatey help - chocolatey v' + expected_value)
PuppetX::Chocolatey::ChocolateyVersion.version.must == expected_value
end
it "should handle other messages that return with version call" do
expected_value = '1.2.3'
Puppet::Util::Execution.expects(:execute).returns("Error setting some value.\nPlease set this value yourself\r\nsound good?\r" + expected_value)
PuppetX::Chocolatey::ChocolateyVersion.version.must == expected_value
end
it "should handle a trailing line break" do
expected_value = '1.2.3'
Puppet::Util::Execution.expects(:execute).returns(expected_value + "\r\n")
PuppetX::Chocolatey::ChocolateyVersion.version.must == expected_value
end
it "should handle 0.9.8.33 of choco" do
expected_value = '1.2.3'
Puppet::Util::Execution.expects(:execute).returns('!!ATTENTION!!
The next version of Chocolatey (v0.9.9) will require -y to perform
behaviors that change state without prompting for confirmation. Start
using it now in your automated scripts.
For details on the all new Chocolatey, visit http://bit.ly/new_choco
Please run chocolatey /? or chocolatey help - chocolatey v' + expected_value)
PuppetX::Chocolatey::ChocolateyVersion.version.must == expected_value
end
end
context "When Chocolatey is not installed" do
before :each do
PuppetX::Chocolatey::ChocolateyInstall.expects(:install_path).returns(nil)
File.expects(:exist?).with('\bin\choco.exe').returns(false)
end
it "should return nil" do
PuppetX::Chocolatey::ChocolateyVersion.version.must be_nil
end
end
end
context 'on Linux', :if => Puppet.features.posix? do
it "should return nil on a non-windows system" do
PuppetX::Chocolatey::ChocolateyVersion.version.must be_nil
end
end
end

View File

@@ -0,0 +1,151 @@
# ==============================================================================
# Copyright 2011 - Present RealDimensions Software, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use
# this file except in compliance with the License. You may obtain a copy of the
# License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
# specific language governing permissions and limitations under the License.
# ==============================================================================
$ErrorActionPreference = 'Stop'
# For some reason try/catch wrapping only ensures
# that none of this script runs at all
# https://tickets.puppetlabs.com/browse/MODULES-2634
#try {
# variables
$url = '<%= @download_url %>'
$unzipMethod = '<%= @unzip_type %>'
if ($env:TEMP -eq $null) {
$env:TEMP = Join-Path $env:SystemDrive 'temp'
}
$chocTempDir = Join-Path $env:TEMP "chocolatey"
$tempDir = Join-Path $chocTempDir "chocInstall"
if (![System.IO.Directory]::Exists($tempDir)) {[System.IO.Directory]::CreateDirectory($tempDir)}
$file = Join-Path $tempDir "chocolatey.zip"
$chocErrorLog = Join-Path $tempDir "chocError.log"
# PowerShell v2/3 caches the output stream. Then it throws errors due
# to the FileStream not being what is expected. Fixes "The OS handle's
# position is not what FileStream expected. Do not use a handle
# simultaneously in one FileStream and in Win32 code or another
# FileStream."
# This only works with the ConsoleHost (PowerShell InternalHost)
function Fix-PowerShellOutputRedirectionBug {
try{
# http://www.leeholmes.com/blog/2008/07/30/workaround-the-os-handles-position-is-not-what-filestream-expected/ plus comments
$bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField"
$objectRef = $host.GetType().GetField("externalHostRef", $bindingFlags).GetValue($host)
$bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetProperty"
$consoleHost = $objectRef.GetType().GetProperty("Value", $bindingFlags).GetValue($objectRef, @())
[void] $consoleHost.GetType().GetProperty("IsStandardOutputRedirected", $bindingFlags).GetValue($consoleHost, @())
$bindingFlags = [Reflection.BindingFlags] "Instance,NonPublic,GetField"
$field = $consoleHost.GetType().GetField("standardOutputWriter", $bindingFlags)
$field.SetValue($consoleHost, [Console]::Out)
[void] $consoleHost.GetType().GetProperty("IsStandardErrorRedirected", $bindingFlags).GetValue($consoleHost, @())
$field2 = $consoleHost.GetType().GetField("standardErrorWriter", $bindingFlags)
$field2.SetValue($consoleHost, [Console]::Error)
} catch {
Write-Output "Unable to apply redirection fix. Error: $_"
}
}
Fix-PowerShellOutputRedirectionBug
# This should help when certain organizations have issues installing Chocolatey
# Attempt to set highest encryption available for SecurityProtocol.
# PowerShell will not set this by default (until maybe .NET 4.6.x). This
# will typically produce a message for PowerShell v2 (just an info
# message though)
try {
# Set TLS 1.2 (3072), then TLS 1.1 (768), then TLS 1.0 (192), finally SSL 3.0 (48)
# Use integers because the enumeration values for TLS 1.2 and TLS 1.1 won't
# exist in .NET 4.0, even though they are addressable if .NET 4.5+ is
# installed (.NET 4.5 is an in-place upgrade).
[System.Net.ServicePointManager]::SecurityProtocol = 3072 -bor 768 -bor 192 -bor 48
} catch {
Write-Output "Unable to set PowerShell to use TLS 1.2 and TLS 1.1 due to old .NET Framework installed. If you see underlying connection closed or trust errors, you may need to do one or more of the following: (1) upgrade to .NET Framework 4.5 and PowerShell v3 and/or (2) specify internal Chocolatey package location (see https://forge.puppet.com/puppetlabs/chocolatey#manage-chocolatey-installation)."
}
function Download-File {
param (
[string]$url,
[string]$file
)
Write-Output "Downloading $url to $file"
$downloader = new-object System.Net.WebClient
$downloader.Proxy.Credentials=[System.Net.CredentialCache]::DefaultNetworkCredentials;
$downloader.DownloadFile($url, $file)
}
# download the package
Download-File $url $file
if ($unzipMethod -eq '7zip') {
# download 7zip
Write-Output "Download 7Zip commandline tool"
$7zaExe = Join-Path $tempDir '7za.exe'
Download-File 'https://chocolatey.org/7za.exe' "$7zaExe"
# unzip the package
Write-Output "Extracting $file to $tempDir..."
Start-Process "$7zaExe" -ArgumentList "x -o`"$tempDir`" -y `"$file`"" -Wait -NoNewWindow
} else {
if ($PSVersionTable.PSVersion.Major -lt 5) {
$shellApplication = new-object -com shell.application
$zipPackage = $shellApplication.NameSpace($file)
$destinationFolder = $shellApplication.NameSpace($tempDir)
$destinationFolder.CopyHere($zipPackage.Items(),0x10)
} else {
Expand-Archive -Path "$file" -DestinationPath "$tempDir" -Force | Out-Null
}
}
# call chocolatey install
Write-Output "Installing chocolatey on this machine"
$toolsFolder = Join-Path $tempDir "tools"
$chocInstallPS1 = Join-Path $toolsFolder "chocolateyInstall.ps1"
if ($PSVersionTable.PSVersion.Major -gt 2) {
& $chocInstallPS1
} else {
$output = Invoke-Expression $chocInstallPS1
$output
Write-Output "Any errors that occured during install or upgrade are logged here: $chocoErrorLog"
$error | out-file $chocErrorLog
}
Write-Output 'Ensuring chocolatey commands are on the path'
$chocInstallVariableName = "ChocolateyInstall"
$chocoPath = [Environment]::GetEnvironmentVariable($chocInstallVariableName, [System.EnvironmentVariableTarget]::User)
if ($chocoPath -eq $null -or $chocoPath -eq '') {
$chocoPath = 'C:\ProgramData\Chocolatey'
}
$chocoBinPath = Join-Path $chocoPath 'bin'
if ($($env:Path).ToLower().Contains($($chocoBinPath).ToLower()) -eq $false) {
$env:Path = [Environment]::GetEnvironmentVariable('Path',[System.EnvironmentVariableTarget]::Machine);
}
Write-Output 'Ensuring chocolatey.nupkg is in the lib folder'
$chocoPkgDir = Join-Path $chocoPath 'lib\chocolatey'
$nupkg = Join-Path $chocoPkgDir 'chocolatey.nupkg'
if (![System.IO.Directory]::Exists($chocoPkgDir)) { [System.IO.Directory]::CreateDirectory($chocoPkgDir); }
Copy-Item "$file" "$nupkg" -Force -ErrorAction SilentlyContinue
#}
#catch
#{
# Write-Host "$($_.Exception.Message)"
# exit 1
#}

View File

@@ -0,0 +1,20 @@
require 'master_manipulator'
test_name 'MODULES-3138 - C48 - Install Puppet Enterprise'
# Check for a master before continuing
if master == nil
fail_test("Master is not set, are you using a host configuration that has a master?")
end
# Init
step 'Install PE'
install_pe
step 'Disable Node Classifier'
disable_node_classifier(master)
step 'Disable Environment Caching'
disable_env_cache(master)
step 'Restart Puppet Server'
restart_puppet_server(master)

View File

@@ -0,0 +1,25 @@
test_name 'MODULES-3138 - C97814 - Install Pre-suite Acceptance Test'
# Beaker option set if "BEAKER_FORGE_HOST" environment variable is present
staging = { :module_name => 'puppetlabs-chocolatey' }
if options[:forge_host]
# Check to see if module version is specified.
staging[:version] = ENV['MODULE_VERSION'] if ENV['MODULE_VERSION']
step 'Install Chocolatey Module from Forge'
install_dev_puppet_module_on(master, staging)
else
step 'Install Chocolatey Module Dependencies'
%w(puppetlabs-stdlib puppetlabs-powershell badgerious/windows_env).each do |dep|
on(master, puppet("module install #{dep}"))
end
end
step 'Install Chocolatey Module'
proj_root = File.expand_path(File.join(File.dirname(__FILE__), '../../../'))
local = { :module_name => 'chocolatey', :source => proj_root}
# Check to see if module version is specified.
staging[:version] = ENV['MODULE_VERSION'] if ENV['MODULE_VERSION']
# in CI install from staging forge, otherwise from local
install_dev_puppet_module_on(master, local)

View File

@@ -0,0 +1,47 @@
require 'master_manipulator'
require 'chocolatey_helper'
test_name 'MODULES-3043 - C97739 - Install Client on Virgin System'
chocolatey_pp = <<MANIFEST
class {'chocolatey':
chocolatey_download_url => 'file:///C:/chocolatey.nupkg',
use_7zip => false,
}
MANIFEST
chocoVersion = /[0-9]+[\d'.']*/
# Setup
step 'Inject "site.pp" on Master'
site_pp = create_site_pp(master, :manifest => chocolatey_pp)
inject_site_pp(master, get_site_pp_path(master), site_pp)
#Test
confine_block(:to, :platform => 'windows') do
agents.each do |agent|
opts = {
:acceptable_exit_codes => [0, 2]
}
url = get_latest_chocholatey_download_url
step 'Download chocolatey nuget package' do
curl_on(agent, "#{url} > C:/chocolatey.nupkg")
end
step 'should apply chocolatey manifest and install choco.exe' do
on(agent, puppet('agent -t --environment production'), opts) do |result|
assert_no_match(/Error:/, result.stderr, 'Unexpected error was detected!')
end
end
step 'should have valid version of Chocolatey' do
on(agent, 'C:/ProgramData/chocolatey/bin/choco.exe -v', :acceptable_exit_codes => 0) do |result|
assert_match(chocoVersion, result.stdout, 'Expected: ' + chocoVersion.to_s + ' but got ' + result.stdout)
end
end
end
end

View File

@@ -0,0 +1,7 @@
test_name "Hello Test"
step "Say Hello"
hosts.each do |host|
on(host, "echo hello!")
end

View File

@@ -0,0 +1,3 @@
# Ignore all configs in this directory, they will be created by beaker-hostgenerator
*
!.gitignore

View File

@@ -0,0 +1,50 @@
require 'net/http'
require 'uri'
require 'nokogiri'
$chocolatey_latest_info_url = "http://nexus.delivery.puppetlabs.net/service/local/nuget/choco-pipeline-tests/Packages()?$filter=((Id%20eq%20%27chocolatey%27)%20and%20(not%20IsPrerelease))%20and%20IsLatestVersion"
# Extract the url for the latest Puppet hosted version of Chocolatey
#
# ==== Returns
#
# +string+ - url from the feed/content->src of the $chocolatey_latest_info_url
#
# ==== Raises
#
# URI::InvalidURIError
#
# ==== Examples
#
# url = get_latest_chocholatey_download_url;
def get_latest_chocholatey_download_url()
uri = URI.parse($chocolatey_latest_info_url)
response = Net::HTTP.get_response(uri)
xml_str = Nokogiri::XML(response.body)
src_url = xml_str.css('//feed//content').attr('src')
return src_url
end
def config_file_location
'c:\\ProgramData\\chocolatey\\config\\chocolatey.config'
end
def backup_config
step 'Backup default configuration file'
on(agents, "cmd.exe /c \"copy #{config_file_location} #{config_file_location}.bkp\"")
end
def reset_config
step 'Reset configuration file to default'
on(agents, "cmd.exe /c \"move #{config_file_location}.bkp #{config_file_location}\"")
end
def get_xml_value(xpath, file_text)
doc = Nokogiri::XML(file_text)
doc.xpath(xpath)
end

View File

@@ -0,0 +1,93 @@
test_name "Install CA Certs"
confine(:to, :platform => 'windows')
GEOTRUST_GLOBAL_CA = <<-EOM
-----BEGIN CERTIFICATE-----
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
-----END CERTIFICATE-----
EOM
USERTRUST_NETWORK_CA = <<-EOM
-----BEGIN CERTIFICATE-----
MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
-----END CERTIFICATE-----
EOM
EQUIFAX_CA = <<-EOM
-----BEGIN CERTIFICATE-----
MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
-----END CERTIFICATE-----
EOM
hosts.each do |host|
step "Installing Geotrust CA cert"
create_remote_file(host, "geotrustglobal.pem", GEOTRUST_GLOBAL_CA)
on host, "chmod 644 geotrustglobal.pem"
on host, "cmd /c certutil -v -addstore Root `cygpath -w geotrustglobal.pem`"
step "Installing Usertrust Network CA cert"
create_remote_file(host, "usertrust-network.pem", USERTRUST_NETWORK_CA)
on host, "chmod 644 usertrust-network.pem"
on host, "cmd /c certutil -v -addstore Root `cygpath -w usertrust-network.pem`"
step "Installing Equifax CA cert"
create_remote_file(host, "equifax.pem", EQUIFAX_CA)
on host, "chmod 644 equifax.pem"
on host, "cmd /c certutil -v -addstore Root `cygpath -w equifax.pem`"
end

View File

@@ -0,0 +1,13 @@
test_name 'Install Puppet Agent'
confine(:to, :platform => 'windows')
step 'Install Puppet Agent'
if ENV['BEAKER_PUPPET_AGENT_VERSION']
install_puppet_agent_on(agents, :version => ENV['BEAKER_PUPPET_AGENT_VERSION'])
else
install_puppet_agent_on(agents)
end
step 'Prevent Puppet Service from Running'
on(agents, puppet('resource service puppet ensure=stopped enable=false'))

View File

@@ -0,0 +1,27 @@
test_name 'MODULES-3138 - C97813 - Install Pre-suite Reference Test'
confine(:to, :platform => 'windows')
# Init
proj_root = File.expand_path(File.join(File.dirname(__FILE__), '../../../'))
staging = { :module_name => 'puppetlabs-chocolatey' }
local = { :module_name => 'chocolatey', :source => proj_root }
# Beaker option set if "BEAKER_FORGE_HOST" environment variable is present
agents.each do |agent|
if options[:forge_host]
# Check to see if module version is specified.
staging[:version] = ENV['MODULE_VERSION'] if ENV['MODULE_VERSION']
step 'Install Chocolatey Module from Forge'
install_dev_puppet_module_on(agent, staging)
else
step 'Install Chocolatey Module Dependencies'
%w(puppetlabs-stdlib puppetlabs-powershell badgerious/windows_env).each do |dep|
on(agent, puppet("module install #{dep}"))
end
step 'Install Chocolatey Module from Local Source'
# in CI install from staging forge, otherwise from local
install_dev_puppet_module_on(agent, local)
end
end

View File

@@ -0,0 +1,39 @@
require 'chocolatey_helper'
test_name 'MODULES-3043 - C97739 - Install Client on Virgin System'
confine(:to, :platform => 'windows')
chocolatey_pp = <<MANIFEST
class {'chocolatey':
chocolatey_download_url => 'file:///C:/chocolatey.nupkg',
use_7zip => false,
}
MANIFEST
chocoVersion = /[0-9]+[\d'.']*/
agents.each do |agent|
opts = {
:acceptable_exit_codes => [0, 2]
}
url = get_latest_chocholatey_download_url;
step 'Download chocolatey nuget package' do
curl_on(agent, "#{url} > C:/chocolatey.nupkg")
end
step 'should apply chocolatey manifest and install choco.exe' do
apply_manifest_on(agent, chocolatey_pp, opts) do |result|
assert_no_match(/Error:/, result.stderr, 'Unexpected error was detected!')
end
end
step 'should have valid version of Chocolatey' do
on(agent, 'C:/ProgramData/chocolatey/bin/choco.exe -v', :acceptable_exit_codes => 0) do |result|
assert_match(chocoVersion, result.stdout, 'Expected: ' + chocoVersion.to_s + ' but got ' + result.stdout)
end
end
end

View File

@@ -0,0 +1,29 @@
require 'chocolatey_helper'
test_name 'MODULES-3035 - Add New Config Item'
confine(:to, :platform => 'windows')
backup_config
# arrange
chocolatey_src = <<-PP
chocolateyconfig {'hello123':
ensure => present,
value => 'this guy',
}
PP
# teardown
teardown do
reset_config
end
# act
step 'Apply manifest'
apply_manifest(chocolatey_src, :catch_failures => true)
step 'Verify results'
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
assert_match(/this guy/, get_xml_value("//config/add[@key='hello123']/@value", result.output).to_s, 'Value did not match')
end
end

View File

@@ -0,0 +1,29 @@
require 'chocolatey_helper'
test_name 'MODULES-3035 - Add a Value to an Existing Config Setting'
confine(:to, :platform => 'windows')
backup_config
# arrange
chocolatey_src = <<-PP
chocolateyconfig {'proxy':
ensure => present,
value => 'https://somewhere',
}
PP
# teardown
teardown do
reset_config
end
# act
step 'Apply manifest'
apply_manifest(chocolatey_src, :catch_failures => true)
step 'Verify results'
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
assert_match(/https\:\/\/somewhere/, get_xml_value("//config/add[@key='proxy']/@value", result.output).to_s, 'Value did not match')
end
end

View File

@@ -0,0 +1,46 @@
require 'chocolatey_helper'
test_name 'MODULES-3035 - Config Settings Change Config Value'
confine(:to, :platform => 'windows')
backup_config
# arrange
chocolatey_src = <<-PP
chocolateyconfig {'proxyUser':
value => 'bob',
}
PP
# teardown
teardown do
reset_config
end
# act
step 'Apply manifest to setup'
apply_manifest(chocolatey_src, :catch_failures => true)
step 'Verify setup'
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
assert_match(/bob/, get_xml_value("//config/add[@key='proxyUser']/@value", result.output).to_s, 'Value did not match')
end
end
# arrange
chocolatey_src_change = <<-PP
chocolateyconfig {'proxyuser':
value => 'tim',
}
PP
# act
step 'Apply manifest to change config setting'
apply_manifest(chocolatey_src_change, :catch_failures => true)
step 'Verify results'
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
assert_match(/tim/, get_xml_value("//config/add[@key='proxyUser']/@value", result.output).to_s, 'Value did not change')
end
end

View File

@@ -0,0 +1,50 @@
require 'chocolatey_helper'
test_name 'MODULES-3035 - Ensure Config Value with Password In Name'
confine(:to, :platform => 'windows')
backup_config
# arrange
chocolatey_src = <<-PP
chocolateyconfig {'proxypassword':
value => 'secrect',
}
PP
# teardown
teardown do
reset_config
end
password = ''
# act
step 'Apply manifest to setup proxyPassword'
apply_manifest(chocolatey_src, :catch_failures => true)
step 'Verify setup'
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
password = get_xml_value("//config/add[@key='proxyPassword']/@value", result.output).to_s
assert_match(/.+/, password, 'Value did not match')
end
end
# arrange
chocolatey_src_change = <<-PP
chocolateyconfig {'proxypassword':
value => 'secrect2',
}
PP
# act
step 'Apply manifest to attempt to change proxyPassword - should have no effect'
apply_manifest(chocolatey_src_change, :catch_failures => true)
step 'Verify results'
# should have no effect
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
assert_match(password, get_xml_value("//config/add[@key='proxyPassword']/@value", result.output).to_s, 'Value should not have changed')
end
end

View File

@@ -0,0 +1,25 @@
require 'chocolatey_helper'
test_name 'MODULES-3035 - Fail to Apply Bad Manifest'
confine(:to, :platform => 'windows')
backup_config
# arrange
chocolatey_src = <<-PP
chocolateyconfig {'bob':
ensure => sad,
value => 'yes',
}
PP
# teardown
teardown do
reset_config
end
# act
step 'Apply Manifest'
apply_manifest(chocolatey_src, :expect_failures => true) do
step 'Verify Failure'
assert_match(/Error: Parameter ensure failed on Chocolateyconfig\[bob\]: Invalid value "sad"/, stderr, "stderr did not match expected")
end

View File

@@ -0,0 +1,24 @@
require 'chocolatey_helper'
test_name 'MODULES-3035 - Fail to Set Present With No Value'
confine(:to, :platform => 'windows')
backup_config
# arrange
chocolatey_src = <<-PP
chocolateyconfig {'bob':
ensure => present,
}
PP
# teardown
teardown do
reset_config
end
# act
step 'Apply Manifest'
apply_manifest(chocolatey_src, :expect_failures => true) do
step 'Verify Failure'
assert_match(/Error: Validation of Chocolateyconfig\[bob\] failed: Unless ensure => absent, value is required/, stderr, "stderr did not match expected")
end

View File

@@ -0,0 +1,50 @@
require 'chocolatey_helper'
test_name 'MODULES-3035 - Config Settings Remove Value with Password in Name'
confine(:to, :platform => 'windows')
backup_config
# arrange
chocolatey_src = <<-PP
chocolateyconfig {'proxypassword':
value => 'secrect',
}
PP
# teardown
teardown do
reset_config
end
password = ''
# act
step 'Apply manifest to setup proxyPassword'
apply_manifest(chocolatey_src, :catch_failures => true)
step 'Verify setup'
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
password = get_xml_value("//config/add[@key='proxyPassword']/@value", result.output).to_s
assert_match(/.+/, password, 'Value did not match')
end
end
# arrange
chocolatey_src_change = <<-PP
chocolateyconfig {'proxypassword':
ensure => absent,
}
PP
# act
step 'Apply manifest to remove proxyPassword'
apply_manifest(chocolatey_src_change, :catch_failures => true)
step 'Verify results'
# should have no effect
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
assert_not_match(/.+/, get_xml_value("//config/add[@key='proxyPassword']/@value", result.output).to_s, 'Value should have been removed')
end
end

View File

@@ -0,0 +1,28 @@
require 'chocolatey_helper'
test_name 'MODULES-3035 - Remove Value From Config Setting'
confine(:to, :platform => 'windows')
backup_config
# arrange
chocolatey_src = <<-PP
chocolateyconfig {'commandExecutionTimeoutSeconds':
ensure => absent,
}
PP
# teardown
teardown do
reset_config
end
# act
step 'Apply manifest'
apply_manifest(chocolatey_src, :catch_failures => true)
step 'Verify results'
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
assert_not_match(/.+/, get_xml_value("//config/add[@key='commandExecutionTimeoutSeconds']/@value", result.output).to_s, 'Value did not match')
end
end

View File

@@ -0,0 +1,35 @@
require 'chocolatey_helper'
test_name 'MODULES-3034 - Disable an Already Disabled Feature'
confine(:to, :platform => 'windows')
backup_config
# arrange
chocolatey_src = <<-PP
chocolateyfeature {'failOnAutoUninstaller':
ensure => disabled,
}
PP
# teardown
teardown do
reset_config
end
# verify prior
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
assert_match(/false/, get_xml_value("//features/feature[@name='failOnAutoUninstaller']/@enabled", result.output).to_s, 'Was not disabled by default, please adjust test to find another value.')
end
end
# act
step 'Apply manifest'
apply_manifest(chocolatey_src, :catch_failures => true)
step 'Verify results'
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
assert_match(/false/, get_xml_value("//features/feature[@name='failOnAutoUninstaller']/@enabled", result.output).to_s, 'Was not found disabled')
end
end

View File

@@ -0,0 +1,35 @@
require 'chocolatey_helper'
test_name 'MODULES-3034 - Disable an Enabled Feature'
confine(:to, :platform => 'windows')
backup_config
# arrange
chocolatey_src = <<-PP
chocolateyfeature {'checksumFiles':
ensure => disabled,
}
PP
# teardown
teardown do
reset_config
end
#verify prior
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
assert_match(/true/, get_xml_value("//features/feature[@name='checksumFiles']/@enabled", result.output).to_s, 'Was not enabled by default, please adjust test to find another value.')
end
end
# act
step 'Apply manifest'
apply_manifest(chocolatey_src, :catch_failures => true)
step 'Verify results'
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
assert_match(/false/, get_xml_value("//features/feature[@name='checksumFiles']/@enabled", result.output).to_s, 'Was not found disabled')
end
end

View File

@@ -0,0 +1,35 @@
require 'chocolatey_helper'
test_name 'MODULES-3034 - Enable a Disabled Feature'
confine(:to, :platform => 'windows')
backup_config
# arrange
chocolatey_src = <<-PP
chocolateyfeature {'failOnAutoUninstaller':
ensure => enabled,
}
PP
# teardown
teardown do
reset_config
end
# verify prior
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
assert_match(/false/, get_xml_value("//features/feature[@name='failOnAutoUninstaller']/@enabled", result.output).to_s, 'Was not disabled by default, please adjust test to find another value.')
end
end
# act
step 'Apply manifest'
apply_manifest(chocolatey_src, :catch_failures => true)
step 'Verify results'
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
assert_match(/true/, get_xml_value("//features/feature[@name='failOnAutoUninstaller']/@enabled", result.output).to_s, 'Was not found enabled')
end
end

View File

@@ -0,0 +1,35 @@
require 'chocolatey_helper'
test_name 'MODULES-3034 - Enable Already Enabled Feature'
confine(:to, :platform => 'windows')
backup_config
# arrange
chocolatey_src = <<-PP
chocolateyfeature {'checksumFiles':
ensure => enabled,
}
PP
# teardown
teardown do
reset_config
end
#verify prior
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
assert_match(/true/, get_xml_value("//features/feature[@name='checksumFiles']/@enabled", result.output).to_s, 'Was not enabled by default, please adjust test to find another value.')
end
end
# act
step 'Apply manifest'
apply_manifest(chocolatey_src, :catch_failures => true)
step 'Verify results'
agents.each do |agent|
on(agent, "cmd.exe /c \"type #{config_file_location}\"") do |result|
assert_match(/true/, get_xml_value("//features/feature[@name='checksumFiles']/@enabled", result.output).to_s, 'Was not found enabled')
end
end

View File

@@ -0,0 +1,24 @@
require 'chocolatey_helper'
test_name 'MODULES-3034 - Enable non-existent feature'
confine(:to, :platform => 'windows')
backup_config
# arrange
chocolatey_src = <<-PP
chocolateyfeature {'idontexistfeature123123':
ensure => enabled,
}
PP
# teardown
teardown do
reset_config
end
# act
step 'Apply manifest'
apply_manifest(chocolatey_src, :expect_failures => true) do
step 'Verify Failure'
assert_match(/returned 1: Feature 'idontexistfeature123123' not found/, stderr, "stderr did not match expected")
end

Some files were not shown because too many files have changed in this diff Show More