morpheus-cli 9.0.0 → 9.0.2
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 +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +4 -0
- data/lib/morpheus/api/clusters_interface.rb +72 -0
- data/lib/morpheus/api/instances_interface.rb +1 -1
- data/lib/morpheus/api/options_interface.rb +1 -1
- data/lib/morpheus/api/servers_interface.rb +8 -0
- data/lib/morpheus/api/storage_volumes_interface.rb +8 -0
- data/lib/morpheus/api/virtual_images_interface.rb +10 -2
- data/lib/morpheus/api/virtual_switches_interface.rb +9 -0
- data/lib/morpheus/cli/commands/backups_command.rb +20 -6
- data/lib/morpheus/cli/commands/clusters.rb +575 -14
- data/lib/morpheus/cli/commands/hosts.rb +72 -1
- data/lib/morpheus/cli/commands/instances.rb +13 -2
- data/lib/morpheus/cli/commands/networks_command.rb +35 -3
- data/lib/morpheus/cli/commands/storage_volumes.rb +77 -2
- data/lib/morpheus/cli/commands/virtual_switches_command.rb +336 -0
- data/lib/morpheus/cli/mixins/infrastructure_helper.rb +6 -4
- data/lib/morpheus/cli/version.rb +1 -1
- data/test/cli/storage_volumes_test.rb +79 -0
- metadata +6 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a1c28da8f1406a4119d87de9b4f0defe5e98ad69d347625c8c8018bcf02f196b
|
|
4
|
+
data.tar.gz: 65164bb33eb05de4d1627de11a43297316e8bb5a82849a6010d91cfdcb2d5236
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a265975de9ea8d79e23679f035536d6d201929c4133cd3cd4a410ae626597b4931019fed1c354e4ff0e67d8a83506719f10b921580522656aab858ddea23c69e
|
|
7
|
+
data.tar.gz: 142b6cd4634d72f4636e0d251d0cfd905050ba9cceed13e75acd6091f4ca4f263e03043d30f10b40158ab15962e0a22307e2acdcfae75cfe18a059e8279b0049
|
data/Dockerfile
CHANGED
|
@@ -1038,6 +1038,10 @@ class Morpheus::APIClient
|
|
|
1038
1038
|
Morpheus::TokensInterface.new(common_interface_options).setopts(@options)
|
|
1039
1039
|
end
|
|
1040
1040
|
|
|
1041
|
+
def virtual_switches
|
|
1042
|
+
Morpheus::VirtualSwitchesInterface.new(common_interface_options).setopts(@options)
|
|
1043
|
+
end
|
|
1044
|
+
|
|
1041
1045
|
def rest(endpoint)
|
|
1042
1046
|
Morpheus::RestInterface.new(common_interface_options).setopts(@options.merge({base_path: "#{@base_url}/api/#{endpoint}"}))
|
|
1043
1047
|
end
|
|
@@ -389,5 +389,77 @@ class Morpheus::ClustersInterface < Morpheus::APIClient
|
|
|
389
389
|
headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
|
390
390
|
execute(method: :delete, url: url, headers: headers)
|
|
391
391
|
end
|
|
392
|
+
|
|
393
|
+
def affinity_group_form_options(id, params={})
|
|
394
|
+
url = "#{base_path}/#{id}/affinity-groups/form-options"
|
|
395
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
|
396
|
+
execute(method: :get, url: url, headers: headers)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def affinity_group_violations(params={})
|
|
400
|
+
url = "#{@base_url}/api/affinity-groups/violations"
|
|
401
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
|
402
|
+
execute(method: :get, url: url, headers: headers)
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def list_host_vm_groups(id, params={})
|
|
406
|
+
url = "#{base_path}/#{id}/host-vm-groups"
|
|
407
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
|
408
|
+
execute(method: :get, url: url, headers: headers)
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def get_host_vm_group(id, host_vm_group_id, params={})
|
|
412
|
+
url = "#{base_path}/#{id}/host-vm-groups/#{host_vm_group_id}"
|
|
413
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
|
414
|
+
execute(method: :get, url: url, headers: headers)
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
def create_host_vm_group(id, payload)
|
|
418
|
+
url = "#{base_path}/#{id}/host-vm-groups"
|
|
419
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
|
420
|
+
execute(method: :post, url: url, headers: headers, payload: payload.to_json)
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def update_host_vm_group(id, host_vm_group_id, payload)
|
|
424
|
+
url = "#{base_path}/#{id}/host-vm-groups/#{host_vm_group_id}"
|
|
425
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
|
426
|
+
execute(method: :put, url: url, headers: headers, payload: payload.to_json)
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
def destroy_host_vm_group(id, host_vm_group_id, params={})
|
|
430
|
+
url = "#{base_path}/#{id}/host-vm-groups/#{host_vm_group_id}"
|
|
431
|
+
headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
|
432
|
+
execute(method: :delete, url: url, headers: headers)
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def host_vm_group_form_options(id, params={})
|
|
436
|
+
url = "#{base_path}/#{id}/host-vm-groups/form-options"
|
|
437
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
|
438
|
+
execute(method: :get, url: url, headers: headers)
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
def available_updates(id, params={})
|
|
442
|
+
url = "#{base_path}/#{id}/available-updates"
|
|
443
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
|
444
|
+
execute(method: :get, url: url, headers: headers)
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
def list_updates(id, update_id, params={})
|
|
448
|
+
url = "#{base_path}/#{id}/available-updates"
|
|
449
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
|
450
|
+
execute(method: :get, url: url, headers: headers)
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
def get_update(id, update_id, params={})
|
|
454
|
+
url = "#{base_path}/#{id}/available-updates/#{update_id}"
|
|
455
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
|
456
|
+
execute(method: :get, url: url, headers: headers)
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
def execute_update(id, payload)
|
|
460
|
+
url = "#{base_path}/#{id}/execute-update"
|
|
461
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
|
462
|
+
execute(method: :post, url: url, headers: headers, payload: payload.to_json)
|
|
463
|
+
end
|
|
392
464
|
|
|
393
465
|
end
|
|
@@ -296,7 +296,7 @@ class Morpheus::InstancesInterface < Morpheus::APIClient
|
|
|
296
296
|
def service_plans(params={})
|
|
297
297
|
url = "#{@base_url}/api/instances/service-plans"
|
|
298
298
|
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
|
299
|
-
opts = {method: :get, url: url, headers: headers}
|
|
299
|
+
opts = {method: :get, url: url, headers: headers, timeout: 180}
|
|
300
300
|
execute(opts)
|
|
301
301
|
end
|
|
302
302
|
|
|
@@ -12,6 +12,6 @@ class Morpheus::OptionsInterface < Morpheus::APIClient
|
|
|
12
12
|
url = "#{@base_url}/api/options/#{option_source_type}/#{source}"
|
|
13
13
|
end
|
|
14
14
|
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
|
15
|
-
execute(method: :get, url: url, headers: headers)
|
|
15
|
+
execute(method: :get, url: url, headers: headers, timeout: 180)
|
|
16
16
|
end
|
|
17
17
|
end
|
|
@@ -219,4 +219,12 @@ class Morpheus::ServersInterface < Morpheus::APIClient
|
|
|
219
219
|
execute(opts)
|
|
220
220
|
end
|
|
221
221
|
|
|
222
|
+
|
|
223
|
+
def create_linked_clone(id, snapshot_id, payload={})
|
|
224
|
+
url = "#{@base_url}/api/servers/#{id}/linked-clone/#{snapshot_id}"
|
|
225
|
+
headers = {:authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
|
226
|
+
opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
|
|
227
|
+
execute(opts)
|
|
228
|
+
end
|
|
229
|
+
|
|
222
230
|
end
|
|
@@ -13,4 +13,12 @@ class Morpheus::StorageVolumesInterface < Morpheus::RestInterface
|
|
|
13
13
|
execute(opts)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
+
# Transfer ownership of a storage volume to another tenant.
|
|
17
|
+
# The server expects { "storageVolume": { "tenant": { "id": <id> } } }
|
|
18
|
+
# and handles all authorization and business-rule validation.
|
|
19
|
+
def update_tenant(id, payload, params={}, headers={})
|
|
20
|
+
validate_id!(id)
|
|
21
|
+
execute(method: :put, url: "#{base_path}/#{CGI::escape(id.to_s)}", params: params, payload: payload, headers: headers)
|
|
22
|
+
end
|
|
23
|
+
|
|
16
24
|
end
|
|
@@ -117,7 +117,11 @@ class Morpheus::VirtualImagesInterface < Morpheus::APIClient
|
|
|
117
117
|
gz.close
|
|
118
118
|
}
|
|
119
119
|
http_opts[:body] = Morpheus::BodyIO.new(rd)
|
|
120
|
-
|
|
120
|
+
if Gem::Version.new(HTTP::VERSION) >= Gem::Version.new("6.0.0")
|
|
121
|
+
response = http.post(url, **http_opts)
|
|
122
|
+
else
|
|
123
|
+
response = http.post(url, http_opts)
|
|
124
|
+
end
|
|
121
125
|
else
|
|
122
126
|
if @dry_run
|
|
123
127
|
return {method: :post, url: url, headers: headers, params: query_params, payload: payload}
|
|
@@ -126,7 +130,11 @@ class Morpheus::VirtualImagesInterface < Morpheus::APIClient
|
|
|
126
130
|
http = HTTP.headers(headers)
|
|
127
131
|
http_opts[:params] = query_params
|
|
128
132
|
http_opts[:body] = payload
|
|
129
|
-
|
|
133
|
+
if Gem::Version.new(HTTP::VERSION) >= Gem::Version.new("6.0.0")
|
|
134
|
+
response = http.post(url, **http_opts)
|
|
135
|
+
else
|
|
136
|
+
response = http.post(url, http_opts)
|
|
137
|
+
end
|
|
130
138
|
end
|
|
131
139
|
# puts "Took #{Time.now.to_i - start_time.to_i}"
|
|
132
140
|
# return response
|
|
@@ -96,6 +96,8 @@ EOT
|
|
|
96
96
|
print_h1 "Backup Details", [], options
|
|
97
97
|
print cyan
|
|
98
98
|
columns = backup_column_definitions
|
|
99
|
+
columns.delete("Backup Provider") if backup['backupProvider'].nil?
|
|
100
|
+
columns.delete("Storage Provider") if backup['storageProvider'].nil?
|
|
99
101
|
columns.delete("Instance") if backup['instance'].nil?
|
|
100
102
|
columns.delete("Container ID") if backup['containerId'].nil?
|
|
101
103
|
columns.delete("Host") if backup['server'].nil?
|
|
@@ -185,6 +187,17 @@ EOT
|
|
|
185
187
|
params['backupType'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'backupType', 'fieldLabel' => 'Backup Type', 'type' => 'select', 'selectOptions' => avail_backup_types, 'defaultValue' => avail_backup_types[0] ? avail_backup_types[0]['name'] : nil, 'required' => true}], options[:options], @api_client)['backupType']
|
|
186
188
|
end
|
|
187
189
|
|
|
190
|
+
# Plugin optionTypes
|
|
191
|
+
plugin_option_type_inputs = @options_interface.options_for_source('backupOptionTypes', {'backupTypeCode' => params['backupType']} )['data']['optionTypes']
|
|
192
|
+
plugin_opt_parser = Morpheus::Cli::OptionParser.new do |opts|
|
|
193
|
+
build_option_type_options(opts, options, plugin_option_type_inputs)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
plugin_opt_parser.parse!(args)
|
|
197
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt(plugin_option_type_inputs, options[:options].deep_merge({:context_map => {'domain' => 'backup'}}), @api_client)
|
|
198
|
+
v_prompt.deep_compact!.booleanize! # remove empty values and convert checkbox "on" and "off" to true and false
|
|
199
|
+
params.merge!(v_prompt.delete('backup'))
|
|
200
|
+
|
|
188
201
|
# Job / Schedule
|
|
189
202
|
params['jobAction'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'jobAction', 'fieldLabel' => 'Backup Job Type', 'type' => 'select', 'optionSource' => 'backupJobActions', 'required' => true, 'defaultValue' => 'new'}], options[:options], @api_client)['jobAction']
|
|
190
203
|
if params['jobAction'] == 'new'
|
|
@@ -541,8 +554,9 @@ EOT
|
|
|
541
554
|
{
|
|
542
555
|
"ID" => 'id',
|
|
543
556
|
"Name" => 'name',
|
|
544
|
-
"Backup Type" => lambda {|it| format_backup_type_tag(it) },
|
|
545
|
-
"Backup
|
|
557
|
+
"Backup Type" => lambda {|it| (it['backupType'] && it['backupType']['name']) ? it['backupType']['name'] : format_backup_type_tag(it) },
|
|
558
|
+
"Backup Provider" => lambda {|it| it['backupProvider']['name'] rescue '' },
|
|
559
|
+
"Storage Provider" => lambda {|it| it['storageProvider']['name'] rescue '' },
|
|
546
560
|
"Location Type" => lambda {|it|
|
|
547
561
|
if it['locationType'] == "instance"
|
|
548
562
|
"Instance"
|
|
@@ -610,11 +624,11 @@ EOT
|
|
|
610
624
|
def format_backup_location_tag(backup)
|
|
611
625
|
# check storage provider or backup provider indicating remote storage
|
|
612
626
|
if backup['storageProvider'] && backup['storageProvider']['id']
|
|
613
|
-
|
|
614
|
-
"#{green}REMOTE#{reset} (#{
|
|
627
|
+
provider_label = backup['storageProvider']['type'] || backup['storageProvider']['providerType'] || backup['storageProvider']['name'] || ''
|
|
628
|
+
"#{green}REMOTE#{reset} (#{provider_label})"
|
|
615
629
|
elsif backup['backupProvider'] && backup['backupProvider']['id']
|
|
616
|
-
|
|
617
|
-
"#{green}REMOTE#{reset} (#{
|
|
630
|
+
provider_label = backup['backupProvider']['type'] || backup['backupProvider']['providerType'] || backup['backupProvider']['name'] || ''
|
|
631
|
+
"#{green}REMOTE#{reset} (#{provider_label})"
|
|
618
632
|
else
|
|
619
633
|
"#{blue}LOCAL#{reset}"
|
|
620
634
|
end
|