knife-softlayer 0.1.3 → 0.2.0.pre.f0ba31b95

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,34 @@
1
+ #
2
+ # Author:: Matt Eldridge (<matt.eldridge@us.ibm.com>)
3
+ # © Copyright IBM Corporation 2014.
4
+ #
5
+ # LICENSE: Apache 2.0 (http://www.apache.org/licenses/)
6
+ #
7
+
8
+ require 'chef/knife/softlayer_base'
9
+
10
+ class Chef
11
+ class Knife
12
+ class SoftlayerGlobalIpList < Knife
13
+
14
+ include Knife::SoftlayerBase
15
+
16
+ banner 'knife softlayer global ips list (options)'
17
+
18
+ def run
19
+ $stdout.sync = true
20
+
21
+ if connection(:network).get_global_ip_records.body.empty?
22
+ puts ui.color("No global ip addresses found.", :green)
23
+ else
24
+ puts ui.color("This operation can take several minutes. ", :yellow)
25
+ table_data = connection(:network).ips.map do |ip|
26
+ {:address => ip.address, :destination => ip.destination_ip.respond_to?(:address) ? ip.destination_ip.address : 'NOT ROUTED'} if ip.global?
27
+ end.compact
28
+ puts Formatador.display_table(table_data, [:address, :destination])
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,26 @@
1
+ #
2
+ # Author:: Matt Eldridge (<matt.eldridge@us.ibm.com>)
3
+ # © Copyright IBM Corporation 2014.
4
+ #
5
+ # LICENSE: Apache 2.0 (http://www.apache.org/licenses/)
6
+ #
7
+
8
+ require 'chef/knife/softlayer_base'
9
+
10
+ class Chef
11
+ class Knife
12
+ class SoftlayerImageList < Knife
13
+
14
+ include Knife::SoftlayerBase
15
+
16
+ banner 'knife softlayer image list'
17
+
18
+ def run
19
+ $stdout.sync = true
20
+ table_data = connection(:compute).images.map { |i| {:id => i.id, :name => i.name, :access => i.public? ? 'PUBLIC' : 'PRIVATE' } }
21
+ puts Formatador.display_table(table_data, [:id, :access, :name,])
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -6,7 +6,6 @@
6
6
  #
7
7
 
8
8
  require 'chef/knife/softlayer_base'
9
- require 'chef/knife/flavor/base'
10
9
 
11
10
  class Chef
12
11
  class Knife
@@ -33,31 +32,28 @@ class Chef
33
32
  :long => '--domain VALUE',
34
33
  :short => '-D VALUE',
35
34
  :description => 'The FQDN SoftLayer will assign to the VM instance.',
36
- :default => 'example.com'
35
+ :default => Chef::Config[:knife][:softlayer_default_domain]
37
36
 
38
37
  option :cores,
39
38
  :long => '--cores VALUE',
40
39
  :short => '-C VALUE',
41
- :description => 'The number of virtual cores SoftLayer will assign to the VM instance.',
42
- :default => 1
40
+ :description => 'The number of virtual cores SoftLayer will assign to the VM instance.'
43
41
 
44
42
  option :os_code,
45
43
  :long => '--os-code VALUE',
46
44
  :short => '-O VALUE',
47
- :description => 'A valid SoftLayer operating system code. See `knife softlayer flavor list --all` for a list of valid codes.',
48
- :default => 'UBUNTU_LATEST'
45
+ :description => 'A valid SoftLayer operating system code. See `knife softlayer flavor list --all` for a list of valid codes.'
49
46
 
50
47
  option :ram,
51
48
  :long => '--ram VALUE',
52
49
  :short => '-R VALUE',
53
- :description => 'The number of virtual cores SoftLayer will assign to the VM instance.',
54
- :default => 1024
50
+ :description => 'The number of virtual cores SoftLayer will assign to the VM instance.'
51
+
55
52
 
56
53
  option :block_storage,
57
54
  :long => '--block-storage VALUE',
