knife-clc 0.0.1 → 0.0.2.pre

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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +62 -40
  3. data/lib/chef/knife/clc_ip_create.rb +1 -0
  4. data/lib/chef/knife/clc_server_create.rb +25 -528
  5. data/lib/clc/client.rb +1 -1
  6. data/lib/knife-clc/async/config_options.rb +18 -0
  7. data/lib/knife-clc/async.rb +11 -0
  8. data/lib/knife-clc/base/config_options.rb +26 -0
  9. data/lib/knife-clc/base.rb +56 -0
  10. data/lib/knife-clc/bootstrap/bootstrapper.rb +92 -0
  11. data/lib/knife-clc/bootstrap/config_options.rb +66 -0
  12. data/lib/knife-clc/bootstrap/connectivity_helper.rb +39 -0
  13. data/lib/knife-clc/bootstrap/methods/async_linux_package.rb +41 -0
  14. data/lib/knife-clc/bootstrap/methods/async_windows_package.rb +69 -0
  15. data/lib/knife-clc/bootstrap/methods/sync_linux_ssh.rb +67 -0
  16. data/lib/knife-clc/bootstrap/methods/sync_windows_winrm.rb +61 -0
  17. data/lib/knife-clc/bootstrap/subcommand_loader.rb +18 -0
  18. data/lib/knife-clc/bootstrap/validator.rb +149 -0
  19. data/lib/knife-clc/bootstrap.rb +20 -0
  20. data/lib/knife-clc/cloud_extensions/cloud_adapter.rb +35 -0
  21. data/lib/knife-clc/cloud_extensions.rb +11 -0
  22. data/lib/knife-clc/ip_assignment/config_options.rb +29 -0
  23. data/lib/knife-clc/ip_assignment/ip_assigner.rb +41 -0
  24. data/lib/knife-clc/ip_assignment/mapper.rb +20 -0
  25. data/lib/knife-clc/ip_assignment/validator.rb +74 -0
  26. data/lib/knife-clc/ip_assignment.rb +20 -0
  27. data/lib/knife-clc/server_launch/config_options.rb +145 -0
  28. data/lib/knife-clc/server_launch/mapper.rb +40 -0
  29. data/lib/knife-clc/server_launch/server_launcher.rb +40 -0
  30. data/lib/knife-clc/server_launch/validator.rb +100 -0
  31. data/lib/knife-clc/server_launch.rb +21 -0
  32. data/lib/knife-clc/version.rb +1 -1
  33. metadata +44 -4
@@ -1,440 +1,28 @@
1
- require 'chef/knife/clc_base'
2
1
  require 'chef/knife/clc_server_show'
3
- require 'chef/knife/bootstrap'
4
- require 'chef/node'
2
+
3
+ require 'knife-clc/base'
4
+ require 'knife-clc/async'
5
+ require 'knife-clc/cloud_extensions'
6
+ require 'knife-clc/server_launch'
7
+ require 'knife-clc/bootstrap'
8
+ require 'knife-clc/ip_assignment'
5
9
 
6
10
  class Chef
7
11
  class Knife
8
12
  class ClcServerCreate < Knife
9
- include Knife::ClcBase
13
+ include ::Knife::Clc::Base
14
+ include ::Knife::Clc::Async
15
+ include ::Knife::Clc::CloudExtensions
16
+ include ::Knife::Clc::ServerLaunch
17
+ include ::Knife::Clc::IpAssignment
18
+ include ::Knife::Clc::Bootstrap
10
19
 
11
20
  banner 'knife clc server create (options)'
12
21
 
