morpheus-cli 4.1.8 → 4.1.9
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 +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
|
|