58
55
  :short => '-B VALUE',
59
- :description => 'The size in GB of the block storage devices (disks) for this instance. Specify 1 - 5 entries in a comma separated list following the format "dev:size". Example: "0:25,2:500" would be a 25GB volume on device 0 (the root partition) and a 100GB volume on on device 2. [NOTE: SoftLayer VMs always reserve device 1 for a swap device.] ',
60
- :default => '0:25'
56
+ :description => 'The size in GB of the block storage devices (disks) for this instance. Specify 1 - 5 entries in a comma separated list following the format "dev:size". Example: "0:25,2:500" would be a 25GB volume on device 0 (the root partition) and a 100GB volume on on device 2. [NOTE: SoftLayer VMs always reserve device 1 for a swap device.] '
61
57
 
62
58
  option :nic,
63
59
  :long => '--network-interface-speed VALUE',
@@ -71,11 +67,32 @@ class Chef
71
67
  :boolean => true,
72
68
  :default => false
73
69
 
74
- option :single_tenant,
75
- :long => '--single-tenant',
76
- :description => 'Create a VM with a dedicated physical host.',
77
- :boolean => true,
78
- :default => false
70
+ option :vlan,
71
+ :long => '--vlan VLAN-ID',
72
+ :description => 'Internal SoftLayer ID of the public VLAN into which the compute instance should be placed.'
73
+
74
+ option :private_vlan,
75
+ :long => '--private-vlan VLAN-ID',
76
+ :description => 'Internal SoftLayer ID of the private VLAN into which the compute instance should be placed.'
77
+
78
+ option :image_id,
79
+ :long => '--image-id IMAGE-ID',
80
+ :description => 'Internal SoftLayer uuid specifying the image template from which the compute instance should be booted.'
81
+
82
+ option :private_network_only,
83
+ :long => '--private-network-only',
84
+ :description => 'Flag to be passed when the compute instance should have no public facing network interface.',
85
+ :boolean => true
86
+
87
+ option :from_file,
88
+ :long => '--from-file PATH',
89
+ :description => 'Path to JSON file containing arguments for provisoning and bootstrap.'
90
+
91
+ #option :single_tenant,
92
+ # :long => '--single-tenant',
93
+ # :description => 'Create a VM with a dedicated physical host.',
94
+ # :boolean => true,
95
+ # :default => false
79
96
 
80
97
  option :local_storage,
81
98
  :long => '--local-storage',
@@ -85,7 +102,8 @@ class Chef
85
102
 
86
103
  option :datacenter,
87
104
  :long => '--datacenter VALUE',
88
- :description => 'Create a VM in a particular datacenter.'
105
+ :description => 'Create a VM in a particular datacenter.',
106
+ :default => Chef::Config[:knife][:softlayer_default_datacenter]
89
107
 
90
108
  option :tags,
91
109
  :short => "-T T=V[,T=V,...]",
@@ -99,7 +117,6 @@ class Chef
99
117
  :description => "The Chef node name for your new node",
100
118
  :proc => Proc.new { |key| Chef::Config[:knife][:chef_node_name] = key }
101
119
 
102
-
103
120
  option :ssh_user,
104
121
  :short => "-x USERNAME",
105
122
  :long => "--ssh-user USERNAME",
@@ -111,6 +128,12 @@ class Chef
111
128
  :long => "--ssh-password PASSWORD",
112
129
  :description => "The ssh password"
113
130
 
131
+ option :ssh_keys,
132
+ :short => "-S KEY",
133
+ :long => "--ssh-keys KEY",
134
+ :description => "The ssh keys for the SoftLayer Virtual Guest environment. Accepts a space separated list of integers.",
135
+ :proc => Proc.new { |ssh_keys| ssh_keys.split(' ').map { |k| {:id => k}} }
136
+
114
137
  option :ssh_port,
115
138
  :short => "-p PORT",
116
139
  :long => "--ssh-port PORT",
@@ -203,7 +226,7 @@ class Chef
203
226
  :default => nil
