knife-cloudstack 0.0.14 → 0.0.15

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.
@@ -0,0 +1,60 @@
1
+ # Copyright:: Copyright (c) 2013
2
+ # License:: Apache License, Version 2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'chef/knife/cs_base'
18
+
19
+ module KnifeCloudstack
20
+ class CsKeypairDelete < Chef::Knife
21
+
22
+ include Chef::Knife::KnifeCloudstackBase
23
+
24
+ deps do
25
+ require 'knife-cloudstack/connection'
26
+ Chef::Knife.load_deps
27
+ end
28
+
29
+ banner "knife cs keypair delete KEY_NAME (options)"
30
+
31
+ option :name,
32
+ :long => "--name NAME",
33
+ :description => "Specify the ssh keypair name"
34
+
35
+ def run
36
+ validate_base_options
37
+
38
+ Chef::Log.debug("Validate keypair name")
39
+ keypairname = locate_config_value(:name) || @name_args.first
40
+ unless /^[a-zA-Z0-9][a-zA-Z0-9\-\_]*$/.match(keypairname) then
41
+ ui.error "Invalid keypairname. Please specify a short name for the keypair"
42
+ exit 1
43
+ end
44
+
45
+ params = {
46
+ 'command' => 'deleteSSHKeyPair',
47
+ 'name' => keypairname,
48
+ }
49
+
50
+ json = connection.send_request(params)
51
+
52
+ unless json['success'] == 'true' then
53
+ ui.error("Unable to delete SSH Keypair")
54
+ exit 1
55
+ end
56
+ print "#{ui.color("Deleted the SSH Keypair: #{keypairname}", :magenta)}\n"
57
+ end
58
+
59
+ end # class
60
+ end
@@ -0,0 +1,83 @@
1
+ # Copyright:: Copyright (c) 2011 Edmunds, Inc.
2
+ # Copyright:: Copyright (c) 2013 Sander Botman.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'chef/knife/cs_base'
19
+ require 'chef/knife/cs_baselist'
20
+
21
+ module KnifeCloudstack
22
+ class CsKeypairList < Chef::Knife
23
+
24
+ include Chef::Knife::KnifeCloudstackBase
25
+ include Chef::Knife::KnifeCloudstackBaseList
26
+
27
+ deps do
28
+ require 'chef/knife'
29
+ require 'knife-cloudstack/connection'
30
+ Chef::Knife.load_deps
31
+ end
32
+
33
+ banner "knife cs keypair list (options)"
34
+
35
+ def run
36
+ validate_base_options
37
+
38
+ object_list = []
39
+ object_list << ui.color('Index', :bold) if locate_config_value(:index)
40
+
41
+ if locate_config_value(:fields)
42
+ locate_config_value(:fields).split(',').each { |n| object_list << ui.color(("#{n}").strip, :bold) }
43
+ else
44
+ [
45
+ ui.color('Name', :bold),
46
+ ui.color('Fingerprint', :bold),
47
+ ].each { |field| object_list << field }
48
+ end
49
+
50
+ columns = object_list.count
51
+ object_list = [] if locate_config_value(:noheader)
52
+
53
+ connection_result = connection.list_object(
54
+ "listSSHKeyPairs",
55
+ "sshkeypair",
56
+ locate_config_value(:filter),
57
+ false,
58
+ locate_config_value(:keyword),
59
+ locate_config_value(:name)
60
+ )
61
+
62
+ output_format(connection_result)
63
+
64
+ index_num = 0
65
+ connection_result.each do |r|
66
+ if locate_config_value(:index)
67
+ index_num += 1
68
+ object_list << index_num.to_s
69
+ end
70
+
71
+ if locate_config_value(:fields)
72
+ locate_config_value(:fields).downcase.split(',').each { |n| object_list << ((r[("#{n}").strip]).to_s || 'N/A') }
73
+ else
74
+ object_list << r['name'].to_s
75
+ object_list << r['fingerprint'].to_s
76
+ end
77
+ end
78
+ puts ui.list(object_list, :uneven_columns_across, columns)
79
+ list_object_fields(connection_result) if locate_config_value(:fieldlist)
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,88 @@
1
+ #
2
+ # Author:: Sander Botman (<sbotman@schubergphilis.com>)
3
+ # Copyright:: Copyright (c) 2013 Sander Botman.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'chef/knife/cs_base'
20
+ require 'chef/knife/cs_baselist'
21
+
22
+ module KnifeCloudstack
23
+ class CsPublicipList < Chef::Knife
24
+
25
+ include Chef::Knife::KnifeCloudstackBase
26
+ include Chef::Knife::KnifeCloudstackBaseList
27
+
28
+ deps do
29
+ require 'knife-cloudstack/connection'
30
+ Chef::Knife.load_deps
31
+ end
32
+
33
+ banner "knife cs publicip list (options)"
34
+
35
+ option :listall,
36
+ :long => "--listall",
37
+ :description => "List all public ip addresses",
38
+ :boolean => true
39
+
40
+ def run
41
+ validate_base_options
42
+
43
+ if locate_config_value(:fields)
44
+ object_list = []
45
+ locate_config_value(:fields).split(',').each { |n| object_list << ui.color(("#{n}").strip, :bold) }
46
+ else
47
+ object_list = [
48
+ ui.color('IP', :bold),
49
+ ui.color('Account', :bold),
50
+ ui.color('Domain', :bold),
51
+ ui.color('Zone', :bold),
52
+ ui.color('State', :bold),
53
+ ui.color('Allocated', :bold)
54
+ ]
55
+ end
56
+
57
+ columns = object_list.count
58
+ object_list = [] if locate_config_value(:noheader)
59
+
60
+ connection_result = connection.list_object(
61
+ "listPublicIpAddresses",
62
+ "publicipaddress",
63
+ locate_config_value(:filter),
64
+ locate_config_value(:listall),
65
+ locate_config_value(:keyword),
66
+ locate_config_value(:name)
67
+ )
68
+
69
+ output_format(connection_result)
70
+
71
+ connection_result.each do |r|
72
+ if locate_config_value(:fields)
73
+ locate_config_value(:fields).downcase.split(',').each { |n| object_list << ((r[("#{n}").strip]).to_s || 'N/A') }
74
+ else
75
+ object_list << r['ipaddress'].to_s
76
+ object_list << r['account'].to_s
77
+ object_list << r['domain'].to_s
78
+ object_list << r['zonename'].to_s
79
+ object_list << r['state'].to_s
80
+ object_list << r['allocated'].to_s
81
+ end
82
+ end
83
+ puts ui.list(object_list, :uneven_columns_across, columns)
84
+ list_object_fields(connection_result) if locate_config_value(:fieldlist)
85
+ end
86
+
87
+ end
88
+ end
@@ -0,0 +1,134 @@
1
+ #
2
+ # Author:: Ryan Holmes (<rholmes@edmunds.com>)
3
+ # Author:: Sander Botman (<sbotman@schubergphilis.com>)
4
+ # Author:: Sebastien Goasguen (<runseb@gmail.com>)
5
+ # Copyright:: Copyright (c) 2011 Edmunds, Inc.
6
+ # Copyright:: Copyright (c) 2013 Sander Botman.
7
+ # License:: Apache License, Version 2.0
8
+ #
9
+ # Licensed under the Apache License, Version 2.0 (the "License");
10
+ # you may not use this file except in compliance with the License.
11
+ # You may obtain a copy of the License at
12
+ #
13
+ # http://www.apache.org/licenses/LICENSE-2.0
14
+ #
15
+ # Unless required by applicable law or agreed to in writing, software
16
+ # distributed under the License is distributed on an "AS IS" BASIS,
17
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ # See the License for the specific language governing permissions and
19
+ # limitations under the License.
20
+ #
21
+
22
+ require 'chef/knife/cs_base'
23
+ require 'chef/knife/cs_baselist'
24
+
25
+ module KnifeCloudstack
26
+ class CsSecuritygroupList < Chef::Knife
27
+
28
+ include Chef::Knife::KnifeCloudstackBase
29
+ include Chef::Knife::KnifeCloudstackBaseList
30
+
31
+ deps do
32
+ require 'chef/knife'
33
+ require 'knife-cloudstack/connection'
34
+ Chef::Knife.load_deps
35
+ end
36
+
37
+ banner "knife cs securitygroup list (options)"
38
+
39
+ option :name,
40
+ :long => "--name NAME",
41
+ :description => "Specify security group to list"
42
+
43
+ option :keyword,
44
+ :long => "--keyword NAME",
45
+ :description => "Specify part of servicename to list"
46
+
47
+ option :index,
48
+ :long => "--index",
49
+ :description => "Add index numbers to the output",
50
+ :boolean => true
51
+
52
+ def run
53
+ validate_base_options
54
+
55
+ object_list = []
56
+ object_list << ui.color('Index', :bold) if locate_config_value(:index)
57
+
58
+ if locate_config_value(:fields)
59
+ locate_config_value(:fields).split(',').each { |n| object_list << ui.color(("#{n}").strip, :bold) }
60
+ elsif locate_config_value(:keyword)
61
+ [
62
+ ui.color('Name', :bold),
63
+ ui.color('Description', :bold),
64
+ ui.color('Account', :bold),
65
+ ui.color('IngressRules', :bold)
66
+ ].each { |field| object_list << field }
67
+ else
68
+ [
69
+ ui.color('Name', :bold),
70
+ ui.color('Description', :bold),
71
+ ui.color('Account', :bold)
72
+ ].each { |field| object_list << field }
73
+ end
74
+
75
+ columns = object_list.count
76
+ object_list = [] if locate_config_value(:noheader)
77
+
78
+ connection_result = connection.list_object(
79
+ "listSecurityGroups",
80
+ "securitygroup",
81
+ locate_config_value(:filter),
82
+ false,
83
+ locate_config_value(:keyword),
84
+ locate_config_value(:name)
85
+ )
86
+
87
+ output_format(connection_result)
88
+
89
+ if locate_config_value(:keyword)
90
+ index_num = 0
91
+ connection_result['ingressrule'].each do |r|
92
+ if r.nil?
93
+ else
94
+ if locate_config_value(:index)
95
+ index_num += 1
96
+ object_list << index_num.to_s
97
+ end
98
+
99
+ if locate_config_value(:fields)
100
+ locate_config_value(:fields).downcase.split(',').each { |n| object_list << ((r[("#{n}").strip]).to_s || 'N/A') }
101
+ else
102
+ object_list << connection_result['name'].to_s
103
+ object_list << connection_result['description'].to_s
104
+ object_list << connection_result['account'].to_s
105
+ object_list << r.to_s
106
+ end
107
+ end
108
+ end
109
+
110
+ else
111
+ index_num = 0
112
+ connection_result.each do |r|
113
+ if locate_config_value(:index)
114
+ index_num += 1
115
+ object_list << index_num.to_s
116
+ end
117
+
118
+ if locate_config_value(:fields)
119
+ locate_config_value(:fields).downcase.split(',').each { |n| object_list << ((r[("#{n}").strip]).to_s || 'N/A') }
120
+ else
121
+ object_list << r['name'].to_s
122
+ object_list << r['description'].to_s
123
+ object_list << r['account'].to_s
124
+ end
125
+ end
126
+
127
+ end
128
+
129
+ puts ui.list(object_list, :uneven_columns_across, columns)
130
+ list_object_fields(connection_result) if locate_config_value(:fieldlist)
131
+ end
132
+
133
+ end
134
+ end
@@ -1,6 +1,7 @@
1
1
  #
