morpheus-cli 5.5.1.4 → 5.5.2
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 +25 -0
- data/lib/morpheus/api/archive_buckets_interface.rb +1 -1
- data/lib/morpheus/api/body_io.rb +22 -0
- data/lib/morpheus/api/catalog_item_types_interface.rb +5 -1
- data/lib/morpheus/api/clients_interface.rb +41 -0
- data/lib/morpheus/api/clouds_interface.rb +21 -0
- data/lib/morpheus/api/instances_interface.rb +8 -1
- data/lib/morpheus/api/integrations_interface.rb +30 -0
- data/lib/morpheus/api/library_instance_types_interface.rb +15 -3
- data/lib/morpheus/api/network_pool_server_types_interface.rb +9 -0
- data/lib/morpheus/api/plugins_interface.rb +22 -0
- data/lib/morpheus/api/roles_interface.rb +20 -1
- data/lib/morpheus/api/security_package_types_interface.rb +9 -0
- data/lib/morpheus/api/security_packages_interface.rb +9 -0
- data/lib/morpheus/api/security_scans_interface.rb +9 -0
- data/lib/morpheus/api/servers_interface.rb +17 -17
- data/lib/morpheus/api/storage_providers_interface.rb +1 -1
- data/lib/morpheus/api/virtual_images_interface.rb +1 -23
- data/lib/morpheus/cli/cli_command.rb +81 -7
- data/lib/morpheus/cli/commands/apps.rb +28 -2
- data/lib/morpheus/cli/commands/archives_command.rb +2 -2
- data/lib/morpheus/cli/commands/blueprints_command.rb +16 -0
- data/lib/morpheus/cli/commands/catalog_item_types_command.rb +34 -2
- data/lib/morpheus/cli/commands/clients_command.rb +338 -0
- data/lib/morpheus/cli/commands/clouds.rb +127 -1
- data/lib/morpheus/cli/commands/clusters.rb +42 -12
- data/lib/morpheus/cli/commands/curl_command.rb +114 -135
- data/lib/morpheus/cli/commands/hosts.rb +108 -11
- data/lib/morpheus/cli/commands/instances.rb +115 -14
- data/lib/morpheus/cli/commands/integrations_command.rb +215 -4
- data/lib/morpheus/cli/commands/invoices_command.rb +20 -11
- data/lib/morpheus/cli/commands/jobs_command.rb +299 -190
- data/lib/morpheus/cli/commands/library_cluster_layouts_command.rb +16 -2
- data/lib/morpheus/cli/commands/library_container_scripts_command.rb +14 -0
- data/lib/morpheus/cli/commands/library_container_templates_command.rb +131 -48
- data/lib/morpheus/cli/commands/library_container_types_command.rb +17 -4
- data/lib/morpheus/cli/commands/library_instance_types_command.rb +85 -7
- data/lib/morpheus/cli/commands/library_layouts_command.rb +32 -1
- data/lib/morpheus/cli/commands/library_option_lists_command.rb +30 -18
- data/lib/morpheus/cli/commands/library_option_types_command.rb +31 -14
- data/lib/morpheus/cli/commands/library_spec_templates_command.rb +14 -0
- data/lib/morpheus/cli/commands/library_upgrades_command.rb +2 -2
- data/lib/morpheus/cli/commands/network_pool_server_types.rb +20 -0
- data/lib/morpheus/cli/commands/network_pool_servers_command.rb +55 -158
- data/lib/morpheus/cli/commands/network_pools_command.rb +49 -23
- data/lib/morpheus/cli/commands/networks_command.rb +262 -45
- data/lib/morpheus/cli/commands/plugins.rb +213 -0
- data/lib/morpheus/cli/commands/price_sets_command.rb +40 -10
- data/lib/morpheus/cli/commands/prices_command.rb +17 -5
- data/lib/morpheus/cli/commands/processes_command.rb +2 -1
- data/lib/morpheus/cli/commands/remote.rb +7 -10
- data/lib/morpheus/cli/commands/roles.rb +924 -335
- data/lib/morpheus/cli/commands/search_command.rb +2 -0
- data/lib/morpheus/cli/commands/security_groups.rb +72 -84
- data/lib/morpheus/cli/commands/security_package_types.rb +32 -0
- data/lib/morpheus/cli/commands/security_packages.rb +84 -0
- data/lib/morpheus/cli/commands/security_scans.rb +107 -0
- data/lib/morpheus/cli/commands/service_plans_command.rb +16 -14
- data/lib/morpheus/cli/commands/subnets_command.rb +15 -1
- data/lib/morpheus/cli/commands/tasks.rb +34 -1
- data/lib/morpheus/cli/commands/tenants_command.rb +1 -1
- data/lib/morpheus/cli/commands/user_settings_command.rb +11 -2
- data/lib/morpheus/cli/commands/users.rb +50 -9
- data/lib/morpheus/cli/commands/virtual_images.rb +14 -0
- data/lib/morpheus/cli/commands/workflows.rb +14 -0
- data/lib/morpheus/cli/mixins/accounts_helper.rb +6 -5
- data/lib/morpheus/cli/mixins/infrastructure_helper.rb +79 -0
- data/lib/morpheus/cli/mixins/jobs_helper.rb +4 -5
- data/lib/morpheus/cli/mixins/library_helper.rb +2 -0
- data/lib/morpheus/cli/mixins/logs_helper.rb +3 -0
- data/lib/morpheus/cli/mixins/monitoring_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +29 -4
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +38 -9
- data/lib/morpheus/cli/mixins/rest_command.rb +106 -8
- data/lib/morpheus/cli/mixins/secondary_rest_command.rb +6 -2
- data/lib/morpheus/cli/option_types.rb +94 -25
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/formatters.rb +10 -1
- metadata +15 -2
|
@@ -8,7 +8,7 @@ class Morpheus::Cli::Hosts
|
|
|
8
8
|
set_command_name :hosts
|
|
9
9
|
set_command_description "View and manage hosts (servers)."
|
|
10
10
|
register_subcommands :list, :count, :get, :view, :stats, :add, :update, :remove, :logs, :start, :stop, :resize,
|
|
11
|
-
:run_workflow, :make_managed, :upgrade_agent, :snapshots, :software, :software_sync,
|
|
11
|
+
:run_workflow, :make_managed, :upgrade_agent, :snapshots, :software, :software_sync, :update_network_label,
|
|
12
12
|
{:'types' => :list_types},
|
|
13
13
|
{:exec => :execution_request},
|
|
14
14
|
:wiki, :update_wiki
|
|
@@ -109,11 +109,11 @@ class Morpheus::Cli::Hosts
|
|
|
109
109
|
opts.on( '--tenant TENANT', "Tenant Name or ID" ) do |val|
|
|
110
110
|
options[:account] = val
|
|
111
111
|
end
|
|
112
|
-
opts.on('--labels
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
112
|
+
opts.on('-l', '--labels LABEL', String, "Filter by labels, can match any of the values") do |val|
|
|
113
|
+
add_query_parameter(params, 'labels', parse_labels(val))
|
|
114
|
+
end
|
|
115
|
+
opts.on('--all-labels LABEL', String, "Filter by labels, must match all of the values") do |val|
|
|
116
|
+
add_query_parameter(params, 'allLabels', parse_labels(val))
|
|
117
117
|
end
|
|
118
118
|
opts.on('--tags Name=Value',String, "Filter by tags.") do |val|
|
|
119
119
|
val.split(",").each do |value_pair|
|
|
@@ -519,7 +519,7 @@ class Morpheus::Cli::Hosts
|
|
|
519
519
|
"Name" => 'name',
|
|
520
520
|
"Hostname" => 'hostname',
|
|
521
521
|
"Description" => 'description',
|
|
522
|
-
"Labels" => lambda {|it| it['labels']
|
|
522
|
+
"Labels" => lambda {|it| format_list(it['labels']) rescue '' },
|
|
523
523
|
"Tags" => lambda {|it| tags ? format_metadata(tags) : '' },
|
|
524
524
|
"Owner" => lambda {|it| it['owner'] ? it['owner']['username'] : '' },
|
|
525
525
|
"Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
|
@@ -751,6 +751,16 @@ class Morpheus::Cli::Hosts
|
|
|
751
751
|
opts.on("--security-groups LIST", Integer, "Security Groups, comma separated list of security group IDs") do |val|
|
|
752
752
|
options[:security_groups] = val.split(",").collect {|s| s.strip }.select {|s| !s.to_s.empty? }
|
|
753
753
|
end
|
|
754
|
+
opts.on('--tags LIST', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
|
|
755
|
+
options[:metadata] = val
|
|
756
|
+
end
|
|
757
|
+
opts.on('--metadata [LIST]', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
|
|
758
|
+
options[:metadata] = val
|
|
759
|
+
end
|
|
760
|
+
opts.add_hidden_option('--metadata')
|
|
761
|
+
opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
|
|
762
|
+
options[:options]['labels'] = parse_labels(val)
|
|
763
|
+
end
|
|
754
764
|
opts.on('--refresh [SECONDS]', String, "Refresh until status is running,failed. Default interval is #{default_refresh_interval} seconds.") do |val|
|
|
755
765
|
options[:refresh_interval] = val.to_s.empty? ? default_refresh_interval : val.to_f
|
|
756
766
|
end
|
|
@@ -933,7 +943,18 @@ class Morpheus::Cli::Hosts
|
|
|
933
943
|
end
|
|
934
944
|
end
|
|
935
945
|
end
|
|
936
|
-
|
|
946
|
+
|
|
947
|
+
# Metadata Tags
|
|
948
|
+
if metadata_option_type
|
|
949
|
+
if options[:metadata]
|
|
950
|
+
metadata = parse_metadata(options[:metadata])
|
|
951
|
+
payload['tags'] = metadata if !metadata.empty?
|
|
952
|
+
else
|
|
953
|
+
metadata = prompt_metadata(options)
|
|
954
|
+
payload['tags'] = metadata if !metadata.empty?
|
|
955
|
+
end
|
|
956
|
+
end
|
|
957
|
+
|
|
937
958
|
api_params = {}
|
|
938
959
|
api_params['zoneId'] = cloud['id']
|
|
939
960
|
api_params['poolId'] = payload['config']['resourcePool'] if (payload['config'] && payload['config']['resourcePool'])
|
|
@@ -988,8 +1009,8 @@ class Morpheus::Cli::Hosts
|
|
|
988
1009
|
opts.on('--power-schedule-type ID', String, "Power Schedule Type ID") do |val|
|
|
989
1010
|
params['powerScheduleType'] = val == "null" ? nil : val
|
|
990
1011
|
end
|
|
991
|
-
opts.on('--labels [LIST]', String, "Labels
|
|
992
|
-
params['labels'] = val
|
|
1012
|
+
opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
|
|
1013
|
+
params['labels'] = parse_labels(val)
|
|
993
1014
|
end
|
|
994
1015
|
opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
|
|
995
1016
|
options[:tags] = val
|
|
@@ -1276,7 +1297,10 @@ class Morpheus::Cli::Hosts
|
|
|
1276
1297
|
current_volumes = volumes_response['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
|
|
1277
1298
|
|
|
1278
1299
|
# prompt for volumes
|
|
1279
|
-
|
|
1300
|
+
vol_options = options
|
|
1301
|
+
vol_options['siteId'] = group_id
|
|
1302
|
+
vol_options['zoneId'] = cloud_id
|
|
1303
|
+
volumes = prompt_resize_volumes(current_volumes, service_plan, provision_type, vol_options)
|
|
1280
1304
|
if !volumes.empty?
|
|
1281
1305
|
payload[:volumes] = volumes
|
|
1282
1306
|
end
|
|
@@ -2219,6 +2243,79 @@ EOT
|
|
|
2219
2243
|
end
|
|
2220
2244
|
out
|
|
2221
2245
|
end
|
|
2246
|
+
|
|
2247
|
+
def update_network_label(args)
|
|
2248
|
+
options = {}
|
|
2249
|
+
params = {}
|
|
2250
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
2251
|
+
opts.banner = subcommand_usage("[server] [options]")
|
|
2252
|
+
opts.on('--network NETWORK', "Network Interface ID" ) do |val|
|
|
2253
|
+
options[:network] = val
|
|
2254
|
+
end
|
|
2255
|
+
opts.on('--label LABEL', "label") do |val|
|
|
2256
|
+
options[:label] = val
|
|
2257
|
+
end
|
|
2258
|
+
opts.footer = "Change the label of a Network Interface.\n" +
|
|
2259
|
+
"Editing an Interface will not apply changes to the physical hardware. The purpose is for a manual override or data correction (mostly for self managed or baremetal servers where cloud sync is not available)\n" +
|
|
2260
|
+
"[name or id] is required. The name or the id of the server.\n" +
|
|
2261
|
+
"[network] ID of the Network Interface. (optional).\n" +
|
|
2262
|
+
"[label] New Label name for the Network Interface (optional)"
|
|
2263
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
|
2264
|
+
end
|
|
2265
|
+
optparse.parse!(args)
|
|
2266
|
+
if args.count != 1
|
|
2267
|
+
puts_error "#{Morpheus::Terminal.angry_prompt}wrong number of arguments. Expected 1 and received #{args.count} #{args.inspect}\n#{optparse}"
|
|
2268
|
+
return 1
|
|
2269
|
+
end
|
|
2270
|
+
connect(options)
|
|
2271
|
+
|
|
2272
|
+
begin
|
|
2273
|
+
host = find_host_by_name_or_id(args[0])
|
|
2274
|
+
return 1 if host.nil?
|
|
2275
|
+
|
|
2276
|
+
network_id = options[:network]
|
|
2277
|
+
if network_id != nil && network_id.to_i == 0
|
|
2278
|
+
print_red_alert "network must be an ID/integer above 0, not a name/string value."
|
|
2279
|
+
network_id = nil
|
|
2280
|
+
end
|
|
2281
|
+
|
|
2282
|
+
|
|
2283
|
+
if !network_id
|
|
2284
|
+
available_networks = get_available_networks(host)
|
|
2285
|
+
network_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'network', 'fieldLabel' => 'Network', 'type' => 'select', 'selectOptions' => available_networks, 'required' => true, 'defaultValue' => available_networks[0], 'description' => "The networks available for relabeling"}], options[:options])
|
|
2286
|
+
network_id = network_prompt['network']
|
|
2287
|
+
end
|
|
2288
|
+
|
|
2289
|
+
label = options[:label]
|
|
2290
|
+
while label.nil? do
|
|
2291
|
+
label_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'label', 'fieldLabel' => 'Label', 'type' => 'text', 'required' => true}], options[:options])
|
|
2292
|
+
label = label_prompt['label']
|
|
2293
|
+
end
|
|
2294
|
+
payload = { "name" => label }
|
|
2295
|
+
if options[:dry_run]
|
|
2296
|
+
print_dry_run @servers_interface.dry.update_network_label(network_id, host["id"], payload)
|
|
2297
|
+
return
|
|
2298
|
+
end
|
|
2299
|
+
json_response = @servers_interface.update_network_label(network_id, host["id"], payload)
|
|
2300
|
+
if options[:json]
|
|
2301
|
+
puts as_json(json_response, options)
|
|
2302
|
+
else
|
|
2303
|
+
print_green_success "Updated label for host #{host['name']} network #{network_id} to #{label}"
|
|
2304
|
+
end
|
|
2305
|
+
return 0
|
|
2306
|
+
rescue RestClient::Exception => e
|
|
2307
|
+
print_rest_exception(e, options)
|
|
2308
|
+
exit 1
|
|
2309
|
+
end
|
|
2310
|
+
end
|
|
2311
|
+
|
|
2312
|
+
def get_available_networks(host)
|
|
2313
|
+
results = @options_interface.options_for_source('availableNetworksForHost',{serverId: host['id'].to_i})
|
|
2314
|
+
available_networks = results['data'].collect {|it|
|
|
2315
|
+
{"id" => it["value"], "name" => it["name"], "value" => it["value"]}
|
|
2316
|
+
}
|
|
2317
|
+
return available_networks
|
|
2318
|
+
end
|
|
2222
2319
|
|
|
2223
2320
|
|
|
2224
2321
|
def make_managed_option_types(connected=true)
|
|
@@ -23,6 +23,7 @@ class Morpheus::Cli::Instances
|
|
|
23
23
|
:console, :status_check, {:containers => :list_containers},
|
|
24
24
|
:scaling, {:'scaling-update' => :scaling_update},
|
|
25
25
|
:wiki, :update_wiki,
|
|
26
|
+
:update_network_label,
|
|
26
27
|
{:exec => :execution_request},
|
|
27
28
|
:deploys,
|
|
28
29
|
:refresh, :prepare_apply, :apply, :state
|
|
@@ -121,11 +122,11 @@ class Morpheus::Cli::Instances
|
|
|
121
122
|
opts.on( '--plan-code CODE', String, "Filter by Plan code(s)" ) do |val|
|
|
122
123
|
params['planCode'] = parse_id_list(val)
|
|
123
124
|
end
|
|
124
|
-
opts.on('--labels
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
125
|
+
opts.on('-l', '--labels LABEL', String, "Filter by labels, can match any of the values") do |val|
|
|
126
|
+
add_query_parameter(params, 'labels', parse_labels(val))
|
|
127
|
+
end
|
|
128
|
+
opts.on('--all-labels LABEL', String, "Filter by labels, must match all of the values") do |val|
|
|
129
|
+
add_query_parameter(params, 'allLabels', parse_labels(val))
|
|
129
130
|
end
|
|
130
131
|
opts.on('--tags Name=Value',String, "Filter by tags (metadata name value pairs).") do |val|
|
|
131
132
|
val.split(",").each do |value_pair|
|
|
@@ -182,7 +183,6 @@ class Morpheus::Cli::Instances
|
|
|
182
183
|
|
|
183
184
|
params['showDeleted'] = true if options[:showDeleted]
|
|
184
185
|
params['deleted'] = true if options[:deleted]
|
|
185
|
-
params['labels'] = options[:labels] if options[:labels]
|
|
186
186
|
if options[:tags]
|
|
187
187
|
options[:tags].each do |k,v|
|
|
188
188
|
params['tags.' + k] = v
|
|
@@ -257,6 +257,7 @@ class Morpheus::Cli::Instances
|
|
|
257
257
|
row = {
|
|
258
258
|
id: instance['id'],
|
|
259
259
|
name: instance['name'],
|
|
260
|
+
labels: format_list(instance['labels'], '', 3),
|
|
260
261
|
connection: format_instance_connection_string(instance),
|
|
261
262
|
environment: instance['instanceContext'],
|
|
262
263
|
user: (instance['owner'] ? (instance['owner']['username'] || instance['owner']['id']) : (instance['createdBy'].is_a?(Hash) ? instance['createdBy']['username'] : instance['createdBy'])),
|
|
@@ -275,16 +276,16 @@ class Morpheus::Cli::Instances
|
|
|
275
276
|
}
|
|
276
277
|
row
|
|
277
278
|
}
|
|
278
|
-
columns = [:id, {:name => {:max_width => 50}}, :group, :cloud,
|
|
279
|
-
:type, :version, :environment,
|
|
279
|
+
columns = [:id, {:name => {:max_width => 50}}, :labels, :group, :cloud,
|
|
280
|
+
:type, :version, :environment, :plan,
|
|
280
281
|
{:created => {:display_name => "CREATED"}},
|
|
281
282
|
# {:tenant => {:display_name => "TENANT"}},
|
|
282
283
|
{:user => {:display_name => "OWNER", :max_width => 20}},
|
|
283
|
-
:plan,
|
|
284
284
|
:nodes, {:connection => {:max_width => 30}}, :status, :cpu, :memory, :storage]
|
|
285
285
|
# custom pretty table columns ... this is handled in as_pretty_table now(),
|
|
286
286
|
# todo: remove all these.. and try to always pass rows as the json data itself..
|
|
287
287
|
if options[:details] != true
|
|
288
|
+
columns.delete(:labels)
|
|
288
289
|
columns.delete(:plan)
|
|
289
290
|
end
|
|
290
291
|
print cyan
|
|
@@ -404,7 +405,7 @@ class Morpheus::Cli::Instances
|
|
|
404
405
|
end
|
|
405
406
|
opts.add_hidden_option('--metadata')
|
|
406
407
|
opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
|
|
407
|
-
options[:labels] = val
|
|
408
|
+
options[:labels] = parse_labels(val)
|
|
408
409
|
end
|
|
409
410
|
opts.on("--copies NUMBER", Integer, "Number of copies to provision") do |val|
|
|
410
411
|
options[:copies] = val.to_i
|
|
@@ -608,7 +609,7 @@ class Morpheus::Cli::Instances
|
|
|
608
609
|
options[:group] = val
|
|
609
610
|
end
|
|
610
611
|
opts.on('--labels [LIST]', String, "Labels (keywords) in the format 'foo, bar'") do |val|
|
|
611
|
-
params['labels'] = val
|
|
612
|
+
params['labels'] = parse_labels(val)
|
|
612
613
|
end
|
|
613
614
|
opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
|
|
614
615
|
options[:tags] = val
|
|
@@ -902,6 +903,74 @@ class Morpheus::Cli::Instances
|
|
|
902
903
|
end
|
|
903
904
|
end
|
|
904
905
|
|
|
906
|
+
def update_network_label(args)
|
|
907
|
+
options = {}
|
|
908
|
+
params = {}
|
|
909
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
910
|
+
opts.banner = subcommand_usage("[instance] [options]")
|
|
911
|
+
opts.on('--network NETWORK', "Network Interface ID" ) do |val|
|
|
912
|
+
options[:network] = val
|
|
913
|
+
end
|
|
914
|
+
opts.on('--label LABEL', "label") do |val|
|
|
915
|
+
options[:label] = val
|
|
916
|
+
end
|
|
917
|
+
opts.footer = "Change the label of a Network Interface.\n" +
|
|
918
|
+
"Editing an Interface will not apply changes to the physical hardware. The purpose is for a manual override or data correction (mostly for self managed or baremetal servers where cloud sync is not available)\n" +
|
|
919
|
+
"[name or id] is required. The name or the id of the instance.\n" +
|
|
920
|
+
"[network] ID of the Network Interface. (optional).\n" +
|
|
921
|
+
"[label] New Label name for the Network Interface (optional)"
|
|
922
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
|
923
|
+
end
|
|
924
|
+
optparse.parse!(args)
|
|
925
|
+
if args.count != 1
|
|
926
|
+
puts_error "#{Morpheus::Terminal.angry_prompt}wrong number of arguments. Expected 1 and received #{args.count} #{args.inspect}\n#{optparse}"
|
|
927
|
+
return 1
|
|
928
|
+
end
|
|
929
|
+
connect(options)
|
|
930
|
+
|
|
931
|
+
begin
|
|
932
|
+
instance = find_instance_by_name_or_id(args[0])
|
|
933
|
+
return 1 if instance.nil?
|
|
934
|
+
|
|
935
|
+
network_id = options[:network]
|
|
936
|
+
if network_id != nil && network_id.to_i == 0
|
|
937
|
+
print_red_alert "network must be an ID/integer above 0, not a name/string value."
|
|
938
|
+
network_id = nil
|
|
939
|
+
end
|
|
940
|
+
|
|
941
|
+
if !network_id
|
|
942
|
+
available_networks = get_available_networks(instance)
|
|
943
|
+
network_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'network', 'fieldLabel' => 'Network', 'type' => 'select', 'selectOptions' => available_networks, 'required' => true, 'defaultValue' => available_networks[0], 'description' => "The networks available for relabeling"}], options[:options])
|
|
944
|
+
network_id = network_prompt['network']
|
|
945
|
+
end
|
|
946
|
+
|
|
947
|
+
|
|
948
|
+
|
|
949
|
+
label = options[:label]
|
|
950
|
+
while label.nil? do
|
|
951
|
+
label_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'label', 'fieldLabel' => 'Label', 'type' => 'text', 'required' => true}], options[:options])
|
|
952
|
+
label = label_prompt['label']
|
|
953
|
+
end
|
|
954
|
+
payload = { "name" => label }
|
|
955
|
+
if options[:dry_run]
|
|
956
|
+
print_dry_run @instances_interface.dry.update_network_label(network_id, instance["id"], payload)
|
|
957
|
+
return
|
|
958
|
+
end
|
|
959
|
+
json_response = @instances_interface.update_network_label(network_id, instance["id"], payload)
|
|
960
|
+
if options[:json]
|
|
961
|
+
puts as_json(json_response, options)
|
|
962
|
+
else
|
|
963
|
+
print_green_success "Updated label for instance #{instance['name']} network #{network_id} to #{label}"
|
|
964
|
+
end
|
|
965
|
+
return 0
|
|
966
|
+
rescue RestClient::Exception => e
|
|
967
|
+
print_rest_exception(e, options)
|
|
968
|
+
exit 1
|
|
969
|
+
end
|
|
970
|
+
end
|
|
971
|
+
|
|
972
|
+
|
|
973
|
+
|
|
905
974
|
def status_check(args)
|
|
906
975
|
out = ""
|
|
907
976
|
options = {}
|
|
@@ -1725,7 +1794,7 @@ class Morpheus::Cli::Instances
|
|
|
1725
1794
|
end
|
|
1726
1795
|
opts.add_hidden_option('--metadata')
|
|
1727
1796
|
opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
|
|
1728
|
-
options[:labels] = val
|
|
1797
|
+
options[:labels] = parse_labels(val)
|
|
1729
1798
|
end
|
|
1730
1799
|
# opts.on("--copies NUMBER", Integer, "Number of copies to provision") do |val|
|
|
1731
1800
|
# options[:copies] = val.to_i
|
|
@@ -2697,13 +2766,19 @@ class Morpheus::Cli::Instances
|
|
|
2697
2766
|
cloud_id = instance['cloud']['id']
|
|
2698
2767
|
layout_id = instance['layout']['id']
|
|
2699
2768
|
plan_id = instance['plan']['id']
|
|
2769
|
+
resource_pool_id = instance['config']['resourcePoolId'] if instance['config']
|
|
2700
2770
|
current_plan_name = instance['plan']['name']
|
|
2771
|
+
current_interfaces = get_instance_interfaces(instance)
|
|
2772
|
+
if current_interfaces != false
|
|
2773
|
+
payload['networkInterfaces'] = current_interfaces
|
|
2774
|
+
end
|
|
2775
|
+
|
|
2701
2776
|
|
|
2702
2777
|
# need to GET provision type for some settings...
|
|
2703
2778
|
provision_type = @provision_types_interface.get(instance['layout']['provisionTypeId'])['provisionType']
|
|
2704
2779
|
|
|
2705
2780
|
# prompt for service plan
|
|
2706
|
-
service_plans_json = @instances_interface.service_plans({zoneId: cloud_id, siteId: group_id, layoutId: layout_id})
|
|
2781
|
+
service_plans_json = @instances_interface.service_plans({zoneId: cloud_id, siteId: group_id, layoutId: layout_id, resourcePoolId: resource_pool_id})
|
|
2707
2782
|
service_plans = service_plans_json["plans"]
|
|
2708
2783
|
service_plans_dropdown = service_plans.collect {|sp| {'name' => sp["name"], 'value' => sp["id"]} } # already sorted
|
|
2709
2784
|
service_plans_dropdown.each do |plan|
|
|
@@ -2723,7 +2798,10 @@ class Morpheus::Cli::Instances
|
|
|
2723
2798
|
current_volumes = volumes_response['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
|
|
2724
2799
|
|
|
2725
2800
|
# prompt for volumes
|
|
2726
|
-
|
|
2801
|
+
vol_options = options
|
|
2802
|
+
vol_options['siteId'] = group_id
|
|
2803
|
+
vol_options['zoneId'] = cloud_id
|
|
2804
|
+
volumes = prompt_resize_volumes(current_volumes, service_plan, provision_type, vol_options)
|
|
2727
2805
|
if !volumes.empty?
|
|
2728
2806
|
payload["volumes"] = volumes
|
|
2729
2807
|
end
|
|
@@ -5184,4 +5262,27 @@ private
|
|
|
5184
5262
|
}
|
|
5185
5263
|
end
|
|
5186
5264
|
|
|
5265
|
+
def get_available_networks(instance)
|
|
5266
|
+
results = @options_interface.options_for_source('availableNetworksForInstance',{instanceId: instance['id'].to_i})
|
|
5267
|
+
available_networks = results['data'].collect {|it|
|
|
5268
|
+
{"id" => it["value"], "name" => it["name"], "value" => it["value"]}
|
|
5269
|
+
}
|
|
5270
|
+
return available_networks
|
|
5271
|
+
end
|
|
5272
|
+
|
|
5273
|
+
def get_instance_interfaces(instance)
|
|
5274
|
+
begin
|
|
5275
|
+
servers = instance['servers']
|
|
5276
|
+
interfaces = []
|
|
5277
|
+
servers.each do |server|
|
|
5278
|
+
details = @servers_interface.get(server.to_i)['server']
|
|
5279
|
+
details['interfaces'].each do |inter|
|
|
5280
|
+
interfaces.push(inter)
|
|
5281
|
+
end
|
|
5282
|
+
end
|
|
5283
|
+
return interfaces
|
|
5284
|
+
rescue
|
|
5285
|
+
return false
|
|
5286
|
+
end
|
|
5287
|
+
end
|
|
5187
5288
|
end
|
|
@@ -8,6 +8,7 @@ class Morpheus::Cli::IntegrationsCommand
|
|
|
8
8
|
|
|
9
9
|
register_subcommands :list, :get, :add, :update, :remove, :refresh
|
|
10
10
|
register_subcommands :list_objects, :get_object, :add_object, :remove_object
|
|
11
|
+
register_subcommands :list_inventory, :get_inventory, :update_inventory
|
|
11
12
|
register_subcommands :list_types, :get_type
|
|
12
13
|
|
|
13
14
|
def connect(opts)
|
|
@@ -936,6 +937,170 @@ EOT
|
|
|
936
937
|
return 0, nil
|
|
937
938
|
end
|
|
938
939
|
|
|
940
|
+
def list_inventory(args)
|
|
941
|
+
options = {}
|
|
942
|
+
params = {}
|
|
943
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
944
|
+
opts.banner = subcommand_usage("[integration] [search]")
|
|
945
|
+
build_standard_list_options(opts, options)
|
|
946
|
+
opts.footer = <<-EOT
|
|
947
|
+
List integration inventory.
|
|
948
|
+
[integration] is required. This is the name or id of an integration.
|
|
949
|
+
Only certain types of integrations support this operation, such as Ansible Tower.
|
|
950
|
+
EOT
|
|
951
|
+
end
|
|
952
|
+
optparse.parse!(args)
|
|
953
|
+
verify_args!(args:args, optparse:optparse, min:1)
|
|
954
|
+
connect(options)
|
|
955
|
+
|
|
956
|
+
integration = find_integration_by_name_or_id(args[0])
|
|
957
|
+
return 1, "integration not found for #{args[0]}" if integration.nil?
|
|
958
|
+
|
|
959
|
+
if args.count > 1
|
|
960
|
+
options[:phrase] = args[1..-1].join(" ")
|
|
961
|
+
end
|
|
962
|
+
params.merge!(parse_list_options(options))
|
|
963
|
+
@integrations_interface.setopts(options)
|
|
964
|
+
if options[:dry_run]
|
|
965
|
+
print_dry_run @integrations_interface.dry.list_inventory(integration['id'], params)
|
|
966
|
+
return 0, nil
|
|
967
|
+
end
|
|
968
|
+
json_response = @integrations_interface.list_inventory(integration['id'], params)
|
|
969
|
+
render_response(json_response, options, integration_inventory_list_key) do
|
|
970
|
+
integration_inventory = json_response[integration_inventory_list_key]
|
|
971
|
+
print_h1 "Integration Inventory [#{integration['name']}]", parse_list_subtitles(options), options
|
|
972
|
+
if integration_inventory.empty?
|
|
973
|
+
print cyan,"No inventory found.",reset,"\n"
|
|
974
|
+
else
|
|
975
|
+
list_columns = {
|
|
976
|
+
"ID" => 'id',
|
|
977
|
+
"Name" => 'name',
|
|
978
|
+
"Description" => 'description',
|
|
979
|
+
"Tenant Default" => lambda {|it| (format_list(it['tenants'].collect {|t| t['name'] }) rescue "") },
|
|
980
|
+
}
|
|
981
|
+
print as_pretty_table(integration_inventory, list_columns.upcase_keys!, options)
|
|
982
|
+
print_results_pagination(json_response)
|
|
983
|
+
end
|
|
984
|
+
print reset,"\n"
|
|
985
|
+
end
|
|
986
|
+
return 0, nil
|
|
987
|
+
end
|
|
988
|
+
|
|
989
|
+
def get_inventory(args)
|
|
990
|
+
params = {}
|
|
991
|
+
options = {}
|
|
992
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
993
|
+
opts.banner = subcommand_usage("[integration] [inventory]")
|
|
994
|
+
build_standard_get_options(opts, options)
|
|
995
|
+
opts.footer = <<-EOT
|
|
996
|
+
Get details about a specific integration inventory item.
|
|
997
|
+
[integration] is required. This is the name or id of an integration.
|
|
998
|
+
[inventory] is required. This is the name or id of an integration inventory item.
|
|
999
|
+
Only certain types of integrations support this operation, such as Ansible Tower.
|
|
1000
|
+
EOT
|
|
1001
|
+
end
|
|
1002
|
+
optparse.parse!(args)
|
|
1003
|
+
verify_args!(args:args, optparse:optparse, min:2)
|
|
1004
|
+
connect(options)
|
|
1005
|
+
integration = find_integration_by_name_or_id(args[0])
|
|
1006
|
+
return 1, "integration not found for #{args[0]}" if integration.nil?
|
|
1007
|
+
params.merge!(parse_query_options(options))
|
|
1008
|
+
id_list = parse_id_list(args[1..-1])
|
|
1009
|
+
return run_command_for_each_arg(id_list) do |arg|
|
|
1010
|
+
_get_inventory(integration, arg, params, options)
|
|
1011
|
+
end
|
|
1012
|
+
end
|
|
1013
|
+
|
|
1014
|
+
def _get_inventory(integration, id, params, options)
|
|
1015
|
+
integration_object = nil
|
|
1016
|
+
if id.to_s !~ /\A\d{1,}\Z/
|
|
1017
|
+
integration_inventory = find_integration_inventory_by_name_or_id(integration['id'], id)
|
|
1018
|
+
return 1, "integration inventory not found for #{id}" if integration_inventory.nil?
|
|
1019
|
+
id = integration_inventory['id']
|
|
1020
|
+
end
|
|
1021
|
+
@integrations_interface.setopts(options)
|
|
1022
|
+
if options[:dry_run]
|
|
1023
|
+
print_dry_run @integrations_interface.dry.get_inventory(integration['id'], id, params)
|
|
1024
|
+
return
|
|
1025
|
+
end
|
|
1026
|
+
json_response = @integrations_interface.get_inventory(integration['id'], id, params)
|
|
1027
|
+
integration_inventory = json_response[integration_inventory_object_key]
|
|
1028
|
+
render_response(json_response, options, integration_inventory_object_key) do
|
|
1029
|
+
print_h1 "Integration Inventory Details", [], options
|
|
1030
|
+
print cyan
|
|
1031
|
+
show_columns = {
|
|
1032
|
+
"ID" => 'id',
|
|
1033
|
+
"Name" => 'name',
|
|
1034
|
+
"Description" => 'description',
|
|
1035
|
+
"Tenant Default" => lambda {|it| (format_list(it['tenants'].collect {|t| t['name'] }) rescue "") },
|
|
1036
|
+
}
|
|
1037
|
+
print_description_list(show_columns, integration_inventory, options)
|
|
1038
|
+
print reset,"\n"
|
|
1039
|
+
end
|
|
1040
|
+
return 0, nil
|
|
1041
|
+
end
|
|
1042
|
+
|
|
1043
|
+
def update_inventory(args)
|
|
1044
|
+
options = {}
|
|
1045
|
+
params = {}
|
|
1046
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
1047
|
+
opts.banner = subcommand_usage("[integration] [inventory] [options]")
|
|
1048
|
+
opts.on('--tenants [LIST]', String, "Tenant Default, comma separated list of account IDs") do |val|
|
|
1049
|
+
options[:tenants] = parse_array(val)
|
|
1050
|
+
end
|
|
1051
|
+
build_standard_update_options(opts, options)
|
|
1052
|
+
opts.footer = <<-EOT
|
|
1053
|
+
Update an integration inventory item.
|
|
1054
|
+
[integration] is required. This is the name or id of an integration.
|
|
1055
|
+
[inventory] is required. This is the name or id of an integration inventory item.
|
|
1056
|
+
Only certain types of integrations support this operation, such as Ansible Tower.
|
|
1057
|
+
EOT
|
|
1058
|
+
end
|
|
1059
|
+
optparse.parse!(args)
|
|
1060
|
+
verify_args!(args:args, optparse:optparse, count:2)
|
|
1061
|
+
connect(options)
|
|
1062
|
+
integration = find_integration_by_name_or_id(args[0])
|
|
1063
|
+
return 1, "integration not found for #{args[0]}" if integration.nil?
|
|
1064
|
+
integration_inventory = find_integration_inventory_by_name_or_id(integration['id'], args[1])
|
|
1065
|
+
return 1, "integration inventory not found for #{args[1]}" if integration_inventory.nil?
|
|
1066
|
+
# construct payload
|
|
1067
|
+
object_key = integration_inventory_object_key
|
|
1068
|
+
payload = build_payload(options, object_key)
|
|
1069
|
+
if options[:tenants]
|
|
1070
|
+
#params['tenants'] = options[:tenants]
|
|
1071
|
+
params['tenants'] = options[:tenants].collect do |val|
|
|
1072
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
|
1073
|
+
val.to_i
|
|
1074
|
+
else
|
|
1075
|
+
# todo: use /api/options/allTenants to avoid permission errors here..
|
|
1076
|
+
record = find_by_name_or_id(:account, val)
|
|
1077
|
+
if record.nil?
|
|
1078
|
+
exit 1 #return 1, "Tenant not found by '#{val}'"
|
|
1079
|
+
else
|
|
1080
|
+
record['id']
|
|
1081
|
+
end
|
|
1082
|
+
end
|
|
1083
|
+
end
|
|
1084
|
+
end
|
|
1085
|
+
payload.deep_merge!({object_key => params})
|
|
1086
|
+
if payload.empty? || payload[object_key].empty?
|
|
1087
|
+
raise_command_error "Specify at least one option to update.\n#{optparse}"
|
|
1088
|
+
end
|
|
1089
|
+
# make request
|
|
1090
|
+
@integrations_interface.setopts(options)
|
|
1091
|
+
if options[:dry_run]
|
|
1092
|
+
print_dry_run @integrations_interface.dry.update_inventory(integration['id'], integration_inventory['id'], payload)
|
|
1093
|
+
return
|
|
1094
|
+
end
|
|
1095
|
+
json_response = @integrations_interface.update_inventory(integration['id'], integration_inventory['id'], payload)
|
|
1096
|
+
integration_inventory = json_response[object_key]
|
|
1097
|
+
render_response(json_response, options, object_key) do
|
|
1098
|
+
print_green_success "Updated integration inventory #{integration_inventory['name']}"
|
|
1099
|
+
# return _get_inventory(integration, integration_inventory["id"], {}, options)
|
|
1100
|
+
end
|
|
1101
|
+
return 0, nil
|
|
1102
|
+
end
|
|
1103
|
+
|
|
939
1104
|
private
|
|
940
1105
|
|
|
941
1106
|
def format_integration_type(integration)
|
|
@@ -999,7 +1164,7 @@ EOT
|
|
|
999
1164
|
return json_response[integration_object_key]
|
|
1000
1165
|
rescue RestClient::Exception => e
|
|
1001
1166
|
if e.response && e.response.code == 404
|
|
1002
|
-
print_red_alert "
|
|
1167
|
+
print_red_alert "Integration not found by id '#{id}'"
|
|
1003
1168
|
else
|
|
1004
1169
|
raise e
|
|
1005
1170
|
end
|
|
@@ -1010,7 +1175,7 @@ EOT
|
|
|
1010
1175
|
json_response = @integrations_interface.list({name: name.to_s})
|
|
1011
1176
|
integrations = json_response[integration_list_key]
|
|
1012
1177
|
if integrations.empty?
|
|
1013
|
-
print_red_alert "
|
|
1178
|
+
print_red_alert "Integration not found by name '#{name}'"
|
|
1014
1179
|
return nil
|
|
1015
1180
|
elsif integrations.size > 1
|
|
1016
1181
|
print_red_alert "#{integrations.size} integrations found by name '#{name}'"
|
|
@@ -1075,7 +1240,7 @@ EOT
|
|
|
1075
1240
|
return json_response[integration_object_key]
|
|
1076
1241
|
rescue RestClient::Exception => e
|
|
1077
1242
|
if e.response && e.response.code == 404
|
|
1078
|
-
print_red_alert "
|
|
1243
|
+
print_red_alert "Integration not found by id '#{id}'"
|
|
1079
1244
|
else
|
|
1080
1245
|
raise e
|
|
1081
1246
|
end
|
|
@@ -1086,7 +1251,7 @@ EOT
|
|
|
1086
1251
|
json_response = @integration_types_interface.list(params.merge({name: name.to_s}))
|
|
1087
1252
|
integration_types = json_response[integration_type_list_key]
|
|
1088
1253
|
if integration_types.empty?
|
|
1089
|
-
print_red_alert "
|
|
1254
|
+
print_red_alert "Integration type not found by name '#{name}'"
|
|
1090
1255
|
return nil
|
|
1091
1256
|
elsif integration_types.size > 1
|
|
1092
1257
|
print_red_alert "#{integration_types.size} integration types found by name '#{name}'"
|
|
@@ -1196,4 +1361,50 @@ EOT
|
|
|
1196
1361
|
end
|
|
1197
1362
|
end
|
|
1198
1363
|
|
|
1364
|
+
def integration_inventory_object_key
|
|
1365
|
+
'inventory'
|
|
1366
|
+
end
|
|
1367
|
+
|
|
1368
|
+
def integration_inventory_list_key
|
|
1369
|
+
'inventory'
|
|
1370
|
+
end
|
|
1371
|
+
|
|
1372
|
+
def find_integration_inventory_by_name_or_id(integration_id, val)
|
|
1373
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
|
1374
|
+
return find_integration_inventory_by_id(integration_id, val)
|
|
1375
|
+
else
|
|
1376
|
+
return find_integration_inventory_by_name(integration_id, val)
|
|
1377
|
+
end
|
|
1378
|
+
end
|
|
1379
|
+
|
|
1380
|
+
def find_integration_inventory_by_id(integration_id, id)
|
|
1381
|
+
begin
|
|
1382
|
+
json_response = @integrations_interface.get_inventory(integration_id, id.to_i)
|
|
1383
|
+
return json_response[integration_inventory_object_key]
|
|
1384
|
+
rescue RestClient::Exception => e
|
|
1385
|
+
if e.response && e.response.code == 404
|
|
1386
|
+
print_red_alert "Inventory not found by id '#{id}'"
|
|
1387
|
+
else
|
|
1388
|
+
raise e
|
|
1389
|
+
end
|
|
1390
|
+
end
|
|
1391
|
+
end
|
|
1392
|
+
|
|
1393
|
+
def find_integration_inventory_by_name(integration_id, name)
|
|
1394
|
+
json_response = @integrations_interface.list_inventory(integration_id, {name: name.to_s})
|
|
1395
|
+
integration_inventory = json_response[integration_inventory_list_key]
|
|
1396
|
+
if integration_inventory.empty?
|
|
1397
|
+
print_red_alert "Inventory not found by name '#{name}'"
|
|
1398
|
+
return nil
|
|
1399
|
+
elsif integration_inventory.size > 1
|
|
1400
|
+
print_red_alert "#{integration_inventory.size} inventory found by name '#{name}'"
|
|
1401
|
+
puts_error as_pretty_table(integration_inventory, [:id, :name], {color:red})
|
|
1402
|
+
print_red_alert "Try using ID instead"
|
|
1403
|
+
print reset,"\n"
|
|
1404
|
+
return nil
|
|
1405
|
+
else
|
|
1406
|
+
return integration_inventory[0]
|
|
1407
|
+
end
|
|
1408
|
+
end
|
|
1409
|
+
|
|
1199
1410
|
end
|