13
- option :clc_name,
14
- :long => '--name NAME',
15
- :description => 'Name of the server to create',
16
- :on => :head
17
-
18
- option :clc_description,
19
- :long => '--description DESCRIPTION',
20
- :description => 'User-defined description of this server',
21
- :on => :head
22
-
23
- option :clc_group,
24
- :long => '--group ID',
25
- :description => 'ID of the parent group',
26
- :on => :head
27
-
28
- option :clc_source_server,
29
- :long => '--source-server ID',
30
- :description => 'ID of the server to use a source. May be the ID of a template, or when cloning, an existing server ID',
31
- :on => :head
32
-
33
- option :clc_managed,
34
- :long => '--managed',
35
- :boolean => true,
36
- :description => 'Whether to create the server as managed or not',
37
- :on => :head
38
-
39
- option :clc_managed_backup,
40
- :long => '--managed-backup',
41
- :boolean => true,
42
- :description => 'Whether to add managed backup to the server',
43
- :on => :head
44
-
45
- option :clc_primary_dns,
46
- :long => '--primary-dns ADDRESS',
47
- :description => 'Primary DNS to set on the server',
48
- :on => :head
49
-
50
- option :clc_secondary_dns,
51
- :long => '--secondary-dns ADDRESS',
52
- :description => 'Secondary DNS to set on the server',
53
- :on => :head
54
-
55
- option :clc_network,
56
- :long => '--network ID',
57
- :description => 'ID of the network to which to deploy the server',
58
- :on => :head
59
-
60
- option :clc_ip,
61
- :long => '--ip ADDRESS',
62
- :description => 'IP address to assign to the server',
63
- :on => :head
64
-
65
- option :clc_server_password,
66
- :long => '--server-password PASSWORD',
67
- :description => 'Password of administrator or root user on server',
68
- :on => :head
69
-
70
- option :clc_source_server_password,
71
- :long => '--source-server-password PASSWORD',
72
- :description => 'Password of the source server, used only when creating a clone from an existing server',
73
- :on => :head
74
-
75
- option :clc_cpu,
76
- :long => '--cpu COUNT',
77
- :description => 'Number of processors to configure the server with',
78
- :on => :head
79
-
80
- option :clc_cpu_autoscale_policy,
81
- :long => '--cpu-autoscale-policy ID',
82
- :description => 'ID of the vertical CPU Autoscale policy to associate the server with',
83
- :on => :head
84
-
85
- option :clc_memory,
86
- :long => '--memory COUNT',
87
- :description => 'Number of GB of memory to configure the server with',
88
- :on => :head
89
-
90
- option :clc_type,
91
- :long => '--type TYPE',
92
- :description => 'Whether to create a standard or hyperscale server',
93
- :on => :head
94
-
95
- option :clc_storage_type,
96
- :long => '--storage-type TYPE',
97
- :description => 'For standard servers, whether to use standard or premium storage',
98
- :on => :head
99
-
100
- option :clc_anti_affinity_policy,
101
- :long => '--anti-affinity-policy ID',
102
- :description => 'ID of the Anti-Affinity policy to associate the server with',
103
- :on => :head
104
-
105
- option :clc_custom_fields,
106
- :long => '--custom-field KEY=VALUE',
107
- :description => 'Custom field key-value pair',
108
- :on => :head,
109
- :proc => ->(param) do
110
- Chef::Config[:knife][:clc_custom_fields] ||= []
111
- Chef::Config[:knife][:clc_custom_fields] << param
112
- end
113
-
114
- option :clc_disks,
115
- :long => '--disk PATH,SIZE,TYPE',
116
- :description => 'Configuration for an additional server disk',
117
- :on => :head,
118
- :proc => ->(param) do
119
- Chef::Config[:knife][:clc_disks] ||= []
120
- Chef::Config[:knife][:clc_disks] << param
121
- end
122
-
123
- option :clc_ttl,
124
- :long => '--ttl DATETIME',
125
- :description => 'Date/time that the server should be deleted',
126
- :on => :head
127
-
128
- option :clc_packages,
129
- :long => '--package ID,KEY_1=VALUE[,KEY_2=VALUE]',
130
- :description => 'Package to run on the server after it has been built',
131
- :on => :head,
132
- :proc => ->(param) do
133
- Chef::Config[:knife][:clc_packages] ||= []
134
- Chef::Config[:knife][:clc_packages] << param
135
- end
136
-
137
- option :clc_configuration,
138
- :long => '--configuration ID',
139
- :description => 'Specifies the identifier for the specific configuration type of bare metal server to deploy',
140
- :on => :head
141
-
142
- option :clc_os_type,
143
- :long => '--os-type TYPE',
144
- :description => 'Specifies the OS to provision with the bare metal server',
145
- :on => :head
146
-
147
- option :clc_allowed_protocols,
148
- :long => '--allow PROTOCOL:FROM[-TO]',
149
- :description => 'Assigns public IP with permissions for specified protocol',
150
- :on => :head,
151
- :proc => ->(param) do
152
- Chef::Config[:knife][:clc_allowed_protocols] ||= []
153
- Chef::Config[:knife][:clc_allowed_protocols] << param
154
- end
155
-
156
- option :clc_sources,
157
- :long => '--source CIDR',
158
- :description => 'The source IP address range allowed to access the new public IP address',
159
- :on => :head,
160
- :proc => ->(param) do
161
- Chef::Config[:knife][:clc_sources] ||= []
162
- Chef::Config[:knife][:clc_sources] << param
163
- end
164
-
165
- option :clc_wait,
166
- :long => '--wait',
167
- :description => 'Wait for operation completion',
168
- :boolean => true,
169
- :default => false,
170
- :on => :head
171
-
172
- option :clc_bootstrap,
173
- :long => '--bootstrap',
174
- :description => 'Bootstrap launched server using standard `knife bootstrap` command',
175
- :boolean => true,
176
- :default => false,
177
- :on => :head
178
-
179
- option :clc_bootstrap_private,
180
- :long => '--bootstrap-private',
181
- :description => 'Bootstrap from private network. Requires client or SSH gateway to have an access to private network of the server',
182
- :boolean => true,
183
- :default => false,
184
- :on => :head
185
-
186
22
  def parse_and_validate_parameters