2
2
  # Author:: Ryan Holmes (<rholmes@edmunds.com>)
3
3
  # Author:: Sander Botman (<sbotman@schubergphilis.com>)
4
+ # Author:: Sander van Harmelen (<svanharmelen@schubergphilis.com>)
4
5
  # Copyright:: Copyright (c) 2011 Edmunds, Inc.
5
6
  # Copyright:: Copyright (c) 2013 Sander Botman.
6
7
  # License:: Apache License, Version 2.0
@@ -81,6 +82,12 @@ module KnifeCloudstack
81
82
  :proc => lambda { |n| n.split(',').map {|sn| sn.strip}} ,
82
83
  :default => []
83
84
 
85
+ option :cloudstack_disk,
86
+ :short => "-D DISK",
87
+ :long => "--disk DISK",
88
+ :description => "The CloudStack disk offering name",
89
+ :proc => Proc.new { |d| Chef::Config[:knife][:cloudstack_disk] = d }
90
+
84
91
  option :cloudstack_hypervisor,
85
92
  :long => '--cloudstack-hypervisor HYPERVISOR',
86
93
  :description => "The CloudStack hypervisor type for the server"
@@ -169,6 +176,11 @@ module KnifeCloudstack
169
176
  :proc => lambda { |o| o.split(/[\s,]+/) },
