cheftacular 2.14.1 → 2.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 827adc94d0f767ea316d7bcf827cfb10cd3fa2ee
4
- data.tar.gz: f5cf035f7411a8a7ec542c836e28f5820581dbb7
3
+ metadata.gz: 762ef5692d31be7837a7650547269c06c510abbd
4
+ data.tar.gz: 1bdc839a22e03b37935c26430964bdf610e69895
5
5
  SHA512:
6
- metadata.gz: 0f5e9bc8c1f3e075fa0f084857bf6ba940b2adf3434be56f903e2f6ed3ca35aad6ea1914dbdd5011e35332cec9da7a0e6bb7b2babbe092758bef1fe316f46318
7
- data.tar.gz: b2360f856866988ff682fa1aa4f1b223fb955bbe89604f73fb9309603de1e1796367505dc31bcbc6455943e80fd55f87c1d998df5cc77491a8c4cad23cdb50ab
6
+ metadata.gz: 8d711abe36bb50ac08e7021bfe597fc1436cdedc4fbfba0c063bea93cfbe3efeb3fe01ac490e89fd10fbf84b4b4a0a7797074f16ccc7d56f0d5a6df8e3b3fd53
7
+ data.tar.gz: 5ee2d5ef64a6ffffb4059a134734dafbb6a1fadfb76c852bb07edcedcee1794685058eacab46b9b334611e4850dc68761496ce6464b14d3fc94830c61fd62f4d
@@ -19,9 +19,9 @@ class Cheftacular
19
19
 
20
20
  class Action
21
21
  def console
22
- self.send("console_#{ @config['getter'].get_current_stack }")
22
+ nodes = self.send("console_#{ @config['getter'].get_current_stack }")
23
23
 
24
- @config['auditor'].notify_slack_on_completion("console run completed\n") if @config['cheftacular']['auditing']
24
+ @config['auditor'].notify_slack_on_completion("console run completed on #{ nodes.map { |node| node.name }.join(', ') }\n") if @config['cheftacular']['auditing']
25
25
  end
26
26
 
27
27
  def console_ruby_on_rails node_args=[{unless: 'role[rails]'}]
@@ -39,6 +39,8 @@ class Cheftacular
39
39
 
40
40
  start_console_ruby_on_rails(n.public_ipaddress, n.run_list)
41
41
  end
42
+
43
+ consolable_nodes
42
44
  end
43
45
 
44
46
  def console_nodejs
@@ -19,7 +19,7 @@ class Cheftacular
19
19
 
20
20
  class Action
21
21
  def db_console
22
- self.send("db_console_#{ @config['getter'].get_current_database }")
22
+ nodes = self.send("db_console_#{ @config['getter'].get_current_database }")
23
23
  end
24
24
 
25
25
  def db_console_postgresql
@@ -23,7 +23,9 @@ class Cheftacular
23
23
 
24
24
  " 7. The `cft deploy verify` argument will force a check AND verify run under the same environment as the initial deploy. This is also aliased to `cft d ve`",
25
25
 
26
- " 8. Aliased to `cft d`"
26
+ " 8. Deploy locks (if set in the cheftacular.yml for the repo(s)) can be bypassed with the `--override-deploy-locks` flag",
27
+
28
+ " 9. Aliased to `cft d`"
27
29
  ]
28
30
  ]
29
31
 
@@ -66,7 +68,7 @@ class Cheftacular
66
68
 
67
69
  @config['action'].check('verify') if run_verify && !@options['run_migration_already']
68
70
 
69
- @config['auditor'].notify_slack_on_completion("deploy run completed on #{ nodes.map {|n| n.name }.join(', ') }\n") if @config['cheftacular']['auditing'] && !@options['run_migration_already']
71
+ @config['auditor'].notify_slack_on_completion_for_deploy(nodes.map {|n| n.name }, logs_bag_hash) if @config['cheftacular']['auditing'] && !@options['run_migration_already']
70
72
 
71
73
  @config['action'].migrate(nodes) if @config['getter'].get_current_repo_config['database'] != 'none' && !@options['run_migration_already']
72
74
 
@@ -49,7 +49,7 @@ class Cheftacular
49
49
 
50
50
  #restart the servers again after a deploy with a migration just in case
51
51
  if !log_data.empty? && log_data != @config['cheftacular']['repositories'][@options['role']]['not_a_migration_message']