187
- unless config[:clc_name]
188
- errors << 'Name is required'
189
- end
190
-
191
- unless config[:clc_group]
192
- errors << 'Group ID is required'
193
- end
194
-
195
- unless config[:clc_source_server]
196
- errors << 'Source server ID is required'
197
- end
198
-
199
- unless config[:clc_cpu]
200
- errors << 'Number of CPUs is required'
201
- end
202
-
203
- unless config[:clc_memory]
204
- errors << 'Number of memory GBs is required'
205
- end
206
-
207
- unless config[:clc_type]
208
- errors << 'Type is required'
209
- end
210
-
211
- custom_fields = config[:clc_custom_fields]
212
- if custom_fields && custom_fields.any?
213
- parse_custom_fields(custom_fields)
214
- end
215
-
216
- disks = config[:clc_disks]
217
- if disks && disks.any?
218
- parse_disks(disks)
219
- end
220
-
221
- packages = config[:clc_packages]
222
- if packages && packages.any?
223
- parse_packages(packages)
224
- end
225
-
226
- permissions = config[:clc_allowed_protocols]
227
- if permissions && permissions.any?
228
- parse_protocol_permissions(permissions)
229
- end
230
-
231
- sources = config[:clc_sources]
232
- if sources && sources.any?
233
- parse_sources(sources)
234
- end
235
-
236
- bootstrap = config[:clc_bootstrap]
237
- if bootstrap
238
- check_chef_server_connectivity
239
- check_server_platform
240
- if config[:clc_wait]
241
- check_bootstrap_connectivity_params
242
- else
243
- check_bootstrap_node_connectivity_params
244
- end
245
- end
246
- end
247
-
248
- def check_chef_server_connectivity
249
- Chef::Node.list
250
- rescue Exception => e
251
- errors << 'Could not connect to Chef Server: ' + e.message
252
- end
253
-
254
- def check_bootstrap_node_connectivity_params
255
- command = bootstrap_command
256
- # Chef 12.0 does not have bootstrap context accessor and validates key by itself
257
- return unless command.respond_to?(:bootstrap_context)
258
-
259
- context = command.bootstrap_context
260
- unless context.validation_key
261
- errors << "Validatorless async bootstrap is not supported. Validation key #{Chef::Config[:validation_key]} not found"
262
- end
263
- end
264
-
265
- def check_bootstrap_connectivity_params
266
- return if indirect_bootstrap?
267
-
268
- if public_ip_requested?
269
- errors << 'Bootstrapping requires SSH access to the server' unless ssh_access_requested?
270
- else
271
- errors << 'Bootstrapping requires public IP access to the server. Ignore this check with --bootstrap-private'
272
- end
273
- end
274
-
275
- def check_server_platform
276
- return unless config[:clc_group] && config[:clc_source_server]
277
-
278
- if template = find_source_template
279
- windows_platform = template['osType'] =~ /windows/
280
- elsif server = find_source_server
281
- windows_platform = server['os'] =~ /windows/
282
- end
283
-
284
- if windows_platform
285
- errors << 'Bootstrapping is available for Linux platform only'
286
- end
287
- rescue Clc::CloudExceptions::Error => e
288
- errors << "Could not derive server bootstrap platform: #{e.message}"
289
- end
290
-
291
- def find_source_template
292
- group = connection.show_group(config[:clc_group])
293
- datacenter_id = group['locationId']
294
- connection.list_templates(datacenter_id).find do |template|
295
- template['name'] == config[:clc_source_server]
296
- end
297
- end
298
-
299
- def find_source_server
300
- connection.show_server(config[:clc_source_server])
301
- end
302
-
303
- def public_ip_requested?
304
- config[:clc_allowed_protocols] && config[:clc_allowed_protocols].any?
305
- end
306
-
307
- def ssh_access_requested?
308
- ssh_port = requested_ssh_port
309
-
310
- config[:clc_allowed_protocols].find do |permission|
311
- protocol, from, to = permission.values_at('protocol', 'port', 'portTo')
312
- next unless protocol == 'tcp'
313
- next unless from
314
-
315
- to ||= from
316
-
317
- Range.new(from, to).include? ssh_port
318
- end
319
- end
320
-
321
- def requested_ssh_port
322
- (config[:ssh_port] && Integer(config[:ssh_port])) || 22
323
- end
324
-
325
- def parse_custom_fields(custom_fields)
326
- custom_fields.map! do |param|
327
- key, value = param.split('=', 2)
328
-
329
- unless key && value
330
- errors << "Custom field definition #{param} is malformed"
331
- next
332
- end
333
-
334
- { 'id' => key, 'value' => value }
335
- end
336
- end
337
-
338
- def parse_disks(disks)
339
- disks.map! do |param|
340
- path, size, type = param.split(',', 3)
341
-
342
- unless path && size && type
343
- errors << "Disk definition #{param} is malformed"
344
- end
345
-
346
- { 'path' => path, 'sizeGB' => size, 'type' => type }
347
- end
348
- end
349
-
350
- def parse_packages(packages)
351
- packages.map! do |param|
352
- begin
353
- id, package_params = param.split(',', 2)
354
- package_params = package_params.split(',').map { |pair| Hash[*pair.split('=', 2)] }
355
- { 'packageId' => id, 'parameters' => package_params }
356
- rescue Exception => e
357
- errors << "Package definition #{param} is malformed"
358
- end
359
- end
360
- end
361
-
362
- def parse_protocol_permissions(permissions)
363
- permissions.map! do |param|
364
- protocol, port_range = param.split(':', 2)
365
-
366
- case protocol.downcase
367
- when 'ssh', 'sftp' then { 'protocol' => 'tcp', 'port' => 22 }
368
- when 'rdp' then { 'protocol' => 'tcp', 'port' => 3389 }
369
- when 'icmp' then { 'protocol' => 'icmp' }
370
- when 'http' then [{ 'protocol' => 'tcp', 'port' => 80 }, { 'protocol' => 'tcp', 'port' => 8080 }]
371
- when 'https' then { 'protocol' => 'tcp', 'port' => 443 }
372
- when 'ftp' then { 'protocol' => 'tcp', 'port' => 21 }
373
- when 'ftps' then { 'protocol' => 'tcp', 'port' => 990 }
374
- when 'udp', 'tcp'
375
- unless port_range
376
- errors << "No ports specified for #{param}"
377
- else
378
- ports = port_range.split('-').map do |port_string|
379
- Integer(port_string) rescue nil
380
- end
381
-
382
- if ports.any?(&:nil?) || ports.size > 2 || ports.size < 1
383
- errors << "Malformed port range for #{param}"
384
- end
385
-
386
- {
387
- 'protocol' => protocol.downcase,
388
- 'port' => ports[0],
389
- 'portTo' => ports[1]
390
- }.keep_if { |_, value| value }
391
- end
392
- else
393
- errors << "Unsupported protocol for #{param}"
394
- end
395
- end
396
-
397
- permissions.flatten!
398
- end
399
-
400
- def parse_sources(sources)
401
- sources.map! do |cidr|
402
- { 'cidr' => cidr }
403
- end
404
- end
405
-
406
- def prepare_launch_params
407
- {
408
- 'name' => config[:clc_name],
409
- 'description' => config[:clc_description],
410
- 'groupId' => config[:clc_group],
411
- 'sourceServerId' => config[:clc_source_server],
412
- 'isManagedOS' => config[:clc_managed],
413
- 'isManagedBackup' => config[:clc_managed_backup],
414
- 'primaryDns' => config[:clc_primary_dns],
415
- 'secondaryDns' => config[:clc_secondary_dns],
416
- 'networkId' => config[:clc_network],
417
- 'ipAddress' => config[:clc_ip],
418
- 'password' => config[:clc_server_password],
419
- 'sourceServerPassword' => config[:clc_source_server_password],
420
- 'cpu' => config[:clc_cpu].to_i,
421
- 'cpuAutoscalePolicyId' => config[:clc_cpu_autoscale_policy],
422
- 'memoryGB' => config[:clc_memory].to_i,
423
- 'type' => config[:clc_type],
424
- 'storageType' => config[:clc_storage_type],
425
- 'antiAffinityPolicyId' => config[:clc_anti_affinity_policy],
426
- 'customFields' => config[:clc_custom_fields],
427
- 'additionalDisks' => config[:clc_disks],
428
- 'ttl' => config[:clc_ttl],
429
- 'packages' => config[:clc_packages],
430
- }.delete_if { |_, value| !value.kind_of?(Integer) && (value.nil? || value.empty?) }
431
- end
432
-
433
- def prepare_ip_params
434
- {
435
- 'ports' => config[:clc_allowed_protocols],
436
- 'sourceRestrictions' => config[:clc_sources]
437
- }.delete_if { |_, value| value.nil? || value.empty? }
23
+ server_launcher.prepare
24
+ ip_assigner.prepare
25
+ bootstrapper.prepare
438
26
  end
