cheftacular 2.14.1 → 2.15.0

Sign up to get free protection for your applications and to get access to all the features.
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