52
- @config['auditor'].notify_slack_on_completion("migrate run completed\n") if @config['cheftacular']['auditing']
52
+ @config['auditor'].notify_slack_on_completion("migrate run completed on #{ nodes.map { |node| node.name }.join(', ') }\n") if @config['cheftacular']['auditing']
53
53
 
54
54
  @config['action'].deploy
55
55
  end
@@ -30,9 +30,9 @@ class Cheftacular
30
30
  def run
31
31
  command = @config['parser'].parse_runtime_arguments 0, 'range'
32
32
 
33
- self.send("run_#{ @config['getter'].get_current_stack }", command)
33
+ nodes = self.send("run_#{ @config['getter'].get_current_stack }", command)
34
34
 
35
- @config['auditor'].notify_slack_on_completion("run #{ command } completed\n") if @config['cheftacular']['auditing']
35
+ @config['auditor'].notify_slack_on_completion("run #{ command } completed on #{ nodes.map { |node| node.name }.join(', ') }\n") if @config['cheftacular']['auditing']
36
36
  end
37
37
 
38
38
  def run_ruby_on_rails command
@@ -84,6 +84,8 @@ class Cheftacular
84
84
  @config['ChefDataBag'].save_logs_bag
85
85
 
86
86
  @config['helper'].send_log_bag_hash_slack_notification(logs_bag_hash, __method__, 'Failing command detected, exiting...')
87
+
88
+ nodes
87
89
  end
88
90
  end
89
91
  end
@@ -47,7 +47,7 @@ class Cheftacular
47
47
  def start_tail_role_map ip_address, run_list, pattern_to_match
48
48
  log_loc = @config['getter'].get_current_role_map(run_list)['log_location'].split(',').first.gsub('|current_repo_location|', "#{ @config['cheftacular']['base_file_path'] }/#{ @options['repository'] }/current")
49
49
 
50
- `ssh -oStrictHostKeyChecking=no -tt #{ @config['cheftacular']['deploy_user'] }@#{ ip_address } "#{ @config['helper'].sudo(ip_address) } tail -f #{ log_loc } #{ get_tail_grep_string(pattern_to_match) }" > /dev/tty`
50
+ `ssh #{ Cheftacular::SSH_INLINE_VARS } -tt #{ @config['cheftacular']['deploy_user'] }@#{ ip_address } "#{ @config['helper'].sudo(ip_address) } tail -f #{ log_loc } #{ get_tail_grep_string(pattern_to_match) }" > /dev/tty`
51
51
  end
52
52
 
53
53
  def start_tail_ruby_on_rails ip_address, run_list, pattern_to_match
@@ -56,7 +56,7 @@ class Cheftacular
56
56
  #special servers should be listed first as most of them will have web role
57
57
  log_loc = "#{ @config['cheftacular']['base_file_path'] }/#{ @options['repository'] }/current/log/#{ true_env }.log"
58
58
 
59
- `ssh -oStrictHostKeyChecking=no -tt #{ @config['cheftacular']['deploy_user'] }@#{ ip_address } "#{ @config['helper'].sudo(ip_address) } tail -f #{ log_loc } #{ get_tail_grep_string(pattern_to_match) }" > /dev/tty`
59
+ `ssh #{ Cheftacular::SSH_INLINE_VARS } -tt #{ @config['cheftacular']['deploy_user'] }@#{ ip_address } "#{ @config['helper'].sudo(ip_address) } tail -f #{ log_loc } #{ get_tail_grep_string(pattern_to_match) }" > /dev/tty`
60
60
  end
61
61
 
62
62
  def start_tail_nodejs ip_address, run_list, pattern_to_match
@@ -31,6 +31,9 @@ class Cheftacular
31
31
  options_to_ignore << :preferred_cloud_region if @options['preferred_cloud_region'] == @config['cheftacular']['preferred_cloud_region']
32
32
  options_to_ignore << :virtualization_mode if @options['virtualization_mode'] == @config['cheftacular']['virtualization_mode']
33
33
  options_to_ignore << :route_dns_changes_via if @options['route_dns_changes_via'] == @config['cheftacular']['route_dns_changes_via']
34
+ options_to_ignore << :role unless @options['repository'].nil?
35
+ options_to_ignore << :role if @config['helper'].is_stateless_command?(@options['command'])
36
+ options_to_ignore << :repository if @config['helper'].is_stateless_command?(@options['command'])
34
37
  options_to_ignore << :sub_env
35
38
  options_to_ignore << :command
36
39
 
@@ -49,8 +52,10 @@ class Cheftacular
49
52
  ret_array << " Hostname: #{ audit_hash['hostname'] }#{ directory_content }#{ version_content }"