439
27
 
440
28
  def execute
@@ -443,22 +31,24 @@ class Chef
443
31
 
444
32
  def sync_create_server
445
33
  ui.info 'Requesting server launch...'
446
- links = connection.create_server(prepare_launch_params)
34
+ links = server_launcher.execute
447
35
  connection.wait_for(links['operation']['id']) { putc '.' }
448
36
  ui.info "\n"
449
37
  ui.info "Server has been launched"
450
38
 
39
+ server = connection.follow(links['resource'])
40
+
451
41
  if config[:clc_allowed_protocols]
452
42
  ui.info 'Requesting public IP...'
453
- server = connection.follow(links['resource'])
454
- ip_links = connection.create_ip_address(server['id'], prepare_ip_params)
43
+ ip_links = ip_assigner.execute(server['id'])
455
44
  connection.wait_for(ip_links['operation']['id']) { putc '.' }
456
45
  ui.info "\n"
457
46
  ui.info 'Public IP has been assigned'
47
+ server = connection.follow(links['resource'])
458
48
  end
459
49
 
460
50
  if config[:clc_bootstrap]
461
- sync_bootstrap(links['resource']['id'])
51
+ bootstrapper.sync_bootstrap(server)
462
52
  end
463
53
 
464
54
  argv = [links['resource']['id'], '--uuid', '--creds']
