morpheus-cli 5.4.0 → 5.4.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/account_users_interface.rb +68 -0
- data/lib/morpheus/api/api_client.rb +55 -10
- data/lib/morpheus/api/audit_interface.rb +9 -0
- data/lib/morpheus/api/catalog_item_types_interface.rb +20 -0
- data/lib/morpheus/api/instances_interface.rb +49 -0
- data/lib/morpheus/api/load_balancer_monitors_interface.rb +9 -0
- data/lib/morpheus/api/load_balancer_pools_interface.rb +4 -4
- data/lib/morpheus/api/load_balancer_profiles_interface.rb +4 -5
- data/lib/morpheus/api/load_balancer_virtual_servers_interface.rb +13 -4
- data/lib/morpheus/api/load_balancers_interface.rb +5 -0
- data/lib/morpheus/api/network_routers_interface.rb +9 -0
- data/lib/morpheus/api/network_static_routes_interface.rb +36 -0
- data/lib/morpheus/api/ping_interface.rb +2 -0
- data/lib/morpheus/api/read_interface.rb +4 -3
- data/lib/morpheus/api/rest_interface.rb +3 -3
- data/lib/morpheus/api/secondary_read_interface.rb +1 -1
- data/lib/morpheus/api/secondary_rest_interface.rb +19 -19
- data/lib/morpheus/api/setup_interface.rb +4 -0
- data/lib/morpheus/api/snapshots_interface.rb +19 -0
- data/lib/morpheus/api/storage_server_types_interface.rb +14 -0
- data/lib/morpheus/api/storage_servers_interface.rb +9 -0
- data/lib/morpheus/api/storage_volume_types_interface.rb +9 -0
- data/lib/morpheus/api/storage_volumes_interface.rb +9 -0
- data/lib/morpheus/api/users_interface.rb +16 -63
- data/lib/morpheus/cli/cli_command.rb +253 -5
- data/lib/morpheus/cli/cli_registry.rb +1 -1
- data/lib/morpheus/cli/commands/alias_command.rb +1 -1
- data/lib/morpheus/cli/commands/apps.rb +14 -78
- data/lib/morpheus/cli/commands/audit.rb +188 -0
- data/lib/morpheus/cli/commands/blueprints_command.rb +1 -1
- data/lib/morpheus/cli/commands/catalog_item_types_command.rb +88 -0
- data/lib/morpheus/cli/commands/change_password_command.rb +4 -4
- data/lib/morpheus/cli/commands/clusters.rb +96 -58
- data/lib/morpheus/cli/commands/hosts.rb +27 -15
- data/lib/morpheus/cli/commands/image_builder_command.rb +4 -8
- data/lib/morpheus/cli/commands/instances.rb +359 -3
- data/lib/morpheus/cli/commands/integrations_command.rb +1 -12
- data/lib/morpheus/cli/commands/library_instance_types_command.rb +3 -0
- data/lib/morpheus/cli/commands/load_balancer_monitors.rb +70 -0
- data/lib/morpheus/cli/commands/load_balancer_pools.rb +29 -50
- data/lib/morpheus/cli/commands/load_balancer_profiles.rb +64 -0
- data/lib/morpheus/cli/commands/load_balancer_types.rb +9 -4
- data/lib/morpheus/cli/commands/load_balancer_virtual_servers.rb +69 -58
- data/lib/morpheus/cli/commands/load_balancers.rb +109 -6
- data/lib/morpheus/cli/commands/network_firewalls_command.rb +22 -5
- data/lib/morpheus/cli/commands/network_routers_command.rb +96 -45
- data/lib/morpheus/cli/commands/network_static_routes_command.rb +451 -0
- data/lib/morpheus/cli/commands/network_transport_zones_command.rb +4 -4
- data/lib/morpheus/cli/commands/networks_command.rb +2 -2
- data/lib/morpheus/cli/commands/open_command.rb +30 -0
- data/lib/morpheus/cli/commands/options.rb +98 -0
- data/lib/morpheus/cli/commands/ping.rb +3 -5
- data/lib/morpheus/cli/commands/policies_command.rb +2 -2
- data/lib/morpheus/cli/commands/prices_command.rb +7 -7
- data/lib/morpheus/cli/commands/provisioning_settings_command.rb +1 -0
- data/lib/morpheus/cli/commands/remote.rb +20 -12
- data/lib/morpheus/cli/commands/roles.rb +1 -1
- data/lib/morpheus/cli/commands/security_groups.rb +2 -2
- data/lib/morpheus/cli/commands/service_plans_command.rb +1 -1
- data/lib/morpheus/cli/commands/setup.rb +1 -1
- data/lib/morpheus/cli/commands/shell.rb +2 -2
- data/lib/morpheus/cli/commands/snapshots.rb +139 -0
- data/lib/morpheus/cli/commands/storage_server_types.rb +50 -0
- data/lib/morpheus/cli/commands/storage_servers.rb +122 -0
- data/lib/morpheus/cli/commands/storage_volume_types.rb +50 -0
- data/lib/morpheus/cli/commands/storage_volumes.rb +103 -0
- data/lib/morpheus/cli/commands/tasks.rb +5 -5
- data/lib/morpheus/cli/commands/tenants_command.rb +1 -1
- data/lib/morpheus/cli/commands/user_groups_command.rb +1 -1
- data/lib/morpheus/cli/commands/user_settings_command.rb +3 -2
- data/lib/morpheus/cli/commands/user_sources_command.rb +1 -1
- data/lib/morpheus/cli/commands/users.rb +28 -28
- data/lib/morpheus/cli/commands/view.rb +102 -0
- data/lib/morpheus/cli/commands/virtual_images.rb +4 -1
- data/lib/morpheus/cli/mixins/accounts_helper.rb +5 -5
- data/lib/morpheus/cli/mixins/load_balancers_helper.rb +24 -4
- data/lib/morpheus/cli/mixins/print_helper.rb +50 -18
- data/lib/morpheus/cli/mixins/processes_helper.rb +1 -2
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +96 -6
- data/lib/morpheus/cli/mixins/rest_command.rb +148 -74
- data/lib/morpheus/cli/mixins/secondary_rest_command.rb +174 -82
- data/lib/morpheus/cli/mixins/storage_servers_helper.rb +156 -0
- data/lib/morpheus/cli/mixins/storage_volumes_helper.rb +119 -0
- data/lib/morpheus/cli/option_types.rb +95 -28
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli.rb +1 -0
- data/lib/morpheus/ext/string.rb +29 -6
- data/lib/morpheus/routes.rb +238 -0
- data/lib/morpheus/util.rb +6 -1
- metadata +26 -2
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
|
2
|
+
|
|
3
|
+
class Morpheus::Cli::Audit
|
|
4
|
+
include Morpheus::Cli::CliCommand
|
|
5
|
+
include Morpheus::Cli::LogsHelper
|
|
6
|
+
include Morpheus::Cli::RestCommand
|
|
7
|
+
include Morpheus::Cli::OptionSourceHelper
|
|
8
|
+
|
|
9
|
+
set_command_description "View audit log records."
|
|
10
|
+
set_command_name :'audit'
|
|
11
|
+
register_subcommands :list, :get
|
|
12
|
+
|
|
13
|
+
# audit is not published yet
|
|
14
|
+
set_command_hidden
|
|
15
|
+
|
|
16
|
+
# RestCommand settings
|
|
17
|
+
|
|
18
|
+
# interfaces
|
|
19
|
+
register_interfaces :audit
|
|
20
|
+
set_rest_interface_name :audit
|
|
21
|
+
|
|
22
|
+
# resource name is "Audit Log"
|
|
23
|
+
set_rest_name :audit_log
|
|
24
|
+
|
|
25
|
+
# display argument as [id] instead of [audit log]
|
|
26
|
+
set_rest_has_name false
|
|
27
|
+
set_rest_arg "id"
|
|
28
|
+
|
|
29
|
+
# def connect(opts)
|
|
30
|
+
# @api_client = establish_remote_appliance_connection(opts)
|
|
31
|
+
# @audit_interface = @api_client.audit # @api_client.rest("audit")
|
|
32
|
+
# end
|
|
33
|
+
|
|
34
|
+
# def handle(args)
|
|
35
|
+
# handle_subcommand(args)
|
|
36
|
+
# end
|
|
37
|
+
|
|
38
|
+
def list(args)
|
|
39
|
+
options = {}
|
|
40
|
+
params = {}
|
|
41
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
42
|
+
opts.banner = subcommand_usage("[search]")
|
|
43
|
+
opts.on('--user USER', String, "Filter by User Username or ID") do |val|
|
|
44
|
+
params['user'] = params['user'] ? [params['user'], val].flatten : [val]
|
|
45
|
+
end
|
|
46
|
+
opts.on('--level VALUE', String, "Log Level. DEBUG|INFO|WARN|ERROR") do |val|
|
|
47
|
+
params['level'] = params['level'] ? [params['level'], val].flatten : [val]
|
|
48
|
+
end
|
|
49
|
+
opts.on('--start TIMESTAMP','--start TIMESTAMP', "Start date timestamp in standard iso8601 format.") do |val|
|
|
50
|
+
params['startDate'] = val # parse_time(val).utc.iso8601
|
|
51
|
+
end
|
|
52
|
+
opts.on('--end TIMESTAMP','--end TIMESTAMP', "End date timestamp in standard iso8601 format.") do |val|
|
|
53
|
+
params['endDate'] = val # parse_time(val).utc.iso8601
|
|
54
|
+
end
|
|
55
|
+
build_standard_list_options(opts, options)
|
|
56
|
+
opts.footer = "List audit logs records."
|
|
57
|
+
end
|
|
58
|
+
optparse.parse!(args)
|
|
59
|
+
if args.count > 0
|
|
60
|
+
options[:phrase] = args.join(" ")
|
|
61
|
+
end
|
|
62
|
+
connect(options)
|
|
63
|
+
params.merge!(parse_list_options(options))
|
|
64
|
+
# parse --user id,name
|
|
65
|
+
if params['user']
|
|
66
|
+
user_ids = parse_user_id_list(params['user'])
|
|
67
|
+
return 1 if user_ids.nil?
|
|
68
|
+
params['user'] = user_ids
|
|
69
|
+
end
|
|
70
|
+
# api works with level=INFO|WARN
|
|
71
|
+
if params['level']
|
|
72
|
+
params['level'] = [params['level']].flatten.collect {|it| it.to_s.upcase }.join('|')
|
|
73
|
+
end
|
|
74
|
+
# could find_by_name_or_id for params['servers'] and params['containers']
|
|
75
|
+
@audit_interface.setopts(options)
|
|
76
|
+
if options[:dry_run]
|
|
77
|
+
print_dry_run @audit_interface.dry.list(params)
|
|
78
|
+
return
|
|
79
|
+
end
|
|
80
|
+
json_response = @audit_interface.list(params)
|
|
81
|
+
|
|
82
|
+
render_response(json_response, options, rest_list_key) do
|
|
83
|
+
records = json_response[rest_list_key]
|
|
84
|
+
print_h1 "Morpheus Audit Log", parse_list_subtitles(options), options
|
|
85
|
+
if records.nil? || records.empty?
|
|
86
|
+
print cyan,"No #{rest_label_plural.downcase} found.",reset,"\n"
|
|
87
|
+
else
|
|
88
|
+
print as_pretty_table(records, rest_list_column_definitions(options).upcase_keys!, options)
|
|
89
|
+
print_results_pagination(json_response) if json_response['meta']
|
|
90
|
+
end
|
|
91
|
+
print reset,"\n"
|
|
92
|
+
end
|
|
93
|
+
return 0, nil
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
protected
|
|
97
|
+
|
|
98
|
+
# custom rendering to print Message below description list
|
|
99
|
+
def render_response_for_get(json_response, options)
|
|
100
|
+
render_response(json_response, options, rest_object_key) do
|
|
101
|
+
record = json_response[rest_object_key]
|
|
102
|
+
print_h1 rest_label, [], options
|
|
103
|
+
print cyan
|
|
104
|
+
print_description_list(rest_column_definitions(options), record, options)
|
|
105
|
+
# show log message settings...
|
|
106
|
+
print_h2 "Message", options
|
|
107
|
+
print cyan
|
|
108
|
+
puts record['message']
|
|
109
|
+
print reset,"\n"
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def audit_log_object_key
|
|
114
|
+
"auditLog"
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def audit_log_list_key
|
|
118
|
+
"auditLogs"
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def audit_log_list_column_definitions(options={})
|
|
122
|
+
{
|
|
123
|
+
"ID" => 'id',
|
|
124
|
+
"Level" => lambda {|it| format_log_level(it['level']) },
|
|
125
|
+
"Message" => {display_method:'message', max_width: (options[:wrap] ? nil : 75)},
|
|
126
|
+
"Event Type" => 'eventType',
|
|
127
|
+
"Object" => lambda {|it| "#{it['objectClass']} #{it['objectId']}".strip },
|
|
128
|
+
# "Object Type" => 'objectClass',
|
|
129
|
+
# "Object ID" => 'objectId',
|
|
130
|
+
"User" => lambda {|it|
|
|
131
|
+
if it['actualUser'] && it['user'] && it['actualUser']['username'] != it['user']['username']
|
|
132
|
+
it['user']['username'] + '(' + it['actualUser']['username'].to_s + ')'
|
|
133
|
+
elsif it['user']
|
|
134
|
+
it['user']['username']
|
|
135
|
+
else
|
|
136
|
+
# system or deleted user maybe?
|
|
137
|
+
end
|
|
138
|
+
},
|
|
139
|
+
# "Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
|
140
|
+
"Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
|
141
|
+
}
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def audit_log_column_definitions(options={})
|
|
145
|
+
{
|
|
146
|
+
"ID" => 'id',
|
|
147
|
+
"Level" => lambda {|it| format_log_level(it['level']) },
|
|
148
|
+
#"Message" => 'message',
|
|
149
|
+
"Event Type" => 'eventType',
|
|
150
|
+
"Object Type" => 'objectClass',
|
|
151
|
+
"Object ID" => 'objectId',
|
|
152
|
+
"User" => lambda {|it|
|
|
153
|
+
if it['actualUser'] && it['user'] && it['actualUser']['username'] != it['user']['username']
|
|
154
|
+
it['user']['username'] + '(' + it['actualUser']['username'].to_s + ')'
|
|
155
|
+
elsif it['user']
|
|
156
|
+
it['user']['username']
|
|
157
|
+
else
|
|
158
|
+
# system or deleted user maybe?
|
|
159
|
+
end
|
|
160
|
+
},
|
|
161
|
+
# "Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
|
162
|
+
"Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
|
163
|
+
}
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def find_audit_log_by_name_or_id(val)
|
|
167
|
+
return find_audit_log_by_id(val)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def find_audit_log_by_id(id)
|
|
171
|
+
begin
|
|
172
|
+
json_response = @audit_interface.get(id)
|
|
173
|
+
return json_response[audit_log_object_key]
|
|
174
|
+
rescue RestClient::Exception => e
|
|
175
|
+
if e.response && e.response.code == 404
|
|
176
|
+
print_red_alert "Audit Log not found by id #{id}"
|
|
177
|
+
return nil
|
|
178
|
+
else
|
|
179
|
+
raise e
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def find_audit_log_by_name(name)
|
|
185
|
+
raise_command_error "finding audit log by name not supported"
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
end
|
|
@@ -36,7 +36,7 @@ class Morpheus::Cli::BlueprintsCommand
|
|
|
36
36
|
@options_interface = @api_client.options
|
|
37
37
|
@active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
|
|
38
38
|
@clouds_interface = @api_client.clouds
|
|
39
|
-
@
|
|
39
|
+
@account_users_interface = @api_client.account_users
|
|
40
40
|
@library_layouts_interface = @api_client.library_layouts
|
|
41
41
|
end
|
|
42
42
|
|
|
@@ -13,6 +13,7 @@ class Morpheus::Cli::CatalogItemTypesCommand
|
|
|
13
13
|
set_command_description "Self Service: View and manage catalog item types"
|
|
14
14
|
|
|
15
15
|
register_subcommands :list, :get, :add, :update, :remove
|
|
16
|
+
register_subcommands({:'update-logo' => :update_logo})
|
|
16
17
|
|
|
17
18
|
def connect(opts)
|
|
18
19
|
@api_client = establish_remote_appliance_connection(opts)
|
|
@@ -222,6 +223,7 @@ EOT
|
|
|
222
223
|
def add(args)
|
|
223
224
|
options = {}
|
|
224
225
|
params = {}
|
|
226
|
+
logo_file = nil
|
|
225
227
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
226
228
|
opts.banner = subcommand_usage("[name] [options]")
|
|
227
229
|
# opts.on('-t', '--type [instance|blueprint|workflow]', "Item Type, default is instance.") do |val|
|
|
@@ -229,6 +231,19 @@ EOT
|
|
|
229
231
|
# options[:options]['type'] = val.to_s.downcase
|
|
230
232
|
# end
|
|
231
233
|
build_option_type_options(opts, options, add_catalog_item_type_option_types)
|
|
234
|
+
opts.on('--logo FILE', String, "Upload a custom logo icon") do |val|
|
|
235
|
+
filename = val
|
|
236
|
+
logo_file = nil
|
|
237
|
+
if filename == 'null'
|
|
238
|
+
filename = 'null' # clear it
|
|
239
|
+
else
|
|
240
|
+
filename = File.expand_path(filename)
|
|
241
|
+
if !File.exists?(filename)
|
|
242
|
+
raise_command_error "File not found: #{filename}"
|
|
243
|
+
end
|
|
244
|
+
logo_file = File.new(filename, 'rb')
|
|
245
|
+
end
|
|
246
|
+
end
|
|
232
247
|
opts.on('--config-file FILE', String, "Config from a local JSON or YAML file") do |val|
|
|
233
248
|
options[:config_file] = val.to_s
|
|
234
249
|
file_content = nil
|
|
@@ -330,6 +345,16 @@ EOT
|
|
|
330
345
|
return 0, nil
|
|
331
346
|
end
|
|
332
347
|
json_response = @catalog_item_types_interface.create(payload)
|
|
348
|
+
if json_response['success']
|
|
349
|
+
if logo_file
|
|
350
|
+
begin
|
|
351
|
+
@catalog_item_types_interface.update_logo(json_response['catalogItemType']['id'], logo_file)
|
|
352
|
+
rescue RestClient::Exception => e
|
|
353
|
+
print_red_alert "Failed to save logo!"
|
|
354
|
+
print_rest_exception(e, options)
|
|
355
|
+
end
|
|
356
|
+
end
|
|
357
|
+
end
|
|
333
358
|
catalog_item_type = json_response[catalog_item_type_object_key]
|
|
334
359
|
render_response(json_response, options, catalog_item_type_object_key) do
|
|
335
360
|
print_green_success "Added catalog item type #{catalog_item_type['name']}"
|
|
@@ -342,9 +367,23 @@ EOT
|
|
|
342
367
|
options = {}
|
|
343
368
|
params = {}
|
|
344
369
|
payload = {}
|
|
370
|
+
logo_file = nil
|
|
345
371
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
346
372
|
opts.banner = subcommand_usage("[type] [options]")
|
|
347
373
|
build_option_type_options(opts, options, update_catalog_item_type_option_types)
|
|
374
|
+
opts.on('--logo FILE', String, "Upload a custom logo icon") do |val|
|
|
375
|
+
filename = val
|
|
376
|
+
logo_file = nil
|
|
377
|
+
if filename == 'null'
|
|
378
|
+
filename = 'null' # clear it
|
|
379
|
+
else
|
|
380
|
+
filename = File.expand_path(filename)
|
|
381
|
+
if !File.exists?(filename)
|
|
382
|
+
raise_command_error "File not found: #{filename}"
|
|
383
|
+
end
|
|
384
|
+
logo_file = File.new(filename, 'rb')
|
|
385
|
+
end
|
|
386
|
+
end
|
|
348
387
|
opts.on('--config-file FILE', String, "Config from a local JSON or YAML file") do |val|
|
|
349
388
|
options[:config_file] = val.to_s
|
|
350
389
|
file_content = nil
|
|
@@ -445,6 +484,16 @@ EOT
|
|
|
445
484
|
return
|
|
446
485
|
end
|
|
447
486
|
json_response = @catalog_item_types_interface.update(catalog_item_type['id'], payload)
|
|
487
|
+
if json_response['success']
|
|
488
|
+
if logo_file
|
|
489
|
+
begin
|
|
490
|
+
@catalog_item_types_interface.update_logo(json_response['catalogItemType']['id'], logo_file)
|
|
491
|
+
rescue RestClient::Exception => e
|
|
492
|
+
print_red_alert "Failed to save logo!"
|
|
493
|
+
print_rest_exception(e, options)
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
end
|
|
448
497
|
catalog_item_type = json_response[catalog_item_type_object_key]
|
|
449
498
|
render_response(json_response, options, catalog_item_type_object_key) do
|
|
450
499
|
print_green_success "Updated catalog item type #{catalog_item_type['name']}"
|
|
@@ -453,6 +502,45 @@ EOT
|
|
|
453
502
|
return 0, nil
|
|
454
503
|
end
|
|
455
504
|
|
|
505
|
+
def update_logo(args)
|
|
506
|
+
options = {}
|
|
507
|
+
params = {}
|
|
508
|
+
filename = nil
|
|
509
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
|
510
|
+
opts.banner = subcommand_usage("[type] [file]")
|
|
511
|
+
build_common_options(opts, options, [:json, :dry_run, :remote])
|
|
512
|
+
opts.footer = "Update the logo for a catalog item type." + "\n" +
|
|
513
|
+
"[type] is required. This is the name or id of a catalog item type." + "\n" +
|
|
514
|
+
"[file] is required. This is the path of the logo file"
|
|
515
|
+
end
|
|
516
|
+
optparse.parse!(args)
|
|
517
|
+
verify_args!(args:args, optparse:optparse, count:2)
|
|
518
|
+
connect(options)
|
|
519
|
+
catalog_item_type = find_catalog_item_type_by_name_or_id(args[0])
|
|
520
|
+
return 1 if catalog_item_type.nil?
|
|
521
|
+
filename = args[1]
|
|
522
|
+
logo_file = nil
|
|
523
|
+
if filename == 'null'
|
|
524
|
+
filename = 'null' # clear it
|
|
525
|
+
else
|
|
526
|
+
filename = File.expand_path(filename)
|
|
527
|
+
if !File.exists?(filename)
|
|
528
|
+
raise_command_error "File not found: #{filename}"
|
|
529
|
+
end
|
|
530
|
+
logo_file = File.new(filename, 'rb')
|
|
531
|
+
end
|
|
532
|
+
@catalog_item_types_interface.setopts(options)
|
|
533
|
+
if options[:dry_run]
|
|
534
|
+
print_dry_run @catalog_item_types_interface.dry.update_logo(catalog_item_type['id'], logo_file)
|
|
535
|
+
return
|
|
536
|
+
end
|
|
537
|
+
json_response = @catalog_item_types_interface.update_logo(catalog_item_type['id'], logo_file)
|
|
538
|
+
render_response(json_response, options, catalog_item_type_object_key) do
|
|
539
|
+
print_green_success "Updated catalog item type #{catalog_item_type['name']} logo"
|
|
540
|
+
return _get(catalog_item_type["id"], {}, options)
|
|
541
|
+
end
|
|
542
|
+
end
|
|
543
|
+
|
|
456
544
|
def remove(args)
|
|
457
545
|
options = {}
|
|
458
546
|
params = {}
|
|
@@ -9,7 +9,7 @@ class Morpheus::Cli::ChangePasswordCommand
|
|
|
9
9
|
def connect(opts)
|
|
10
10
|
@api_client = establish_remote_appliance_connection(opts)
|
|
11
11
|
@whoami_interface = @api_client.whoami
|
|
12
|
-
@
|
|
12
|
+
@account_users_interface = @api_client.account_users
|
|
13
13
|
@accounts_interface = @api_client.accounts
|
|
14
14
|
@roles_interface = @api_client.roles
|
|
15
15
|
end
|
|
@@ -105,9 +105,9 @@ class Morpheus::Cli::ChangePasswordCommand
|
|
|
105
105
|
'password' => new_password
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
-
@
|
|
108
|
+
@account_users_interface.setopts(options)
|
|
109
109
|
if options[:dry_run]
|
|
110
|
-
print_dry_run @
|
|
110
|
+
print_dry_run @account_users_interface.dry.update(account_id, user['id'], payload)
|
|
111
111
|
return 0
|
|
112
112
|
end
|
|
113
113
|
|
|
@@ -117,7 +117,7 @@ class Morpheus::Cli::ChangePasswordCommand
|
|
|
117
117
|
end
|
|
118
118
|
end
|
|
119
119
|
|
|
120
|
-
json_response = @
|
|
120
|
+
json_response = @account_users_interface.update(account_id, user['id'], payload)
|
|
121
121
|
if options[:json]
|
|
122
122
|
puts as_json(json_response)
|
|
123
123
|
elsif !options[:quiet]
|
|
@@ -458,6 +458,10 @@ class Morpheus::Cli::Clusters
|
|
|
458
458
|
|
|
459
459
|
cluster_payload['type'] = cluster_type['code'] # {'id' => cluster_type['id']}
|
|
460
460
|
|
|
461
|
+
# Group / Site
|
|
462
|
+
group = load_group(cluster_type['code'], options)
|
|
463
|
+
cluster_payload['group'] = {'id' => group['id']}
|
|
464
|
+
|
|
461
465
|
# Cluster Name
|
|
462
466
|
if args.empty? && options[:no_prompt]
|
|
463
467
|
print_red_alert "No cluster name provided"
|
|
@@ -514,10 +518,6 @@ class Morpheus::Cli::Clusters
|
|
|
514
518
|
|
|
515
519
|
server_payload['tags'] = tags if tags
|
|
516
520
|
|
|
517
|
-
# Group / Site
|
|
518
|
-
group = load_group(options)
|
|
519
|
-
cluster_payload['group'] = {'id' => group['id']}
|
|
520
|
-
|
|
521
521
|
# Cloud / Zone
|
|
522
522
|
cloud_id = nil
|
|
523
523
|
cloud = options[:cloud] ? find_cloud_by_name_or_id_for_provisioning(group['id'], options[:cloud]) : nil
|
|
@@ -526,7 +526,7 @@ class Morpheus::Cli::Clusters
|
|
|
526
526
|
cloud = @clouds_interface.get(cloud['id'])['zone']
|
|
527
527
|
cloud_id = cloud['id']
|
|
528
528
|
else
|
|
529
|
-
available_clouds = get_available_clouds(group['id'])
|
|
529
|
+
available_clouds = get_available_clouds(group['id'], {groupType: cluster_payload['type']})
|
|
530
530
|
|
|
531
531
|
if available_clouds.empty?
|
|
532
532
|
print_red_alert "Group #{group['name']} has no available clouds"
|
|
@@ -547,30 +547,34 @@ class Morpheus::Cli::Clusters
|
|
|
547
547
|
available_layouts = layouts_for_dropdown(cloud['id'], cluster_type['id'])
|
|
548
548
|
|
|
549
549
|
if !available_layouts.empty?
|
|
550
|
-
|
|
551
|
-
layout_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'layout', 'type' => 'select', 'fieldLabel' => 'Layout', 'selectOptions' => available_layouts, 'required' => true, 'description' => 'Select Layout.'}],options[:options],@api_client,{})['layout']
|
|
552
|
-
else
|
|
553
|
-
layout_id = available_layouts.first['id']
|
|
554
|
-
end
|
|
550
|
+
layout_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'layout', 'type' => 'select', 'fieldLabel' => 'Layout', 'selectOptions' => available_layouts, 'required' => true, 'description' => 'Select Layout.'}],options[:options],@api_client,{})['layout']
|
|
555
551
|
layout = find_layout_by_name_or_id(layout_id)
|
|
556
552
|
end
|
|
557
553
|
end
|
|
558
554
|
|
|
559
|
-
cluster_payload['layout'] = {id
|
|
555
|
+
cluster_payload['layout'] = {'id' => layout['id']}
|
|
560
556
|
|
|
561
557
|
# Provision Type
|
|
562
558
|
provision_type = (layout && layout['provisionType'] ? layout['provisionType'] : nil) || get_provision_type_for_zone_type(cloud['zoneType']['id'])
|
|
559
|
+
provision_type = @provision_types_interface.get(provision_type['id'])['provisionType'] if !provision_type.nil?
|
|
563
560
|
|
|
564
|
-
api_params = {zoneId: cloud['id'], siteId: group['id'], layoutId: layout['id'], groupTypeId: cluster_type['id'], provisionTypeId: provision_type['id']}
|
|
561
|
+
api_params = {zoneId: cloud['id'], siteId: group['id'], layoutId: layout['id'], groupTypeId: cluster_type['id'], provisionType: provision_type['code'], provisionTypeId: provision_type['id']}
|
|
565
562
|
|
|
566
563
|
# Controller type
|
|
567
|
-
server_types = @server_types_interface.list({
|
|
564
|
+
server_types = @server_types_interface.list({computeTypeId: cluster_type['controllerTypes'].first['id'], zoneTypeId: cloud['zoneType']['id'], useZoneProvisionTypes: true})['serverTypes'].reject {|it| it['provisionType']['code'] == 'manual'}
|
|
568
565
|
controller_provision_type = nil
|
|
569
566
|
resource_pool = nil
|
|
570
567
|
|
|
571
568
|
if !server_types.empty?
|
|
572
569
|
controller_type = server_types.first
|
|
573
|
-
|
|
570
|
+
|
|
571
|
+
if controller_type['provisionType']
|
|
572
|
+
if provision_type && provision_type['id'] == controller_type['provisionType']['id']
|
|
573
|
+
controller_provision_type = provision_type
|
|
574
|
+
else
|
|
575
|
+
controller_provision_type = @provision_types_interface.get(controller_type['provisionType']['id'])['provisionType'] rescue nil
|
|
576
|
+
end
|
|
577
|
+
end
|
|
574
578
|
|
|
575
579
|
if controller_provision_type && resource_pool = prompt_resource_pool(group, cloud, nil, controller_provision_type, options)
|
|
576
580
|
server_payload['config']['resourcePoolId'] = resource_pool['id']
|
|
@@ -585,21 +589,23 @@ class Morpheus::Cli::Clusters
|
|
|
585
589
|
service_plan = prompt_service_plan(api_params, options)
|
|
586
590
|
|
|
587
591
|
if service_plan
|
|
588
|
-
server_payload['plan'] = {'id' => service_plan['id'], 'code' => service_plan['code'], 'options' => prompt_service_plan_options(service_plan, options)}
|
|
592
|
+
server_payload['plan'] = {'id' => service_plan['id'], 'code' => service_plan['code'], 'options' => prompt_service_plan_options(service_plan, provision_type, options)}
|
|
589
593
|
api_params['planId'] = service_plan['id']
|
|
590
594
|
end
|
|
591
595
|
|
|
592
596
|
# Multi-disk / prompt for volumes
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
+
if provision_type['hasVolumes']
|
|
598
|
+
volumes = options[:volumes] || prompt_volumes(service_plan, options.merge({'defaultAddFirstDataVolume': true}), @api_client, api_params)
|
|
599
|
+
if !volumes.empty?
|
|
600
|
+
server_payload['volumes'] = volumes
|
|
601
|
+
end
|
|
597
602
|
end
|
|
598
603
|
|
|
599
604
|
# Options / Custom Config
|
|
600
605
|
option_type_list =
|
|
601
|
-
((controller_type['optionTypes'].reject { |type| !type['enabled'] || type['fieldComponent'] } rescue []) +
|
|
602
|
-
|
|
606
|
+
((controller_type.nil? ? [] : controller_type['optionTypes'].reject { |type| !type['enabled'] || type['fieldComponent'] } rescue []) +
|
|
607
|
+
layout['optionTypes'] +
|
|
608
|
+
(cluster_type['optionTypes'].reject { |type| !type['enabled'] || !type['creatable'] || type['fieldComponent'] } rescue []))
|
|
603
609
|
|
|
604
610
|
# KLUDGE: google zone required for network selection
|
|
605
611
|
if option_type = option_type_list.find {|type| type['code'] == 'computeServerType.googleLinux.googleZoneId'}
|
|
@@ -621,11 +627,17 @@ class Morpheus::Cli::Clusters
|
|
|
621
627
|
# Visibility
|
|
622
628
|
server_payload['visibility'] = options[:visibility] || (Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'defaultValue' => 'private', 'required' => true, 'selectOptions' => [{'name' => 'Private', 'value' => 'private'},{'name' => 'Public', 'value' => 'public'}]}], options[:options], @api_client, {})['visibility'])
|
|
623
629
|
|
|
624
|
-
|
|
630
|
+
# Layout template options
|
|
631
|
+
cluster_payload.deep_merge!(Morpheus::Cli::OptionTypes.prompt(load_layout_options(cluster_payload), options[:options], @api_client, api_params, options[:no_prompt], true))
|
|
632
|
+
|
|
633
|
+
# Server options
|
|
634
|
+
server_payload.deep_merge!(Morpheus::Cli::OptionTypes.prompt(option_type_list, options[:options].deep_merge({:context_map => {'domain' => ''}}), @api_client, api_params, options[:no_prompt], true))
|
|
625
635
|
|
|
626
636
|
# Worker count
|
|
627
|
-
|
|
628
|
-
|
|
637
|
+
if !['manual', 'external'].include?(provision_type['code'])
|
|
638
|
+
default_node_count = layout['computeServers'] ? (layout['computeServers'].find {|it| it['nodeType'] == 'worker'} || {'nodeCount' => 3})['nodeCount'] : 3
|
|
639
|
+
server_payload['config']['nodeCount'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => "config.nodeCount", 'type' => 'number', 'fieldLabel' => "#{['docker-cluster', 'kvm-cluster'].include?(cluster_type['code']) ? 'Host' : 'Worker'} Count", 'required' => true, 'defaultValue' => default_node_count > 0 ? default_node_count : 3}], options[:options], @api_client, api_params, options[:no_prompt])['config']['nodeCount']
|
|
640
|
+
end
|
|
629
641
|
|
|
630
642
|
# Create User
|
|
631
643
|
if !options[:createUser].nil?
|
|
@@ -653,10 +665,12 @@ class Morpheus::Cli::Clusters
|
|
|
653
665
|
server_payload['hostname'] = options[:hostname] || Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'hostname', 'fieldLabel' => 'Hostname', 'type' => 'text', 'required' => true, 'description' => 'Hostname', 'defaultValue' => resourceName}], options[:options], @api_client, api_params)['hostname']
|
|
654
666
|
|
|
655
667
|
# Workflow / Automation
|
|
656
|
-
|
|
668
|
+
if provision_type['code'] != 'manual' && controller_type && controller_type['hasAutomation']
|
|
669
|
+
task_set_id = options[:taskSetId] || Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'taskSet', 'fieldLabel' => 'Workflow', 'type' => 'select', 'required' => false, 'optionSource' => 'taskSets'}], options[:options], @api_client, api_params.merge({'phase' => 'postProvision'}))['taskSet']
|
|
657
670
|
|
|
658
|
-
|
|
659
|
-
|
|
671
|
+
if !task_set_id.nil?
|
|
672
|
+
server_payload['taskSet'] = {'id' => task_set_id}
|
|
673
|
+
end
|
|
660
674
|
end
|
|
661
675
|
|
|
662
676
|
cluster_payload['server'] = server_payload
|
|
@@ -1168,7 +1182,7 @@ class Morpheus::Cli::Clusters
|
|
|
1168
1182
|
service_plan = prompt_service_plan({zoneId: cloud_id, siteId: cluster['site']['id'], provisionTypeId: server_type['provisionType']['id'], groupTypeId: cluster_type['id'], }, options)
|
|
1169
1183
|
|
|
1170
1184
|
if service_plan
|
|
1171
|
-
server_payload['plan'] = {'code' => service_plan['code'], 'options' => prompt_service_plan_options(service_plan, options)}
|
|
1185
|
+
server_payload['plan'] = {'code' => service_plan['code'], 'options' => prompt_service_plan_options(service_plan, nil, options)}
|
|
1172
1186
|
end
|
|
1173
1187
|
|
|
1174
1188
|
if resource_pool = prompt_resource_pool(cluster, cloud, service_plan, server_type['provisionType'], options)
|
|
@@ -3665,7 +3679,7 @@ class Morpheus::Cli::Clusters
|
|
|
3665
3679
|
@clouds_interface.cloud_type(zone_type_id)['zoneType']['provisionTypes'].first rescue nil
|
|
3666
3680
|
end
|
|
3667
3681
|
|
|
3668
|
-
def load_group(options)
|
|
3682
|
+
def load_group(group_type, options)
|
|
3669
3683
|
# Group / Site
|
|
3670
3684
|
group_id = nil
|
|
3671
3685
|
group = options[:group] ? find_group_by_name_or_id_for_provisioning(options[:group]) : nil
|
|
@@ -3676,15 +3690,13 @@ class Morpheus::Cli::Clusters
|
|
|
3676
3690
|
if @active_group_id
|
|
3677
3691
|
group_id = @active_group_id
|
|
3678
3692
|
else
|
|
3679
|
-
available_groups = get_available_groups
|
|
3693
|
+
available_groups = get_available_groups({groupType: group_type})
|
|
3680
3694
|
|
|
3681
3695
|
if available_groups.empty?
|
|
3682
3696
|
print_red_alert "No available groups"
|
|
3683
3697
|
exit 1
|
|
3684
|
-
|
|
3698
|
+
else available_groups.count > 1 && !options[:no_prompt]
|
|
3685
3699
|
group_id = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'type' => 'select', 'fieldLabel' => 'Group', 'selectOptions' => available_groups, 'required' => true, 'description' => 'Select Group.'}],options[:options],@api_client,{})['group']
|
|
3686
|
-
else
|
|
3687
|
-
group_id = available_groups.first['id']
|
|
3688
3700
|
end
|
|
3689
3701
|
end
|
|
3690
3702
|
end
|
|
@@ -3711,34 +3723,37 @@ class Morpheus::Cli::Clusters
|
|
|
3711
3723
|
service_plan
|
|
3712
3724
|
end
|
|
3713
3725
|
|
|
3714
|
-
def prompt_service_plan_options(service_plan, options)
|
|
3726
|
+
def prompt_service_plan_options(service_plan, provision_type, options)
|
|
3715
3727
|
plan_options = {}
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
if
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3728
|
+
hide_custom_options = provision_type && provision_type['code'] == 'manual'
|
|
3729
|
+
|
|
3730
|
+
if !hide_custom_options
|
|
3731
|
+
# custom max memory
|
|
3732
|
+
if service_plan['customMaxMemory']
|
|
3733
|
+
if !options[:maxMemory]
|
|
3734
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'maxMemory', 'type' => 'number', 'fieldLabel' => 'Max Memory (MB)', 'required' => false, 'description' => 'This will override any memory requirement set on the virtual image', 'defaultValue' => service_plan['maxMemory'] ? service_plan['maxMemory'] / (1024 * 1024) : 10 }], options[:options])
|
|
3735
|
+
plan_options['maxMemory'] = v_prompt['maxMemory'] * 1024 * 1024 if v_prompt['maxMemory']
|
|
3736
|
+
else
|
|
3737
|
+
plan_options['maxMemory'] = options[:maxMemory]
|
|
3738
|
+
end
|
|
3724
3739
|
end
|
|
3725
|
-
end
|
|
3726
3740
|
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3741
|
+
# custom cores: max cpu, max cores, cores per socket
|
|
3742
|
+
if service_plan['customCores']
|
|
3743
|
+
if options[:cpuCount].empty?
|
|
3744
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'cpuCount', 'type' => 'number', 'fieldLabel' => 'CPU Count', 'required' => false, 'description' => 'Set CPU Count', 'defaultValue' => service_plan['maxCpu'] ? service_plan['maxCpu'] : 1 }], options[:options])
|
|
3745
|
+
plan_options['cpuCount'] = v_prompt['cpuCount'] if v_prompt['cpuCount']
|
|
3746
|
+
else
|
|
3747
|
+
plan_options['cpuCount']
|
|
3748
|
+
end
|
|
3749
|
+
if options[:coreCount].empty?
|
|
3750
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'coreCount', 'type' => 'number', 'fieldLabel' => 'Core Count', 'required' => false, 'description' => 'Set Core Count', 'defaultValue' => service_plan['maxCores'] ? service_plan['maxCores'] : 1 }], options[:options])
|
|
3751
|
+
plan_options['coreCount'] = v_prompt['coreCount'] if v_prompt['coreCount']
|
|
3752
|
+
end
|
|
3753
|
+
if options[:coresPerSocket].empty? && service_plan['coresPerSocket']
|
|
3754
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'coresPerSocket', 'type' => 'number', 'fieldLabel' => 'Cores Per Socket', 'required' => false, 'description' => 'Set Core Per Socket', 'defaultValue' => service_plan['coresPerSocket']}], options[:options])
|
|
3755
|
+
plan_options['coresPerSocket'] = v_prompt['coresPerSocket'] if v_prompt['coresPerSocket']
|
|
3756
|
+
end
|
|
3742
3757
|
end
|
|
3743
3758
|
end
|
|
3744
3759
|
plan_options
|
|
@@ -3926,4 +3941,27 @@ class Morpheus::Cli::Clusters
|
|
|
3926
3941
|
]
|
|
3927
3942
|
end
|
|
3928
3943
|
|
|
3944
|
+
def load_layout_options(cluster)
|
|
3945
|
+
(@api_client.options.options_for_source('computeTypeLayoutParameters', {layoutId: cluster['layout']['id']})['data'] || []).collect do |it|
|
|
3946
|
+
it['fieldName'] = it['name']
|
|
3947
|
+
it['fieldLabel'] = it['displayName']
|
|
3948
|
+
it['fieldContext'] = 'config.templateParameter'
|
|
3949
|
+
if it['type'] == 'ServicePlan'
|
|
3950
|
+
it['optionSource'] = 'servicePlans'
|
|
3951
|
+
it['type'] = 'select'
|
|
3952
|
+
it['params'] = {:provisionType => '', :zoneId => '', :siteId => '', :resourcePoolId => ''}
|
|
3953
|
+
it['params'][:provisionType] = 'azure' if it['azureServicePlanType']
|
|
3954
|
+
elsif it['type'] == 'Subnet'
|
|
3955
|
+
it['optionSource'] = 'networks'
|
|
3956
|
+
it['type'] = 'select'
|
|
3957
|
+
it['params'] = {:siteId => '', :instanceId => '', :serverId => '', :zonePoolId => '', :zoneRegionId => '', :zoneId => '', :provisionType => ''}
|
|
3958
|
+
if cluster['type'] == 'aks-cluster'
|
|
3959
|
+
it['params'][:provisionType] = 'azure'
|
|
3960
|
+
end
|
|
3961
|
+
else
|
|
3962
|
+
it['type'] = 'text'
|
|
3963
|
+
end
|
|
3964
|
+
it
|
|
3965
|
+
end
|
|
3966
|
+
end
|
|
3929
3967
|
end
|