170
177
  :default => []
171
178
 
179
+ option :keypair,
180
+ :long => "--keypair NAME",
181
+ :description => "Name of the keypair that should be used to create the vm",
182
+ :default => false
183
+
172
184
  option :static_nat,
173
185
  :long => '--static-nat',
174
186
  :description => 'Support Static NAT',
@@ -184,7 +196,7 @@ module KnifeCloudstack
184
196
  option :fw_rules,
185
197
  :short => "-f PORT_RULES",
186
198
  :long => "--fw-rules PORT_RULES",
187
- :description => "Comma separated list of firewall rules, e.g. '1024:10000:TCP:192.168.0.0/16,25:25:TCP:10.0.0.0/8'",
199
+ :description => "Comma separated list of firewall rules, e.g. 'TCP:192.168.0.0/16:1024:65535,TCP::22,UDP::123,ICMP'",
188
200
  :proc => lambda { |o| o.split(/[\s,]+/) },
189
201
  :default => []
190
202
 
@@ -197,6 +209,13 @@ module KnifeCloudstack
197
209
  :long => '--fqdn',
198
210
  :description => "FQDN which Kerberos Understands (only for Windows Servers)"
199
211
 
212
+ option :set_display_name,
213
+ :long => '--set-display-name',
214
+ :description => "Set the same server display name as Chef node name.",
215
+ :boolean => true,
216
+ :default => false
217
+
218
+
200
219
  def run