@@ -474,22 +64,20 @@ class Chef
474
64
  end
475
65
 
476
66
  def async_create_server
477
- launch_params = prepare_launch_params
478
-
479
67
  if config[:clc_bootstrap]
480
- add_bootstrapping_params(launch_params)
68
+ bootstrapper.async_bootstrap(server_launcher.launch_parameters)
481
69
  ui.info 'Bootstrap has been scheduled'
482
70
  end
483
71
 
484
72
  ui.info 'Requesting server launch...'
485
- links = connection.create_server(launch_params)
73
+ links = server_launcher.execute
486
74
  ui.info 'Launch request has been sent'
487
75
  ui.info "You can check launch operation status with 'knife clc operation show #{links['operation']['id']}'"
488
76
 
489
77
  if config[:clc_allowed_protocols]
490
78
  ui.info 'Requesting public IP...'
491
79
  server = connection.follow(links['resource'])
492
- ip_links = connection.create_ip_address(server['id'], prepare_ip_params)
80
+ ip_links = ip_assigner.execute(server['id'])
493
81
  ui.info 'Public IP request has been sent'
494
82
  ui.info "You can check assignment operation status with 'knife clc operation show #{ip_links['operation']['id']}'"
495
83
  end
@@ -499,97 +87,6 @@ class Chef
499
87
 
500
88
  ui.info "You can check server status later with 'knife clc server show #{argv.join(' ')}'"
501
89
  end
