morpheus-cli 8.1.2 → 9.0.1
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 +2 -2
- data/lib/morpheus/api/api_client.rb +8 -0
- data/lib/morpheus/api/clusters_interface.rb +24 -0
- data/lib/morpheus/api/groups_interface.rb +2 -1
- 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 +0 -1
- data/lib/morpheus/api/storage_volumes_interface.rb +8 -0
- data/lib/morpheus/api/support_bundles_interface.rb +46 -0
- data/lib/morpheus/api/systems_interface.rb +32 -0
- data/lib/morpheus/api/tokens_interface.rb +39 -0
- data/lib/morpheus/api/virtual_images_interface.rb +10 -2
- data/lib/morpheus/cli/cli_command.rb +6 -1
- data/lib/morpheus/cli/commands/backups_command.rb +9 -6
- data/lib/morpheus/cli/commands/clients_command.rb +60 -74
- data/lib/morpheus/cli/commands/clouds.rb +30 -2
- data/lib/morpheus/cli/commands/clusters.rb +77 -0
- data/lib/morpheus/cli/commands/execution_request_command.rb +6 -2
- data/lib/morpheus/cli/commands/groups.rb +46 -23
- data/lib/morpheus/cli/commands/hosts.rb +21 -14
- data/lib/morpheus/cli/commands/instances.rb +32 -6
- data/lib/morpheus/cli/commands/storage_volumes.rb +78 -3
- data/lib/morpheus/cli/commands/support_bundles_command.rb +606 -0
- data/lib/morpheus/cli/commands/systems.rb +606 -2
- data/lib/morpheus/cli/commands/tokens_command.rb +391 -0
- data/lib/morpheus/cli/commands/workflows.rb +16 -3
- data/lib/morpheus/cli/mixins/infrastructure_helper.rb +30 -14
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +21 -7
- data/lib/morpheus/cli/version.rb +1 -1
- data/test/api/systems_interface_test.rb +26 -0
- data/test/cli/storage_volumes_test.rb +79 -0
- data/test/cli/systems_test.rb +206 -0
- metadata +12 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1f2fdd08e0bf0dbe8567812778748a10d38dbb6efd64430fc50fdf1134528be3
|
|
4
|
+
data.tar.gz: 2219cdf94a929a790e75d727068567adb10d09a80c30971e96365726812d3334
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7b276775f4746e397b8d4b05c3c09c04d9b02409c7511e6a40a3ac80a160642d376fb10a2bf78477bfe84f3b3fc9abc1680ca332307efe4c250ec2b478a961f3
|
|
7
|
+
data.tar.gz: 7046dcbfff992519d64e93c1fd1383b0bb1c3166dfad466d56661a2ee65e0b45038a9d94d4c7812ab423c285267347609337e0312fddeeae82fe5f001b67cc6e
|
data/Dockerfile
CHANGED
|
@@ -1034,6 +1034,10 @@ class Morpheus::APIClient
|
|
|
1034
1034
|
Morpheus::MigrationsInterface.new(common_interface_options).setopts(@options)
|
|
1035
1035
|
end
|
|
1036
1036
|
|
|
1037
|
+
def tokens
|
|
1038
|
+
Morpheus::TokensInterface.new(common_interface_options).setopts(@options)
|
|
1039
|
+
end
|
|
1040
|
+
|
|
1037
1041
|
def rest(endpoint)
|
|
1038
1042
|
Morpheus::RestInterface.new(common_interface_options).setopts(@options.merge({base_path: "#{@base_url}/api/#{endpoint}"}))
|
|
1039
1043
|
end
|
|
@@ -1048,6 +1052,10 @@ class Morpheus::APIClient
|
|
|
1048
1052
|
end
|
|
1049
1053
|
alias :get_interface :interface
|
|
1050
1054
|
|
|
1055
|
+
def support_bundles
|
|
1056
|
+
Morpheus::SupportBundlesInterface.new(common_interface_options).setopts(@options)
|
|
1057
|
+
end
|
|
1058
|
+
|
|
1051
1059
|
# add new interfaces here
|
|
1052
1060
|
|
|
1053
1061
|
protected
|
|
@@ -389,5 +389,29 @@ 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 available_updates(id, params={})
|
|
394
|
+
url = "#{base_path}/#{id}/available-updates"
|
|
395
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
|
396
|
+
execute(method: :get, url: url, headers: headers)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
def list_updates(id, update_id, params={})
|
|
400
|
+
url = "#{base_path}/#{id}/available-updates"
|
|
401
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
|
402
|
+
execute(method: :get, url: url, headers: headers)
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def get_update(id, update_id, params={})
|
|
406
|
+
url = "#{base_path}/#{id}/available-updates/#{update_id}"
|
|
407
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
|
408
|
+
execute(method: :get, url: url, headers: headers)
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def execute_update(id, payload)
|
|
412
|
+
url = "#{base_path}/#{id}/execute-update"
|
|
413
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
|
414
|
+
execute(method: :post, url: url, headers: headers, payload: payload.to_json)
|
|
415
|
+
end
|
|
392
416
|
|
|
393
417
|
end
|
|
@@ -9,7 +9,7 @@ class Morpheus::GroupsInterface < Morpheus::APIClient
|
|
|
9
9
|
execute(opts)
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
def get(options=nil)
|
|
12
|
+
def get(options=nil, params={})
|
|
13
13
|
url = "#{@base_url}/api/groups"
|
|
14
14
|
headers = { params: {}, authorization: "Bearer #{@access_token}" }
|
|
15
15
|
|
|
@@ -17,6 +17,7 @@ class Morpheus::GroupsInterface < Morpheus::APIClient
|
|
|
17
17
|
headers[:params].merge!(options)
|
|
18
18
|
elsif options.is_a?(Numeric)
|
|
19
19
|
url = "#{@base_url}/api/groups/#{options}"
|
|
20
|
+
headers[:params] = params
|
|
20
21
|
elsif options.is_a?(String)
|
|
21
22
|
headers[:params]['name'] = options
|
|
22
23
|
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
|
|
@@ -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
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'morpheus/api/rest_interface'
|
|
2
|
+
|
|
3
|
+
class Morpheus::SupportBundlesInterface < Morpheus::RestInterface
|
|
4
|
+
|
|
5
|
+
def base_path
|
|
6
|
+
"/api/support-bundles"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Download uses chunked streaming to write directly to a file.
|
|
10
|
+
# Follows the same pattern as file_copy_request_interface.rb#download_file_chunked.
|
|
11
|
+
def download(id, outfile, params={})
|
|
12
|
+
raise "#{self.class}.download() passed a blank id!" if id.to_s == ''
|
|
13
|
+
url = "#{base_path}/#{CGI::escape(id.to_s)}/download"
|
|
14
|
+
headers = { params: params }
|
|
15
|
+
opts = {method: :get, url: url, headers: headers, parse_json: false}
|
|
16
|
+
if Dir.exist?(outfile)
|
|
17
|
+
raise "outfile is invalid. It is the name of an existing directory: #{outfile}"
|
|
18
|
+
end
|
|
19
|
+
if @dry_run
|
|
20
|
+
return execute(opts)
|
|
21
|
+
end
|
|
22
|
+
http_response = nil
|
|
23
|
+
begin
|
|
24
|
+
File.open(outfile, 'w') {|f|
|
|
25
|
+
block = proc { |response|
|
|
26
|
+
response.read_body do |chunk|
|
|
27
|
+
f.write chunk
|
|
28
|
+
end
|
|
29
|
+
}
|
|
30
|
+
opts[:block_response] = block
|
|
31
|
+
http_response = execute(opts)
|
|
32
|
+
}
|
|
33
|
+
rescue
|
|
34
|
+
if File.exist?(outfile) && File.file?(outfile)
|
|
35
|
+
File.delete(outfile)
|
|
36
|
+
end
|
|
37
|
+
raise
|
|
38
|
+
end
|
|
39
|
+
return http_response
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def cancel(id, payload={}, params={}, headers={})
|
|
43
|
+
execute(method: :post, url: "#{base_path}/#{CGI::escape(id.to_s)}/cancel", params: params, payload: payload, headers: headers)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
@@ -20,4 +20,36 @@ class Morpheus::SystemsInterface < Morpheus::RestInterface
|
|
|
20
20
|
execute(method: :get, url: "#{base_path}/#{CGI::escape(id.to_s)}/validate", params: params, headers: headers)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
+
def list_compute_server_update_definitions(system_id, server_id, params={}, headers={})
|
|
24
|
+
execute(method: :get, url: "#{base_path}/#{CGI::escape(system_id.to_s)}/servers/#{CGI::escape(server_id.to_s)}/update-definitions", params: params, headers: headers)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def apply_compute_server_update_definition(system_id, server_id, update_definition_id, payload={}, params={}, headers={})
|
|
28
|
+
execute(method: :post, url: "#{base_path}/#{CGI::escape(system_id.to_s)}/servers/#{CGI::escape(server_id.to_s)}/update-definitions/#{CGI::escape(update_definition_id.to_s)}", params: params, payload: payload, headers: headers)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def list_storage_server_update_definitions(system_id, server_id, params={}, headers={})
|
|
32
|
+
execute(method: :get, url: "#{base_path}/#{CGI::escape(system_id.to_s)}/storage-servers/#{CGI::escape(server_id.to_s)}/update-definitions", params: params, headers: headers)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def apply_storage_server_update_definition(system_id, server_id, update_definition_id, payload={}, params={}, headers={})
|
|
36
|
+
execute(method: :post, url: "#{base_path}/#{CGI::escape(system_id.to_s)}/storage-servers/#{CGI::escape(server_id.to_s)}/update-definitions/#{CGI::escape(update_definition_id.to_s)}", params: params, payload: payload, headers: headers)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def list_network_server_update_definitions(system_id, server_id, params={}, headers={})
|
|
40
|
+
execute(method: :get, url: "#{base_path}/#{CGI::escape(system_id.to_s)}/network-servers/#{CGI::escape(server_id.to_s)}/update-definitions", params: params, headers: headers)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def apply_network_server_update_definition(system_id, server_id, update_definition_id, payload={}, params={}, headers={})
|
|
44
|
+
execute(method: :post, url: "#{base_path}/#{CGI::escape(system_id.to_s)}/network-servers/#{CGI::escape(server_id.to_s)}/update-definitions/#{CGI::escape(update_definition_id.to_s)}", params: params, payload: payload, headers: headers)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def list_cluster_update_definitions(system_id, cluster_id, params={}, headers={})
|
|
48
|
+
execute(method: :get, url: "#{base_path}/#{CGI::escape(system_id.to_s)}/clusters/#{CGI::escape(cluster_id.to_s)}/update-definitions", params: params, headers: headers)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def apply_cluster_update_definition(system_id, cluster_id, update_definition_id, payload={}, params={}, headers={})
|
|
52
|
+
execute(method: :post, url: "#{base_path}/#{CGI::escape(system_id.to_s)}/clusters/#{CGI::escape(cluster_id.to_s)}/update-definitions/#{CGI::escape(update_definition_id.to_s)}", params: params, payload: payload, headers: headers)
|
|
53
|
+
end
|
|
54
|
+
|
|
23
55
|
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'morpheus/api/api_client'
|
|
2
|
+
|
|
3
|
+
class Morpheus::TokensInterface < Morpheus::APIClient
|
|
4
|
+
|
|
5
|
+
def base_path
|
|
6
|
+
"/api/tokens"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def list(params={}, headers={})
|
|
10
|
+
execute(method: :get, url: "#{base_path}", params: params, headers: headers)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def get(id, params={}, headers={})
|
|
14
|
+
validate_id!(id)
|
|
15
|
+
execute(method: :get, url: "#{base_path}/#{id}", params: params, headers: headers)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def create(payload, params={})
|
|
19
|
+
execute(method: :post, url: "#{base_path}", payload: payload, params: params)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# def update(id, payload, params={})
|
|
23
|
+
# execute(method: :put, url: "#{base_path}/#{id}", params: params, headers: headers)
|
|
24
|
+
# end
|
|
25
|
+
|
|
26
|
+
def destroy(id, params={})
|
|
27
|
+
validate_id!(id)
|
|
28
|
+
execute(method: :delete, url: "#{base_path}/#{id}", params: params)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def destroy_all(params={})
|
|
32
|
+
execute(method: :delete, url: "#{base_path}", params: params)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def available_clients(params={})
|
|
36
|
+
execute(method: :get, url: "#{base_path}/api-clients", params: params)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
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
|
|
@@ -1485,7 +1485,12 @@ module Morpheus
|
|
|
1485
1485
|
# returns Array of subtitles as strings in the format ["Phrase: blah", "Max: 100"]
|
|
1486
1486
|
def parse_list_subtitles(options={})
|
|
1487
1487
|
subtitles = []
|
|
1488
|
-
|
|
1488
|
+
if options[:tenant]
|
|
1489
|
+
subtitles << "Tenant: #{options[:tenant]}".strip
|
|
1490
|
+
end
|
|
1491
|
+
if options[:include_tenants]
|
|
1492
|
+
subtitles << "Include Tenants: true".strip
|
|
1493
|
+
end
|
|
1489
1494
|
[:phrase, :offset, :max, :sort, :direction, :lastUpdated].each do |k|
|
|
1490
1495
|
if options.key?(k)
|
|
1491
1496
|
subtitles << "#{k.to_s}: #{options[k]}"
|
|
@@ -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?
|
|
@@ -541,8 +543,9 @@ EOT
|
|
|
541
543
|
{
|
|
542
544
|
"ID" => 'id',
|
|
543
545
|
"Name" => 'name',
|
|
544
|
-
"Backup Type" => lambda {|it| format_backup_type_tag(it) },
|
|
545
|
-
"Backup
|
|
546
|
+
"Backup Type" => lambda {|it| (it['backupType'] && it['backupType']['name']) ? it['backupType']['name'] : format_backup_type_tag(it) },
|
|
547
|
+
"Backup Provider" => lambda {|it| it['backupProvider']['name'] rescue '' },
|
|
548
|
+
"Storage Provider" => lambda {|it| it['storageProvider']['name'] rescue '' },
|
|
546
549
|
"Location Type" => lambda {|it|
|
|
547
550
|
if it['locationType'] == "instance"
|
|
548
551
|
"Instance"
|
|
@@ -610,11 +613,11 @@ EOT
|
|
|
610
613
|
def format_backup_location_tag(backup)
|
|
611
614
|
# check storage provider or backup provider indicating remote storage
|
|
612
615
|
if backup['storageProvider'] && backup['storageProvider']['id']
|
|
613
|
-
|
|
614
|
-
"#{green}REMOTE#{reset} (#{
|
|
616
|
+
provider_label = backup['storageProvider']['type'] || backup['storageProvider']['providerType'] || backup['storageProvider']['name'] || ''
|
|
617
|
+
"#{green}REMOTE#{reset} (#{provider_label})"
|
|
615
618
|
elsif backup['backupProvider'] && backup['backupProvider']['id']
|
|
616
|
-
|
|
617
|
-
"#{green}REMOTE#{reset} (#{
|
|
619
|
+
provider_label = backup['backupProvider']['type'] || backup['backupProvider']['providerType'] || backup['backupProvider']['name'] || ''
|
|
620
|
+
"#{green}REMOTE#{reset} (#{provider_label})"
|
|
618
621
|
else
|
|
619
622
|
"#{blue}LOCAL#{reset}"
|
|
620
623
|
end
|
|
@@ -30,41 +30,29 @@ class Morpheus::Cli::ClientsCommand
|
|
|
30
30
|
end
|
|
31
31
|
optparse.parse!(args)
|
|
32
32
|
connect(options)
|
|
33
|
-
|
|
33
|
+
# verify_args!(args:args, optparse:optparse, count:0)
|
|
34
|
+
if args.count > 0
|
|
35
|
+
options[:phrase] = args.join(" ")
|
|
36
|
+
end
|
|
34
37
|
params.merge!(parse_list_options(options))
|
|
35
38
|
@clients_interface.setopts(options)
|
|
36
39
|
if options[:dry_run]
|
|
37
40
|
print_dry_run @clients_interface.dry.list(params)
|
|
38
41
|
return 0
|
|
39
42
|
end
|
|
40
|
-
|
|
41
43
|
json_response = @clients_interface.list(params)
|
|
42
44
|
render_response(json_response, options, "clients") do
|
|
43
|
-
clients = json_response[
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
row = {
|
|
49
|
-
id: client['id'],
|
|
50
|
-
client_id: client['clientId'],
|
|
51
|
-
access_token_seconds: client['accessTokenValiditySeconds'],
|
|
52
|
-
refresh_token_seconds: client['refreshTokenValiditySeconds']
|
|
53
|
-
}
|
|
54
|
-
row
|
|
55
|
-
}
|
|
56
|
-
columns = [:id, {:client_id => {:max_width => 50}}, :access_token_seconds, :refresh_token_seconds]
|
|
57
|
-
print_h1 "Morpheus Clients", [], options
|
|
58
|
-
print as_pretty_table(rows, columns, options)
|
|
59
|
-
print reset
|
|
60
|
-
print_results_pagination(json_response)
|
|
61
|
-
end
|
|
45
|
+
clients = json_response['clients']
|
|
46
|
+
print_h1 "Morpheus Clients", [], options
|
|
47
|
+
print as_pretty_table(clients, client_columns.upcase_keys!, options)
|
|
48
|
+
print reset
|
|
49
|
+
print_results_pagination(json_response)
|
|
62
50
|
print reset,"\n"
|
|
63
51
|
end
|
|
64
|
-
return 0, nil
|
|
65
52
|
end
|
|
66
53
|
|
|
67
54
|
def get(args)
|
|
55
|
+
params = {}
|
|
68
56
|
options = {}
|
|
69
57
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
70
58
|
opts.banner = subcommand_usage("[client]")
|
|
@@ -74,47 +62,28 @@ class Morpheus::Cli::ClientsCommand
|
|
|
74
62
|
|
|
75
63
|
end
|
|
76
64
|
optparse.parse!(args)
|
|
77
|
-
|
|
78
|
-
puts optparse
|
|
79
|
-
exit 1
|
|
80
|
-
end
|
|
65
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
|
81
66
|
connect(options)
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
if args[0].to_s =~ /\A\d{1,}\Z/
|
|
86
|
-
print_dry_run @clients_interface.dry.get(args[0])
|
|
87
|
-
else
|
|
88
|
-
print_dry_run @clients_interface.dry.list({name: args[0].to_s})
|
|
89
|
-
end
|
|
90
|
-
return 0
|
|
91
|
-
end
|
|
92
|
-
client = find_client_by_name_or_id(args[0])
|
|
67
|
+
id = args[0]
|
|
68
|
+
if id.to_s !~ /\A\d{1,}\Z/
|
|
69
|
+
client = find_client_by_client_id(id)
|
|
93
70
|
return 1 if client.nil?
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
print_description_list(client_columns, client)
|
|
110
|
-
print reset,"\n"
|
|
111
|
-
|
|
112
|
-
end
|
|
71
|
+
id = client['id']
|
|
72
|
+
else
|
|
73
|
+
id = id.to_i
|
|
74
|
+
end
|
|
75
|
+
@clients_interface.setopts(options)
|
|
76
|
+
if options[:dry_run]
|
|
77
|
+
print_dry_run @clients_interface.dry.get(id, params)
|
|
78
|
+
return
|
|
79
|
+
end
|
|
80
|
+
json_response = @clients_interface.get(id, params)
|
|
81
|
+
render_response(json_response, options, 'client') do
|
|
82
|
+
client = json_response['client']
|
|
83
|
+
print_h1 "Client Details", [], options
|
|
84
|
+
print cyan
|
|
85
|
+
print_description_list(client_columns, client)
|
|
113
86
|
print reset,"\n"
|
|
114
|
-
return 0
|
|
115
|
-
rescue RestClient::Exception => e
|
|
116
|
-
print_rest_exception(e, options)
|
|
117
|
-
exit 1
|
|
118
87
|
end
|
|
119
88
|
end
|
|
120
89
|
|
|
@@ -151,6 +120,7 @@ class Morpheus::Cli::ClientsCommand
|
|
|
151
120
|
payload.deep_merge!({'client' => passed_options}) unless passed_options.empty?
|
|
152
121
|
# prompt for options
|
|
153
122
|
params = Morpheus::Cli::OptionTypes.prompt(add_client_option_types, options[:options], @api_client, options[:params])
|
|
123
|
+
params.booleanize!
|
|
154
124
|
if params['redirectUris'] && params['redirectUris'].is_a?(String)
|
|
155
125
|
params['redirectUris'] = params['redirectUris'].split(',').collect {|it| it.strip}.reject {|it| it.empty?}
|
|
156
126
|
end
|
|
@@ -182,7 +152,7 @@ class Morpheus::Cli::ClientsCommand
|
|
|
182
152
|
options = {}
|
|
183
153
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
184
154
|
opts.banner = subcommand_usage("[clientId] [options]")
|
|
185
|
-
build_option_type_options(opts, options,
|
|
155
|
+
build_option_type_options(opts, options, update_client_option_types)
|
|
186
156
|
build_standard_update_options(opts, options)
|
|
187
157
|
opts.footer = "Update Oauth Client Record."
|
|
188
158
|
end
|
|
@@ -212,8 +182,9 @@ class Morpheus::Cli::ClientsCommand
|
|
|
212
182
|
# allow arbitrary -O options
|
|
213
183
|
payload.deep_merge!({'client' => passed_options}) unless passed_options.empty?
|
|
214
184
|
# prompt for options
|
|
215
|
-
#params = Morpheus::Cli::OptionTypes.
|
|
185
|
+
#params = Morpheus::Cli::OptionTypes.no_prompt(update_client_option_types, options[:options], @api_client, options[:params])
|
|
216
186
|
params = passed_options
|
|
187
|
+
params.booleanize!
|
|
217
188
|
if params['redirectUris'] && params['redirectUris'].is_a?(String)
|
|
218
189
|
params['redirectUris'] = params['redirectUris'].split(',').collect {|it| it.strip}.reject {|it| it.empty?}
|
|
219
190
|
end
|
|
@@ -325,21 +296,36 @@ class Morpheus::Cli::ClientsCommand
|
|
|
325
296
|
end
|
|
326
297
|
end
|
|
327
298
|
|
|
328
|
-
def
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
299
|
+
def client_columns
|
|
300
|
+
{
|
|
301
|
+
"ID" => lambda {|it| it['id'] },
|
|
302
|
+
"Client ID" => lambda {|it| it['clientId'] },
|
|
303
|
+
"TTL" => lambda {|it| it['accessTokenValiditySeconds'] },
|
|
304
|
+
"Refresh TTL" => lambda {|it| it['refreshTokenValiditySeconds'] },
|
|
305
|
+
"Redirect URI" => lambda {|client| client['redirectUris'].join(", ")},
|
|
306
|
+
"Requires Consent" => lambda {|it| format_boolean it['requireConsent']}
|
|
307
|
+
}
|
|
334
308
|
end
|
|
335
309
|
|
|
336
|
-
|
|
310
|
+
|
|
311
|
+
def add_client_option_types
|
|
337
312
|
[
|
|
338
|
-
{'fieldName' => 'clientId', 'fieldLabel' => 'Client Id', 'type' => 'text', 'required' => true
|
|
339
|
-
{'fieldName' => 'clientSecret', 'fieldLabel' => 'Client Secret', 'type' => 'text'
|
|
340
|
-
{'fieldName' => 'accessTokenValiditySeconds', 'fieldLabel' => '
|
|
341
|
-
{'fieldName' => 'refreshTokenValiditySeconds', 'fieldLabel' => 'Refresh
|
|
342
|
-
{'fieldName' => 'redirectUris', 'fieldLabel' => 'Redirect URI', 'type' => 'text', '
|
|
313
|
+
{'fieldName' => 'clientId', 'fieldLabel' => 'Client Id', 'type' => 'text', 'required' => true},
|
|
314
|
+
{'fieldName' => 'clientSecret', 'fieldLabel' => 'Client Secret', 'type' => 'text'},
|
|
315
|
+
{'switch' => 'ttl', 'fieldName' => 'accessTokenValiditySeconds', 'fieldLabel' => 'TTL (Seconds)', 'type' => 'number', 'required' => true,'defaultValue' => 43200, 'description' => 'Access Token Validity Seconds'},
|
|
316
|
+
{'switch' => 'refresh-ttl', 'fieldName' => 'refreshTokenValiditySeconds', 'fieldLabel' => 'Refresh TTL (Seconds)', 'type' => 'number', 'required' => true,'defaultValue' => 43200, 'description' => 'Refresh Token Validity Seconds'},
|
|
317
|
+
{'fieldName' => 'redirectUris', 'fieldLabel' => 'Redirect URI', 'type' => 'text', 'description' => 'Redirect URI(s), use commas to delimit values.'},
|
|
318
|
+
{'fieldName' => 'requireConsent', 'fieldLabel' => 'Requires Consent', 'type' => 'checkbox', 'defaultValue' => false}
|
|
343
319
|
]
|
|
344
320
|
end
|
|
321
|
+
|
|
322
|
+
def update_client_option_types
|
|
323
|
+
option_types = add_client_option_types #.select {|it| ['clientId', 'clientSecret', 'accessTokenValiditySeconds'].include?(it['fieldName']) }
|
|
324
|
+
option_types.each {|it|
|
|
325
|
+
it.delete('required')
|
|
326
|
+
it.delete('defaultValue')
|
|
327
|
+
it.delete('skipSingleOption')
|
|
328
|
+
}
|
|
329
|
+
option_types
|
|
330
|
+
end
|
|
345
331
|
end
|
|
@@ -2,6 +2,7 @@ require 'morpheus/cli/cli_command'
|
|
|
2
2
|
|
|
3
3
|
class Morpheus::Cli::Clouds
|
|
4
4
|
include Morpheus::Cli::CliCommand
|
|
5
|
+
include Morpheus::Cli::AccountsHelper
|
|
5
6
|
include Morpheus::Cli::InfrastructureHelper
|
|
6
7
|
include Morpheus::Cli::ProvisioningHelper
|
|
7
8
|
include Morpheus::Cli::WhoamiHelper
|
|
@@ -25,6 +26,8 @@ class Morpheus::Cli::Clouds
|
|
|
25
26
|
@api_client = establish_remote_appliance_connection(opts)
|
|
26
27
|
@clouds_interface = @api_client.clouds
|
|
27
28
|
@groups_interface = @api_client.groups
|
|
29
|
+
@accounts_interface = @api_client.accounts
|
|
30
|
+
@account_users_interface = @api_client.account_users
|
|
28
31
|
@active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
|
|
29
32
|
end
|
|
30
33
|
|
|
@@ -49,6 +52,13 @@ class Morpheus::Cli::Clouds
|
|
|
49
52
|
opts.on('--all-labels LABEL', String, "Filter by labels, must match all of the values") do |val|
|
|
50
53
|
add_query_parameter(params, 'allLabels', parse_labels(val))
|
|
51
54
|
end
|
|
55
|
+
opts.on('--include-tenants','--include-tenants', "Include sub tenant clouds") do
|
|
56
|
+
options[:include_tenants] = true
|
|
57
|
+
params['includeTenants'] = true
|
|
58
|
+
end
|
|
59
|
+
opts.on('--tenant TENANT', String, "Tenant Name or ID" ) do |val|
|
|
60
|
+
options[:tenant] = val
|
|
61
|
+
end
|
|
52
62
|
build_standard_list_options(opts, options)
|
|
53
63
|
opts.footer = "List clouds."
|
|
54
64
|
end
|
|
@@ -69,7 +79,18 @@ class Morpheus::Cli::Clouds
|
|
|
69
79
|
params['groupId'] = group['id']
|
|
70
80
|
end
|
|
71
81
|
end
|
|
72
|
-
|
|
82
|
+
if options[:tenant]
|
|
83
|
+
if options[:tenant].to_s !~ /\A\d{1,}\Z/
|
|
84
|
+
account = find_account_by_name_or_id(options[:tenant])
|
|
85
|
+
if account.nil?
|
|
86
|
+
return 1, "Tenant not found by name: #{options[:tenant]}"
|
|
87
|
+
else
|
|
88
|
+
params['tenantId'] = account['id']
|
|
89
|
+
end
|
|
90
|
+
else
|
|
91
|
+
params['tenantId'] = options[:tenant]
|
|
92
|
+
end
|
|
93
|
+
end
|
|
73
94
|
params.merge!(parse_list_options(options))
|
|
74
95
|
@clouds_interface.setopts(options)
|
|
75
96
|
if options[:dry_run]
|
|
@@ -94,6 +115,9 @@ class Morpheus::Cli::Clouds
|
|
|
94
115
|
print cyan,"No clouds found.",reset,"\n"
|
|
95
116
|
else
|
|
96
117
|
columns = cloud_list_column_definitions(options).upcase_keys!
|
|
118
|
+
if !options[:include_tenants] && !options[:tenant]
|
|
119
|
+
columns.delete("Tenant")
|
|
120
|
+
end
|
|
97
121
|
print as_pretty_table(clouds, columns, options)
|
|
98
122
|
print_results_pagination(json_response)
|
|
99
123
|
end
|
|
@@ -141,6 +165,9 @@ class Morpheus::Cli::Clouds
|
|
|
141
165
|
params = {}
|
|
142
166
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
143
167
|
opts.banner = subcommand_usage("[name]")
|
|
168
|
+
opts.on('--include-tenants','--include-tenants', "Include sub tenant clouds when finding cloud by name") do
|
|
169
|
+
options[:include_tenants] = true
|
|
170
|
+
end
|
|
144
171
|
build_standard_list_options(opts, options)
|
|
145
172
|
opts.footer = "Get details about a cloud.\n" +
|
|
146
173
|
"[name] is required. This is the name or id of a cloud."
|
|
@@ -158,7 +185,7 @@ class Morpheus::Cli::Clouds
|
|
|
158
185
|
def _get(id, params, options={})
|
|
159
186
|
cloud = nil
|
|
160
187
|
if id.to_s !~ /\A\d{1,}\Z/
|
|
161
|
-
cloud = find_cloud_by_name_or_id(id)
|
|
188
|
+
cloud = find_cloud_by_name_or_id(id, options[:include_tenants])
|
|
162
189
|
id = cloud['id']
|
|
163
190
|
end
|
|
164
191
|
@clouds_interface.setopts(options)
|
|
@@ -1481,6 +1508,7 @@ EOT
|
|
|
1481
1508
|
{
|
|
1482
1509
|
"ID" => 'id',
|
|
1483
1510
|
"Name" => 'name',
|
|
1511
|
+
"Tenant" => lambda {|it| it['owner'] ? it['owner']['name'] : '' },
|
|
1484
1512
|
"Type" => lambda {|it| it['zoneType'] ? it['zoneType']['name'] : '' },
|
|
1485
1513
|
"Labels" => lambda {|it| format_list(it['labels'], '', 3) rescue '' },
|
|
1486
1514
|
"Location" => 'location',
|