50
53
 
51
54
  if mode =~ /normal/
52
- ret_array << " Arguments: #{ audit_hash['arguments'] }" if !audit_hash['arguments'].nil? && !audit_hash['arguments'].empty?
53
- ret_array << " Options: #{ audit_hash['options'].to_hash }" unless audit_hash['options'].empty?
55
+ arg_opts_string = ''
56
+ arg_opts_string << " Arguments: #{ audit_hash['arguments'] }".ljust(38) if !audit_hash['arguments'].nil? && !audit_hash['arguments'].empty?
57
+ arg_opts_string << " Options: #{ audit_hash['options'].to_hash }" unless audit_hash['options'].empty?
58
+ ret_array << arg_opts_string
54
59
  end
55
60
 
56
61
  ret_array = ret_array.map { |entry| entry.prepend(' ')} unless entry_number == 0
@@ -62,6 +67,20 @@ class Cheftacular
62
67
  audit_command_to_slack_queue(audit_run_as_hash, 'short', msg)
63
68
  end
64
69
 
70
+ def notify_slack_on_completion_for_deploy node_name_array, logs_bag_hash, msg='', failed_node_names=[]
71
+ node_name_array.each do |node_name|
72
+ if logs_bag_hash.has_key?("#{ node_name }-deploy") && logs_bag_hash["#{ node_name }-deploy"]['exit_status'] == 1
73
+ failed_node_names << node_name_array.delete(node_name)
74
+ end
75
+ end
76
+
77
+ msg << "deploy run succeeded on #{ node_name_array.join(', ') }\n" unless node_name_array.empty?
78
+
79
+ msg << "#{ 'and ' unless msg.blank? }deploy run FAILED on #{ failed_node_names.join(', ') }\n" unless failed_node_names.empty?
80
+
81
+ audit_command_to_slack_queue(audit_run_as_hash, 'short', msg)
82
+ end
83
+
65
84
  def return_true_command command
66
85
  final_command = command
67
86
 
@@ -55,6 +55,8 @@ class Cheftacular
55
55
 
56
56
  @config['parser'].parse_context
57
57
 
58
+ @config['helper'].unset_repository_if_role_has_no_repository
59
+
58
60
  puts("Preparing to run command \"#{ @options['command'] }\"...") if @options['verbose']
59
61
 
60
62
  @config['auditor'].audit_run if @config['cheftacular']['auditing']
@@ -170,7 +170,6 @@ class Cheftacular
170
170
  skip = true if repo_hash[key.to_s] != val && restrict_hash.has_key?(:ignore_value)
171
171
  skip = true if val == 'NOT NIL' && repo_hash[key.to_s].nil?
172
172
  skip = true if val == 'NIL' && !repo_hash[key.to_s].nil?
173
- puts "#{ name } => k:#{ key }::v:#{ val }:::#{ skip }:[#{ repo_hash[key.to_s] }]"
174
173
  end
175
174
  end
176
175
 
@@ -213,14 +213,20 @@ class Cheftacular
213
213
  end
214
214
  end
215
215
 
216
+ def get_cheftacular_yml_override filename='override.cheftacular.yml', ret_hash={}
217
+ ret_hash = get_cheftacular_yml_as_hash(filename) if File.exist?(File.join( Dir.getwd, 'config', filename ))
218
+
219
+ ret_hash
220
+ end
221
+
216
222
  #this must be in helpers because getter class is not yet loaded at the time this method is needed.
217
- def get_cheftacular_yml_as_hash
218
- config_location = if File.exist?(File.join( Dir.getwd, 'config', 'cheftacular.yml' ))
219
- File.join( Dir.getwd, 'config', 'cheftacular.yml' )
220
- elsif File.exist?('/root/cheftacular.yml')
221
- '/root/cheftacular.yml'
223
+ def get_cheftacular_yml_as_hash filename='cheftacular.yml'
224
+ config_location = if File.exist?(File.join( Dir.getwd, 'config', filename ))
225
+ File.join( Dir.getwd, 'config', filename )
226
+ elsif File.exist?("/root/#{ filename }")
227
+ "/root/#{ filename }"
222
228
  else
223
- raise "cheftacular.yml configuration file could not be found in either #{ File.join( Dir.getwd, 'config', 'cheftacular.yml' ) } or /root/cheftacular.yml"
229
+ raise "cheftacular.yml configuration file could not be found in either #{ File.join( Dir.getwd, 'config', filename ) } or /root/#{ filename }"
224
230
  end