204
227
 
205
228
  option :new_global_ip,
206
- :long => "--new-global-ip",
229
+ :long => "--new-global-ip VERSION",
207
230
  :description => "Order a new SoftLayer Global IP address and assign it to the instance."
208
231
 
209
232
  option :hint,
@@ -219,94 +242,127 @@ class Chef
219
242
  # Run the procedure to create a SoftLayer VM and bootstrap it.
220
243
  # @return [nil]
221
244
  def run
222
-
223
245
  $stdout.sync = true
224
-
225
- config[:os_code] =~ /^WIN_/ and raise SoftlayerServerCreateError, "#{ui.color("Windows VMs not currently supported.", :red)}"
226
-
227
- if config[:flavor]
228
- @template = SoftlayerFlavorBase.load_flavor(config[:flavor])
229
- else
230
- @template = {}
231
- @template['startCpus'] = config[:cores]
232
- @template['maxMemory'] = config[:ram]
233
- @template['localDiskFlag'] = config[:local_storage]
234
- @template['blockDevices'] = config[:block_storage].split(',').map do |i|
235
- dev, cap = i.split(':')
236
- {'device' => dev, 'diskImage' => {'capacity' => cap } }
237
- end
246
+ config.merge!(slurp_from_file(config[:from_file])) if config[:from_file]
247
+
248
+ # TODO: Windows support.
249
+ raise SoftlayerServerCreateError, "#{ui.color("Windows VMs not currently supported.", :red)}" if config[:os_code] =~ /^WIN_/
250
+ raise SoftlayerServerCreateError, "#{ui.color("identity file (-i) option is incompatible with password (-P) option required.", :red)}" if !!config[:identity_file] and !!config[:ssh_password]
251
+ raise SoftlayerServerCreateError, "#{ui.color("--new-global-ip value must be 'v4' or 'v6'.", :red)}" if config[:new_global_ip] and !config[:new_global_ip].to_s.match(/^v[4,6]$/i)
252
+
253
+ # TODO: create a pre-launch method for clean up tasks.
254
+ # TODO: create a pre-launch method for clean up tasks.
255
+ config[:vlan] = config[:vlan].to_i if config[:vlan]
256
+ config[:private_vlan] = config[:private_vlan].to_i if config[:private_vlan]
257
+ Fog.credentials[:private_key_path] = config[:identity_file] if config[:identity_file]
258
+ # TODO: create a pre-launch method for clean up tasks.
259
+ # TODO: create a pre-launch method for clean up tasks.
260
+
261
+ opts = {
262
+ :flavor => :flavor_id,
263
+ :hostname => :name,
264
+ :domain => nil,
265
+ :cores => :cpu,
266
+ :os_code => nil,
267
+ :ram => nil,
268
+ :block_storage => :disk,
269
+ :local_storage => :ephemeral_storage,
270
+ :datacenter => nil,
271
+ :ssh_keys => :key_pairs,
272
+ :vlan => nil,
273
+ :private_vlan => nil,
274
+ :image_id => nil,
275
+ :private_network_only => nil,
276
+ #:tags => nil
277
+ }
278
+
279
+
280
+ opts.keys.each do |opt|
281
+ if opts[opt].nil?
282
+ opts[opt] = config[opt]
283
+ else
284
+ opts[opts.delete(opt)] = config[opt] # clever shit like this is why I like programming :-]
285
+ end
238
286
  end
239
287
 
240
- @template['complexType'] = SoftlayerBase.cci
241
- @template['hostname'] = config[:hostname]
242
- @template['domain'] = config[:domain]
243
- @template['dedicatedAccountHostOnlyFlag'] = config[:single_tenant]
244
- @template['operatingSystemReferenceCode'] = config[:os_code]
245
- @template['hourlyBillingFlag'] = !config[:bill_monthly]
246
- @template['networkComponents'] = [{ 'maxSpeed' => config[:nic]}]
247
-
248
- @template['datacenter'] = { 'name' => config[:datacenter] } if config[:datacenter]
249
-
250
- @response = connection.createObject(@template)
288
+ opts.delete_if { |k,v| v.nil? }
251
289
 
