morpheus-cli 8.1.2 → 9.0.0
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/groups_interface.rb +2 -1
- data/lib/morpheus/api/servers_interface.rb +0 -1
- 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/cli/cli_command.rb +6 -1
- 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 +5 -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 +1 -1
- 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/systems_test.rb +206 -0
- metadata +10 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1b224b836c51abacb14e3e75c0cc9d88a59b84932c1550f708ffbae41ea08ad3
|
|
4
|
+
data.tar.gz: ee787f62e945490b8537dc9bbbf3a027dadbb7dde1272a57492c92b1111d5f39
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cbe5cf5150058a44b1441ff60de0473af2814390bede4750195bae54973918a828ee5b9a747e4470d1cc084eee45c0d62eff5cad647535a6ccef1d8765335005
|
|
7
|
+
data.tar.gz: 2edbb553a70619a8e8ac47f14aa7f920949add47dd92beaaea0c8cdc1761e7b8aeafcde6e29a2ad0c1b16c31f37728f47d1f941d9af3f189e238233aa3bac59b
|
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
|
|
@@ -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
|
|
@@ -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
|
|
@@ -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]}"
|
|
@@ -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',
|
|
@@ -3064,6 +3064,7 @@ class Morpheus::Cli::Clusters
|
|
|
3064
3064
|
"Active" => lambda { |it| format_boolean(it['active']) },
|
|
3065
3065
|
"Visibility" => lambda { |it| it['visibility'].nil? ? '' : it['visibility'].to_s.capitalize },
|
|
3066
3066
|
"Tenants" => lambda { |it| it['tenants'].nil? ? '' : it['tenants'].collect {|it| it['name']}.join(', ') },
|
|
3067
|
+
"Supports VM Secure Metadata" => lambda { |it| format_boolean(it['supportsVmSecureMetadata']) },
|
|
3067
3068
|
"Cluster" => lambda { |it| cluster['name'] }
|
|
3068
3069
|
}
|
|
3069
3070
|
print_description_list(description_cols, datastore)
|
|
@@ -3233,6 +3234,9 @@ class Morpheus::Cli::Clusters
|
|
|
3233
3234
|
opts.on('--active [on|off]', String, "Enable datastore") do |val|
|
|
3234
3235
|
options[:active] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
|
3235
3236
|
end
|
|
3237
|
+
opts.on('--supports-vm-secure-metadata [on|off]', String, "Enable VM Secure Metadata support") do |val|
|
|
3238
|
+
options[:supportsVmSecureMetadata] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
|
3239
|
+
end
|
|
3236
3240
|
add_perms_options(opts, options, ['plans', 'groupDefaults'])
|
|
3237
3241
|
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
|
3238
3242
|
opts.footer = "Update a cluster datastore.\n" +
|
|
@@ -3264,6 +3268,7 @@ class Morpheus::Cli::Clusters
|
|
|
3264
3268
|
else
|
|
3265
3269
|
payload = {'datastore' => {}}
|
|
3266
3270
|
payload['datastore']['active'] = options[:active].nil? ? (Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'active', 'fieldLabel' => 'Active', 'type' => 'checkbox', 'description' => 'Datastore Active', 'defaultValue' => true}], options[:options], @api_client))['active'] == 'on' : options[:active]
|
|
3271
|
+
payload['datastore']['supportsVmSecureMetadata'] = options[:supportsVmSecureMetadata] unless options[:supportsVmSecureMetadata].nil?
|
|
3267
3272
|
|
|
3268
3273
|
perms = prompt_permissions(options.merge({:available_plans => namespace_service_plans}), datastore['owner']['id'] == current_user['accountId'] ? ['plans', 'groupDefaults'] : ['plans', 'groupDefaults', 'visibility', 'tenants'])
|
|
3269
3274
|
perms_payload = {}
|
|
@@ -83,13 +83,13 @@ class Morpheus::Cli::ExecutionRequestCommand
|
|
|
83
83
|
if options[:refresh_interval].nil? || options[:refresh_interval].to_f < 0
|
|
84
84
|
options[:refresh_interval] = default_refresh_interval
|
|
85
85
|
end
|
|
86
|
-
if
|
|
86
|
+
if is_finished(execution_request)
|
|
87
87
|
# it is finished
|
|
88
88
|
else
|
|
89
89
|
print cyan
|
|
90
90
|
refresh_display_seconds = options[:refresh_interval] % 1.0 == 0 ? options[:refresh_interval].to_i : options[:refresh_interval]
|
|
91
91
|
print "Execution request has not yet finished. Refreshing every #{refresh_display_seconds} seconds"
|
|
92
|
-
while execution_request
|
|
92
|
+
while !is_finished(execution_request) do
|
|
93
93
|
sleep(options[:refresh_interval])
|
|
94
94
|
print cyan,".",reset
|
|
95
95
|
json_response = @execution_request_interface.get(execution_request_id, params)
|
|
@@ -326,4 +326,8 @@ class Morpheus::Cli::ExecutionRequestCommand
|
|
|
326
326
|
out
|
|
327
327
|
end
|
|
328
328
|
|
|
329
|
+
def is_finished(execution_request)
|
|
330
|
+
['executing', 'pending', 'new'].include?(execution_request['status']) ? false : true
|
|
331
|
+
end
|
|
332
|
+
|
|
329
333
|
end
|