225
231
 
226
232
  YAML::load(ERB.new(IO.read(File.open(config_location))).result)
@@ -330,7 +336,7 @@ class Cheftacular
330
336
  end
331
337
 
332
338
  def display_cheftacular_config_diff
333
- diff_hash = @config['initial_cheftacular_yml'].deep_diff(@config['default']['cheftacular_bag_hash'], true).except('mode', 'default_repository').compact
339
+ diff_hash = @config['initial_cheftacular_yml'].deep_diff(@config['default']['cheftacular_bag_hash'], true).except('mode', 'default_repository', 'default_environment').compact
334
340
 
335
341
  recursive_hash_scrub(diff_hash)
336
342
 
@@ -364,6 +370,10 @@ class Cheftacular
364
370
  end
365
371
  end
366
372
  end
373
+
374
+ def unset_repository_if_role_has_no_repository #at this point, we should of already verified that the role exists so the repository key is useless data
375
+ @options.delete('repository') if @config['getter'].get_repository_from_role_name(@options['role'], 'do_not_raise_on_unknown').nil?
376
+ end
367
377
  end
368
378
  end
369
379
 
@@ -8,6 +8,8 @@ class Cheftacular
8
8
 
9
9
  initialize_yaml_configuration
10
10
 
11
+ initialize_override_yaml_configuration
12
+
11
13
  initialize_default_cheftacular_options
12
14
 
13
15
  initialize_locations
@@ -92,6 +94,10 @@ class Cheftacular
92
94
  @options['env'] = 'staging'
93
95
  end
94
96
 
97
+ #opts.on('-S', '--split-staging', "Set the sub-environment to split_staging") do
98
+ # @options['sub_env'] = 'split-staging'
99
+ #end
100
+
95
101
  opts.on('--split-env SPLIT_ENV_NAME', "Set the sub-environment to the specified split_env") do |sub_env|
96
102
  @options['sub_env'] = sub_env
97
103
  end
@@ -131,11 +137,11 @@ class Cheftacular
131
137
  @options['repository'] = name
132
138
  end
133
139
 
134
- opts.on('-s', '--search-node-name NODE_NAME', 'For commands that support searching, return results with NODE_NAME in them') do |name|
140
+ opts.on('-N', '--search-node-name NODE_NAME', 'For commands that support searching, return results with NODE_NAME in them') do |name|
135
141
  @options['search_node_name'] = name
136
142
  end
137
143
 
138
- opts.on('-S', '--search-role-name ROLE_NAME', 'For commands that support searching, return results with ROLE_NAME in them') do |name|
144
+ opts.on('-L', '--search-role-name ROLE_NAME', 'For commands that support searching, return results with ROLE_NAME in them') do |name|
139
145
  @options['search_role_name'] = name
140
146
  end
141
147
 
@@ -263,6 +269,17 @@ class Cheftacular
263
269
  @config['cheftacular'] = @config['helper'].get_cheftacular_yml_as_hash
264
270
  end
265
271
 
272
+ def initialize_override_yaml_configuration
273
+ @config['cheftacular_overrides'] = @config['helper'].get_cheftacular_yml_override
274
+
275
+ @config['cheftacular'] = @config['cheftacular'].merge(@config['cheftacular_overrides'])
276
+ end
277
+
278
+ def initialize_default_cheftacular_options
279
+ @options['env'] = @config['cheftacular']['default_environment'] if @config['cheftacular'].has_key?('default_environment')
280
+ @options['repository'] = @config['cheftacular']['default_repository'] if @config['cheftacular'].has_key?('default_repository')
281
+ end
282
+
266
283
  def initialize_data_bag_cheftacular_hash
267
284
  initialize_ridley
268
285
 
@@ -285,11 +302,6 @@ class Cheftacular
285
302
  @config['filesystem'].write_local_cheftacular_cache_file parsed_cheftacular
286
303
  end
287
304
 
288
- def initialize_default_cheftacular_options
289
- @options['env'] = @config['cheftacular']['default_environment'] if @config['cheftacular'].has_key?('default_environment')
290
- @options['repository'] = @config['cheftacular']['default_repository'] if @config['cheftacular'].has_key?('default_repository')
291
- end
292
-
293
305
  def initialize_monkeypatches
294
306
  if File.exists?(File.expand_path("#{ @config['locs']['app-root'] }/config/initializers/cheftacular.rb"))
295
307
  puts "Cheftacular Monkeypatch file detected! Preparing to require..."
