morpheus-cli 4.1.8 → 4.1.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +24 -0
- data/lib/morpheus/api/{old_cypher_interface.rb → budgets_interface.rb} +10 -11
- data/lib/morpheus/api/cloud_datastores_interface.rb +7 -0
- data/lib/morpheus/api/cloud_resource_pools_interface.rb +2 -2
- data/lib/morpheus/api/cypher_interface.rb +18 -12
- data/lib/morpheus/api/health_interface.rb +72 -0
- data/lib/morpheus/api/instances_interface.rb +1 -1
- data/lib/morpheus/api/library_instance_types_interface.rb +7 -0
- data/lib/morpheus/api/log_settings_interface.rb +6 -0
- data/lib/morpheus/api/network_security_servers_interface.rb +30 -0
- data/lib/morpheus/api/price_sets_interface.rb +42 -0
- data/lib/morpheus/api/prices_interface.rb +68 -0
- data/lib/morpheus/api/provisioning_settings_interface.rb +29 -0
- data/lib/morpheus/api/servers_interface.rb +1 -1
- data/lib/morpheus/api/service_plans_interface.rb +34 -11
- data/lib/morpheus/api/task_sets_interface.rb +8 -0
- data/lib/morpheus/api/tasks_interface.rb +8 -0
- data/lib/morpheus/cli.rb +6 -3
- data/lib/morpheus/cli/appliance_settings_command.rb +13 -5
- data/lib/morpheus/cli/approvals_command.rb +1 -1
- data/lib/morpheus/cli/apps.rb +88 -28
- data/lib/morpheus/cli/backup_settings_command.rb +1 -1
- data/lib/morpheus/cli/blueprints_command.rb +2 -0
- data/lib/morpheus/cli/budgets_command.rb +672 -0
- data/lib/morpheus/cli/cli_command.rb +13 -2
- data/lib/morpheus/cli/cli_registry.rb +1 -0
- data/lib/morpheus/cli/clusters.rb +40 -274
- data/lib/morpheus/cli/commands/standard/benchmark_command.rb +114 -66
- data/lib/morpheus/cli/commands/standard/coloring_command.rb +12 -0
- data/lib/morpheus/cli/commands/standard/curl_command.rb +31 -6
- data/lib/morpheus/cli/commands/standard/echo_command.rb +8 -3
- data/lib/morpheus/cli/commands/standard/set_prompt_command.rb +1 -1
- data/lib/morpheus/cli/containers_command.rb +37 -24
- data/lib/morpheus/cli/cypher_command.rb +191 -150
- data/lib/morpheus/cli/health_command.rb +903 -0
- data/lib/morpheus/cli/hosts.rb +43 -32
- data/lib/morpheus/cli/instances.rb +119 -68
- data/lib/morpheus/cli/jobs_command.rb +1 -1
- data/lib/morpheus/cli/library_instance_types_command.rb +61 -11
- data/lib/morpheus/cli/library_option_types_command.rb +2 -2
- data/lib/morpheus/cli/log_settings_command.rb +46 -3
- data/lib/morpheus/cli/logs_command.rb +24 -17
- data/lib/morpheus/cli/mixins/accounts_helper.rb +2 -0
- data/lib/morpheus/cli/mixins/logs_helper.rb +73 -19
- data/lib/morpheus/cli/mixins/print_helper.rb +29 -1
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +554 -96
- data/lib/morpheus/cli/mixins/whoami_helper.rb +13 -1
- data/lib/morpheus/cli/networks_command.rb +3 -0
- data/lib/morpheus/cli/option_types.rb +83 -53
- data/lib/morpheus/cli/price_sets_command.rb +543 -0
- data/lib/morpheus/cli/prices_command.rb +669 -0
- data/lib/morpheus/cli/processes_command.rb +0 -2
- data/lib/morpheus/cli/provisioning_settings_command.rb +237 -0
- data/lib/morpheus/cli/remote.rb +9 -4
- data/lib/morpheus/cli/reports_command.rb +10 -4
- data/lib/morpheus/cli/roles.rb +93 -38
- data/lib/morpheus/cli/security_groups.rb +10 -0
- data/lib/morpheus/cli/service_plans_command.rb +736 -0
- data/lib/morpheus/cli/tasks.rb +220 -8
- data/lib/morpheus/cli/tenants_command.rb +3 -16
- data/lib/morpheus/cli/users.rb +2 -25
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/whitelabel_settings_command.rb +18 -18
- data/lib/morpheus/cli/whoami.rb +28 -10
- data/lib/morpheus/cli/workflows.rb +488 -36
- data/lib/morpheus/formatters.rb +22 -0
- data/morpheus-cli.gemspec +1 -0
- metadata +28 -5
- data/lib/morpheus/cli/accounts.rb +0 -335
- data/lib/morpheus/cli/old_cypher_command.rb +0 -412
@@ -69,7 +69,6 @@ class Morpheus::Cli::Processes
|
|
69
69
|
connect(options)
|
70
70
|
begin
|
71
71
|
params.merge!(parse_list_options(options))
|
72
|
-
# params[:query] = params.delete(:phrase) unless params[:phrase].nil?
|
73
72
|
@processes_interface.setopts(options)
|
74
73
|
if options[:dry_run]
|
75
74
|
print_dry_run @processes_interface.dry.list(params)
|
@@ -201,7 +200,6 @@ class Morpheus::Cli::Processes
|
|
201
200
|
begin
|
202
201
|
process_id = args[0]
|
203
202
|
params.merge!(parse_list_options(options))
|
204
|
-
params[:query] = params.delete(:phrase) unless params[:phrase].nil?
|
205
203
|
@processes_interface.setopts(options)
|
206
204
|
if options[:dry_run]
|
207
205
|
print_dry_run @processes_interface.dry.get(process_id, params)
|
@@ -0,0 +1,237 @@
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
2
|
+
|
3
|
+
class Morpheus::Cli::ProvisioningSettingsCommand
|
4
|
+
include Morpheus::Cli::CliCommand
|
5
|
+
include Morpheus::Cli::AccountsHelper
|
6
|
+
include Morpheus::Cli::WhoamiHelper
|
7
|
+
|
8
|
+
set_command_name :'provisioning-settings'
|
9
|
+
|
10
|
+
register_subcommands :get, :update
|
11
|
+
|
12
|
+
set_default_subcommand :get
|
13
|
+
|
14
|
+
def connect(opts)
|
15
|
+
@api_client = establish_remote_appliance_connection(opts)
|
16
|
+
@provisioning_settings_interface = @api_client.provisioning_settings
|
17
|
+
@storage_providers_interface = @api_client.storage_providers
|
18
|
+
@key_pairs_interface = @api_client.key_pairs
|
19
|
+
@blueprints_interface = @api_client.blueprints
|
20
|
+
end
|
21
|
+
|
22
|
+
def handle(args)
|
23
|
+
handle_subcommand(args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def get(args)
|
27
|
+
options = {}
|
28
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
29
|
+
opts.banner = subcommand_usage()
|
30
|
+
build_common_options(opts, options, [:query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
31
|
+
opts.footer = "Get provisioning settings."
|
32
|
+
end
|
33
|
+
optparse.parse!(args)
|
34
|
+
connect(options)
|
35
|
+
if args.count != 0
|
36
|
+
raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args}\n#{optparse}"
|
37
|
+
return 1
|
38
|
+
end
|
39
|
+
|
40
|
+
begin
|
41
|
+
@provisioning_settings_interface.setopts(options)
|
42
|
+
|
43
|
+
if options[:dry_run]
|
44
|
+
print_dry_run @provisioning_settings_interface.dry.get()
|
45
|
+
return
|
46
|
+
end
|
47
|
+
json_response = @provisioning_settings_interface.get()
|
48
|
+
if options[:json]
|
49
|
+
puts as_json(json_response, options, "provisioningSettings")
|
50
|
+
return 0
|
51
|
+
elsif options[:yaml]
|
52
|
+
puts as_yaml(json_response, options, "provisioningSettings")
|
53
|
+
return 0
|
54
|
+
elsif options[:csv]
|
55
|
+
puts records_as_csv([json_response['provisioningSettings']], options)
|
56
|
+
return 0
|
57
|
+
end
|
58
|
+
|
59
|
+
settings = json_response['provisioningSettings']
|
60
|
+
|
61
|
+
print_h1 "Provisioning Settings"
|
62
|
+
print cyan
|
63
|
+
|
64
|
+
description_cols = {
|
65
|
+
"Allow Cloud Selection" => lambda {|it| format_boolean(it['allowZoneSelection'])},
|
66
|
+
"Allow Host Selection" => lambda {|it| format_boolean(it['allowServerSelection'])},
|
67
|
+
"Require Environment Selection" => lambda {|it| format_boolean(it['requireEnvironments'])},
|
68
|
+
"Show Pricing" => lambda {|it| format_boolean(it['showPricing'])},
|
69
|
+
"Hide Datastore Stats On Selection" => lambda {|it| format_boolean(it['hideDatastoreStats'])},
|
70
|
+
"Cross-Tenant Naming Policies" => lambda {|it| format_boolean(it['crossTenantNamingPolicies'])},
|
71
|
+
"Reuse Naming Sequence Numbers" => lambda {|it| format_boolean(it['reuseSequence'])},
|
72
|
+
"Deployment Archive Store" => lambda {|it| it['deployStorageProvider'] ? it['deployStorageProvider']['name'] : nil},
|
73
|
+
# Cloud-Init Settings
|
74
|
+
"Cloud-Init Username" => lambda {|it| it['cloudInitUsername']},
|
75
|
+
"Cloud-Init Password" => lambda {|it| it['cloudInitPassword']},
|
76
|
+
"Cloud-Init Key Pair" => lambda {|it| it['cloudInitKeyPair'] ? it['cloudInitKeyPair']['name'] : nil},
|
77
|
+
# Windows Settings
|
78
|
+
"Windows Adminstrator Password" => lambda {|it| it['windowsPassword']},
|
79
|
+
# PXE Boot Settings
|
80
|
+
"Default Root Password" => lambda {|it| it['pxeRootPassword']},
|
81
|
+
# App Blueprint Settings
|
82
|
+
"Default Blueprint Type" => lambda {|it| it['defaultTemplateType'] ? it['defaultTemplateType']['name'].capitalize : 'Morpheus'}
|
83
|
+
}
|
84
|
+
print_description_list(description_cols, settings)
|
85
|
+
print reset "\n"
|
86
|
+
return 0
|
87
|
+
rescue RestClient::Exception => e
|
88
|
+
print_rest_exception(e, options)
|
89
|
+
return 1
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def update(args)
|
94
|
+
options = {}
|
95
|
+
params = {}
|
96
|
+
|
97
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
98
|
+
opts.banner = opts.banner = subcommand_usage()
|
99
|
+
opts.on("--allow-cloud [on|off]", ['on','off'], "Allow cloud selection. Default is on") do |val|
|
100
|
+
params['allowZoneSelection'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
101
|
+
end
|
102
|
+
opts.on("--allow-host [on|off]", ['on','off'], "Allow host selection. Default is on") do |val|
|
103
|
+
params['allowServerSelection'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
104
|
+
end
|
105
|
+
opts.on("--require-env [on|off]", ['on','off'], "Require environment selection. Default is on") do |val|
|
106
|
+
params['requireEnvironments'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
107
|
+
end
|
108
|
+
opts.on("--show-pricing [on|off]", ['on','off'], "Show pricing. Default is on") do |val|
|
109
|
+
params['showPricing'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
110
|
+
end
|
111
|
+
opts.on("--ds-hide-stats [on|off]", ['on','off'], "Hide datastore stats on selection. Default is on") do |val|
|
112
|
+
params['hideDatastoreStats'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
113
|
+
end
|
114
|
+
opts.on("--x-tenant-naming [on|off]", ['on','off'], "Cross-tenant naming policies. Default is on") do |val|
|
115
|
+
params['crossTenantNamingPolicies'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
116
|
+
end
|
117
|
+
opts.on("--reuse-name-seq [on|off]", ['on','off'], "Reuse naming sequence numbers. Default is on") do |val|
|
118
|
+
params['reuseSequence'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
119
|
+
end
|
120
|
+
opts.on("--deploy-bucket BUCKET", String, "Deployment archive storage provider ID or name") do |val|
|
121
|
+
if val == 'null'
|
122
|
+
params['deployStorageProvider'] = nil
|
123
|
+
else
|
124
|
+
options[:deployBucket] = val
|
125
|
+
end
|
126
|
+
end
|
127
|
+
opts.on("--cloud-username STRING", String, "Cloud-init username") do |val|
|
128
|
+
params['cloudInitUsername'] = val == 'null' ? nil : val
|
129
|
+
end
|
130
|
+
opts.on("--cloud-pwd STRING", String, "Cloud-init password") do |val|
|
131
|
+
params['cloudInitPassword'] = val == 'null' ? nil : val
|
132
|
+
end
|
133
|
+
opts.on("--cloud-keypair KEYPAIR", String, "Cloud-init key pair ID or name") do |val|
|
134
|
+
if val == 'null'
|
135
|
+
params['cloudInitKeyPair'] = nil
|
136
|
+
else
|
137
|
+
options[:cloudKeyPair] = val
|
138
|
+
end
|
139
|
+
end
|
140
|
+
opts.on("--windows-pwd STRING", String, "Windows administrator password") do |val|
|
141
|
+
params['windowsPassword'] = val == 'null' ? nil : val
|
142
|
+
end
|
143
|
+
opts.on("--pxe-pwd STRING", String, "PXE Boot default root password") do |val|
|
144
|
+
params['pxeRootPassword'] = val == 'null' ? nil : val
|
145
|
+
end
|
146
|
+
opts.on("--blueprint-type TYPE", String, "Default blueprint type ID, name or code") do |val|
|
147
|
+
if val == 'null'
|
148
|
+
params['defaultTemplateType'] = nil
|
149
|
+
else
|
150
|
+
options[:blueprintType] = val
|
151
|
+
end
|
152
|
+
end
|
153
|
+
build_common_options(opts, options, [:json, :payload, :dry_run, :quiet, :remote])
|
154
|
+
end
|
155
|
+
|
156
|
+
optparse.parse!(args)
|
157
|
+
connect(options)
|
158
|
+
if args.count != 0
|
159
|
+
raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args}\n#{optparse}"
|
160
|
+
return 1
|
161
|
+
end
|
162
|
+
|
163
|
+
begin
|
164
|
+
payload = parse_payload(options)
|
165
|
+
|
166
|
+
if !payload
|
167
|
+
if options[:deployBucket]
|
168
|
+
bucket = find_storage_provider(options[:deployBucket])
|
169
|
+
|
170
|
+
if !bucket
|
171
|
+
print_red_alert "Storage provider #{options[:deployBucket]} not found"
|
172
|
+
exit 1
|
173
|
+
end
|
174
|
+
params['deployStorageProvider'] = {'id' => bucket['id']}
|
175
|
+
end
|
176
|
+
|
177
|
+
if options[:cloudKeyPair]
|
178
|
+
key_pair = find_key_pair(options[:cloudKeyPair])
|
179
|
+
|
180
|
+
if !key_pair
|
181
|
+
print_red_alert "Key pair #{options[:cloudKeyPair]} not found"
|
182
|
+
exit 1
|
183
|
+
end
|
184
|
+
params['cloudInitKeyPair'] = {'id' => key_pair['id']}
|
185
|
+
end
|
186
|
+
|
187
|
+
if options[:blueprintType]
|
188
|
+
template_type = find_template_type(options[:blueprintType])
|
189
|
+
|
190
|
+
if !template_type
|
191
|
+
print_red_alert "Blueprint type #{options[:blueprintType]} not found"
|
192
|
+
end
|
193
|
+
params['defaultTemplateType'] = {'id' => template_type['id']}
|
194
|
+
end
|
195
|
+
payload = {'provisioningSettings' => params}
|
196
|
+
end
|
197
|
+
|
198
|
+
@provisioning_settings_interface.setopts(options)
|
199
|
+
if options[:dry_run]
|
200
|
+
print_dry_run @provisioning_settings_interface.dry.update(payload)
|
201
|
+
return
|
202
|
+
end
|
203
|
+
json_response = @provisioning_settings_interface.update(payload)
|
204
|
+
|
205
|
+
if options[:json]
|
206
|
+
puts as_json(json_response, options)
|
207
|
+
elsif !options[:quiet]
|
208
|
+
if json_response['success']
|
209
|
+
print_green_success "Updated provisioning settings"
|
210
|
+
get([] + (options[:remote] ? ["-r",options[:remote]] : []))
|
211
|
+
else
|
212
|
+
print_red_alert "Error updating provisioning settings: #{json_response['msg'] || json_response['errors']}"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
return 0
|
216
|
+
|
217
|
+
rescue RestClient::Exception => e
|
218
|
+
print_rest_exception(e, options)
|
219
|
+
exit 1
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
|
225
|
+
def find_storage_provider(val)
|
226
|
+
(val.to_s =~ /\A\d{1,}\Z/) ? @storage_providers_interface.get(val.to_i)['storageBucket'] : @storage_providers_interface.list({'name' => val})["storageBuckets"].first
|
227
|
+
end
|
228
|
+
|
229
|
+
def find_key_pair(val)
|
230
|
+
(val.to_s =~ /\A\d{1,}\Z/) ? @key_pairs_interface.get(current_account['id'], val.to_i)['keyPair'] : @key_pairs_interface.list(current_account['id'], {'name' => val})["keyPairs"].first
|
231
|
+
end
|
232
|
+
|
233
|
+
def find_template_type(val)
|
234
|
+
template_types = @provisioning_settings_interface.template_types['templateTypes']
|
235
|
+
(val.to_s =~ /\A\d{1,}\Z/) ? template_types.find {|it| it['id'] == val.to_i} : template_types.find {|it| it['name'].casecmp(val) == 0 || it['code'].casecmp(val) == 0}
|
236
|
+
end
|
237
|
+
end
|
data/lib/morpheus/cli/remote.rb
CHANGED
@@ -133,7 +133,7 @@ EOT
|
|
133
133
|
opts.on(nil, "--insecure", "Allow insecure HTTPS communication. i.e. Ignore SSL errors.") do
|
134
134
|
secure = false
|
135
135
|
end
|
136
|
-
build_common_options(opts, options, [:quiet])
|
136
|
+
build_common_options(opts, options, [:options, :quiet])
|
137
137
|
opts.footer = <<-EOT
|
138
138
|
This will add a new remote appliance to your morpheus client configuration.
|
139
139
|
If this is your first remote, --use is automatically applied so
|
@@ -233,7 +233,7 @@ EOT
|
|
233
233
|
# hit check api and store version and other info
|
234
234
|
if !options[:quiet]
|
235
235
|
print cyan
|
236
|
-
puts "Inspecting remote appliance
|
236
|
+
puts "Inspecting remote appliance #{appliance[:host]} ..."
|
237
237
|
end
|
238
238
|
appliance, check_json_response = ::Morpheus::Cli::Remote.refresh_remote(new_appliance_name.to_sym)
|
239
239
|
if !options[:quiet]
|
@@ -260,6 +260,11 @@ EOT
|
|
260
260
|
return exit_code, err
|
261
261
|
end
|
262
262
|
|
263
|
+
# just skip setup/login stuff is no prompt -N is used.
|
264
|
+
if options[:no_prompt]
|
265
|
+
return exit_code, err
|
266
|
+
end
|
267
|
+
|
263
268
|
# check_cmd_result = check_appliance([new_appliance_name, "--quiet"])
|
264
269
|
# check_cmd_result = check_appliance([new_appliance_name])
|
265
270
|
|
@@ -1299,9 +1304,9 @@ EOT
|
|
1299
1304
|
elsif status_str == "ready"
|
1300
1305
|
out << "#{green}#{status_str.upcase}#{return_color}"
|
1301
1306
|
elsif status_str == "http-error"
|
1302
|
-
out << "#{red}#{
|
1307
|
+
out << "#{red}HTTP ERROR#{return_color}"
|
1303
1308
|
elsif ['error', 'net-error', 'ssl-error', 'http-timeout', 'unreachable', 'unrecognized'].include?(status_str)
|
1304
|
-
out << "#{red}#{status_str.upcase}#{return_color}"
|
1309
|
+
out << "#{red}#{status_str.gsub('-', ' ').upcase}#{return_color}"
|
1305
1310
|
else
|
1306
1311
|
# dunno
|
1307
1312
|
out << "#{yellow}#{status_str.upcase}#{return_color}"
|
@@ -17,6 +17,10 @@ class Morpheus::Cli::ReportsCommand
|
|
17
17
|
|
18
18
|
register_subcommands :list, :get, :run, :view, :export, :remove, :types
|
19
19
|
|
20
|
+
def default_refresh_interval
|
21
|
+
5
|
22
|
+
end
|
23
|
+
|
20
24
|
def handle(args)
|
21
25
|
handle_subcommand(args)
|
22
26
|
end
|
@@ -29,14 +33,13 @@ class Morpheus::Cli::ReportsCommand
|
|
29
33
|
opts.on( '--type CODE', String, "Report Type code(s)" ) do |val|
|
30
34
|
params['reportType'] = val.to_s.split(",").compact.collect {|it| it.strip }
|
31
35
|
end
|
32
|
-
build_common_options(opts, options, [:list, :json, :dry_run, :remote])
|
36
|
+
build_common_options(opts, options, [:list, :query, :json, :dry_run, :remote])
|
33
37
|
opts.footer = "List report history."
|
34
38
|
end
|
35
39
|
optparse.parse!(args)
|
36
40
|
connect(options)
|
37
41
|
begin
|
38
42
|
params.merge!(parse_list_options(options))
|
39
|
-
|
40
43
|
@reports_interface.setopts(options)
|
41
44
|
if options[:dry_run]
|
42
45
|
print_dry_run @reports_interface.dry.list(params)
|
@@ -268,6 +271,10 @@ class Morpheus::Cli::ReportsCommand
|
|
268
271
|
|
269
272
|
# Report Types tell us what the available filters are...
|
270
273
|
report_option_types = report_type['optionTypes'] || []
|
274
|
+
report_option_types = report_option_types.collect {|it|
|
275
|
+
it['fieldContext'] = nil
|
276
|
+
it
|
277
|
+
}
|
271
278
|
# pluck out optionTypes like the UI does..
|
272
279
|
metadata_option_type = nil
|
273
280
|
if report_option_types.find {|it| it['fieldName'] == 'metadata' }
|
@@ -275,6 +282,7 @@ class Morpheus::Cli::ReportsCommand
|
|
275
282
|
end
|
276
283
|
|
277
284
|
v_prompt = Morpheus::Cli::OptionTypes.prompt(report_option_types, options[:options], @api_client)
|
285
|
+
payload.deep_merge!({'report' => v_prompt}) unless v_prompt.empty?
|
278
286
|
|
279
287
|
if metadata_option_type
|
280
288
|
if !options[:options]['metadata']
|
@@ -285,8 +293,6 @@ class Morpheus::Cli::ReportsCommand
|
|
285
293
|
end
|
286
294
|
end
|
287
295
|
|
288
|
-
# payload.deep_merge!({'report' => v_prompt}) unless v_prompt.empty?
|
289
|
-
payload.deep_merge!(v_prompt) unless v_prompt.empty?
|
290
296
|
end
|
291
297
|
|
292
298
|
@reports_interface.setopts(options)
|
data/lib/morpheus/cli/roles.rb
CHANGED
@@ -27,7 +27,7 @@ class Morpheus::Cli::Roles
|
|
27
27
|
@instances_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instances
|
28
28
|
@instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
|
29
29
|
@blueprints_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).blueprints
|
30
|
-
@active_group_id = Morpheus::Cli::Groups.
|
30
|
+
@active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
|
31
31
|
end
|
32
32
|
|
33
33
|
def handle(args)
|
@@ -88,6 +88,7 @@ class Morpheus::Cli::Roles
|
|
88
88
|
|
89
89
|
def get(args)
|
90
90
|
options = {}
|
91
|
+
params = {}
|
91
92
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
92
93
|
opts.banner = subcommand_usage("[name]")
|
93
94
|
opts.on('-p','--permissions', "Display Permissions") do |val|
|
@@ -116,7 +117,7 @@ class Morpheus::Cli::Roles
|
|
116
117
|
options[:include_instance_type_access] = true
|
117
118
|
options[:include_blueprint_access] = true
|
118
119
|
end
|
119
|
-
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
120
|
+
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
120
121
|
opts.footer = "Get details about a role.\n" +
|
121
122
|
"[name] is required. This is the name or id of a role."
|
122
123
|
end
|
@@ -131,6 +132,9 @@ class Morpheus::Cli::Roles
|
|
131
132
|
begin
|
132
133
|
account = find_account_from_options(options)
|
133
134
|
account_id = account ? account['id'] : nil
|
135
|
+
|
136
|
+
params.merge!(parse_query_options(options))
|
137
|
+
|
134
138
|
@roles_interface.setopts(options)
|
135
139
|
if options[:dry_run]
|
136
140
|
if args[0].to_s =~ /\A\d{1,}\Z/
|
@@ -159,16 +163,8 @@ class Morpheus::Cli::Roles
|
|
159
163
|
role = json_response['role']
|
160
164
|
end
|
161
165
|
|
162
|
-
|
163
|
-
|
164
|
-
return 0
|
165
|
-
elsif options[:yaml]
|
166
|
-
puts as_yaml(json_response, options, "role")
|
167
|
-
return 0
|
168
|
-
elsif options[:csv]
|
169
|
-
puts records_as_csv([json_response['role']], options)
|
170
|
-
return 0
|
171
|
-
end
|
166
|
+
render_result = render_with_format(json_response, options, 'role')
|
167
|
+
return 0 if render_result
|
172
168
|
|
173
169
|
print cyan
|
174
170
|
print_h1 "Role Details", options
|
@@ -179,7 +175,9 @@ class Morpheus::Cli::Roles
|
|
179
175
|
"Description" => 'description',
|
180
176
|
"Scope" => lambda {|it| it['scope'] },
|
181
177
|
"Type" => lambda {|it| format_role_type(it) },
|
182
|
-
"Multitenant" => lambda {|it|
|
178
|
+
"Multitenant" => lambda {|it|
|
179
|
+
format_boolean(it['multitenant']).to_s + (it['multitenantLocked'] ? " (LOCKED)" : "")
|
180
|
+
},
|
183
181
|
"Owner" => lambda {|it| role['owner'] ? role['owner']['name'] : '' },
|
184
182
|
#"Account" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
185
183
|
"Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
@@ -205,15 +203,40 @@ class Morpheus::Cli::Roles
|
|
205
203
|
access: get_access_string(it['access']),
|
206
204
|
}
|
207
205
|
end
|
206
|
+
if options[:sort]
|
207
|
+
rows.sort! {|a,b| a[options[:sort]] <=> b[options[:sort]] }
|
208
|
+
end
|
209
|
+
if options[:direction] == 'desc'
|
210
|
+
rows.reverse!
|
211
|
+
end
|
212
|
+
if options[:phrase]
|
213
|
+
phrase_regexp = /#{Regexp.escape(options[:phrase])}/i
|
214
|
+
rows = rows.select {|row| row[:code].to_s =~ phrase_regexp || row[:name].to_s =~ phrase_regexp }
|
215
|
+
end
|
208
216
|
print as_pretty_table(rows, [:code, :name, :access], options)
|
209
217
|
else
|
210
|
-
|
211
|
-
end
|
212
|
-
|
213
|
-
print_h2 "
|
218
|
+
print cyan,"Use --permissions to list permissions","\n"
|
219
|
+
end
|
220
|
+
|
221
|
+
print_h2 "Global Access", options
|
222
|
+
# role_access_rows = [
|
223
|
+
# {name: "Groups", access: get_access_string(json_response['globalSiteAccess']) },
|
224
|
+
# {name: "Clouds", access: get_access_string(json_response['globalZoneAccess']) },
|
225
|
+
# {name: "Instance Types", access: get_access_string(json_response['globalInstanceTypeAccess']) },
|
226
|
+
# {name: "Blueprints", access: get_access_string(json_response['globalAppTemplateAccess'] || json_response['globalBlueprintAccess']) }
|
227
|
+
# ]
|
228
|
+
# puts as_pretty_table(role_access_rows, [:name, :access], options)
|
229
|
+
puts as_pretty_table([json_response], [
|
230
|
+
{"Groups" => lambda {|it| get_access_string(it['globalSiteAccess']) } },
|
231
|
+
{"Clouds" => lambda {|it| get_access_string(it['globalZoneAccess']) } },
|
232
|
+
{"Instance Types" => lambda {|it| get_access_string(it['globalInstanceTypeAccess']) } },
|
233
|
+
{"Blueprints" => lambda {|it| get_access_string(it['globalAppTemplateAccess'] || it['globalBlueprintAccess']) } },
|
234
|
+
], options)
|
235
|
+
|
236
|
+
#print_h2 "Group Access: #{get_access_string(json_response['globalSiteAccess'])}", options
|
214
237
|
print cyan
|
215
|
-
puts "Global Group Access: #{get_access_string(json_response['globalSiteAccess'])}\n\n"
|
216
238
|
if json_response['globalSiteAccess'] == 'custom'
|
239
|
+
print_h2 "Group Access", options
|
217
240
|
if options[:include_group_access]
|
218
241
|
rows = json_response['sites'].collect do |it|
|
219
242
|
{
|
@@ -223,14 +246,18 @@ class Morpheus::Cli::Roles
|
|
223
246
|
end
|
224
247
|
print as_pretty_table(rows, [:name, :access], options)
|
225
248
|
else
|
226
|
-
|
249
|
+
print cyan,"Use -g, --group-access to list custom access","\n"
|
227
250
|
end
|
251
|
+
else
|
252
|
+
# print "\n"
|
253
|
+
# print cyan,bold,"Group Access: #{get_access_string(json_response['globalSiteAccess'])}",reset,"\n"
|
228
254
|
end
|
229
|
-
|
230
|
-
print_h2 "Cloud Access", options
|
255
|
+
|
231
256
|
print cyan
|
232
|
-
puts "
|
257
|
+
#puts "Cloud Access: #{get_access_string(json_response['globalZoneAccess'])}"
|
258
|
+
#print "\n"
|
233
259
|
if json_response['globalZoneAccess'] == 'custom'
|
260
|
+
print_h2 "Cloud Access", options
|
234
261
|
if options[:include_cloud_access]
|
235
262
|
rows = json_response['zones'].collect do |it|
|
236
263
|
{
|
@@ -240,14 +267,18 @@ class Morpheus::Cli::Roles
|
|
240
267
|
end
|
241
268
|
print as_pretty_table(rows, [:name, :access], options)
|
242
269
|
else
|
243
|
-
|
270
|
+
print cyan,"Use -c, --cloud-access to list custom access","\n"
|
244
271
|
end
|
272
|
+
else
|
273
|
+
# print "\n"
|
274
|
+
# print cyan,bold,"Cloud Access: #{get_access_string(json_response['globalZoneAccess'])}",reset,"\n"
|
245
275
|
end
|
246
276
|
|
247
|
-
print_h2 "Instance Type Access", options
|
248
277
|
print cyan
|
249
|
-
puts "
|
278
|
+
# puts "Instance Type Access: #{get_access_string(json_response['globalInstanceTypeAccess'])}"
|
279
|
+
# print "\n"
|
250
280
|
if json_response['globalInstanceTypeAccess'] == 'custom'
|
281
|
+
print_h2 "Instance Type Access", options
|
251
282
|
if options[:include_instance_type_access]
|
252
283
|
rows = json_response['instanceTypePermissions'].collect do |it|
|
253
284
|
{
|
@@ -257,16 +288,20 @@ class Morpheus::Cli::Roles
|
|
257
288
|
end
|
258
289
|
print as_pretty_table(rows, [:name, :access], options)
|
259
290
|
else
|
260
|
-
|
291
|
+
print cyan,"Use -i, --instance-type-access to list custom access","\n"
|
261
292
|
end
|
293
|
+
else
|
294
|
+
# print "\n"
|
295
|
+
# print cyan,bold,"Instance Type Access: #{get_access_string(json_response['globalInstanceTypeAccess'])}",reset,"\n"
|
262
296
|
end
|
263
297
|
|
264
298
|
blueprint_global_access = json_response['globalAppTemplateAccess'] || json_response['globalBlueprintAccess']
|
265
299
|
blueprint_permissions = json_response['appTemplatePermissions'] || json_response['blueprintPermissions'] || []
|
266
|
-
print_h2 "Blueprint Access", options
|
267
300
|
print cyan
|
268
|
-
|
301
|
+
# print_h2 "Blueprint Access: #{get_access_string(json_response['globalAppTemplateAccess'])}", options
|
302
|
+
# print "\n"
|
269
303
|
if blueprint_global_access == 'custom'
|
304
|
+
print_h2 "Blueprint Access", options
|
270
305
|
if options[:include_blueprint_access]
|
271
306
|
rows = blueprint_permissions.collect do |it|
|
272
307
|
{
|
@@ -276,8 +311,11 @@ class Morpheus::Cli::Roles
|
|
276
311
|
end
|
277
312
|
print as_pretty_table(rows, [:name, :access], options)
|
278
313
|
else
|
279
|
-
|
314
|
+
print cyan,"Use -b, --blueprint-access to list custom access","\n"
|
280
315
|
end
|
316
|
+
else
|
317
|
+
# print "\n"
|
318
|
+
# print cyan,bold,"Blueprint Access: #{get_access_string(json_response['globalAppTemplateAccess'])}",reset,"\n"
|
281
319
|
end
|
282
320
|
|
283
321
|
print reset,"\n"
|
@@ -292,7 +330,7 @@ class Morpheus::Cli::Roles
|
|
292
330
|
options = {}
|
293
331
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
294
332
|
opts.banner = subcommand_usage("[role]")
|
295
|
-
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
333
|
+
build_common_options(opts, options, [:list, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
296
334
|
opts.footer = "List the permissions for a role.\n" +
|
297
335
|
"[role] is required. This is the name or id of a role."
|
298
336
|
end
|
@@ -358,9 +396,19 @@ class Morpheus::Cli::Roles
|
|
358
396
|
access: get_access_string(it['access']),
|
359
397
|
}
|
360
398
|
end
|
399
|
+
if options[:sort]
|
400
|
+
rows.sort! {|a,b| a[options[:sort]] <=> b[options[:sort]] }
|
401
|
+
end
|
402
|
+
if options[:direction] == 'desc'
|
403
|
+
rows.reverse!
|
404
|
+
end
|
405
|
+
if options[:phrase]
|
406
|
+
phrase_regexp = /#{Regexp.escape(options[:phrase])}/i
|
407
|
+
rows = rows.select {|row| row[:code].to_s =~ phrase_regexp || row[:name].to_s =~ phrase_regexp }
|
408
|
+
end
|
361
409
|
print as_pretty_table(rows, [:code, :name, :access], options)
|
362
410
|
else
|
363
|
-
puts "No permissions found
|
411
|
+
puts "No permissions found"
|
364
412
|
end
|
365
413
|
|
366
414
|
print reset,"\n"
|
@@ -376,12 +424,17 @@ class Morpheus::Cli::Roles
|
|
376
424
|
options = {}
|
377
425
|
params = {}
|
378
426
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
379
|
-
opts.banner = subcommand_usage("[options]")
|
427
|
+
opts.banner = subcommand_usage("[name] [options]")
|
380
428
|
build_option_type_options(opts, options, add_role_option_types)
|
381
429
|
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
382
430
|
end
|
383
431
|
optparse.parse!(args)
|
384
|
-
|
432
|
+
if args.count > 1
|
433
|
+
raise_command_error "wrong number of arguments, expected 0-1 and got (#{args.count}) #{args}\n#{optparse}"
|
434
|
+
end
|
435
|
+
if args[0]
|
436
|
+
options[:options]['authority'] = args[0]
|
437
|
+
end
|
385
438
|
connect(options)
|
386
439
|
begin
|
387
440
|
|
@@ -425,6 +478,10 @@ class Morpheus::Cli::Roles
|
|
425
478
|
if role_payload['roleType'] == 'user'
|
426
479
|
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'multitenant', 'fieldLabel' => 'Multitenant', 'type' => 'checkbox', 'defaultValue' => 'off', 'description' => 'A Multitenant role is automatically copied into all existing subaccounts as well as placed into a subaccount when created. Useful for providing a set of predefined roles a Customer can use', 'displayOrder' => 5}], options[:options])
|
427
480
|
role_payload['multitenant'] = ['on','true'].include?(v_prompt['multitenant'].to_s)
|
481
|
+
if role_payload['multitenant']
|
482
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'multitenantLocked', 'fieldLabel' => 'Multitenant Locked', 'type' => 'checkbox', 'defaultValue' => 'off', 'description' => 'Prevents subtenants from branching off this role/modifying it. '}], options[:options])
|
483
|
+
role_payload['multitenantLocked'] = ['on','true'].include?(v_prompt['multitenantLocked'].to_s)
|
484
|
+
end
|
428
485
|
end
|
429
486
|
end
|
430
487
|
|
@@ -505,10 +562,10 @@ class Morpheus::Cli::Roles
|
|
505
562
|
params.deep_merge!(passed_options)
|
506
563
|
prompt_option_types = update_role_option_types()
|
507
564
|
if !@is_master_account
|
508
|
-
prompt_option_types = prompt_option_types.reject {|it| ['roleType', 'multitenant'].include?(it['fieldName']) }
|
565
|
+
prompt_option_types = prompt_option_types.reject {|it| ['roleType', 'multitenant','multitenantLocked'].include?(it['fieldName']) }
|
509
566
|
end
|
510
567
|
if role['roleType'] != 'user'
|
511
|
-
prompt_option_types = prompt_option_types.reject {|it| ['multitenant'].include?(it['fieldName']) }
|
568
|
+
prompt_option_types = prompt_option_types.reject {|it| ['multitenant','multitenantLocked'].include?(it['fieldName']) }
|
512
569
|
end
|
513
570
|
#params = Morpheus::Cli::OptionTypes.prompt(prompt_option_types, options[:options], @api_client, options[:params])
|
514
571
|
|
@@ -1265,9 +1322,7 @@ class Morpheus::Cli::Roles
|
|
1265
1322
|
{'fieldName' => 'roleType', 'fieldLabel' => 'Role Type', 'type' => 'select', 'selectOptions' => [{'name' => 'User Role', 'value' => 'user'}, {'name' => 'Account Role', 'value' => 'account'}], 'defaultValue' => 'user', 'displayOrder' => 3},
|
1266
1323
|
{'fieldName' => 'baseRole', 'fieldLabel' => 'Copy From Role', 'type' => 'text', 'displayOrder' => 4},
|
1267
1324
|
{'fieldName' => 'multitenant', 'fieldLabel' => 'Multitenant', 'type' => 'checkbox', 'defaultValue' => 'off', 'description' => 'A Multitenant role is automatically copied into all existing subaccounts as well as placed into a subaccount when created. Useful for providing a set of predefined roles a Customer can use', 'displayOrder' => 5},
|
1268
|
-
|
1269
|
-
# {'fieldName' => 'instanceLimits.maxMemory', 'fieldLabel' => 'Max Memory (bytes)', 'type' => 'text', 'displayOrder' => 9},
|
1270
|
-
# {'fieldName' => 'instanceLimits.maxCpu', 'fieldLabel' => 'CPU Count', 'type' => 'text', 'displayOrder' => 10},
|
1325
|
+
{'fieldName' => 'multitenantLocked', 'fieldLabel' => 'Multitenant Locked', 'type' => 'checkbox', 'defaultValue' => 'off', 'description' => 'Prevents subtenants from branching off this role/modifying it. ', 'displayOrder' => 6}
|
1271
1326
|
]
|
1272
1327
|
end
|
1273
1328
|
|