502
-
503
- def sync_bootstrap(uuid)
504
- server = connection.show_server(uuid, true)
505
-
506
- ensure_server_powered_on(server)
507
-
508
- command = bootstrap_command
509
-
510
- command.name_args = [get_server_fqdn(server)]
511
-
512
- username, password = config.values_at(:ssh_user, :ssh_password)
513
- unless username && password
514
- creds = get_server_credentials(server)
515
- command.config.merge!(:ssh_user => creds['userName'], :ssh_password => creds['password'])
516
- end
517
-
518
- command.config[:chef_node_name] ||= server['name']
519
-
520
- retry_on_timeouts { command.run }
521
- end
522
-
523
- def retry_on_timeouts(tries = 2, &block)
524
- yield
525
- rescue Errno::ETIMEDOUT => e
526
- tries -= 1
527
-
528
- if tries > 0
529
- ui.info 'Retrying host connection...'
530
- retry
531
- else
532
- raise
533
- end
534
- end
535
-
536
- def ensure_server_powered_on(server)
537
- return unless server['details']['powerState'] == 'stopped'
538
- ui.info 'Requesting server power on...'
539
- links = connection.power_on_server(server['id'])
540
- connection.wait_for(links['operation']['id']) { putc '.' }
541
- ui.info "\n"
542
- ui.info 'Server has been powered on'
543
- end
544
-
545
- def add_bootstrapping_params(launch_params)
546
- launch_params['packages'] ||= []
547
- launch_params['packages'] << package_for_async_bootstrap
548
- end
549
-
550
- def package_for_async_bootstrap
551
- {
552
- 'packageId' => 'a5d9d04369df4276a4f98f2ca7f7872b',
553
- 'parameters' => {
554
- 'Mode' => 'Ssh',
555
- 'Script' => bootstrap_command.render_template
556
- }
557
- }
558
- end
559
-
560
- def get_server_fqdn(server)
561
- if indirect_bootstrap?
562
- private_ips = server['details']['ipAddresses'].map { |addr| addr['internal'] }.compact
563
- private_ips.first
564
- else
565
- public_ips = server['details']['ipAddresses'].map { |addr| addr['public'] }.compact
566
- public_ips.first
567
- end
568
- end
569
-
570
- def indirect_bootstrap?
571
- config[:clc_bootstrap_private] || config[:ssh_gateway]
572
- end
573
-
574
- def get_server_credentials(server)
575
- creds_link = server['links'].find { |link| link['rel'] == 'credentials' }
576
- connection.follow(creds_link) if creds_link
577
- end
578
-
579
- def self.bootstrap_command_class
580
- Chef::Knife::Bootstrap
581
- end
582
-
583
- def bootstrap_command
584
- command_class = self.class.bootstrap_command_class
585
- command_class.load_deps
586
- command = command_class.new
587
- command.config.merge!(config)
588
- command.configure_chef
589
- command
590
- end
591
-
592
- self.options.merge!(bootstrap_command_class.options)
593
90
  end
594
91
  end
595
92
  end
data/lib/clc/client.rb CHANGED
@@ -144,7 +144,7 @@ module Clc
144
144
  connection.get(link['href']).body
145
145
  end
146
146
 
147
- def wait_for(operation_id, timeout = 360)
147
+ def wait_for(operation_id, timeout = 1200)
148
148
  expire_at = Time.now + timeout
149
149
  loop do
150
150
  operation = show_operation(operation_id)
@@ -0,0 +1,18 @@
1
+ module Knife
2
+ module Clc
3
+ module Async
4
+ class ConfigOptions
5
+ def self.attach(command_class)
6
+ command_class.class_eval do
7
+ option :clc_wait,
8
+ :long => '--wait',
9
+ :description => 'Wait for operation completion',
10
+ :boolean => true,
11
+ :default => false,
12
+ :on => :head
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'async/config_options'
2
+
3
+ module Knife
4
+ module Clc
5
+ module Async
6
+ def self.included(command_class)
7
+ ConfigOptions.attach(command_class)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,26 @@
1
+ module Knife
2
+ module Clc
3
+ module Base
4
+ class ConfigOptions
5
+ def self.attach(command_class)
6
+ command_class.class_eval do
7
+ option :clc_username,
8
+ :long => '--username NAME',
9
+ :description => 'Name of the user to access CLC API',
10
+ :on => :head
11
+
12
+ option :clc_password,
13
+ :long => '--password PASSWORD',
14
+ :description => 'Password for CLC user account',
15
+ :on => :head
16
+
17
+ option :clc_endpoint,
18
+ :long => '--endpoint URL',
19
+ :description => 'Alternative CLC API URL',
20
+ :on => :head
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end