@@ -9,12 +9,10 @@ class Cheftacular
9
9
  def parse_context
10
10
  return if @config['repository'] && @config['command'] && @config['role']
11
11
 
12
- roles ||= []
13
-
14
- @config['chef_roles'].each {|r| roles << r.name }
15
-
16
12
  @options['command'] = ARGV[0] unless @options['command']
17
13
 
14
+ parse_role(@options['role']) unless @options['role'].nil?
15
+
18
16
  parse_repository(@options['repository'])
19
17
 
20
18
  parse_node_name(@options['node_name']) if @options['node_name']
@@ -16,6 +16,8 @@ class Cheftacular
16
16
 
17
17
  '5. `-s|--staging` toggles on staging mode. Commands passed to cft will hit the staging server(s) instead of the default server(s)',
18
18
 
19
+ #'6. `-S|--split-staging` toggles on split-staging as a sub environment.',
20
+
19
21
  '6. `--split-env SPLIT_ENV_NAME` sets the sub-environment to SPLIT_ENV_NAME. This only slightly affects certain commands.',
20
22
 
21
23
  '7. `-t|--test` toggles on test mode. Commands passed to cft will hit the test server(s) instead of the default server(s)',
@@ -36,9 +38,9 @@ class Cheftacular
36
38
 
37
39
  '7. `-R|--repository NAME` will make the command run against a specific repository or context (automatically set for application mode)',
38
40
 
39
- '8. `-s|--search-node-name NODE_NAME` option will make this command return results that INCLUDE the NODE_NAME.',
41
+ '8. `-N|--search-node-name NODE_NAME` option will make this command return results that INCLUDE the NODE_NAME.',
40
42
 
41
- '9. `-S|--search-role-name ROLE_NAME` option will make this command return results that INCLUDE the ROLE_NAME.',
43
+ '9. `-L|--search-role-name ROLE_NAME` option will make this command return results that INCLUDE the ROLE_NAME.',
42
44
 
43
45
  '10. `-E|--search-env-name ENV_NAME` option will make this command return results that have this environment.',
44
46
 
@@ -21,7 +21,9 @@ class Cheftacular
21
21
 
22
22
  " 6. This command also accepts a *comma delimited list* of server names to boot / destroy instead of all the stored ones for an environment.",
23
23
 
24
- " 7. Aliased to `cft e`"
24
+ " 7. This command works with all the flags that `cft deploy` works with, like -Z -z -O and so on.",
25
+
26
+ " 8. Aliased to `cft e`"
25
27
  ]
26
28
  ]
27
29
 
@@ -6,7 +6,9 @@ class Cheftacular
6
6
  "`cft get_active_ssh_connections` will fetch the active ssh connections from every server and output it into your log directory.",
7
7
 
8
8
  [
9
- " 1. This command runs on all servers in an environment by default"
9
+ " 1. This command runs on all servers in an environment by default",
10
+
11
+ " 2. Packets can be examined more closely with `tcpdump src port PORT`"
10
12
  ]
11
13
  ]
12
14
 
@@ -4,8 +4,12 @@ class Cheftacular
4
4
  def ssh
5
5
  @config['documentation']['stateless_action'][__method__] ||= {}
6
6
  @config['documentation']['stateless_action'][__method__]['long_description'] = [
7
- "`cft ssh NODE_NAME` ssh you into the node name you are trying to access. "+
8
- "It will also drop the server's sudo password into your clipboard. "
7
+ "`cft ssh NODE_NAME [exec] [command]` ssh you into the node name you are trying to access. "+
8
+ "It will also drop the server's sudo password into your clipboard. ",
9
+
10
+ [
11
+ " 1. `cft ssh NODE_NAME exec COMMAND` will execute a command on the server as root"
12
+ ]
9
13
  ]
10
14
 
11
15
  @config['documentation']['stateless_action'][__method__]['short_description'] = 'SSHs you into a node regardless of environment'
@@ -15,26 +19,30 @@ class Cheftacular
15
19
  end
16
20
 
17
21
  class StatelessAction
18
- def ssh
22
+ def ssh node_name='', command=''
19
23
  @options['node_name'] = ARGV[1] unless @options['node_name']
20
24
 
21
- @config['stateless_action'].pass(@options['node_name'])
25
+ command = ARGV[3] if command.blank? && ARGV[2] == 'exec'
26
+
27
+ @config['stateless_action'].pass(@options['node_name']) if command.blank?
22
28
 
23
29
  nodes = @config['error'].is_valid_node_name_option?