201
220
  validate_base_options
202
221
 
@@ -208,6 +227,11 @@ module KnifeCloudstack
208
227
  end
209
228
  validate_options
210
229
 
230
+ # This little peace of code sets the Chef node-name to the VM name when a node-name is not specifically given
231
+ unless locate_config_value :chef_node_name
232
+ Chef::Config[:knife][:chef_node_name] = @name_args.first
233
+ end
234
+
211
235
  if @windows_image and locate_config_value(:kerberos_realm)
212
236
  Chef::Log.debug("Load additional gems for AD/Kerberos Authentication")
213
237
  if @windows_platform
@@ -222,18 +246,23 @@ module KnifeCloudstack
222
246
  Chef::Log.info("Creating instance with
223
247
  service : #{locate_config_value(:cloudstack_service)}
224
248
  template : #{locate_config_value(:cloudstack_template)}
249
+ disk : #{locate_config_value(:cloudstack_disk)}
225
250
  zone : #{locate_config_value(:cloudstack_zone)}
226
251
  project: #{locate_config_value(:cloudstack_project)}
227
252
  network: #{locate_config_value(:cloudstack_networks)}")
228
253
 
229
254
  print "\n#{ui.color("Waiting for Server to be created", :magenta)}"
230
- params = {}
255
+ params = {}
231
256
  params['hypervisor'] = locate_config_value(:cloudstack_hypervisor) if locate_config_value(:cloudstack_hypervisor)
232
257
 
258
+ params['keypair'] = locate_config_value :keypair if locate_config_value :keypair
259
+ params['displayname'] = if locate_config_value :set_display_name and locate_config_value :chef_node_name then locate_config_value :chef_node_name else hostname end
260
+
233
261
  server = connection.create_server(
234
262
  hostname,
235
263
  locate_config_value(:cloudstack_service),
236
264
  locate_config_value(:cloudstack_template),
265
+ locate_config_value(:cloudstack_disk),
237
266
  locate_config_value(:cloudstack_zone),
238
267
  locate_config_value(:cloudstack_networks),
239
268
  params
@@ -244,7 +273,7 @@ module KnifeCloudstack
244
273
  object_fields = []
245
274
  object_fields << ui.color("Name:", :cyan)
246
275
  object_fields << server['name'].to_s
247
- object_fields << ui.color("Name:", :cyan) if locate_config_value(:cloudstack_password)
276
+ object_fields << ui.color("Password:", :cyan) if locate_config_value(:cloudstack_password)
248
277
  object_fields << server['password'] if locate_config_value(:cloudstack_password)
249
278
  object_fields << ui.color("Public IP:", :cyan)
250
279
  object_fields << public_ip
@@ -256,18 +285,22 @@ module KnifeCloudstack
256
285
  return unless config[:bootstrap]
257
286
 
258
287
  if @bootstrap_protocol == 'ssh'
259
- print "\n#{ui.color("Waiting for sshd", :magenta)}"
288
+ print "\n#{ui.color("Waiting for sshd on: #{public_ip}", :magenta)}"
260
289
 
261
290
  print(".") until is_ssh_open?(public_ip) {
262
291
  sleep BOOTSTRAP_DELAY
263
292
  puts "\n"
264
293
  }
265
- else
266
- print "\n#{ui.color("Waiting for winrm to be active", :magenta)}"
294
+ elsif @bootstrap_protocol == 'winrm'
295
+ print "\n#{ui.color("Waiting for winrm to be active on: #{public_ip}", :magenta)}"
267
296
  print(".") until tcp_test_winrm(public_ip,locate_config_value(:winrm_port)) {
268
297
  sleep WINRM_BOOTSTRAP_DELAY
269
298
  puts("\n")
270
299
  }
300
+ else
301
+ puts "Cannot determine the bootstrap protocol."
302
+ puts "Please specify either ssh or winrm as bootstrap protocol."
303
+ exit 1
271
304
  end
272
305
 
273
306
  object_fields = []
@@ -293,7 +326,7 @@ module KnifeCloudstack
293
326
  end
294
327
 
295
328
  def is_image_windows?
296
- template = connection.get_template(locate_config_value(:cloudstack_template))
329
+ template = connection.get_template(locate_config_value(:cloudstack_template),locate_config_value(:cloudstack_zone))
297
330
  if !template
298
331
  ui.error("Template: #{template} does not exist")
299
332
  exit 1
@@ -364,6 +397,7 @@ module KnifeCloudstack
364
397
  end
365
398
 
366
399
  def create_port_forwarding_rules(ip_address, server_id, connection)
400
+ Chef::Log.debug("Creating IP Forwarding Rule")
367
401
  rules = locate_config_value(:port_rules)
368
402
  if config[:bootstrap]
369
403
  if @bootstrap_protocol == 'ssh'
@@ -394,6 +428,7 @@ module KnifeCloudstack
394
428
  end
395
429
 
396
430
  def create_ip_forwarding_rules(ip_address, connection)
431
+ Chef::Log.debug("Creating IP Forwarding Rule")
397
432
  rules = locate_config_value(:ipfwd_rules)
398
433
  return unless rules
399
434
  rules.each do |rule|
@@ -410,17 +445,33 @@ module KnifeCloudstack
410
445
  end
411
446
 
412
447
  def create_firewall_rules(ip_address, connection)
448
+ Chef::Log.debug("Creating Firewall Rule")
413
449
  rules = locate_config_value(:fw_rules)
414
450
  return unless rules
451
+ icmptype={
452
+ '0' => {'code' => [0]},
453
+ '8' => {'code' => [0]},
454
+ '3' => {'code' => [0, 1]}
455
+ }
415
456
  rules.each do |rule|
416
457
  args = rule.split(':')
417
- startport = args[0]
418
- endport = args[1] || args[0]
419
- protocol = args[2] || "TCP"
420
- cidr_list = args[3] || "0.0.0.0/0"
421
- Chef::Log.debug("Creating Firewall Rule for
458
+ protocol = args[0]
459
+ cidr_list = (args[1].nil? || args[1].length == 0) ? "0.0.0.0/0" : args[1]
460
+ startport = args[2]
461
+ endport = args[3] || args[2]
462
+ if protocol == "ICMP"
463
+ icmptype.each do |type, value|
464
+ value['code'].each do |code_id|
465
+ Chef::Log.debug("Creating Firewall Rule for
466
+ #{ip_address['ipaddress']} with protocol: #{protocol}, icmptype: #{type}, icmpcode: #{code_id}, cidrList: #{cidr_list}")
467
+ connection.create_firewall_rule(ip_address['id'], protocol, type, code_id, cidr_list)
468
+ end
469
+ end
470
+ else
471
+ Chef::Log.debug("Creating Firewall Rule for
422
472
  #{ip_address['ipaddress']} with protocol: #{protocol}, startport: #{startport}, endport: #{endport}, cidrList: #{cidr_list}")
423
- connection.create_firewall_rule(ip_address['id'], protocol, startport, endport, cidr_list)
473
+ connection.create_firewall_rule(ip_address['id'], protocol, startport, endport, cidr_list)
474
+ end
424
475
  end
425
476
  end
426
477
 
@@ -516,7 +567,6 @@ module KnifeCloudstack
516
567
  ui.error("Unsupported Bootstrapping Protocol. Supported : winrm, ssh")
517
568
  exit 1
518
569
  end
519
- bootstrap.config[:environment] = locate_config_value(:environment)
520
570
  bootstrap.config[:chef_node_name] = config[:chef_node_name] || server['id']
521
571
  bootstrap.config[:encrypted_data_bag_secret] = config[:encrypted_data_bag_secret]
522
572
  bootstrap.config[:encrypted_data_bag_secret_file] = config[:encrypted_data_bag_secret_file]
@@ -529,6 +579,8 @@ module KnifeCloudstack
529
579
  bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
530
580
  bootstrap.config[:distro] = locate_config_value(:distro)
531
581
  bootstrap.config[:template_file] = locate_config_value(:template_file)
582
+ bootstrap.config[:first_boot_attributes] = locate_config_value(:first_boot_attributes)
583
+ bootstrap.config[:environment] = locate_config_value(:environment)
532
584
  bootstrap
533
585
  end
534
586
 
@@ -545,7 +597,6 @@ module KnifeCloudstack
545
597
  bootstrap.config[:identity_file] = locate_config_value(:identity_file)
546
598
  bootstrap.config[:chef_node_name] = locate_config_value(:chef_node_name) || server["name"]
547
599
  bootstrap.config[:use_sudo] = true unless locate_config_value(:ssh_user) == 'root'
548
- bootstrap.config[:environment] = locate_config_value(:environment)
549
600
 
550
601
  # may be needed for vpc_mode
551
602
  bootstrap.config[:host_key_verify] = config[:host_key_verify]