252
290
  puts ui.color("Launching SoftLayer VM, this may take a few minutes.", :green)
291
+ instance = connection.servers.create(opts)
292
+ progress Proc.new { instance.wait_for { ready? and sshable? } }
293
+ putc("\n")
294
+
295
+ if config[:tags]
296
+ puts ui.color("Applying tags to SoftLayer instance.", :green)
297
+ progress Proc.new { instance.add_tags(config[:tags]) }
298
+ putc("\n")
299
+ end
253
300
 
254
- begin
255
- @cci = connection.object_mask('mask.operatingSystem.passwords.password').object_with_id(@response['id']).getObject
256
- sleep 1
257
- putc('.')
258
- end while @cci['operatingSystem'].nil? or @cci['operatingSystem']['passwords'].empty?
259
-
260
- linux_bootstrap(@cci).run
261
301
 
262
302
  if config[:new_global_ip] || config[:assign_global_ip]
263
- if config[:new_global_ip]
303
+ if config[:new_global_ip] # <— the value of this will be v4 or v6
264
304
  begin
265
- order = SoftlayerBase.build_global_ipv4_order
266
- response = connection(:order).placeOrder(order)
267
- global_ip_id = response['placedOrder']['account']['globalIpv4Records'].first['id']
268
-
269
- if global_ip_id
270
- puts ui.color('Global IP Address successfully created.', :green)
271
- else
272
- raise 'Unable to find Global IP Address ID. Address not created.'
305
+ puts ui.color('Provisioning new Global IP' + config[:new_global_ip].downcase + ', this may take a few minutes.', :green)
306
+ create_global_ip = Proc.new do
307
+ existing_records = connection(:network).get_global_ip_records.body
308
+ connection(:network).send('create_new_global_ip' + config[:new_global_ip].downcase) or raise SoftlayerServerCreateError, "Unable to create new Global IP Address.";
309
+ sleep 20 # if we look for the new record too quickly it won't be there yet...
310
+ new_record_global_id = (connection(:network).get_global_ip_records.body - existing_records).reduce['id']
311
+ connection(:network).ips.select { |ip| ip.global_id == new_record_global_id }.reduce
273
312
  end
274
- rescue Exception => e
313
+ global_ip = progress(create_global_ip) or raise SoftlayerServerCreateError, "Error encountered creating Global IP Address."
314
+ puts ui.color('Global IP Address successfully created.', :green)
315
+ rescue SoftlayerServerCreateError => e
275
316
  puts ui.color('We have encountered a problem ordering the requested global IP. The transaction may not have completed.', :red)
276
317
  puts ui.color(e.message, :yellow)
277
318
  end
278
319
  end
279
320
 
280
321
  if config[:assign_global_ip]
281
- global_ip_id = connection(:account).object_mask('ipAddress').getGlobalIpv4Records.map do |global_ip|
282
- global_ip['id'] if global_ip['ipAddress']['ipAddress'] == config[:assign_global_ip]
283
- end.compact.first
284
- if global_ip_id
285
- puts ui.color('Global IP Address ID found.', :green)
322
+ case config[:assign_global_ip].to_s
323
+ #ipv4
324
+ when /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/
325
+ global_ip = connection(:network).ips.by_address(config[:assign_global_ip])
326
+ #ipv6
327
+ when /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/
328
+ global_ip = connection(:network).ips.by_address(config[:assign_global_ip])
329
+ else
330
+ raise SoftlayerServerCreateError, "--assign-global-ip value must be valid IPv4 or IPv6 address"
286
331
  end
332
+ global_ip or raise SoftlayerServerCreateError, "Global IP address not found. Please check the address or id supplied and try again."
333
+ global_ip.reload
287
334
  end
288
335
 