24
30
 
25
31
  nodes.each do |n|
26
32
  puts("Beginning ssh run for #{ n.name } (#{ n.public_ipaddress })") unless @options['quiet']
27
33
 
28
- start_ssh_session(n.public_ipaddress)
34
+ start_ssh_session(n.public_ipaddress, command)
29
35
  end
30
36
 
31
- @config['auditor'].notify_slack_on_completion("ssh run completed on #{ @options['node_name'] } (#{ nodes.first.public_ipaddress })\n") if @config['cheftacular']['auditing']
37
+ @config['auditor'].notify_slack_on_completion("ssh run completed on #{ @options['node_name'] } (#{ nodes.first.public_ipaddress })\n") if @config['cheftacular']['auditing'] && command.blank?
32
38
  end
33
39
 
34
40
  private
35
41
 
36
- def start_ssh_session ip_address
37
- `ssh #{ Cheftacular::SSH_INLINE_VARS } -t #{ @config['cheftacular']['deploy_user'] }@#{ ip_address } > /dev/tty`
42
+ def start_ssh_session ip_address, command
43
+ puts(`ssh #{ Cheftacular::SSH_INLINE_VARS } -tt #{ @config['cheftacular']['deploy_user'] }@#{ ip_address } "#{ @config['helper'].sudo(ip_address) } #{ command }" > /dev/tty`) unless command.blank?
44
+
45
+ `ssh #{ Cheftacular::SSH_INLINE_VARS } -t #{ @config['cheftacular']['deploy_user'] }@#{ ip_address } > /dev/tty` if command.blank?
38
46
  end
39
47
  end
40
48
  end
@@ -37,7 +37,7 @@ class Cheftacular
37
37
  `rm -Rf #{ @config['locs']['cookbooks'] }/#{ cookbook }` if File.exists?(File.expand_path("#{ @config['locs']['cookbooks'] }/#{ cookbook }"))
38
38
  `cp -Rf #{ @config['locs']['true-root'] }/#{ cookbook } #{ @config['locs']['cookbooks'] }/#{ cookbook }`
39
39
 
40
- `rm -Rf #{ @config['locs']['true-root'] }/#{ cookbook }/.git`
40
+ `rm -Rf #{ @config['locs']['cookbooks'] }/#{ cookbook }/.git`
41
41
  else
42
42
  puts "You do not have #{ cookbook } under the #{ @config['locs']['true-root'] } directory!"
43
43
  end
@@ -12,7 +12,7 @@ class Cheftacular
12
12
  ]
13
13
  ]
14
14
 
15
- @config['documentation']['stateless_action']['utccaku']['short_description'] = 'Runs `update_cookbook` and `knife_upload` for the cheftacular cookbook'
15
+ @config['documentation']['stateless_action'][__method__]['short_description'] = 'Runs `update_cookbook` and `knife_upload` for the cheftacular cookbook'
16
16
  end
17
17
  end
18
18
 
@@ -1,5 +1,5 @@
1
1
  class Cheftacular
2
2
  #major_version.minor_version.bugfixes
3
- VERSION = "2.14.1"
3
+ VERSION = "2.15.0"
4
4
  RUBY_VERSION = "2.2.2"
5
5
  end
@@ -8,9 +8,9 @@ module SSHKit
8
8
 
9
9
  repositories.each_pair { |key, repo_hash| repo_role_name = key if repo_hash['repo_name'] == name }
10
10
 
11
- if repositories.has_key?(name) && args.empty?
11
+ if repositories.has_key?(name) && ( args.empty? || args.include?('do_not_raise_on_unknown') )
12
12
  return repositories[name]['repo_name']
13
- elsif !repo_role_name.empty? && args.empty?
13
+ elsif !repo_role_name.empty? && ( args.empty? || args.include?('do_not_raise_on_unknown') )
14
14
  return repo_role_name
15
15
  end
16
16
 
@@ -20,7 +20,9 @@ module SSHKit
20
20
  return !repo_role_name.empty?
21
21
  end
22
22
 
23
- raise "Unknown repository or rolename for #{ name }"
23
+ raise "Unknown repository or rolename for #{ name }" unless args.include?('do_not_raise_on_unknown')
24
+
25
+ nil
24
26
  end
25
27
 
26
28
  def get_node_from_address nodes, address, ret_node=nil
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cheftacular
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.14.1
4
+ version: 2.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Louis Alridge
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-25 00:00:00.000000000 Z
11
+ date: 2016-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashie