knife-butler 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6cc04e9386149e034f6668aa9a1a451128e887e9
4
+ data.tar.gz: d1e1ebd8d7479011af8ba3c39408e2b28a8899c1
5
+ SHA512:
6
+ metadata.gz: 65597e30106b2570dbfb1ee62565abe91a70d2ad50fc7c4f6deb15b5fb0aed9b5af41c62fc9a7d81664bc67bb94289b96d54e68ca6591a3cd1555f0f08deb007
7
+ data.tar.gz: 5abd3122ea1949896554a3cc2c8acef5d99e90400ade7fd07f88c7114cc41602b40eb2949b95480b24ddce320788015153edbb83ebb3dc53faf71170ef621c7b
data/CHANGES.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ == 2018-04-07 (0.0.1)
2
+
3
+ * Initial release
data/README.rdoc ADDED
@@ -0,0 +1,26 @@
1
+ = knife-butler
2
+
3
+ == DESCRIPTION:
4
+
5
+ Knife plugin for cookbook testing.
6
+
7
+ == INSTALLATION:
8
+ This plugin is distributed as a Ruby Gem. To install it, run:
9
+
10
+ gem install knife-butler (with specific-install for now; not published)
11
+
12
+ Depending on your system's configuration, you may need to run this command with root privileges.
13
+
14
+ == CONFIGURATION:
15
+
16
+ ..
17
+
18
+ == SUBCOMMANDS:
19
+
20
+ ...
21
+
22
+ == LICENSE:
23
+
24
+ Author:: Robbert-Jan Sperna Weiland
25
+
26
+ Copyright:: Copyright (c) 2018
@@ -0,0 +1,69 @@
1
+ #
2
+ # Author:: Robbert-Jan Sperna Weiland (<rspernaweiland@schubergphilis.com>)
3
+ #
4
+
5
+ require 'chef/knife'
6
+ require 'json'
7
+
8
+ module KnifeButler
9
+ class ButlerClean < Chef::Knife
10
+
11
+ deps do
12
+ require 'chef/knife/bootstrap'
13
+ # Depend on knife-cosmic:
14
+ require 'chef/knife/cosmic_server_delete'
15
+ Knifecosmic::CosmicServerDelete.load_deps
16
+ require 'yaml'
17
+ require "erb"
18
+ end
19
+
20
+ banner "knife butler clean"
21
+
22
+ def run
23
+ test_config = config_fetch
24
+ butler_data = butler_data_fetch
25
+
26
+ puts butler_data
27
+
28
+ # Destroy VM
29
+ server_delete = Knifecosmic::CosmicServerDelete.new
30
+
31
+ server_delete.name_args = [butler_data['server_name']]
32
+ server_delete.config[:cosmic_url] = "https://#{test_config['driver']['customize']['host']}/client/api"
33
+ server_delete.config[:cosmic_api_key] = test_config['driver']['customize']['api_key']
34
+ server_delete.config[:cosmic_secret_key] = test_config['driver']['customize']['secret_key']
35
+ server_delete.config[:yes] = true
36
+ puts "Deleting VM..."
37
+ begin
38
+ vm_delete_details = server_delete.run
39
+ rescue
40
+ nil
41
+ end
42
+ puts "Done!"
43
+
44
+ # Wait for the VM do be deleted
45
+ sleep(10)
46
+
47
+ # Expunge!
48
+ begin
49
+ vm_delete_details = server_delete.run
50
+ rescue
51
+ nil
52
+ end
53
+ puts "Done!"
54
+ end
55
+
56
+ def butler_data_fetch
57
+ # Get config
58
+ butler_data_raw = File.read('.butler.yml')
59
+ YAML.load(butler_data_raw)
60
+ end
61
+
62
+ def config_fetch
63
+ # Get config
64
+ test_config_raw = File.read('.kitchen.yml')
65
+ test_config_evaluated = ERB.new(test_config_raw).result( binding )
66
+ YAML.load(test_config_evaluated)
67
+ end
68
+ end # class
69
+ end
@@ -0,0 +1,165 @@
1
+ #
2
+ # Author:: Robbert-Jan Sperna Weiland (<rspernaweiland@schubergphilis.com>)
3
+ #
4
+
5
+ require 'chef/knife'
6
+ require 'json'
7
+
8
+ module KnifeButler
9
+ class ButlerPrepare < Chef::Knife
10
+
11
+ deps do
12
+ require 'chef/knife/bootstrap'
13
+ Chef::Knife::Bootstrap.load_deps
14
+ # Depend on knife-cosmic:
15
+ require 'chef/knife/cosmic_server_create'
16
+ Knifecosmic::CosmicServerCreate.load_deps
17
+ Knifecosmic::CosmicForwardruleCreate.load_deps
18
+ require 'yaml'
19
+ require "erb"
20
+ require 'socket'
21
+ require 'timeout'
22
+ end
23
+
24
+ banner "knife butler prepare"
25
+
26
+ def run
27
+ test_config = config_fetch
28
+ Chef::Log.debug("cosmic HOST: #{test_config['driver']['customize']['host']}")
29
+ Chef::Log.debug("cosmic NETWORK_NAME: #{test_config['driver']['customize']['network_name']}")
30
+
31
+ # Create unique data for this test environment:
32
+ o = [('a'..'z'), ('A'..'Z')].map(&:to_a).flatten
33
+ str_random = (0...8).map { o[rand(o.length)] }.join
34
+ butler_data = {}
35
+ butler_data['server_name'] = "butler-#{str_random}"
36
+ str_random = (0...4).map { [rand(10)] }.join
37
+ butler_data['port_exposed_winrm'] = str_random
38
+ str_random = (0...4).map { [rand(10)] }.join
39
+ butler_data['port_exposed_zipdata'] = str_random
40
+ File.open('.butler.yml', 'w') {|f| f.write butler_data.to_yaml } #Store
41
+
42
+ # Create VM
43
+ server_create = Knifecosmic::CosmicServerCreate.new
44
+
45
+ server_create.name_args = [butler_data['server_name']]
46
+ server_create.config[:cosmic_networks] = [test_config['driver']['customize']['network_name']]
47
+ server_create.config[:cosmic_template] = test_config['platforms'].first['driver_config']['box']
48
+ server_create.config[:bootstrap] = false
49
+ server_create.config[:public_ip] = false
50
+ server_create.config[:cosmic_service] = test_config['driver']['customize']['service_offering_name']
51
+ #server_create.config[:ipfwd_rules] = "#{butler_data['port_exposed_winrm']}:5985:TCP"
52
+ server_create.config[:cosmic_password] = true
53
+ server_create.config[:cosmic_url] = "https://#{test_config['driver']['customize']['host']}/client/api"
54
+ server_create.config[:cosmic_api_key] = test_config['driver']['customize']['api_key']
55
+ server_create.config[:cosmic_secret_key] = test_config['driver']['customize']['secret_key']
56
+ puts "Creating VM..."
57
+ server_create.run
58
+ server_details = server_create.server
59
+ puts "Done!...details:"
60
+ puts server_details
61
+ puts "IP OF SERVER: #{server_details['public_ip']}"
62
+ puts "End of detalis"
63
+ butler_data['server_ip'] = server_details['public_ip']
64
+ butler_data['server_password'] = server_details['passwordenabled'] ? server_details['password'] : test_config['driver']['customize']['vm_password']
65
+ File.open('.butler.yml', 'w') {|f| f.write butler_data.to_yaml } #Store
66
+
67
+ # Wait for the VM to settle into existance
68
+ sleep(5)
69
+
70
+ # Create WinRM forwardrule
71
+ forwardingrule_create = Knifecosmic::CosmicForwardruleCreate.new
72
+
73
+ forwardingrule_create.name_args = [butler_data['server_name'], "#{butler_data['port_exposed_winrm']}:5985:TCP"]
74
+ forwardingrule_create.config[:vrip] = test_config['driver']['customize']['pf_ip_address']
75
+ forwardingrule_create.config[:cosmic_url] = "https://#{test_config['driver']['customize']['host']}/client/api"
76
+ forwardingrule_create.config[:cosmic_api_key] = test_config['driver']['customize']['api_key']
77
+ forwardingrule_create.config[:cosmic_secret_key] = test_config['driver']['customize']['secret_key']
78
+ puts "Creating forwarding rule..."
79
+ forwardingrule_details = forwardingrule_create.run
80
+ puts "Done!"
81
+
82
+ # Create Payload forwardrule
83
+ forwardingrule_create = Knifecosmic::CosmicForwardruleCreate.new
84
+
85
+ forwardingrule_create.name_args = [butler_data['server_name'], "#{butler_data['port_exposed_zipdata']}:5999:TCP"]
86
+ forwardingrule_create.config[:vrip] = test_config['driver']['customize']['pf_ip_address']
87
+ forwardingrule_create.config[:cosmic_url] = "https://#{test_config['driver']['customize']['host']}/client/api"
88
+ forwardingrule_create.config[:cosmic_api_key] = test_config['driver']['customize']['api_key']
89
+ forwardingrule_create.config[:cosmic_secret_key] = test_config['driver']['customize']['secret_key']
90
+ puts "Creating forwarding rule..."
91
+ forwardingrule_details = forwardingrule_create.run
92
+ puts "Done!"
93
+
94
+ # Firewall rule for WinRM
95
+ firewall_rule = Knifecosmic::CosmicFirewallruleCreate.new
96
+ firewall_rule.config[:cosmic_url] = "https://#{test_config['driver']['customize']['host']}/client/api"
97
+ firewall_rule.config[:cosmic_api_key] = test_config['driver']['customize']['api_key']
98
+ firewall_rule.config[:cosmic_secret_key] = test_config['driver']['customize']['secret_key']
99
+ firewall_rule.name_args = [butler_data['server_name']]
100
+ test_config['driver']['customize']['pf_trusted_networks'].split(",").each do |cidr|
101
+ firewall_rule.name_args.push("5985:5985:TCP:#{cidr}")
102
+ end
103
+ firewall_rule.config[:public_ip] = test_config['driver']['customize']['pf_ip_address']
104
+ firewall_rule.run
105
+
106
+ # Firewall rule for zipdata
107
+ firewall_rule = Knifecosmic::CosmicFirewallruleCreate.new
108
+ firewall_rule.config[:cosmic_url] = "https://#{test_config['driver']['customize']['host']}/client/api"
109
+ firewall_rule.config[:cosmic_api_key] = test_config['driver']['customize']['api_key']
110
+ firewall_rule.config[:cosmic_secret_key] = test_config['driver']['customize']['secret_key']
111
+ firewall_rule.name_args = [butler_data['server_name']]
112
+ test_config['driver']['customize']['pf_trusted_networks'].split(",").each do |cidr|
113
+ firewall_rule.name_args.push("5999:5999:TCP:#{cidr}")
114
+ end
115
+ firewall_rule.config[:public_ip] = test_config['driver']['customize']['pf_ip_address']
116
+ firewall_rule.run
117
+
118
+ # Wait for WinRM to become responsive:
119
+ puts "Waiting for WinRM......"
120
+ wait_for_port_open(test_config['driver']['customize']['pf_ip_address'], butler_data['port_exposed_winrm'])
121
+ puts "WinRM available!"
122
+ sleep(2)
123
+ end
124
+
125
+ def config_fetch
126
+ # Get config
127
+ test_config_raw = File.read('.kitchen.yml')
128
+ test_config_evaluated = ERB.new(test_config_raw).result( binding )
129
+ YAML.load(test_config_evaluated)
130
+ end
131
+ def wait_for_port_open(ip, port)
132
+ port_open = false
133
+ while !port_open
134
+ begin
135
+ puts "TRYING PORT....."
136
+ thr = Thread.new {
137
+ begin
138
+ s=TCPSocket.open(ip, port)
139
+ s.close
140
+ rescue
141
+ sleep(3)
142
+ end
143
+ Thread.exit
144
+ }
145
+ sleep(2)
146
+ rescue
147
+ nil
148
+ end
149
+ if !thr.alive?
150
+ puts "PORT IS OPEN!"
151
+ port_open = true
152
+ begin
153
+ thr.exit
154
+ while thr.status
155
+ thr.exit
156
+ end
157
+ rescue
158
+ nil
159
+ end
160
+ end
161
+ thr.join
162
+ end
163
+ end
164
+ end # class
165
+ end
@@ -0,0 +1,170 @@
1
+ #
2
+ # Author:: Robbert-Jan Sperna Weiland (<rspernaweiland@schubergphilis.com>)
3
+ #
4
+
5
+ require 'chef/knife'
6
+ require 'json'
7
+ require 'rubygems'
8
+
9
+ module KnifeButler
10
+ class ButlerRun < Chef::Knife
11
+
12
+ deps do
13
+ require 'chef/knife/bootstrap_windows_winrm'
14
+ Chef::Knife::BootstrapWindowsWinrm.load_deps
15
+ require 'yaml'
16
+ require 'erb'
17
+ require 'socket'
18
+ require 'winrm-fs'
19
+ end
20
+
21
+ banner "knife butler run"
22
+
23
+ def run
24
+ test_config = config_fetch
25
+ butler_data = butler_data_fetch
26
+
27
+ # Prepare chef-solo files
28
+ #
29
+ # exec ( "mkdir .\butler_bootstrap_data" )
30
+ # exec ( "echo dbskjhdbskj > .\butler_bootstrap_data\testfile" )
31
+
32
+
33
+ puts "Fetching windows butler runner file from gem path..."
34
+ butler_runner_windows = Gem.find_files(File.join('chef', 'knife', 'resources', 'butler_runner_windows.ps1')).first
35
+ butler_runner_windows_path = File.dirname(butler_runner_windows)
36
+ puts "Done. Path: #{butler_runner_windows_path}"
37
+
38
+ # Re-run bootstrap with new command (simply tailing butler run wrapper script logfile)
39
+ # until that file is deleted, and then check exit_status of .butler exit status reporting file
40
+
41
+ # Prepare ZIP with chef-solo run:
42
+ puts "Building ZIP with cookbook data"
43
+ berks_result = `bundle exec berks package`
44
+ berks_zip = berks_result.split(' to ').last.chomp("\n")
45
+ puts "ZIPFILE: #{berks_zip}"
46
+
47
+ `tar -xvzf #{berks_zip}`
48
+
49
+ `mkdir ./butler`
50
+ `mv ./cookbooks ./butler/`
51
+ `mkdir ./butler/checksums`
52
+ `echo >> ./butler/checksums/dummy`
53
+ `mkdir ./butler/cache`
54
+ `echo >> ./butler/cache/dummy`
55
+ `mkdir ./butler/backup`
56
+ `echo >> ./butler/backup/dummy`
57
+ `mkdir ./butler/data_bags`
58
+ `echo >> ./butler/data_bags/dummy`
59
+ `mkdir ./butler/environments`
60
+ `echo >> ./butler/environments/dummy`
61
+ `mkdir ./butler/nodes`
62
+ `echo >> ./butler/nodes/dummy`
63
+ `mkdir ./butler/roles`
64
+ `echo >> ./butler/roles/dummy`
65
+
66
+ # Push chef-solo.rb into the butler folder
67
+ chef_solo_rb_path = Gem.find_files(File.join('chef', 'knife', 'resources', 'templates', 'chef-solo.rb')).first
68
+ `cp #{chef_solo_rb_path} ./butler`
69
+
70
+ # Push client.pem into the zip folder
71
+ chef_client_pem = Gem.find_files(File.join('chef', 'knife', 'resources', 'client.pem')).first
72
+ `cp #{chef_client_pem} ./butler`
73
+
74
+ # Push cookbook folder to test VM
75
+ sleep(1)
76
+ puts "PUSHING FILES TO VM"
77
+ opts = {
78
+ endpoint: "http://#{test_config['driver']['customize']['pf_ip_address']}:#{butler_data['port_exposed_winrm']}/wsman",
79
+ user: 'Administrator',
80
+ password: butler_data['server_password']
81
+ }
82
+ connection = WinRM::Connection.new(opts)
83
+ file_manager = WinRM::FS::FileManager.new(connection)
84
+ file_manager.upload('butler', "C:\\Programdata\\")
85
+
86
+ sleep(1)
87
+
88
+ # Bootstrap our VM with the desired runlist
89
+ puts "Configuring bootstrap call"
90
+ bootstrap = Chef::Knife::BootstrapWindowsWinrm.new
91
+
92
+ bootstrap.name_args = [test_config['driver']['customize']['pf_ip_address']]
93
+ bootstrap.config[:winrm_port] = butler_data['port_exposed_winrm']
94
+ bootstrap.config[:winrm_password] = butler_data['server_password']
95
+ bootstrap.config[:winrm_user] = 'Administrator'
96
+ bootstrap.config[:bootstrap_version] = test_config['provisioner']['require_chef_omnibus']
97
+ bootstrap.config[:chef_node_name] = butler_data['server_name']
98
+ bootstrap.config[:chef_server] = false
99
+ bootstrap.config[:payload_folder] = butler_runner_windows_path
100
+ repo_name=File.basename(Dir.pwd)
101
+
102
+ runlist = test_config['suites'][0]['run_list'].join(",")
103
+ bootstrap.config[:bootstrap_run_command] = "C:\\chef\\extra_files\\butler_runner_windows.ps1 #{repo_name} #{test_config['suites'][0]['attributes']['chef_environment']} \"#{runlist}\""
104
+ bootstrap.config[:bootstrap_tail_file] = 'C:\chef\client.log'
105
+ # bootstrap.config[:bootstrap_run_command] = 'get-childitem C:\chef\extra_files'
106
+
107
+ puts "Starting bootstrap.."
108
+ bootstrap.run
109
+ puts "Done!"
110
+ end
111
+
112
+ def folder_zip_recursive(zipfile, folder, subpath=nil)
113
+ folder_list = subpath.nil? ? folder : File.join(folder, subpath)
114
+ Dir.foreach(folder_list) do |item|
115
+ next if item == '.' or item == '..'
116
+ if File.file?(File.join(folder_list,item))
117
+ internal_path = subpath.nil? ? item : File.join(subpath, item)
118
+ zipfile.get_output_stream(internal_path) do |f|
119
+ f.write(File.open(File.join(folder_list,item), 'rb').read)
120
+ end
121
+ # zipfile.add(internal_path, File.join(folder,item))
122
+ #puts File.join(prefix,item)
123
+ else
124
+ forward_subpath = subpath.nil? ? item : File.join(subpath, item)
125
+ folder_zip_recursive(zipfile, folder, forward_subpath)
126
+ end
127
+ end
128
+ end
129
+
130
+ def config_fetch
131
+ # Get config
132
+ test_config_raw = File.read('.kitchen.yml')
133
+ test_config_evaluated = ERB.new(test_config_raw).result( binding )
134
+ YAML.load(test_config_evaluated)
135
+ end
136
+ def butler_data_fetch
137
+ # Get config
138
+ butler_data_raw = File.read('.butler.yml')
139
+ YAML.load(butler_data_raw)
140
+ end
141
+ def wait_for_port_open(ip, port)
142
+ port_open = false
143
+ while !port_open
144
+ begin
145
+ puts "TRYING PORT....."
146
+ thr = Thread.new {
147
+ s=TCPSocket.open(ip, port)
148
+ s.close
149
+ }
150
+ sleep(2)
151
+ rescue
152
+ nil
153
+ end
154
+ if !thr.alive?
155
+ puts "PORT IS OPEN!"
156
+ port_open = true
157
+ begin
158
+ thr.exit
159
+ while thr.status
160
+ thr.exit
161
+ end
162
+ rescue
163
+ nil
164
+ end
165
+ end
166
+ thr.join
167
+ end
168
+ end
169
+ end # class
170
+ end
@@ -0,0 +1,26 @@
1
+ $repo_name = $args[0]
2
+ $environment = $args[1]
3
+ $runlist = $args[2]
4
+
5
+ $repo = $test_data.repository
6
+
7
+ # Copy data bags from repo to databags path
8
+ mkdir -f C:\Programdata\Butler\data_bags
9
+ mkdir -f C:\Users\ADMINI~1\AppData\Local\Temp\kitchen\cache
10
+ copy-item -Recurse "C:\ProgramData\butler\cookbooks\$($repo_name)\test\fixtures\data_bags\*.*" "C:\ProgramData\butler\data_bags"
11
+ copy-item -Recurse "C:\ProgramData\butler\cookbooks\$($repo_name)\test\fixtures\data_bags\*" "C:\ProgramData\butler\data_bags"
12
+ copy-item "C:\ProgramData\butler\cookbooks\$($repo_name)\test\integration\default\encrypted_data_bag_secret" "C:\Chef"
13
+ New-Item C:\Programdata\butler\validation_key -ItemType file
14
+ copy-item "C:\ProgramData\butler\cookbooks\$($repo_name)\test\environments\*.*" "C:\Programdata\butler\environments"
15
+
16
+
17
+ c:\opscode\chef\bin\chef-client.bat -z -E $environment -c C:\ProgramData\butler\chef-solo.rb -o "$runlist" -L C:\chef\client.log
18
+ # Chef manages to exit with return code 0, even when failing and creating a stacktrace file. So lets check for that:
19
+ $resultcode = $LASTEXITCODE
20
+ if (($resultcode -eq 0) -And (Test-Path C:\Users\Administrator\AppData\Local\Temp\kitchen\cache\chef-stacktrace.out)) {
21
+ $resultcode = 7382
22
+ }
23
+ # Remove log to trigger continuation of bootstrap console script
24
+ while (Test-Path 'C:\chef\client.log') { Remove-Item 'C:\chef\client.log' -Force -ErrorAction SilentlyContinue }
25
+ # Throw error code back upstream in case of unsuccessful run
26
+ if ($resultcode -ne 0) { throw $resultcode }
File without changes
@@ -0,0 +1,16 @@
1
+ node_name 'tsttst101'
2
+ checksum_path 'C:\Programdata\butler\checksums'
3
+ file_cache_path 'C:\Users\ADMINI~1\AppData\Local\Temp\kitchen\cache'
4
+ file_backup_path 'C:\Programdata\butler\backup'
5
+ cookbook_path 'C:\Programdata\butler\cookbooks'
6
+ data_bag_path 'C:\Programdata\butler\data_bags'
7
+ environment_path 'C:\Programdata\butler\environments'
8
+ node_path 'C:\Programdata\butler\nodes'
9
+ role_path 'C:\Programdata\butler\roles'
10
+ client_path
11
+ user_path
12
+ validation_key 'C:\Programdata\butler\validation_key'
13
+ client_key 'C:\bogus_key'
14
+ encrypted_data_bag_secret
15
+ treat_deprecation_warnings_as_errors false
16
+ solo 'true'
metadata ADDED
@@ -0,0 +1,165 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: knife-butler
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Robbert-Jan Sperna Weiland
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-04-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: chef
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "<"
18
+ - !ruby/object:Gem::Version
19
+ version: '14'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "<"
25
+ - !ruby/object:Gem::Version
26
+ version: '14'
27
+ - !ruby/object:Gem::Dependency
28
+ name: knife-cosmic
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: knife-winops
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 2.0.0
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 2.0.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: winrm-fs
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rb-readline
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 0.5.5
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 0.5.5
83
+ - !ruby/object:Gem::Dependency
84
+ name: berkshelf
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "<"
88
+ - !ruby/object:Gem::Version
89
+ version: '7'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "<"
95
+ - !ruby/object:Gem::Version
96
+ version: '7'
97
+ - !ruby/object:Gem::Dependency
98
+ name: dep_selector
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">"
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">"
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: knife-solo
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">"
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">"
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: A Knife plugin to test Chef cookbooks
126
+ email:
127
+ - rspernaweiland@schubergphilis.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files:
131
+ - README.rdoc
132
+ - CHANGES.rdoc
133
+ files:
134
+ - CHANGES.rdoc
135
+ - README.rdoc
136
+ - lib/chef/knife/butler_clean.rb
137
+ - lib/chef/knife/butler_prepare.rb
138
+ - lib/chef/knife/butler_run.rb
139
+ - lib/chef/knife/resources/butler_runner_windows.ps1
140
+ - lib/chef/knife/resources/client.pem
141
+ - lib/chef/knife/resources/templates/chef-solo.rb
142
+ homepage: https://www.schubergphilis.com/
143
+ licenses: []
144
+ metadata: {}
145
+ post_install_message:
146
+ rdoc_options: []
147
+ require_paths:
148
+ - lib
149
+ required_ruby_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ required_rubygems_version: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ requirements: []
160
+ rubyforge_project:
161
+ rubygems_version: 2.6.13
162
+ signing_key:
163
+ specification_version: 4
164
+ summary: A knife plugin for testing Chef cookbooks
165
+ test_files: []