289
- puts ui.color('Assigning Global IP Address to Instance.', :green)
290
- connection(:global_ip).object_with_id(global_ip_id).route(@cci['primaryIpAddress'])
291
-
292
- puts ui.color('Global IP Address has been assigned.', :green)
293
- puts ui.color('Global IP Address will not function without networking rules on the endpoint operating system. See http://knowledgelayer.softlayer.com/learning/global-ip-addresses for details.', :yellow)
336
+ route_global_ip = Proc.new do
337
+ puts ui.color('Routing Global IP Address to Instance.', :green)
338
+ global_ip.route(connection(:network).ips.by_address(instance.public_ip_address)) or raise SoftlayerServerCreateError, "Global IP address failed to route."
339
+ puts ui.color('Global IP Address has been assigned.', :green)
340
+ puts ui.color('Global IP Address will not function without networking rules on the endpoint operating system. See http://knowledgelayer.softlayer.com/learning/global-ip-addresses for details.', :yellow)
341
+ end
342
+ progress(route_global_ip)
294
343
 
295
344
  end
296
345
 
346
+ puts ui.color('Bootstrapping Chef node, this may take a few minutes.', :green)
347
+ linux_bootstrap(instance).run
348
+
349
+ puts ui.color("Applying tags to Chef node.", :green)
350
+ progress apply_tags(instance)
351
+
297
352
  end
298
353
 
299
- # @param [Hash] cci
354
+ # @param [Hash] instance
300
355
  # @return [Chef::Knife::Bootstrap]
301
- def linux_bootstrap(cci)
356
+ def linux_bootstrap(instance)
302
357
  bootstrap = Chef::Knife::Bootstrap.new
303
- bootstrap.name_args = [cci['primaryIpAddress']]
358
+ instance.ssh_ip_address = instance.private_ip_address if config[:private_network_only]
359
+ bootstrap.name_args = [instance.ssh_ip_address]
304
360
  bootstrap.config[:ssh_user] = config[:ssh_user]
305
- bootstrap.config[:ssh_password] = cci['operatingSystem']['passwords'].first['password']
361
+ bootstrap.config[:ssh_password] = config[:ssh_password] if config[:ssh_password]
362
+ bootstrap.config[:identity_file] = config[:identity_file] if config[:identity_file]
306
363
  bootstrap.config[:ssh_port] = config[:ssh_port]
307
364
  bootstrap.config[:ssh_gateway] = config[:ssh_gateway]
308
- bootstrap.config[:identity_file] = config[:identity_file]
309
- bootstrap.config[:chef_node_name] = locate_config_value(:chef_node_name) || cci['id']
365
+ bootstrap.config[:chef_node_name] = locate_config_value(:chef_node_name) || instance.id
310
366
  bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root'
311
367
  bootstrap.config[:host_key_verify] = config[:host_key_verify]
312
368
  shared_bootstrap(bootstrap)
@@ -337,6 +393,43 @@ class Chef
337
393
  # TODO: Windows support....
338
394
  end
339
395
 
396
+ def progress(proc)
397
+ t = Thread.new { Thread.current[:output] = proc.call }
398
+ i = 0
399
+ while t.alive?
400
+ sleep 0.5
401
+ putc('.')
402
+ i += 1
403
+ putc("\n") if i == 76
404
+ i = 0 if i == 76
405
+ end
406
+ putc("\n")
407
+ t.join
408
+ t[:output]
409
+ end
410
+
411
+ def slurp_from_file(path)
412
+ args = JSON.parse(IO.read(path))
413
+ args.keys.each { |key| args[key.gsub('-', '_').to_sym] = args.delete(key) }
414
+ # TODO: Something less ugly than the empty rescue block below. The :proc Procs/Lambdas aren't idempotent...
415
+ args.keys.each { |key| begin; args[key] = options[key][:proc] ? options[key][:proc].call(args[key]) : args[key]; rescue; end }
416
+ args
417
+ end
418
+
419
+ def apply_tags(instance)
420
+ Proc.new do
421
+ chef = Chef::Search::Query.new
422
+ chef.search('node', "name:#{locate_config_value(:chef_node_name) || instance.id}") do |n|
423
+ config[:tags] = [] if config[:tags].nil? # we're going to tag every Chef node with the SL id no matter what
424
+ config[:tags] << "slid=#{instance.id}"
425
+ config[:tags].each do |tag|
426
+ n.tag(tag)
427
+ end
428
+ n.save
429
+ end
430
+ end
431
+ end
432
+
340
433
  end
