morpheus-cli 5.3.1 → 5.3.2.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/account_groups_interface.rb +0 -6
- data/lib/morpheus/api/accounts_interface.rb +4 -36
- data/lib/morpheus/api/api_client.rb +120 -106
- data/lib/morpheus/api/appliance_settings_interface.rb +6 -9
- data/lib/morpheus/api/approvals_interface.rb +5 -8
- data/lib/morpheus/api/apps_interface.rb +0 -7
- data/lib/morpheus/api/archive_buckets_interface.rb +9 -16
- data/lib/morpheus/api/archive_files_interface.rb +0 -6
- data/lib/morpheus/api/auth_interface.rb +4 -4
- data/lib/morpheus/api/backup_settings_interface.rb +5 -8
- data/lib/morpheus/api/blueprints_interface.rb +1 -7
- data/lib/morpheus/api/budgets_interface.rb +0 -6
- data/lib/morpheus/api/cloud_datastores_interface.rb +0 -6
- data/lib/morpheus/api/cloud_folders_interface.rb +1 -7
- data/lib/morpheus/api/cloud_policies_interface.rb +0 -6
- data/lib/morpheus/api/cloud_resource_pools_interface.rb +0 -6
- data/lib/morpheus/api/clouds_interface.rb +0 -6
- data/lib/morpheus/api/clusters_interface.rb +39 -42
- data/lib/morpheus/api/containers_interface.rb +0 -6
- data/lib/morpheus/api/custom_instance_types_interface.rb +0 -6
- data/lib/morpheus/api/cypher_interface.rb +0 -6
- data/lib/morpheus/api/datastores_interface.rb +4 -7
- data/lib/morpheus/api/deploy_interface.rb +1 -6
- data/lib/morpheus/api/environments_interface.rb +0 -6
- data/lib/morpheus/api/execute_schedules_interface.rb +0 -6
- data/lib/morpheus/api/execution_request_interface.rb +0 -6
- data/lib/morpheus/api/file_copy_request_interface.rb +2 -9
- data/lib/morpheus/api/group_policies_interface.rb +0 -6
- data/lib/morpheus/api/groups_interface.rb +0 -7
- data/lib/morpheus/api/guidance_interface.rb +9 -12
- data/lib/morpheus/api/health_interface.rb +0 -6
- data/lib/morpheus/api/image_builder_boot_scripts_interface.rb +0 -6
- data/lib/morpheus/api/image_builder_image_builds_interface.rb +0 -6
- data/lib/morpheus/api/image_builder_interface.rb +3 -9
- data/lib/morpheus/api/image_builder_preseed_scripts_interface.rb +0 -6
- data/lib/morpheus/api/instance_types_interface.rb +0 -7
- data/lib/morpheus/api/instances_interface.rb +8 -19
- data/lib/morpheus/api/integrations_interface.rb +30 -0
- data/lib/morpheus/api/invoice_line_items_interface.rb +4 -9
- data/lib/morpheus/api/jobs_interface.rb +11 -14
- data/lib/morpheus/api/key_pairs_interface.rb +0 -6
- data/lib/morpheus/api/library_cluster_layouts_interface.rb +0 -6
- data/lib/morpheus/api/library_container_scripts_interface.rb +0 -6
- data/lib/morpheus/api/library_container_templates_interface.rb +0 -6
- data/lib/morpheus/api/library_container_types_interface.rb +0 -6
- data/lib/morpheus/api/library_container_upgrades_interface.rb +0 -6
- data/lib/morpheus/api/library_instance_types_interface.rb +0 -6
- data/lib/morpheus/api/library_layouts_interface.rb +0 -6
- data/lib/morpheus/api/library_spec_template_types_interface.rb +0 -6
- data/lib/morpheus/api/library_spec_templates_interface.rb +0 -6
- data/lib/morpheus/api/license_interface.rb +0 -6
- data/lib/morpheus/api/load_balancer_pools_interface.rb +9 -0
- data/lib/morpheus/api/load_balancer_types_interface.rb +9 -0
- data/lib/morpheus/api/load_balancer_virtual_servers_interface.rb +9 -0
- data/lib/morpheus/api/load_balancers_interface.rb +4 -59
- data/lib/morpheus/api/log_settings_interface.rb +9 -12
- data/lib/morpheus/api/logs_interface.rb +0 -6
- data/lib/morpheus/api/monitoring_alerts_interface.rb +0 -6
- data/lib/morpheus/api/monitoring_apps_interface.rb +0 -6
- data/lib/morpheus/api/monitoring_checks_interface.rb +0 -6
- data/lib/morpheus/api/monitoring_contacts_interface.rb +0 -6
- data/lib/morpheus/api/monitoring_groups_interface.rb +0 -6
- data/lib/morpheus/api/monitoring_incidents_interface.rb +0 -6
- data/lib/morpheus/api/monitoring_interface.rb +6 -12
- data/lib/morpheus/api/network_domain_records_interface.rb +0 -6
- data/lib/morpheus/api/network_domains_interface.rb +0 -6
- data/lib/morpheus/api/network_groups_interface.rb +0 -6
- data/lib/morpheus/api/network_pool_ips_interface.rb +0 -6
- data/lib/morpheus/api/network_pool_servers_interface.rb +0 -6
- data/lib/morpheus/api/network_pools_interface.rb +0 -6
- data/lib/morpheus/api/network_proxies_interface.rb +0 -6
- data/lib/morpheus/api/network_routers_interface.rb +56 -6
- data/lib/morpheus/api/network_security_servers_interface.rb +6 -9
- data/lib/morpheus/api/network_services_interface.rb +0 -14
- data/lib/morpheus/api/network_subnets_interface.rb +0 -6
- data/lib/morpheus/api/network_types_interface.rb +1 -7
- data/lib/morpheus/api/networks_interface.rb +0 -6
- data/lib/morpheus/api/option_type_lists_interface.rb +18 -12
- data/lib/morpheus/api/option_types_interface.rb +0 -6
- data/lib/morpheus/api/options_interface.rb +0 -6
- data/lib/morpheus/api/packages_interface.rb +0 -6
- data/lib/morpheus/api/policies_interface.rb +1 -8
- data/lib/morpheus/api/power_schedules_interface.rb +0 -6
- data/lib/morpheus/api/price_sets_interface.rb +8 -11
- data/lib/morpheus/api/prices_interface.rb +12 -15
- data/lib/morpheus/api/processes_interface.rb +0 -6
- data/lib/morpheus/api/provision_types_interface.rb +0 -6
- data/lib/morpheus/api/provisioning_license_types_interface.rb +0 -6
- data/lib/morpheus/api/provisioning_licenses_interface.rb +0 -6
- data/lib/morpheus/api/provisioning_settings_interface.rb +6 -9
- data/lib/morpheus/api/reports_interface.rb +0 -6
- data/lib/morpheus/api/roles_interface.rb +0 -6
- data/lib/morpheus/api/secondary_read_interface.rb +25 -0
- data/lib/morpheus/api/secondary_rest_interface.rb +42 -0
- data/lib/morpheus/api/security_group_rules_interface.rb +0 -7
- data/lib/morpheus/api/security_groups_interface.rb +0 -6
- data/lib/morpheus/api/server_types_interface.rb +0 -6
- data/lib/morpheus/api/servers_interface.rb +0 -6
- data/lib/morpheus/api/service_plans_interface.rb +11 -14
- data/lib/morpheus/api/storage_providers_interface.rb +9 -16
- data/lib/morpheus/api/subnet_types_interface.rb +1 -7
- data/lib/morpheus/api/subnets_interface.rb +0 -6
- data/lib/morpheus/api/task_sets_interface.rb +0 -6
- data/lib/morpheus/api/tasks_interface.rb +0 -6
- data/lib/morpheus/api/user_groups_interface.rb +0 -6
- data/lib/morpheus/api/user_sources_interface.rb +0 -6
- data/lib/morpheus/api/users_interface.rb +0 -6
- data/lib/morpheus/api/virtual_images_interface.rb +0 -6
- data/lib/morpheus/api/whitelabel_settings_interface.rb +8 -11
- data/lib/morpheus/api/wiki_interface.rb +0 -6
- data/lib/morpheus/cli/access_token_command.rb +1 -1
- data/lib/morpheus/cli/account_groups_command.rb +4 -4
- data/lib/morpheus/cli/apps.rb +9 -9
- data/lib/morpheus/cli/archives_command.rb +5 -5
- data/lib/morpheus/cli/blueprints_command.rb +5 -5
- data/lib/morpheus/cli/boot_scripts_command.rb +1 -1
- data/lib/morpheus/cli/change_password_command.rb +4 -4
- data/lib/morpheus/cli/cli_command.rb +11 -10
- data/lib/morpheus/cli/clouds.rb +2 -2
- data/lib/morpheus/cli/clusters.rb +2 -2
- data/lib/morpheus/cli/credentials.rb +4 -11
- data/lib/morpheus/cli/environments_command.rb +1 -1
- data/lib/morpheus/cli/execute_schedules_command.rb +3 -3
- data/lib/morpheus/cli/hosts.rb +8 -8
- data/lib/morpheus/cli/image_builder_command.rb +6 -6
- data/lib/morpheus/cli/instance_types.rb +1 -1
- data/lib/morpheus/cli/instances.rb +93 -64
- data/lib/morpheus/cli/integrations_command.rb +567 -1
- data/lib/morpheus/cli/invoices_command.rb +75 -67
- data/lib/morpheus/cli/key_pairs.rb +2 -2
- data/lib/morpheus/cli/library_cluster_layouts_command.rb +2 -3
- data/lib/morpheus/cli/library_container_scripts_command.rb +4 -5
- data/lib/morpheus/cli/library_container_templates_command.rb +5 -1
- data/lib/morpheus/cli/library_container_types_command.rb +8 -9
- data/lib/morpheus/cli/library_instance_types_command.rb +6 -7
- data/lib/morpheus/cli/library_layouts_command.rb +9 -5
- data/lib/morpheus/cli/library_option_lists_command.rb +72 -20
- data/lib/morpheus/cli/library_option_types_command.rb +8 -4
- data/lib/morpheus/cli/library_spec_templates_command.rb +3 -4
- data/lib/morpheus/cli/library_upgrades_command.rb +6 -6
- data/lib/morpheus/cli/license.rb +2 -2
- data/lib/morpheus/cli/load_balancer_types.rb +37 -0
- data/lib/morpheus/cli/load_balancers.rb +149 -314
- data/lib/morpheus/cli/log_settings_command.rb +7 -3
- data/lib/morpheus/cli/login.rb +3 -1
- data/lib/morpheus/cli/mixins/load_balancers_helper.rb +156 -0
- data/lib/morpheus/cli/mixins/print_helper.rb +11 -0
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -2
- data/lib/morpheus/cli/mixins/rest_command.rb +657 -0
- data/lib/morpheus/cli/network_routers_command.rb +1183 -185
- data/lib/morpheus/cli/networks_command.rb +194 -101
- data/lib/morpheus/cli/option_types.rb +34 -40
- data/lib/morpheus/cli/policies_command.rb +0 -1
- data/lib/morpheus/cli/power_schedules_command.rb +3 -3
- data/lib/morpheus/cli/preseed_scripts_command.rb +1 -1
- data/lib/morpheus/cli/remote.rb +1 -1
- data/lib/morpheus/cli/roles.rb +9 -9
- data/lib/morpheus/cli/security_group_rules.rb +1 -1
- data/lib/morpheus/cli/setup.rb +0 -1
- data/lib/morpheus/cli/tenants_command.rb +21 -23
- data/lib/morpheus/cli/user_groups_command.rb +3 -3
- data/lib/morpheus/cli/user_sources_command.rb +3 -3
- data/lib/morpheus/cli/users.rb +3 -3
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/virtual_images.rb +1 -1
- data/lib/morpheus/cli/whoami.rb +0 -15
- data/lib/morpheus/cli/wiki_command.rb +1 -1
- data/lib/morpheus/cli.rb +1 -0
- data/lib/morpheus/ext/string.rb +41 -0
- data/lib/morpheus/formatters.rb +4 -0
- metadata +11 -2
data/lib/morpheus/cli/hosts.rb
CHANGED
|
@@ -32,14 +32,14 @@ class Morpheus::Cli::Hosts
|
|
|
32
32
|
@api_client = establish_remote_appliance_connection(opts)
|
|
33
33
|
@accounts_interface = @api_client.accounts
|
|
34
34
|
@users_interface = @api_client.users
|
|
35
|
-
@clouds_interface =
|
|
36
|
-
@options_interface =
|
|
37
|
-
@tasks_interface =
|
|
38
|
-
@task_sets_interface =
|
|
39
|
-
@servers_interface =
|
|
40
|
-
@server_types_interface =
|
|
41
|
-
@logs_interface =
|
|
42
|
-
@accounts_interface =
|
|
35
|
+
@clouds_interface = @api_client.clouds
|
|
36
|
+
@options_interface = @api_client.options
|
|
37
|
+
@tasks_interface = @api_client.tasks
|
|
38
|
+
@task_sets_interface = @api_client.task_sets
|
|
39
|
+
@servers_interface = @api_client.servers
|
|
40
|
+
@server_types_interface = @api_client.server_types
|
|
41
|
+
@logs_interface = @api_client.logs
|
|
42
|
+
@accounts_interface = @api_client.accounts
|
|
43
43
|
@active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
|
|
44
44
|
@execution_request_interface = @api_client.execution_request
|
|
45
45
|
@clusters_interface = @api_client.clusters
|
|
@@ -30,15 +30,15 @@ class Morpheus::Cli::ImageBuilderCommand
|
|
|
30
30
|
|
|
31
31
|
def connect(opts)
|
|
32
32
|
@api_client = establish_remote_appliance_connection(opts)
|
|
33
|
-
@image_builder_interface =
|
|
33
|
+
@image_builder_interface = @api_client.image_builder
|
|
34
34
|
@image_builds_interface = @image_builder_interface.image_builds
|
|
35
35
|
@boot_scripts_interface = @image_builder_interface.boot_scripts
|
|
36
36
|
@preseed_scripts_interface = @image_builder_interface.preseed_scripts
|
|
37
|
-
@groups_interface =
|
|
38
|
-
@clouds_interface =
|
|
39
|
-
@instances_interface =
|
|
40
|
-
@instance_types_interface =
|
|
41
|
-
@options_interface =
|
|
37
|
+
@groups_interface = @api_client.groups
|
|
38
|
+
@clouds_interface = @api_client.clouds
|
|
39
|
+
@instances_interface = @api_client.instances
|
|
40
|
+
@instance_types_interface = @api_client.instance_types
|
|
41
|
+
@options_interface = @api_client.options
|
|
42
42
|
@active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
|
|
43
43
|
end
|
|
44
44
|
|
|
@@ -17,7 +17,7 @@ class Morpheus::Cli::InstanceTypes
|
|
|
17
17
|
|
|
18
18
|
def connect(opts)
|
|
19
19
|
@api_client = establish_remote_appliance_connection(opts)
|
|
20
|
-
@instance_types_interface =
|
|
20
|
+
@instance_types_interface = @api_client.instance_types
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def handle(args)
|
|
@@ -130,6 +130,7 @@ class Morpheus::Cli::Instances
|
|
|
130
130
|
end
|
|
131
131
|
opts.on('-a', '--details', "Display all details: plan, stats, etc" ) do
|
|
132
132
|
options[:details] = true
|
|
133
|
+
params['details'] = true # get more data from server this way
|
|
133
134
|
end
|
|
134
135
|
build_standard_list_options(opts, options)
|
|
135
136
|
opts.footer = "List instances."
|
|
@@ -1201,7 +1202,15 @@ class Morpheus::Cli::Instances
|
|
|
1201
1202
|
options[:details] = true
|
|
1202
1203
|
options[:include_containers] = true
|
|
1203
1204
|
options[:include_scaling] = true
|
|
1205
|
+
options[:include_costs]
|
|
1204
1206
|
end
|
|
1207
|
+
opts.on(nil, '--details', "Alias for --all" ) do
|
|
1208
|
+
options[:details] = true
|
|
1209
|
+
options[:include_containers] = true
|
|
1210
|
+
options[:include_scaling] = true
|
|
1211
|
+
options[:include_costs]
|
|
1212
|
+
end
|
|
1213
|
+
opts.add_hidden_option('--details')
|
|
1205
1214
|
opts.on( nil, '--containers', "Display Instance Containers" ) do
|
|
1206
1215
|
options[:include_containers] = true
|
|
1207
1216
|
end
|
|
@@ -1216,9 +1225,6 @@ class Morpheus::Cli::Instances
|
|
|
1216
1225
|
opts.on( nil, '--scaling', "Display Instance Scaling Settings" ) do
|
|
1217
1226
|
options[:include_scaling] = true
|
|
1218
1227
|
end
|
|
1219
|
-
opts.on( nil, '--costs', "Display Cost and Price" ) do
|
|
1220
|
-
options[:include_costs] = true
|
|
1221
|
-
end
|
|
1222
1228
|
opts.on('--refresh [SECONDS]', String, "Refresh until status is running,failed. Default interval is #{default_refresh_interval} seconds.") do |val|
|
|
1223
1229
|
options[:refresh_until_status] ||= "running,failed"
|
|
1224
1230
|
if !val.to_s.empty?
|
|
@@ -1250,22 +1256,29 @@ class Morpheus::Cli::Instances
|
|
|
1250
1256
|
end
|
|
1251
1257
|
end
|
|
1252
1258
|
|
|
1253
|
-
def _get(
|
|
1254
|
-
|
|
1259
|
+
def _get(id, options={})
|
|
1260
|
+
params = {}
|
|
1261
|
+
params.merge!(parse_query_options(options))
|
|
1262
|
+
# Use details=true to get more details from the appliance
|
|
1263
|
+
# if options[:details] || options[:include_containers] || options[:include_scaling]
|
|
1264
|
+
if options[:details] || options[:include_containers] || options[:include_scaling]
|
|
1265
|
+
params['details'] = true
|
|
1266
|
+
end
|
|
1267
|
+
instance = nil
|
|
1268
|
+
if id.to_s !~ /\A\d{1,}\Z/
|
|
1269
|
+
instance = find_instance_by_name_or_id(id)
|
|
1270
|
+
return 1, "Instance not found by name #{id}" if instance.nil?
|
|
1271
|
+
id = instance['id']
|
|
1272
|
+
end
|
|
1255
1273
|
if options[:dry_run]
|
|
1256
|
-
@instances_interface.
|
|
1257
|
-
|
|
1258
|
-
print_dry_run @instances_interface.dry.get(arg.to_i)
|
|
1259
|
-
else
|
|
1260
|
-
print_dry_run @instances_interface.dry.get({name:arg})
|
|
1261
|
-
end
|
|
1262
|
-
return
|
|
1274
|
+
print_dry_run @instances_interface.dry.get(id, params)
|
|
1275
|
+
return 0, nil
|
|
1263
1276
|
end
|
|
1264
|
-
instance = find_instance_by_name_or_id(arg =~ /\A\d{1,}\Z/ ? arg.to_i : arg)
|
|
1265
1277
|
@instances_interface.setopts(options)
|
|
1266
|
-
json_response = @instances_interface.get(
|
|
1278
|
+
json_response = @instances_interface.get(id, params)
|
|
1267
1279
|
render_response(json_response, options, "instance") do
|
|
1268
1280
|
instance = json_response['instance']
|
|
1281
|
+
pricing = instance['instancePrice']
|
|
1269
1282
|
stats = instance['stats'] || json_response['stats'] || {}
|
|
1270
1283
|
# load_balancers = json_response['loadBalancers'] || {}
|
|
1271
1284
|
# metadata tags used to be returned as metadata and are now returned as tags
|
|
@@ -1283,7 +1296,12 @@ class Morpheus::Cli::Instances
|
|
|
1283
1296
|
# containers are fetched via separate api call
|
|
1284
1297
|
containers = nil
|
|
1285
1298
|
if options[:include_containers]
|
|
1286
|
-
|
|
1299
|
+
# todo: can use instance['containerDetails'] in api 5.2.7/5.3.2
|
|
1300
|
+
if instance['containerDetails']
|
|
1301
|
+
containers = instance['containerDetails']
|
|
1302
|
+
else
|
|
1303
|
+
containers = @instances_interface.containers(instance['id'])['containers']
|
|
1304
|
+
end
|
|
1287
1305
|
end
|
|
1288
1306
|
|
|
1289
1307
|
# threshold is fetched via separate api call too
|
|
@@ -1317,8 +1335,20 @@ class Morpheus::Cli::Instances
|
|
|
1317
1335
|
"Layout" => lambda {|it| it['layout'] ? it['layout']['name'] : '' },
|
|
1318
1336
|
"Version" => lambda {|it| it['instanceVersion'] },
|
|
1319
1337
|
"Plan" => lambda {|it| it['plan'] ? it['plan']['name'] : '' },
|
|
1320
|
-
|
|
1321
|
-
|
|
1338
|
+
"Price" => lambda {|it|
|
|
1339
|
+
if pricing
|
|
1340
|
+
pricing['price'] ? format_money(pricing['price'], (pricing['currency'] || 'USD')).to_s + ' per ' + pricing['unit'].to_s : ''
|
|
1341
|
+
elsif it['hourlyPrice']
|
|
1342
|
+
format_money(it['hourlyPrice'], (it['currency'] || 'USD')).to_s + ' per hour'
|
|
1343
|
+
end
|
|
1344
|
+
},
|
|
1345
|
+
"Cost" => lambda {|it|
|
|
1346
|
+
if pricing
|
|
1347
|
+
pricing['cost'] ? format_money(pricing['cost'], (pricing['currency'] || 'USD')).to_s + ' per ' + pricing['unit'].to_s : ''
|
|
1348
|
+
elsif it['hourlyCost']
|
|
1349
|
+
format_money(it['hourlyCost'], (it['currency'] || 'USD')).to_s + ' per hour'
|
|
1350
|
+
end
|
|
1351
|
+
},
|
|
1322
1352
|
"Environment" => 'instanceContext',
|
|
1323
1353
|
"Labels" => lambda {|it| labels ? labels.join(',') : '' },
|
|
1324
1354
|
"Tags" => lambda {|it| tags ? tags.collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
|
|
@@ -1330,6 +1360,7 @@ class Morpheus::Cli::Instances
|
|
|
1330
1360
|
end
|
|
1331
1361
|
},
|
|
1332
1362
|
#"Tenant" => lambda {|it| it['tenant'] ? it['tenant']['name'] : '' },
|
|
1363
|
+
"Apps" => lambda {|it| anded_list(it['apps'] ? it['apps'].collect {|app| app['name'] } : [])},
|
|
1333
1364
|
"Date Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
|
1334
1365
|
# "Last Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
|
|
1335
1366
|
"Power Schedule" => lambda {|it| (it['powerSchedule'] && it['powerSchedule']['type']) ? it['powerSchedule']['type']['name'] : '' },
|
|
@@ -1343,12 +1374,17 @@ class Morpheus::Cli::Instances
|
|
|
1343
1374
|
}
|
|
1344
1375
|
description_cols.delete("Labels") if labels.nil? || labels.empty?
|
|
1345
1376
|
description_cols.delete("Tags") if tags.nil? || tags.empty?
|
|
1377
|
+
description_cols.delete("Apps") if instance['apps'].nil? || instance['apps'].empty?
|
|
1346
1378
|
description_cols.delete("Power Schedule") if instance['powerSchedule'].nil?
|
|
1347
1379
|
description_cols.delete("Expire Date") if instance['expireDate'].nil?
|
|
1348
1380
|
description_cols.delete("Shutdown Date") if instance['shutdownDate'].nil?
|
|
1349
1381
|
description_cols["Removal Date"] = lambda {|it| format_local_dt(it['removalDate'])} if instance['status'] == 'pendingRemoval'
|
|
1350
1382
|
description_cols.delete("Last Deployment") if instance['lastDeploy'].nil?
|
|
1351
1383
|
description_cols.delete("Locked") if instance['locked'] != true
|
|
1384
|
+
price_value = (pricing ? pricing['price'] : instance['hourlyPrice']).to_i
|
|
1385
|
+
cost_value = (pricing ? pricing['cost'] : instance['hourlyCost']).to_i
|
|
1386
|
+
description_cols.delete("Price") if price_value == 0
|
|
1387
|
+
description_cols.delete("Cost") if cost_value == 0 || cost_value == price_value
|
|
1352
1388
|
#description_cols.delete("Environment") if instance['instanceContext'].nil?
|
|
1353
1389
|
print_description_list(description_cols, instance)
|
|
1354
1390
|
|
|
@@ -1380,15 +1416,6 @@ class Morpheus::Cli::Instances
|
|
|
1380
1416
|
print_stats_usage(stats)
|
|
1381
1417
|
end
|
|
1382
1418
|
|
|
1383
|
-
if options[:include_costs]
|
|
1384
|
-
print_h2 "Instance Cost"
|
|
1385
|
-
cost_columns = {
|
|
1386
|
-
"Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
|
1387
|
-
"Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
|
|
1388
|
-
}
|
|
1389
|
-
print_description_list(cost_columns, instance)
|
|
1390
|
-
end
|
|
1391
|
-
|
|
1392
1419
|
print reset, "\n"
|
|
1393
1420
|
|
|
1394
1421
|
# if options[:include_lb]
|
|
@@ -1478,7 +1505,7 @@ class Morpheus::Cli::Instances
|
|
|
1478
1505
|
print cyan, "Refreshing in #{options[:refresh_interval] > 1 ? options[:refresh_interval].to_i : options[:refresh_interval]} seconds"
|
|
1479
1506
|
sleep_with_dots(options[:refresh_interval])
|
|
1480
1507
|
print "\n"
|
|
1481
|
-
_get(
|
|
1508
|
+
_get(instance['id'], options)
|
|
1482
1509
|
end
|
|
1483
1510
|
end
|
|
1484
1511
|
end
|
|
@@ -2538,46 +2565,50 @@ class Morpheus::Cli::Instances
|
|
|
2538
2565
|
options = {}
|
|
2539
2566
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
2540
2567
|
opts.banner = subcommand_usage("[instance]")
|
|
2541
|
-
|
|
2568
|
+
build_standard_update_options(opts, options)
|
|
2542
2569
|
end
|
|
2543
2570
|
optparse.parse!(args)
|
|
2544
|
-
|
|
2545
|
-
puts optparse
|
|
2546
|
-
exit 1
|
|
2547
|
-
end
|
|
2571
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
|
2548
2572
|
connect(options)
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2573
|
+
instance = find_instance_by_name_or_id(args[0])
|
|
2574
|
+
return 1, "instance not found" if instance.nil?
|
|
2575
|
+
|
|
2576
|
+
payload = {}
|
|
2577
|
+
if options[:payload]
|
|
2578
|
+
payload = options[:payload]
|
|
2579
|
+
payload.deep_merge!(parse_passed_options(options))
|
|
2580
|
+
else
|
|
2557
2581
|
payload = {
|
|
2558
|
-
|
|
2582
|
+
"instance" => {:id => instance["id"]}
|
|
2559
2583
|
}
|
|
2584
|
+
payload.deep_merge!(parse_passed_options(options))
|
|
2560
2585
|
|
|
2561
2586
|
# avoid 500 error
|
|
2562
2587
|
# payload[:servicePlanOptions] = {}
|
|
2563
2588
|
|
|
2564
2589
|
puts "\nDue to limitations by most Guest Operating Systems, Disk sizes can only be expanded and not reduced.\nIf a smaller plan is selected, memory and CPU (if relevant) will be reduced but storage will not.\n\n"
|
|
2565
2590
|
|
|
2591
|
+
group_id = instance['group']['id']
|
|
2592
|
+
cloud_id = instance['cloud']['id']
|
|
2593
|
+
layout_id = instance['layout']['id']
|
|
2594
|
+
plan_id = instance['plan']['id']
|
|
2595
|
+
current_plan_name = instance['plan']['name']
|
|
2566
2596
|
# prompt for service plan
|
|
2567
2597
|
service_plans_json = @instances_interface.service_plans({zoneId: cloud_id, siteId: group_id, layoutId: layout_id})
|
|
2568
2598
|
service_plans = service_plans_json["plans"]
|
|
2569
2599
|
service_plans_dropdown = service_plans.collect {|sp| {'name' => sp["name"], 'value' => sp["id"]} } # already sorted
|
|
2570
2600
|
service_plans_dropdown.each do |plan|
|
|
2571
|
-
if plan['value'] && plan['value'].to_i == plan_id.to_i
|
|
2572
|
-
|
|
2573
|
-
|
|
2601
|
+
# if plan['value'] && plan['value'].to_i == plan_id.to_i
|
|
2602
|
+
# plan['name'] = "#{plan['name']} (current)"
|
|
2603
|
+
# current_plan_name = plan['name']
|
|
2604
|
+
# end
|
|
2574
2605
|
end
|
|
2575
|
-
plan_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'servicePlan', 'type' => 'select', 'fieldLabel' => 'Plan', 'selectOptions' => service_plans_dropdown, 'required' => true, 'description' => 'Choose the appropriately sized plan for this instance'}],options[:options])
|
|
2606
|
+
plan_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'servicePlan', 'type' => 'select', 'fieldLabel' => 'Plan', 'selectOptions' => service_plans_dropdown, 'required' => true, 'defaultValue' => current_plan_name, 'description' => 'Choose the appropriately sized plan for this instance'}],options[:options])
|
|
2576
2607
|
service_plan = service_plans.find {|sp| sp["id"] == plan_prompt['servicePlan'].to_i }
|
|
2577
2608
|
new_plan_id = service_plan["id"]
|
|
2578
2609
|
#payload[:servicePlan] = new_plan_id # ew, this api uses servicePlanId instead
|
|
2579
2610
|
#payload[:servicePlanId] = new_plan_id
|
|
2580
|
-
payload[
|
|
2611
|
+
payload["instance"]["plan"] = {"id" => service_plan["id"]}
|
|
2581
2612
|
|
|
2582
2613
|
volumes_response = @instances_interface.volumes(instance['id'])
|
|
2583
2614
|
current_volumes = volumes_response['volumes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }
|
|
@@ -2585,29 +2616,27 @@ class Morpheus::Cli::Instances
|
|
|
2585
2616
|
# prompt for volumes
|
|
2586
2617
|
volumes = prompt_resize_volumes(current_volumes, service_plan, options)
|
|
2587
2618
|
if !volumes.empty?
|
|
2588
|
-
payload[
|
|
2619
|
+
payload["volumes"] = volumes
|
|
2589
2620
|
end
|
|
2590
2621
|
|
|
2591
2622
|
# only amazon supports this option
|
|
2592
2623
|
# for now, always do this
|
|
2593
|
-
payload[
|
|
2594
|
-
@instances_interface.setopts(options)
|
|
2595
|
-
if options[:dry_run]
|
|
2596
|
-
print_dry_run @instances_interface.dry.resize(instance['id'], payload)
|
|
2597
|
-
return
|
|
2598
|
-
end
|
|
2599
|
-
json_response = @instances_interface.resize(instance['id'], payload)
|
|
2600
|
-
if options[:json]
|
|
2601
|
-
puts as_json(json_response, options)
|
|
2602
|
-
return 0
|
|
2603
|
-
else
|
|
2604
|
-
print_green_success "Resizing instance #{instance['name']}"
|
|
2605
|
-
#list([])
|
|
2606
|
-
end
|
|
2607
|
-
rescue RestClient::Exception => e
|
|
2608
|
-
print_rest_exception(e, options)
|
|
2609
|
-
exit 1
|
|
2624
|
+
payload["deleteOriginalVolumes"] = true
|
|
2610
2625
|
end
|
|
2626
|
+
payload.delete("rootVolume")
|
|
2627
|
+
(1..20).each {|i| payload.delete("dataVolume#{i}") }
|
|
2628
|
+
@instances_interface.setopts(options)
|
|
2629
|
+
if options[:dry_run]
|
|
2630
|
+
print_dry_run @instances_interface.dry.resize(instance['id'], payload)
|
|
2631
|
+
return
|
|
2632
|
+
end
|
|
2633
|
+
json_response = @instances_interface.resize(instance['id'], payload)
|
|
2634
|
+
render_response(json_response, options, 'snapshots') do
|
|
2635
|
+
print_green_success "Resizing instance #{instance['name']}"
|
|
2636
|
+
end
|
|
2637
|
+
return 0, nil
|
|
2638
|
+
|
|
2639
|
+
|
|
2611
2640
|
end
|
|
2612
2641
|
|
|
2613
2642
|
def backup(args)
|
|
@@ -2,12 +2,12 @@ require 'morpheus/cli/cli_command'
|
|
|
2
2
|
|
|
3
3
|
class Morpheus::Cli::IntegrationsCommand
|
|
4
4
|
include Morpheus::Cli::CliCommand
|
|
5
|
-
include Morpheus::Cli::AccountsHelper
|
|
6
5
|
|
|
7
6
|
set_command_name :'integrations'
|
|
8
7
|
set_command_description "Integrations: View and manage integrations"
|
|
9
8
|
|
|
10
9
|
register_subcommands :list, :get, :add, :update, :remove, :refresh
|
|
10
|
+
register_subcommands :list_objects, :get_object, :add_object, :remove_object
|
|
11
11
|
register_subcommands :list_types, :get_type
|
|
12
12
|
|
|
13
13
|
def connect(opts)
|
|
@@ -78,6 +78,9 @@ class Morpheus::Cli::IntegrationsCommand
|
|
|
78
78
|
options = {}
|
|
79
79
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
80
80
|
opts.banner = subcommand_usage("[integration]")
|
|
81
|
+
opts.on('--objects', 'Display exposed objects for the integration.') do
|
|
82
|
+
options[:show_objects] = true
|
|
83
|
+
end
|
|
81
84
|
build_standard_get_options(opts, options)
|
|
82
85
|
opts.footer = <<-EOT
|
|
83
86
|
Get details about a specific integration.
|
|
@@ -101,6 +104,9 @@ EOT
|
|
|
101
104
|
return 1, "integration not found for #{id}" if integration.nil?
|
|
102
105
|
id = integration['id']
|
|
103
106
|
end
|
|
107
|
+
if options[:show_objects]
|
|
108
|
+
params['objects'] = true
|
|
109
|
+
end
|
|
104
110
|
@integrations_interface.setopts(options)
|
|
105
111
|
if options[:dry_run]
|
|
106
112
|
print_dry_run @integrations_interface.dry.get(id, params)
|
|
@@ -137,6 +143,74 @@ EOT
|
|
|
137
143
|
show_columns.delete("Service Key") if integration['serviceKey'].nil?
|
|
138
144
|
show_columns.delete("Auth Key") if integration['authKey'].nil?
|
|
139
145
|
print_description_list(show_columns, integration, options)
|
|
146
|
+
|
|
147
|
+
if options[:show_objects]
|
|
148
|
+
# they are loaded above with ?objects=true
|
|
149
|
+
integration_objects = integration['objects']
|
|
150
|
+
if integration_objects.nil?
|
|
151
|
+
objects_json_response = @integrations_interface.list_objects(integration['id'], {})
|
|
152
|
+
integration_objects = objects_json_response[integration_object_list_key]
|
|
153
|
+
end
|
|
154
|
+
cloud_objects = integration_objects.select {|it| it['refType'] == "ComputeZone" }
|
|
155
|
+
library_objects = integration_objects.select {|it| it['refType'] == "InstanceTypeLayout" || it['refType'] == "InstanceType" }
|
|
156
|
+
blueprint_objects = integration_objects.select {|it| it['refType'] == "AppTemplate" }
|
|
157
|
+
catalog_objects = integration_objects.select {|it| it['refType'] == "CatalogItemType" }
|
|
158
|
+
if integration_objects.empty?
|
|
159
|
+
print reset,"\n"
|
|
160
|
+
print cyan,"No objects found.",reset,"\n"
|
|
161
|
+
else
|
|
162
|
+
# Exposed Clouds
|
|
163
|
+
if !cloud_objects.empty?
|
|
164
|
+
print_h2 "Exposed Clouds", [], options
|
|
165
|
+
list_columns = {
|
|
166
|
+
# "ID" => 'id',
|
|
167
|
+
"Name" => 'name',
|
|
168
|
+
# "Category" => 'category',
|
|
169
|
+
# "Ref Type" => 'refType',
|
|
170
|
+
# "Cloud ID" => 'refId',
|
|
171
|
+
"Group" => lambda {|it| it['group']['name'] rescue nil },
|
|
172
|
+
}.upcase_keys!
|
|
173
|
+
print as_pretty_table(cloud_objects, list_columns, options)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Exposed Libraries
|
|
177
|
+
if !library_objects.empty?
|
|
178
|
+
# print_h2 "Exposed Libraries", [], options
|
|
179
|
+
print_h2 "Exposed Layouts", [], options
|
|
180
|
+
list_columns = {
|
|
181
|
+
# "ID" => 'id',
|
|
182
|
+
"Name" => 'name',
|
|
183
|
+
"Version" => lambda {|it| it['layout']['instanceVersion'] rescue nil },
|
|
184
|
+
"Instance Type" => lambda {|it| it['layout']['instanceType']['name'] rescue nil },
|
|
185
|
+
"Provision Type" => lambda {|it| it['layout']['provisionType']['name'] rescue nil },
|
|
186
|
+
}.upcase_keys!
|
|
187
|
+
print as_pretty_table(library_objects, list_columns, options)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Exposed Blueprints
|
|
191
|
+
if !blueprint_objects.empty?
|
|
192
|
+
print_h2 "Exposed Blueprints", [], options
|
|
193
|
+
list_columns = {
|
|
194
|
+
# "ID" => 'id',
|
|
195
|
+
"Name" => 'name',
|
|
196
|
+
# "Type" => lambda {|it| it['blueprint']['type'] rescue nil },
|
|
197
|
+
"Blueprint" => lambda {|it| it['blueprint']['name'] rescue nil },
|
|
198
|
+
"Group" => lambda {|it| it['group']['name'] rescue nil },
|
|
199
|
+
}.upcase_keys!
|
|
200
|
+
print as_pretty_table(blueprint_objects, list_columns, options)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Exposed Catalog Items
|
|
204
|
+
if !catalog_objects.empty?
|
|
205
|
+
print_h2 "Exposed Catalog Items", [], options
|
|
206
|
+
list_columns = {
|
|
207
|
+
# "ID" => 'id',
|
|
208
|
+
"Name" => 'name',
|
|
209
|
+
}.upcase_keys!
|
|
210
|
+
print as_pretty_table(catalog_objects, list_columns, options)
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
140
214
|
print reset,"\n"
|
|
141
215
|
end
|
|
142
216
|
return 0, nil
|
|
@@ -459,6 +533,409 @@ EOT
|
|
|
459
533
|
return 0, nil
|
|
460
534
|
end
|
|
461
535
|
|
|
536
|
+
## Integration Objects
|
|
537
|
+
|
|
538
|
+
def list_objects(args)
|
|
539
|
+
options = {}
|
|
540
|
+
params = {}
|
|
541
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
542
|
+
opts.banner = subcommand_usage("[integration] [search]")
|
|
543
|
+
opts.on('-t', '--type CODE', "Filter by types: cloud, layout, blueprint, catalog") do |val|
|
|
544
|
+
params['type'] = [params['type'], val].compact.flatten.collect {|it| it.to_s.strip.split(",") }.flatten.collect {|it| it.to_s.strip }
|
|
545
|
+
end
|
|
546
|
+
build_standard_list_options(opts, options)
|
|
547
|
+
opts.footer = <<-EOT
|
|
548
|
+
List integration objects.
|
|
549
|
+
[integration] is required. This is the name or id of an integration.
|
|
550
|
+
EOT
|
|
551
|
+
end
|
|
552
|
+
optparse.parse!(args)
|
|
553
|
+
verify_args!(args:args, optparse:optparse, min:1)
|
|
554
|
+
connect(options)
|
|
555
|
+
|
|
556
|
+
integration = find_integration_by_name_or_id(args[0])
|
|
557
|
+
return 1, "integration not found for #{args[0]}" if integration.nil?
|
|
558
|
+
|
|
559
|
+
if args.count > 1
|
|
560
|
+
options[:phrase] = args[1..-1].join(" ")
|
|
561
|
+
end
|
|
562
|
+
params.merge!(parse_list_options(options))
|
|
563
|
+
@integrations_interface.setopts(options)
|
|
564
|
+
if options[:dry_run]
|
|
565
|
+
print_dry_run @integrations_interface.dry.list_objects(integration['id'], params)
|
|
566
|
+
return 0, nil
|
|
567
|
+
end
|
|
568
|
+
json_response = @integrations_interface.list_objects(integration['id'], params)
|
|
569
|
+
render_response(json_response, options, integration_list_key) do
|
|
570
|
+
integration_objects = json_response[integration_object_list_key]
|
|
571
|
+
print_h1 "Integration Objects [#{integration['name']}]", parse_list_subtitles(options), options
|
|
572
|
+
if integration_objects.empty?
|
|
573
|
+
print cyan,"No objects found.",reset,"\n"
|
|
574
|
+
else
|
|
575
|
+
list_columns = {
|
|
576
|
+
"ID" => 'id',
|
|
577
|
+
"Name" => 'name',
|
|
578
|
+
# "Category" => 'category',
|
|
579
|
+
# "Ref Type" => 'refType',
|
|
580
|
+
# "Ref ID" => 'refId',
|
|
581
|
+
# "Type" => lambda {|it| it['type'] },
|
|
582
|
+
"Type" => lambda {|it| it['type'].to_s.capitalize },
|
|
583
|
+
"Ref ID" => 'refId',
|
|
584
|
+
}.upcase_keys!
|
|
585
|
+
print as_pretty_table(integration_objects, list_columns, options)
|
|
586
|
+
print_results_pagination(json_response)
|
|
587
|
+
end
|
|
588
|
+
print reset,"\n"
|
|
589
|
+
end
|
|
590
|
+
return 0, nil
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
def get_object(args)
|
|
594
|
+
params = {}
|
|
595
|
+
options = {}
|
|
596
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
597
|
+
opts.banner = subcommand_usage("[integration] [object]")
|
|
598
|
+
opts.on( '-c', '--config', "Display config only, for blueprint objects" ) do
|
|
599
|
+
options[:show_config] = true
|
|
600
|
+
end
|
|
601
|
+
build_standard_get_options(opts, options)
|
|
602
|
+
opts.footer = <<-EOT
|
|
603
|
+
Get details about a specific integration object.
|
|
604
|
+
[integration] is required. This is the name or id of an integration.
|
|
605
|
+
[object] is required. This is the name or id of an integration object.
|
|
606
|
+
EOT
|
|
607
|
+
end
|
|
608
|
+
optparse.parse!(args)
|
|
609
|
+
verify_args!(args:args, optparse:optparse, min:1)
|
|
610
|
+
connect(options)
|
|
611
|
+
optparse.parse!(args)
|
|
612
|
+
verify_args!(args:args, optparse:optparse, min:2)
|
|
613
|
+
connect(options)
|
|
614
|
+
integration = find_integration_by_name_or_id(args[0])
|
|
615
|
+
return 1, "integration not found for #{args[0]}" if integration.nil?
|
|
616
|
+
params.merge!(parse_query_options(options))
|
|
617
|
+
id_list = parse_id_list(args[1..-1])
|
|
618
|
+
return run_command_for_each_arg(id_list) do |arg|
|
|
619
|
+
_get_object(integration, arg, params, options)
|
|
620
|
+
end
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
def _get_object(integration, id, params, options)
|
|
624
|
+
integration_object = nil
|
|
625
|
+
if id.to_s !~ /\A\d{1,}\Z/
|
|
626
|
+
integration_object = find_integration_object_by_name_or_id(integration['id'], id)
|
|
627
|
+
return 1, "integration object not found for #{id}" if integration_object.nil?
|
|
628
|
+
id = integration_object['id']
|
|
629
|
+
end
|
|
630
|
+
@integrations_interface.setopts(options)
|
|
631
|
+
if options[:dry_run]
|
|
632
|
+
print_dry_run @integrations_interface.dry.get_object(integration['id'], id, params)
|
|
633
|
+
return
|
|
634
|
+
end
|
|
635
|
+
json_response = @integrations_interface.get_object(integration['id'], id, params)
|
|
636
|
+
integration_object = json_response[integration_object_object_key]
|
|
637
|
+
config = integration_object['config']
|
|
638
|
+
# export just the config as json (default) or yaml
|
|
639
|
+
if options[:show_config]
|
|
640
|
+
unless options[:json] || options[:yaml] || options[:csv]
|
|
641
|
+
options[:json] = :true
|
|
642
|
+
end
|
|
643
|
+
return render_with_format(config, options)
|
|
644
|
+
end
|
|
645
|
+
render_response(json_response, options, integration_object_object_key) do
|
|
646
|
+
print_h1 "Integration Object Details", [], options
|
|
647
|
+
print cyan
|
|
648
|
+
if integration_object['type'] == 'cloud'
|
|
649
|
+
show_columns = {
|
|
650
|
+
"Integration" => lambda {|it| integration['name'] },
|
|
651
|
+
"Object ID" => 'id',
|
|
652
|
+
"Name" => 'name',
|
|
653
|
+
"Type" => lambda {|it| it['type'].to_s.capitalize },
|
|
654
|
+
# "Cloud" => lambda {|it| it['cloud']['name'] rescue nil },
|
|
655
|
+
# "Ref Type" => 'refType',
|
|
656
|
+
"Ref ID" => 'refId',
|
|
657
|
+
# "Reference" => lambda {|it| ("#{it['refType']}: #{it['refId']}" rescue nil) },
|
|
658
|
+
"Group" => lambda {|it| it['group']['name'] rescue nil },
|
|
659
|
+
}
|
|
660
|
+
print_description_list(show_columns, integration_object, options)
|
|
661
|
+
print reset,"\n"
|
|
662
|
+
elsif integration_object['type'] == 'layout'
|
|
663
|
+
show_columns = {
|
|
664
|
+
"Integration" => lambda {|it| integration['name'] },
|
|
665
|
+
"Object ID" => 'id',
|
|
666
|
+
"Name" => 'name',
|
|
667
|
+
"Type" => lambda {|it| it['type'].to_s.capitalize },
|
|
668
|
+
# "Layout" => lambda {|it| it['layout']['name'] rescue nil },
|
|
669
|
+
# "Ref Type" => 'refType',
|
|
670
|
+
"Ref ID" => 'refId',
|
|
671
|
+
# "Reference" => lambda {|it| ("#{it['refType']}: #{it['refId']}" rescue nil) },
|
|
672
|
+
"Provision Type" => lambda {|it| it['layout']['provisionType']['name'] rescue nil },
|
|
673
|
+
"Instance Type" => lambda {|it| it['layout']['instanceType']['name'] rescue nil },
|
|
674
|
+
"Version" => lambda {|it| it['layout']['instanceVersion'] rescue nil },
|
|
675
|
+
}
|
|
676
|
+
print_description_list(show_columns, integration_object, options)
|
|
677
|
+
print reset,"\n"
|
|
678
|
+
elsif integration_object['type'] == 'blueprint'
|
|
679
|
+
show_columns = {
|
|
680
|
+
"Integration" => lambda {|it| integration['name'] },
|
|
681
|
+
"Object ID" => 'id',
|
|
682
|
+
"Name" => 'name',
|
|
683
|
+
"Type" => lambda {|it| it['type'].to_s.capitalize },
|
|
684
|
+
# "Ref Type" => 'refType',
|
|
685
|
+
"Ref ID" => 'refId',
|
|
686
|
+
# "Reference" => lambda {|it| ("#{it['refType']}: #{it['refId']}" rescue nil) },
|
|
687
|
+
# "Blueprint Type" => lambda {|it| it['blueprint']['type'] rescue nil },
|
|
688
|
+
"Blueprint" => lambda {|it| it['blueprint']['name'] rescue nil },
|
|
689
|
+
"Group" => lambda {|it| it['group']['name'] rescue nil },
|
|
690
|
+
"Default Cloud" => lambda {|it| it['defaultCloud']['name'] rescue nil },
|
|
691
|
+
"Environment" => lambda {|it| it['environment'] rescue nil },
|
|
692
|
+
}
|
|
693
|
+
print_description_list(show_columns, integration_object, options)
|
|
694
|
+
# print reset,"\n"
|
|
695
|
+
# print_h2 "App Spec"
|
|
696
|
+
print_h2 "Config"
|
|
697
|
+
if config
|
|
698
|
+
# config_string = integration_object['config'] || ""
|
|
699
|
+
config_string = config.is_a?(Hash) ? JSON.pretty_generate(config) : config.to_s
|
|
700
|
+
#print reset,config_string,"\n",reset
|
|
701
|
+
config_lines = config_string.split("\n")
|
|
702
|
+
config_line_count = config_lines.size
|
|
703
|
+
max_lines = 10
|
|
704
|
+
if config_lines.size > max_lines
|
|
705
|
+
config_string = config_lines.first(max_lines).join("\n")
|
|
706
|
+
config_string << "\n\n"
|
|
707
|
+
config_string << "#{dark}(#{(config_line_count - max_lines)} more lines were not shown, use -c to show the config)#{reset}"
|
|
708
|
+
#config_string << "\n"
|
|
709
|
+
end
|
|
710
|
+
# strip --- yaml header
|
|
711
|
+
if config_string[0..3] == "---\n"
|
|
712
|
+
config_string = config_string[4..-1]
|
|
713
|
+
end
|
|
714
|
+
print reset,config_string.chomp("\n"),"\n",reset
|
|
715
|
+
else
|
|
716
|
+
print reset,"(blank)","\n",reset
|
|
717
|
+
end
|
|
718
|
+
print reset,"\n"
|
|
719
|
+
elsif integration_object['type'] == 'catalog'
|
|
720
|
+
show_columns = {
|
|
721
|
+
"Integration" => lambda {|it| integration['name'] },
|
|
722
|
+
"Object ID" => 'id',
|
|
723
|
+
"Name" => 'name',
|
|
724
|
+
"Type" => lambda {|it| it['type'].to_s.capitalize },
|
|
725
|
+
"Catalog Item" => lambda {|it| it['catalogItemType']['name'] rescue nil },
|
|
726
|
+
# "Ref Type" => 'refType',
|
|
727
|
+
# "Ref ID" => 'refId',
|
|
728
|
+
# "Reference" => lambda {|it| ("#{it['refType']}: #{it['refId']}" rescue nil) },
|
|
729
|
+
}
|
|
730
|
+
print_description_list(show_columns, integration_object, options)
|
|
731
|
+
print reset,"\n"
|
|
732
|
+
else
|
|
733
|
+
# Unknown type?
|
|
734
|
+
show_columns = {
|
|
735
|
+
"Integration" => lambda {|it| integration['name'] },
|
|
736
|
+
"Object ID" => 'id',
|
|
737
|
+
"Name" => 'name',
|
|
738
|
+
"Type" => lambda {|it| it['type'].to_s.capitalize },
|
|
739
|
+
"Ref Type" => 'refType',
|
|
740
|
+
"Ref ID" => 'refId',
|
|
741
|
+
}
|
|
742
|
+
print_description_list(show_columns, integration_object, options)
|
|
743
|
+
print reset,"\n"
|
|
744
|
+
end
|
|
745
|
+
end
|
|
746
|
+
return 0, nil
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
def add_object(args)
|
|
750
|
+
options = {}
|
|
751
|
+
params = {}
|
|
752
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
753
|
+
opts.banner = subcommand_usage("[integration] [name] -t CODE [options]")
|
|
754
|
+
# opts.on('-t', '--type CODE', "Integration ObjectType code, see `#{command_name} list-types` for available type codes") do |val|
|
|
755
|
+
# options[:options]['type'] = val
|
|
756
|
+
# end
|
|
757
|
+
build_option_type_options(opts, options, add_integration_object_option_types)
|
|
758
|
+
opts.on('--config-file FILE', String, "Config from a local JSON or YAML file") do |val|
|
|
759
|
+
options[:config_file] = val.to_s
|
|
760
|
+
file_content = nil
|
|
761
|
+
full_filename = File.expand_path(options[:config_file])
|
|
762
|
+
if File.exists?(full_filename)
|
|
763
|
+
file_content = File.read(full_filename)
|
|
764
|
+
else
|
|
765
|
+
print_red_alert "File not found: #{full_filename}"
|
|
766
|
+
return 1
|
|
767
|
+
end
|
|
768
|
+
parse_result = parse_json_or_yaml(file_content)
|
|
769
|
+
config_map = parse_result[:data]
|
|
770
|
+
if config_map.nil?
|
|
771
|
+
# todo: bubble up JSON.parse error message
|
|
772
|
+
raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:err]}"
|
|
773
|
+
#raise_command_error "Failed to parse config as valid YAML or JSON."
|
|
774
|
+
else
|
|
775
|
+
params['config'] = config_map
|
|
776
|
+
options[:options]['config'] = params['config'] # or file_content
|
|
777
|
+
end
|
|
778
|
+
end
|
|
779
|
+
# build_option_type_options(opts, options, add_integration_object_advanced_option_types)
|
|
780
|
+
build_standard_add_options(opts, options)
|
|
781
|
+
opts.footer = <<-EOT
|
|
782
|
+
Create a new integration object.
|
|
783
|
+
[integration] is required. This is the name or id of an integration.
|
|
784
|
+
[name] is required. This is the name of the new integration
|
|
785
|
+
Configuration options vary by integration type.
|
|
786
|
+
EOT
|
|
787
|
+
end
|
|
788
|
+
optparse.parse!(args)
|
|
789
|
+
verify_args!(args:args, optparse:optparse, min:1, max:2)
|
|
790
|
+
options[:options]['name'] = args[1] if args[1]
|
|
791
|
+
connect(options)
|
|
792
|
+
integration = find_integration_by_name_or_id(args[0])
|
|
793
|
+
return 1, "integration not found for #{args[0]}" if integration.nil?
|
|
794
|
+
payload = {}
|
|
795
|
+
if options[:payload]
|
|
796
|
+
payload = options[:payload]
|
|
797
|
+
payload.deep_merge!({integration_object_object_key => parse_passed_options(options)})
|
|
798
|
+
else
|
|
799
|
+
payload.deep_merge!({integration_object_object_key => parse_passed_options(options)})
|
|
800
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt(add_integration_object_option_types(), options[:options], @api_client, options[:params])
|
|
801
|
+
v_prompt.deep_compact!
|
|
802
|
+
params.deep_merge!(v_prompt)
|
|
803
|
+
advanced_config = Morpheus::Cli::OptionTypes.no_prompt(add_integration_object_advanced_option_types, options[:options], @api_client, options[:params])
|
|
804
|
+
advanced_config.deep_compact!
|
|
805
|
+
params.deep_merge!(advanced_config)
|
|
806
|
+
params.booleanize!
|
|
807
|
+
|
|
808
|
+
# convert config string to a map
|
|
809
|
+
# config = params['config']
|
|
810
|
+
# if config && config.is_a?(String)
|
|
811
|
+
# parse_result = parse_json_or_yaml(config)
|
|
812
|
+
# config_map = parse_result[:data]
|
|
813
|
+
# if config_map.nil?
|
|
814
|
+
# # todo: bubble up JSON.parse error message
|
|
815
|
+
# raise_command_error "Failed to parse config as YAML or JSON. Error: #{parse_result[:err]}"
|
|
816
|
+
# #raise_command_error "Failed to parse config as valid YAML or JSON."
|
|
817
|
+
# else
|
|
818
|
+
# params['config'] = config_map
|
|
819
|
+
# end
|
|
820
|
+
# end
|
|
821
|
+
# if params['config']
|
|
822
|
+
# config_map = params.delete('config')
|
|
823
|
+
# params['config'] = as_json(config_map, {:pretty_json => true})
|
|
824
|
+
# end
|
|
825
|
+
# if options[:interactive_config]
|
|
826
|
+
# print_h2 "App Config"
|
|
827
|
+
# config_map = prompt_app_config(options)
|
|
828
|
+
# params['config'] = config_map
|
|
829
|
+
# end
|
|
830
|
+
|
|
831
|
+
payload[integration_object_object_key].deep_merge!(params)
|
|
832
|
+
end
|
|
833
|
+
@integrations_interface.setopts(options)
|
|
834
|
+
if options[:dry_run]
|
|
835
|
+
print_dry_run @integrations_interface.dry.create_object(integration['id'], payload)
|
|
836
|
+
return 0, nil
|
|
837
|
+
end
|
|
838
|
+
json_response = @integrations_interface.create_object(integration['id'], payload)
|
|
839
|
+
integration_object = json_response[integration_object_object_key]
|
|
840
|
+
render_response(json_response, options, integration_object_object_key) do
|
|
841
|
+
print_green_success "Added integration_object #{integration_object['name']}"
|
|
842
|
+
return _get_object(integration, integration_object["id"], {}, options)
|
|
843
|
+
end
|
|
844
|
+
return 0, nil
|
|
845
|
+
end
|
|
846
|
+
|
|
847
|
+
# def update_object(args)
|
|
848
|
+
# options = {}
|
|
849
|
+
# params = {}
|
|
850
|
+
# optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
851
|
+
# opts.banner = subcommand_usage("[integration] [object] [options]")
|
|
852
|
+
# build_option_type_options(opts, options, update_integration_option_types)
|
|
853
|
+
# build_option_type_options(opts, options, update_integration_advanced_option_types)
|
|
854
|
+
# build_standard_update_options(opts, options)
|
|
855
|
+
# opts.footer = <<-EOT
|
|
856
|
+
# Update an integration.
|
|
857
|
+
# [integration] is required. This is the name or id of an integration.
|
|
858
|
+
# [object] is required. This is the name or id of an integration object.
|
|
859
|
+
# EOT
|
|
860
|
+
# end
|
|
861
|
+
# optparse.parse!(args)
|
|
862
|
+
# verify_args!(args:args, optparse:optparse, count:2)
|
|
863
|
+
# connect(options)
|
|
864
|
+
# integration = find_integration_by_name_or_id(args[0])
|
|
865
|
+
# return 1, "integration not found for #{args[0]}" if integration.nil?
|
|
866
|
+
# integration_object = find_integration_object_by_name_or_id(integration['id'], args[1])
|
|
867
|
+
# return 1, "integration object not found for #{args[1]}" if integration_object.nil?
|
|
868
|
+
# payload = {}
|
|
869
|
+
# if options[:payload]
|
|
870
|
+
# payload = options[:payload]
|
|
871
|
+
# payload.deep_merge!({integration_object_object_key => parse_passed_options(options)})
|
|
872
|
+
# else
|
|
873
|
+
# payload.deep_merge!({integration_object_object_key => parse_passed_options(options)})
|
|
874
|
+
# # do not prompt on update
|
|
875
|
+
# v_prompt = Morpheus::Cli::OptionTypes.no_prompt(update_integration_object_option_types, options[:options], @api_client, options[:params])
|
|
876
|
+
# v_prompt.deep_compact!
|
|
877
|
+
# params.deep_merge!(v_prompt)
|
|
878
|
+
# advanced_config = Morpheus::Cli::OptionTypes.no_prompt(update_integration_object_advanced_option_types, options[:options], @api_client, options[:params])
|
|
879
|
+
# advanced_config.deep_compact!
|
|
880
|
+
# params.deep_merge!(advanced_config)
|
|
881
|
+
# # convert checkbox "on" and "off" to true and false
|
|
882
|
+
# params.booleanize!
|
|
883
|
+
# # massage association params a bit
|
|
884
|
+
|
|
885
|
+
# payload.deep_merge!({integration_object_object_key => params})
|
|
886
|
+
# if payload[integration_object_object_key].empty? # || options[:no_prompt]
|
|
887
|
+
# raise_command_error "Specify at least one option to update.\n#{optparse}"
|
|
888
|
+
# end
|
|
889
|
+
# end
|
|
890
|
+
# @integrations_interface.setopts(options)
|
|
891
|
+
# if options[:dry_run]
|
|
892
|
+
# print_dry_run @integrations_interface.dry.update_object(integration['id'], integration_object['id'], payload)
|
|
893
|
+
# return
|
|
894
|
+
# end
|
|
895
|
+
# json_response = @integrations_interface.update_object(integration['id'], integration_object['id'], payload)
|
|
896
|
+
# integration_object = json_response[integration_object_object_key]
|
|
897
|
+
# render_response(json_response, options, integration_object_object_key) do
|
|
898
|
+
# print_green_success "Updated integration object #{integration_object['name']}"
|
|
899
|
+
# return _get_object(integration, integration_object["id"], {}, options)
|
|
900
|
+
# end
|
|
901
|
+
# return 0, nil
|
|
902
|
+
# end
|
|
903
|
+
|
|
904
|
+
def remove_object(args)
|
|
905
|
+
options = {}
|
|
906
|
+
params = {}
|
|
907
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
|
908
|
+
opts.banner = subcommand_usage("[integration] [options]")
|
|
909
|
+
build_standard_remove_options(opts, options)
|
|
910
|
+
opts.footer = <<-EOT
|
|
911
|
+
Delete an integration object.
|
|
912
|
+
[integration] is required. This is the name or id of an integration.
|
|
913
|
+
[object] is required. This is the name or id of an integration object.
|
|
914
|
+
EOT
|
|
915
|
+
end
|
|
916
|
+
optparse.parse!(args)
|
|
917
|
+
verify_args!(args:args, optparse:optparse, count:2)
|
|
918
|
+
connect(options)
|
|
919
|
+
integration = find_integration_by_name_or_id(args[0])
|
|
920
|
+
return 1, "integration not found for #{args[0]}" if integration.nil?
|
|
921
|
+
integration_object = find_integration_object_by_name_or_id(integration['id'], args[1])
|
|
922
|
+
return 1, "integration object not found for #{args[1]}" if integration_object.nil?
|
|
923
|
+
params.merge!(parse_query_options(options))
|
|
924
|
+
@integrations_interface.setopts(options)
|
|
925
|
+
if options[:dry_run]
|
|
926
|
+
print_dry_run @integrations_interface.dry.destroy_object(integration['id'], integration_object['id'], params)
|
|
927
|
+
return
|
|
928
|
+
end
|
|
929
|
+
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the integration object #{integration_object['name']}?")
|
|
930
|
+
return 9, "aborted command"
|
|
931
|
+
end
|
|
932
|
+
json_response = @integrations_interface.destroy_object(integration['id'], integration_object['id'], params)
|
|
933
|
+
render_response(json_response, options) do
|
|
934
|
+
print_green_success "Removed integration object #{integration_object['name']}"
|
|
935
|
+
end
|
|
936
|
+
return 0, nil
|
|
937
|
+
end
|
|
938
|
+
|
|
462
939
|
private
|
|
463
940
|
|
|
464
941
|
def format_integration_type(integration)
|
|
@@ -641,4 +1118,93 @@ EOT
|
|
|
641
1118
|
end
|
|
642
1119
|
end
|
|
643
1120
|
|
|
1121
|
+
## Integration Object helpers
|
|
1122
|
+
|
|
1123
|
+
def add_integration_object_option_types
|
|
1124
|
+
[
|
|
1125
|
+
{'code' => 'integrationObject.type', 'shorthand' => '-t', 'switch' => 'type', 'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'optionSource' => 'integrationObjectTypes', 'required' => true, 'description' => "Integration Object Type eg. cloud, layout, blueprint, catalog", 'displayOrder' => 1},
|
|
1126
|
+
# {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => false, 'description' => 'Display Name of the integration object, default is the name of the referenced object', 'displayOrder' => 2},
|
|
1127
|
+
{'dependsOnCode' => 'integrationObject.type:cloud', 'switch' => 'group', 'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'optionSource' => 'groups', 'required' => true, 'description' => 'Group', 'displayOrder' => 3},
|
|
1128
|
+
{'dependsOnCode' => 'integrationObject.type:cloud', 'switch' => 'cloud', 'fieldName' => 'cloud', 'fieldLabel' => 'Cloud', 'type' => 'select', 'optionSource' => 'clouds', 'required' => true, 'description' => 'Cloud', 'displayOrder' => 4},
|
|
1129
|
+
{'dependsOnCode' => 'integrationObject.type:layout', 'switch' => 'instance-type', 'fieldName' => 'instanceType', 'fieldLabel' => 'Instance Type', 'type' => 'select', 'optionSource' => 'instanceTypes', 'required' => true, 'description' => 'Instance Type', 'displayOrder' => 5},
|
|
1130
|
+
{'dependsOnCode' => 'integrationObject.type:layout', 'switch' => 'technology', 'fieldName' => 'zoneType', 'fieldLabel' => 'Cloud Type', 'type' => 'select', 'optionSource' => 'zoneTypes', 'required' => true, 'description' => 'Cloud Type (Technology)', 'displayOrder' => 5},
|
|
1131
|
+
{'dependsOnCode' => 'integrationObject.type:layout', 'switch' => 'layout', 'fieldName' => 'layout', 'fieldLabel' => 'Layout', 'type' => 'select', 'optionSource' => 'layouts', 'required' => true, 'description' => 'Layout', 'displayOrder' => 6},
|
|
1132
|
+
{'dependsOnCode' => 'integrationObject.type:blueprint', 'fieldName' => 'name', 'fieldLabel' => 'Catalog Item Name', 'type' => 'text', 'required' => true, 'description' => 'Display Name of the integration object', 'displayOrder' => 7},
|
|
1133
|
+
{'dependsOnCode' => 'integrationObject.type:blueprint', 'switch' => 'blueprint', 'fieldName' => 'blueprint', 'fieldLabel' => 'Blueprint', 'type' => 'select', 'optionSource' => 'blueprints', 'required' => true, 'description' => 'Blueprint', 'displayOrder' => 8, 'noParams' => true},
|
|
1134
|
+
{'dependsOnCode' => 'integrationObject.type:blueprint', 'switch' => 'group', 'fieldName' => 'group', 'fieldLabel' => 'Group', 'type' => 'select', 'optionSource' => 'groups', 'required' => true, 'description' => 'Group', 'displayOrder' => 9},
|
|
1135
|
+
{'dependsOnCode' => 'integrationObject.type:blueprint', 'switch' => 'default-cloud', 'fieldName' => 'defaultCloud', 'fieldLabel' => 'Default Cloud', 'type' => 'select', 'optionSource' => 'clouds', 'required' => false, 'description' => 'Default Cloud', 'displayOrder' => 10},
|
|
1136
|
+
{'dependsOnCode' => 'integrationObject.type:blueprint', 'switch' => 'environment', 'fieldName' => 'environment', 'fieldLabel' => 'Environment', 'type' => 'select', 'optionSource' => 'environments', 'required' => false, 'description' => 'Environment', 'displayOrder' => 11},
|
|
1137
|
+
{'dependsOnCode' => 'integrationObject.type:blueprint', 'switch' => 'config', 'fieldName' => 'config', 'fieldLabel' => 'Config', 'type' => 'code-editor', 'required' => true, 'description' => 'Config JSON', 'displayOrder' => 12},
|
|
1138
|
+
{'dependsOnCode' => 'integrationObject.type:catalog', 'switch' => 'catalog', 'fieldName' => 'catalog', 'fieldLabel' => 'Catalog Item', 'type' => 'select', 'optionSource' => 'catalogItemTypes', 'required' => true, 'description' => 'Catalog Item', 'displayOrder' => 13},
|
|
1139
|
+
]
|
|
1140
|
+
end
|
|
1141
|
+
|
|
1142
|
+
def add_integration_object_advanced_option_types
|
|
1143
|
+
[]
|
|
1144
|
+
end
|
|
1145
|
+
|
|
1146
|
+
def update_integration_object_option_types
|
|
1147
|
+
list = add_integration_object_option_types.collect {|it|
|
|
1148
|
+
it.delete('required')
|
|
1149
|
+
it.delete('defaultValue')
|
|
1150
|
+
it
|
|
1151
|
+
}
|
|
1152
|
+
list = list.reject {|it| ["type"].include? it['fieldName'] }
|
|
1153
|
+
list
|
|
1154
|
+
end
|
|
1155
|
+
|
|
1156
|
+
def update_integration_object_advanced_option_types
|
|
1157
|
+
add_integration_advanced_option_types.collect {|it|
|
|
1158
|
+
it.delete('required')
|
|
1159
|
+
it.delete('defaultValue')
|
|
1160
|
+
it
|
|
1161
|
+
}
|
|
1162
|
+
end
|
|
1163
|
+
|
|
1164
|
+
def integration_object_object_key
|
|
1165
|
+
'object'
|
|
1166
|
+
end
|
|
1167
|
+
|
|
1168
|
+
def integration_object_list_key
|
|
1169
|
+
'objects'
|
|
1170
|
+
end
|
|
1171
|
+
|
|
1172
|
+
def find_integration_object_by_name_or_id(integration_id, val)
|
|
1173
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
|
1174
|
+
return find_integration_object_by_id(integration_id, val)
|
|
1175
|
+
else
|
|
1176
|
+
return find_integration_object_by_name(integration_id, val)
|
|
1177
|
+
end
|
|
1178
|
+
end
|
|
1179
|
+
|
|
1180
|
+
def find_integration_object_by_id(integration_id, id)
|
|
1181
|
+
begin
|
|
1182
|
+
json_response = @integrations_interface.get_object(integration_id, id.to_i)
|
|
1183
|
+
return json_response[integration_object_object_key]
|
|
1184
|
+
rescue RestClient::Exception => e
|
|
1185
|
+
if e.response && e.response.code == 404
|
|
1186
|
+
print_red_alert "integration object not found by id '#{id}'"
|
|
1187
|
+
else
|
|
1188
|
+
raise e
|
|
1189
|
+
end
|
|
1190
|
+
end
|
|
1191
|
+
end
|
|
1192
|
+
|
|
1193
|
+
def find_integration_object_by_name(integration_id, name)
|
|
1194
|
+
json_response = @integrations_interface.list_objects(integration_id, {name: name.to_s})
|
|
1195
|
+
integration_objects = json_response[integration_object_list_key]
|
|
1196
|
+
if integration_objects.empty?
|
|
1197
|
+
print_red_alert "integration object not found by name '#{name}'"
|
|
1198
|
+
return nil
|
|
1199
|
+
elsif integration_objects.size > 1
|
|
1200
|
+
print_red_alert "#{integration_objects.size} integration object found by name '#{name}'"
|
|
1201
|
+
puts_error as_pretty_table(integration_objects, [:id, :name], {color:red})
|
|
1202
|
+
print_red_alert "Try using ID instead"
|
|
1203
|
+
print reset,"\n"
|
|
1204
|
+
return nil
|
|
1205
|
+
else
|
|
1206
|
+
return integration_objects[0]
|
|
1207
|
+
end
|
|
1208
|
+
end
|
|
1209
|
+
|
|
644
1210
|
end
|