341
434
  end
342
435
  end
@@ -23,7 +23,7 @@ class Chef
23
23
  option :chef_node_name,
24
24
  :short => "-N NAME",
25
25
  :long => "--node-name NAME",
26
- :description => "The Chef node name for your new node"
26
+ :description => "The name of the node to be destroyed."
27
27
 
28
28
  option :ip_address,
29
29
  :long => "--ip-address ADDRESS",
@@ -53,12 +53,11 @@ class Chef
53
53
  else
54
54
  raise "#{ui.color("FATAL: Please supply the node name or IP address.", :red)}"
55
55
  end
56
-
57
- @cci = connection.findByIpAddress(config[:ip_address])
58
-
56
+ @slid = @node.tags.select { |s| s =~ /^slid=/ }.reduce.gsub('slid=', '').to_i
57
+ @instance = connection.servers.get(@slid)
59
58
 
60
59
  @node.nil? and raise "#{ui.color('Chef node not found!', :red)}"
61
- @cci.nil? and raise "#{ui.color('VM instance with IP: ' + config[:ip_address] +' not found!', :red)}"
60
+ @instance.nil? and raise "#{ui.color('VM instance with IP: ' + config[:ip_address] +' not found!', :red)}"
62
61
 
63
62
 
64
63
  begin
@@ -81,7 +80,7 @@ class Chef
81
80
  end
82
81
 
83
82
  begin
84
- connection.object_with_id(@cci['id']).deleteObject
83
+ @instance.destroy
85
84
  puts ui.color("SoftLayer VM successfully deleted. You are no longer being billed for this instance.", :green)
86
85
  rescue Exception => e
87
86
  err_msg ui.color("ERROR DELETING SOFTLAYER VM. IT'S POSSIBLE YOU ARE STILL BEING BILLED FOR THIS INSTANCE. PLEASE CONTACT SUPPORT FOR FURTHER ASSISTANCE", :red)
@@ -0,0 +1,42 @@
1
+ #
2
+ # Author:: Matt Eldridge (<matt.eldridge@us.ibm.com>)
3
+ # © Copyright IBM Corporation 2014.
4
+ #
5
+ # LICENSE: Apache 2.0 (http://www.apache.org/licenses/)
6
+ #
7
+
8
+ require 'chef/knife/softlayer_base'
9
+
10
+ class Chef
11
+ class Knife
12
+ class SoftlayerVlanCreate < Knife
13
+
14
+ include Knife::SoftlayerBase
15
+
16
+ banner 'knife softlayer vlan create'
17
+
18
+ def run
19
+ #unless name_args.size == 1
20
+ # puts ui.color("Specify exactly one vlan to show.", :red)
21
+ # show_usage
22
+ # exit 1
23
+ #end
24
+
25
+ $stdout.sync = true
26
+
27
+ opts = {
28
+ :name => ui.ask_question("Enter a vlan name:"),
29
+ :datacenter => connection(:network).datacenters.by_name(ui.ask_question("Enter a datacenter name:")),
30
+ :router => {'hostname' => ui.ask_question("Enter a router hostname:")},
31
+ :network_space => ui.ask_question("Enter a network space:", :default => 'PUBLIC'),
32
+ }
33
+
34
+ vlan = connection(:network).networks.create(opts)
35
+
36
+ !!vlan and puts "#{ui.color("VLAN successfully created. Provisioning may take a few minutes to complete.", :green)}"
37
+
38
+ end
39
+
40
+ end
41
+ end
42
+ end