mtncloud-cli 1.0.0
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 +7 -0
- data/.dockerignore +20 -0
- data/.github/pull_request_template.md +14 -0
- data/.github/workflows/ci.yml +56 -0
- data/.github/workflows/release.yml +46 -0
- data/.gitignore +25 -0
- data/CLAUDE.md +24 -0
- data/CONTRIBUTING.md +91 -0
- data/Dockerfile +19 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +23 -0
- data/README.md +187 -0
- data/Rakefile +26 -0
- data/bin/mcs +3 -0
- data/bin/mtncloud +27 -0
- data/lib/mtncloud/api/account_groups_interface.rb +48 -0
- data/lib/mtncloud/api/account_users_interface.rb +68 -0
- data/lib/mtncloud/api/accounts_interface.rb +9 -0
- data/lib/mtncloud/api/activity_interface.rb +9 -0
- data/lib/mtncloud/api/affinity_groups_interface.rb +46 -0
- data/lib/mtncloud/api/api_client.rb +1091 -0
- data/lib/mtncloud/api/appliance_settings_interface.rb +49 -0
- data/lib/mtncloud/api/approvals_interface.rb +32 -0
- data/lib/mtncloud/api/apps_interface.rb +180 -0
- data/lib/mtncloud/api/archive_buckets_interface.rb +116 -0
- data/lib/mtncloud/api/archive_files_interface.rb +173 -0
- data/lib/mtncloud/api/audit_interface.rb +9 -0
- data/lib/mtncloud/api/auth_interface.rb +58 -0
- data/lib/mtncloud/api/backup_jobs_interface.rb +13 -0
- data/lib/mtncloud/api/backup_restores_interface.rb +27 -0
- data/lib/mtncloud/api/backup_results_interface.rb +32 -0
- data/lib/mtncloud/api/backup_service_types_interface.rb +9 -0
- data/lib/mtncloud/api/backup_services_interface.rb +9 -0
- data/lib/mtncloud/api/backup_settings_interface.rb +20 -0
- data/lib/mtncloud/api/backup_types_interface.rb +9 -0
- data/lib/mtncloud/api/backups_interface.rb +21 -0
- data/lib/mtncloud/api/billing_interface.rb +34 -0
- data/lib/mtncloud/api/blueprints_interface.rb +70 -0
- data/lib/mtncloud/api/body_io.rb +22 -0
- data/lib/mtncloud/api/budgets_interface.rb +48 -0
- data/lib/mtncloud/api/catalog_item_types_interface.rb +29 -0
- data/lib/mtncloud/api/certificate_types_interface.rb +14 -0
- data/lib/mtncloud/api/certificates_interface.rb +9 -0
- data/lib/mtncloud/api/clients_interface.rb +41 -0
- data/lib/mtncloud/api/cloud_datastores_interface.rb +48 -0
- data/lib/mtncloud/api/cloud_folders_interface.rb +41 -0
- data/lib/mtncloud/api/cloud_policies_interface.rb +41 -0
- data/lib/mtncloud/api/cloud_resource_pools_interface.rb +66 -0
- data/lib/mtncloud/api/clouds_interface.rb +217 -0
- data/lib/mtncloud/api/clusters_interface.rb +471 -0
- data/lib/mtncloud/api/containers_interface.rb +145 -0
- data/lib/mtncloud/api/credential_types_interface.rb +9 -0
- data/lib/mtncloud/api/credentials_interface.rb +9 -0
- data/lib/mtncloud/api/custom_instance_types_interface.rb +99 -0
- data/lib/mtncloud/api/cypher_interface.rb +51 -0
- data/lib/mtncloud/api/dashboard_interface.rb +14 -0
- data/lib/mtncloud/api/datastores_interface.rb +21 -0
- data/lib/mtncloud/api/deploy_interface.rb +44 -0
- data/lib/mtncloud/api/deployments_interface.rb +79 -0
- data/lib/mtncloud/api/distributed_workers_interface.rb +41 -0
- data/lib/mtncloud/api/email_templates_interface.rb +53 -0
- data/lib/mtncloud/api/environments_interface.rb +48 -0
- data/lib/mtncloud/api/execute_schedules_interface.rb +71 -0
- data/lib/mtncloud/api/execution_request_interface.rb +27 -0
- data/lib/mtncloud/api/file_copy_request_interface.rb +68 -0
- data/lib/mtncloud/api/forgot_password_interface.rb +17 -0
- data/lib/mtncloud/api/group_policies_interface.rb +41 -0
- data/lib/mtncloud/api/groups_interface.rb +73 -0
- data/lib/mtncloud/api/guidance_interface.rb +44 -0
- data/lib/mtncloud/api/guidance_settings_interface.rb +17 -0
- data/lib/mtncloud/api/health_interface.rb +100 -0
- data/lib/mtncloud/api/host_vm_groups_interface.rb +37 -0
- data/lib/mtncloud/api/hub_interface.rb +25 -0
- data/lib/mtncloud/api/image_builder_boot_scripts_interface.rb +41 -0
- data/lib/mtncloud/api/image_builder_image_builds_interface.rb +73 -0
- data/lib/mtncloud/api/image_builder_interface.rb +20 -0
- data/lib/mtncloud/api/image_builder_preseed_scripts_interface.rb +41 -0
- data/lib/mtncloud/api/instance_types_interface.rb +20 -0
- data/lib/mtncloud/api/instances_interface.rb +453 -0
- data/lib/mtncloud/api/integration_types_interface.rb +14 -0
- data/lib/mtncloud/api/integrations_interface.rb +74 -0
- data/lib/mtncloud/api/invoice_line_items_interface.rb +9 -0
- data/lib/mtncloud/api/invoices_interface.rb +28 -0
- data/lib/mtncloud/api/jobs_interface.rb +83 -0
- data/lib/mtncloud/api/key_pairs_interface.rb +57 -0
- data/lib/mtncloud/api/library_cluster_layouts_interface.rb +47 -0
- data/lib/mtncloud/api/library_cluster_packages_interface.rb +60 -0
- data/lib/mtncloud/api/library_container_scripts_interface.rb +43 -0
- data/lib/mtncloud/api/library_container_templates_interface.rb +43 -0
- data/lib/mtncloud/api/library_container_types_interface.rb +59 -0
- data/lib/mtncloud/api/library_container_upgrades_interface.rb +60 -0
- data/lib/mtncloud/api/library_instance_types_interface.rb +74 -0
- data/lib/mtncloud/api/library_layouts_interface.rb +69 -0
- data/lib/mtncloud/api/library_operating_systems_interface.rb +63 -0
- data/lib/mtncloud/api/library_spec_template_types_interface.rb +43 -0
- data/lib/mtncloud/api/library_spec_templates_interface.rb +43 -0
- data/lib/mtncloud/api/license_interface.rb +30 -0
- data/lib/mtncloud/api/load_balancer_monitors_interface.rb +9 -0
- data/lib/mtncloud/api/load_balancer_pool_nodes_interface.rb +8 -0
- data/lib/mtncloud/api/load_balancer_pools_interface.rb +9 -0
- data/lib/mtncloud/api/load_balancer_pools_secondary_interface.rb +9 -0
- data/lib/mtncloud/api/load_balancer_profiles_interface.rb +9 -0
- data/lib/mtncloud/api/load_balancer_types_interface.rb +9 -0
- data/lib/mtncloud/api/load_balancer_virtual_servers_interface.rb +18 -0
- data/lib/mtncloud/api/load_balancers_interface.rb +14 -0
- data/lib/mtncloud/api/log_settings_interface.rb +44 -0
- data/lib/mtncloud/api/logs_interface.rb +37 -0
- data/lib/mtncloud/api/migrations_interface.rb +49 -0
- data/lib/mtncloud/api/monitoring_alerts_interface.rb +39 -0
- data/lib/mtncloud/api/monitoring_apps_interface.rb +69 -0
- data/lib/mtncloud/api/monitoring_checks_interface.rb +103 -0
- data/lib/mtncloud/api/monitoring_contacts_interface.rb +41 -0
- data/lib/mtncloud/api/monitoring_groups_interface.rb +77 -0
- data/lib/mtncloud/api/monitoring_incidents_interface.rb +107 -0
- data/lib/mtncloud/api/monitoring_interface.rb +35 -0
- data/lib/mtncloud/api/monitoring_settings_interface.rb +21 -0
- data/lib/mtncloud/api/network_dhcp_relays_interface.rb +36 -0
- data/lib/mtncloud/api/network_dhcp_servers_interface.rb +36 -0
- data/lib/mtncloud/api/network_domain_records_interface.rb +41 -0
- data/lib/mtncloud/api/network_domains_interface.rb +41 -0
- data/lib/mtncloud/api/network_edge_clusters_interface.rb +26 -0
- data/lib/mtncloud/api/network_floating_ips_interface.rb +40 -0
- data/lib/mtncloud/api/network_groups_interface.rb +41 -0
- data/lib/mtncloud/api/network_pool_ips_interface.rb +41 -0
- data/lib/mtncloud/api/network_pool_server_types_interface.rb +9 -0
- data/lib/mtncloud/api/network_pool_servers_interface.rb +48 -0
- data/lib/mtncloud/api/network_pools_interface.rb +41 -0
- data/lib/mtncloud/api/network_proxies_interface.rb +41 -0
- data/lib/mtncloud/api/network_routers_interface.rb +181 -0
- data/lib/mtncloud/api/network_security_server_types_interface.rb +9 -0
- data/lib/mtncloud/api/network_security_servers_interface.rb +27 -0
- data/lib/mtncloud/api/network_server_groups_interface.rb +7 -0
- data/lib/mtncloud/api/network_server_types_interface.rb +9 -0
- data/lib/mtncloud/api/network_servers_interface.rb +102 -0
- data/lib/mtncloud/api/network_services_interface.rb +63 -0
- data/lib/mtncloud/api/network_static_routes_interface.rb +36 -0
- data/lib/mtncloud/api/network_subnets_interface.rb +42 -0
- data/lib/mtncloud/api/network_types_interface.rb +20 -0
- data/lib/mtncloud/api/networks_interface.rb +48 -0
- data/lib/mtncloud/api/option_type_forms_interface.rb +9 -0
- data/lib/mtncloud/api/option_type_lists_interface.rb +53 -0
- data/lib/mtncloud/api/option_types_interface.rb +41 -0
- data/lib/mtncloud/api/options_interface.rb +17 -0
- data/lib/mtncloud/api/packages_interface.rb +112 -0
- data/lib/mtncloud/api/ping_interface.rb +22 -0
- data/lib/mtncloud/api/plugins_interface.rb +22 -0
- data/lib/mtncloud/api/policies_interface.rb +56 -0
- data/lib/mtncloud/api/power_schedules_interface.rb +71 -0
- data/lib/mtncloud/api/price_sets_interface.rb +39 -0
- data/lib/mtncloud/api/prices_interface.rb +71 -0
- data/lib/mtncloud/api/processes_interface.rb +40 -0
- data/lib/mtncloud/api/projects_interface.rb +33 -0
- data/lib/mtncloud/api/provision_types_interface.rb +24 -0
- data/lib/mtncloud/api/provisioning_license_types_interface.rb +31 -0
- data/lib/mtncloud/api/provisioning_licenses_interface.rb +60 -0
- data/lib/mtncloud/api/provisioning_settings_interface.rb +26 -0
- data/lib/mtncloud/api/read_interface.rb +24 -0
- data/lib/mtncloud/api/reports_interface.rb +70 -0
- data/lib/mtncloud/api/resource_pool_groups_interface.rb +51 -0
- data/lib/mtncloud/api/rest_interface.rb +37 -0
- data/lib/mtncloud/api/roles_interface.rb +151 -0
- data/lib/mtncloud/api/scale_thresholds_interface.rb +9 -0
- data/lib/mtncloud/api/search_interface.rb +13 -0
- data/lib/mtncloud/api/secondary_read_interface.rb +25 -0
- data/lib/mtncloud/api/secondary_rest_interface.rb +42 -0
- data/lib/mtncloud/api/security_group_rules_interface.rb +35 -0
- data/lib/mtncloud/api/security_groups_interface.rb +56 -0
- data/lib/mtncloud/api/security_package_types_interface.rb +9 -0
- data/lib/mtncloud/api/security_packages_interface.rb +9 -0
- data/lib/mtncloud/api/security_scans_interface.rb +9 -0
- data/lib/mtncloud/api/server_devices_interface.rb +30 -0
- data/lib/mtncloud/api/server_types_interface.rb +20 -0
- data/lib/mtncloud/api/servers_interface.rb +230 -0
- data/lib/mtncloud/api/service_catalog_interface.rb +89 -0
- data/lib/mtncloud/api/service_plans_interface.rb +62 -0
- data/lib/mtncloud/api/setup_interface.rb +46 -0
- data/lib/mtncloud/api/snapshots_interface.rb +19 -0
- data/lib/mtncloud/api/storage_datastores_interface.rb +44 -0
- data/lib/mtncloud/api/storage_providers_interface.rb +151 -0
- data/lib/mtncloud/api/storage_server_types_interface.rb +14 -0
- data/lib/mtncloud/api/storage_servers_interface.rb +9 -0
- data/lib/mtncloud/api/storage_volume_types_interface.rb +9 -0
- data/lib/mtncloud/api/storage_volumes_interface.rb +24 -0
- data/lib/mtncloud/api/subnet_types_interface.rb +20 -0
- data/lib/mtncloud/api/subnets_interface.rb +41 -0
- data/lib/mtncloud/api/support_bundles_interface.rb +46 -0
- data/lib/mtncloud/api/system_types_interface.rb +13 -0
- data/lib/mtncloud/api/systems_interface.rb +55 -0
- data/lib/mtncloud/api/task_sets_interface.rb +52 -0
- data/lib/mtncloud/api/tasks_interface.rb +66 -0
- data/lib/mtncloud/api/tokens_interface.rb +39 -0
- data/lib/mtncloud/api/usage_interface.rb +18 -0
- data/lib/mtncloud/api/user_groups_interface.rb +59 -0
- data/lib/mtncloud/api/user_settings_interface.rb +90 -0
- data/lib/mtncloud/api/user_sources_interface.rb +99 -0
- data/lib/mtncloud/api/users_interface.rb +33 -0
- data/lib/mtncloud/api/vdi_allocations_interface.rb +9 -0
- data/lib/mtncloud/api/vdi_apps_interface.rb +9 -0
- data/lib/mtncloud/api/vdi_gateways_interface.rb +9 -0
- data/lib/mtncloud/api/vdi_interface.rb +28 -0
- data/lib/mtncloud/api/vdi_pools_interface.rb +19 -0
- data/lib/mtncloud/api/virtual_images_interface.rb +210 -0
- data/lib/mtncloud/api/virtual_servers_interface.rb +9 -0
- data/lib/mtncloud/api/virtual_switches_interface.rb +9 -0
- data/lib/mtncloud/api/whitelabel_settings_interface.rb +57 -0
- data/lib/mtncloud/api/whoami_interface.rb +13 -0
- data/lib/mtncloud/api/wiki_interface.rb +48 -0
- data/lib/mtncloud/api.rb +12 -0
- data/lib/mtncloud/benchmarking.rb +259 -0
- data/lib/mtncloud/cli/cli_command.rb +2281 -0
- data/lib/mtncloud/cli/cli_registry.rb +337 -0
- data/lib/mtncloud/cli/commands/access_token_command.rb +201 -0
- data/lib/mtncloud/cli/commands/account_groups_command.rb +530 -0
- data/lib/mtncloud/cli/commands/activity_command.rb +149 -0
- data/lib/mtncloud/cli/commands/affinity_groups_command.rb +554 -0
- data/lib/mtncloud/cli/commands/alias_command.rb +278 -0
- data/lib/mtncloud/cli/commands/appliance_settings_command.rb +382 -0
- data/lib/mtncloud/cli/commands/approvals_command.rb +236 -0
- data/lib/mtncloud/cli/commands/apps.rb +2549 -0
- data/lib/mtncloud/cli/commands/archives_command.rb +2161 -0
- data/lib/mtncloud/cli/commands/audit.rb +188 -0
- data/lib/mtncloud/cli/commands/backup_jobs_command.rb +366 -0
- data/lib/mtncloud/cli/commands/backup_restores_command.rb +144 -0
- data/lib/mtncloud/cli/commands/backup_results_command.rb +149 -0
- data/lib/mtncloud/cli/commands/backup_services_command.rb +44 -0
- data/lib/mtncloud/cli/commands/backup_settings_command.rb +184 -0
- data/lib/mtncloud/cli/commands/backup_types_command.rb +53 -0
- data/lib/mtncloud/cli/commands/backups_command.rb +674 -0
- data/lib/mtncloud/cli/commands/benchmark_command.rb +458 -0
- data/lib/mtncloud/cli/commands/blueprints_command.rb +2297 -0
- data/lib/mtncloud/cli/commands/boot_scripts_command.rb +379 -0
- data/lib/mtncloud/cli/commands/budgets_command.rb +754 -0
- data/lib/mtncloud/cli/commands/cat_command.rb +45 -0
- data/lib/mtncloud/cli/commands/catalog_item_types_command.rb +858 -0
- data/lib/mtncloud/cli/commands/certificates_command.rb +575 -0
- data/lib/mtncloud/cli/commands/change_password_command.rb +132 -0
- data/lib/mtncloud/cli/commands/clients_command.rb +331 -0
- data/lib/mtncloud/cli/commands/cloud_datastores_command.rb +543 -0
- data/lib/mtncloud/cli/commands/cloud_folders_command.rb +512 -0
- data/lib/mtncloud/cli/commands/cloud_resource_pools_command.rb +870 -0
- data/lib/mtncloud/cli/commands/clouds.rb +2037 -0
- data/lib/mtncloud/cli/commands/clouds_types.rb +140 -0
- data/lib/mtncloud/cli/commands/cluster_types.rb +179 -0
- data/lib/mtncloud/cli/commands/clusters.rb +5855 -0
- data/lib/mtncloud/cli/commands/coloring_command.rb +82 -0
- data/lib/mtncloud/cli/commands/containers_command.rb +967 -0
- data/lib/mtncloud/cli/commands/credential_types_command.rb +36 -0
- data/lib/mtncloud/cli/commands/credentials_command.rb +124 -0
- data/lib/mtncloud/cli/commands/curl_command.rb +168 -0
- data/lib/mtncloud/cli/commands/cypher_command.rb +587 -0
- data/lib/mtncloud/cli/commands/dashboard_command.rb +300 -0
- data/lib/mtncloud/cli/commands/debug_command.rb +75 -0
- data/lib/mtncloud/cli/commands/deploy.rb +485 -0
- data/lib/mtncloud/cli/commands/deployments.rb +923 -0
- data/lib/mtncloud/cli/commands/deploys.rb +485 -0
- data/lib/mtncloud/cli/commands/distributed_workers_command.rb +282 -0
- data/lib/mtncloud/cli/commands/echo_command.rb +61 -0
- data/lib/mtncloud/cli/commands/edit_profile_command.rb +57 -0
- data/lib/mtncloud/cli/commands/edit_rc_command.rb +77 -0
- data/lib/mtncloud/cli/commands/email_templates_command.rb +373 -0
- data/lib/mtncloud/cli/commands/environments_command.rb +401 -0
- data/lib/mtncloud/cli/commands/execute_schedules_command.rb +735 -0
- data/lib/mtncloud/cli/commands/execution_request_command.rb +333 -0
- data/lib/mtncloud/cli/commands/exit_command.rb +34 -0
- data/lib/mtncloud/cli/commands/file_copy_request_command.rb +352 -0
- data/lib/mtncloud/cli/commands/forgot_password.rb +133 -0
- data/lib/mtncloud/cli/commands/get_prompt_command.rb +36 -0
- data/lib/mtncloud/cli/commands/groups.rb +818 -0
- data/lib/mtncloud/cli/commands/guidance_command.rb +529 -0
- data/lib/mtncloud/cli/commands/guidance_settings.rb +148 -0
- data/lib/mtncloud/cli/commands/health_command.rb +1046 -0
- data/lib/mtncloud/cli/commands/history_command.rb +60 -0
- data/lib/mtncloud/cli/commands/host_vm_groups_command.rb +423 -0
- data/lib/mtncloud/cli/commands/hosts.rb +2986 -0
- data/lib/mtncloud/cli/commands/hub.rb +215 -0
- data/lib/mtncloud/cli/commands/image_builder_command.rb +1197 -0
- data/lib/mtncloud/cli/commands/instance_types.rb +163 -0
- data/lib/mtncloud/cli/commands/instances.rb +5813 -0
- data/lib/mtncloud/cli/commands/integrations_command.rb +1412 -0
- data/lib/mtncloud/cli/commands/invoices_command.rb +1151 -0
- data/lib/mtncloud/cli/commands/jobs_command.rb +998 -0
- data/lib/mtncloud/cli/commands/key_pairs.rb +470 -0
- data/lib/mtncloud/cli/commands/library_cluster_layouts_command.rb +901 -0
- data/lib/mtncloud/cli/commands/library_cluster_packages_command.rb +552 -0
- data/lib/mtncloud/cli/commands/library_container_scripts_command.rb +446 -0
- data/lib/mtncloud/cli/commands/library_container_templates_command.rb +526 -0
- data/lib/mtncloud/cli/commands/library_container_types_command.rb +698 -0
- data/lib/mtncloud/cli/commands/library_forms_command.rb +625 -0
- data/lib/mtncloud/cli/commands/library_instance_types_command.rb +668 -0
- data/lib/mtncloud/cli/commands/library_layouts_command.rb +849 -0
- data/lib/mtncloud/cli/commands/library_operating_systems_command.rb +671 -0
- data/lib/mtncloud/cli/commands/library_option_lists_command.rb +503 -0
- data/lib/mtncloud/cli/commands/library_option_types_command.rb +329 -0
- data/lib/mtncloud/cli/commands/library_spec_templates_command.rb +547 -0
- data/lib/mtncloud/cli/commands/library_upgrades_command.rb +596 -0
- data/lib/mtncloud/cli/commands/license.rb +475 -0
- data/lib/mtncloud/cli/commands/load_balancer_monitors.rb +70 -0
- data/lib/mtncloud/cli/commands/load_balancer_pool_nodes.rb +87 -0
- data/lib/mtncloud/cli/commands/load_balancer_pools.rb +129 -0
- data/lib/mtncloud/cli/commands/load_balancer_profiles.rb +64 -0
- data/lib/mtncloud/cli/commands/load_balancer_types.rb +38 -0
- data/lib/mtncloud/cli/commands/load_balancer_virtual_servers.rb +147 -0
- data/lib/mtncloud/cli/commands/load_balancers.rb +189 -0
- data/lib/mtncloud/cli/commands/log_level_command.rb +54 -0
- data/lib/mtncloud/cli/commands/log_settings_command.rb +443 -0
- data/lib/mtncloud/cli/commands/login.rb +148 -0
- data/lib/mtncloud/cli/commands/logout.rb +63 -0
- data/lib/mtncloud/cli/commands/logs_command.rb +140 -0
- data/lib/mtncloud/cli/commands/man_command.rb +409 -0
- data/lib/mtncloud/cli/commands/migrations.rb +453 -0
- data/lib/mtncloud/cli/commands/monitoring_alerts_command.rb +791 -0
- data/lib/mtncloud/cli/commands/monitoring_apps_command.rb +716 -0
- data/lib/mtncloud/cli/commands/monitoring_checks_command.rb +766 -0
- data/lib/mtncloud/cli/commands/monitoring_contacts_command.rb +339 -0
- data/lib/mtncloud/cli/commands/monitoring_groups_command.rb +674 -0
- data/lib/mtncloud/cli/commands/monitoring_incidents_command.rb +835 -0
- data/lib/mtncloud/cli/commands/monitoring_settings.rb +212 -0
- data/lib/mtncloud/cli/commands/network_dhcp_relays_command.rb +375 -0
- data/lib/mtncloud/cli/commands/network_dhcp_servers_command.rb +366 -0
- data/lib/mtncloud/cli/commands/network_domains_command.rb +896 -0
- data/lib/mtncloud/cli/commands/network_edge_clusters_command.rb +288 -0
- data/lib/mtncloud/cli/commands/network_firewalls_command.rb +783 -0
- data/lib/mtncloud/cli/commands/network_floating_ips.rb +147 -0
- data/lib/mtncloud/cli/commands/network_groups_command.rb +654 -0
- data/lib/mtncloud/cli/commands/network_pool_server_types.rb +20 -0
- data/lib/mtncloud/cli/commands/network_pool_servers_command.rb +318 -0
- data/lib/mtncloud/cli/commands/network_pools_command.rb +903 -0
- data/lib/mtncloud/cli/commands/network_proxies_command.rb +578 -0
- data/lib/mtncloud/cli/commands/network_routers_command.rb +2628 -0
- data/lib/mtncloud/cli/commands/network_security_server_types.rb +20 -0
- data/lib/mtncloud/cli/commands/network_server_groups_command.rb +222 -0
- data/lib/mtncloud/cli/commands/network_server_types_command.rb +20 -0
- data/lib/mtncloud/cli/commands/network_servers_command.rb +398 -0
- data/lib/mtncloud/cli/commands/network_services_command.rb +198 -0
- data/lib/mtncloud/cli/commands/network_static_routes_command.rb +451 -0
- data/lib/mtncloud/cli/commands/network_transport_zones_command.rb +412 -0
- data/lib/mtncloud/cli/commands/networks_command.rb +1692 -0
- data/lib/mtncloud/cli/commands/open_command.rb +30 -0
- data/lib/mtncloud/cli/commands/options.rb +231 -0
- data/lib/mtncloud/cli/commands/packages_command.rb +822 -0
- data/lib/mtncloud/cli/commands/ping.rb +242 -0
- data/lib/mtncloud/cli/commands/plugins.rb +214 -0
- data/lib/mtncloud/cli/commands/policies_command.rb +990 -0
- data/lib/mtncloud/cli/commands/power_schedules_command.rb +731 -0
- data/lib/mtncloud/cli/commands/preseed_scripts_command.rb +378 -0
- data/lib/mtncloud/cli/commands/price_sets_command.rb +557 -0
- data/lib/mtncloud/cli/commands/prices_command.rb +692 -0
- data/lib/mtncloud/cli/commands/processes_command.rb +469 -0
- data/lib/mtncloud/cli/commands/projects_command.rb +537 -0
- data/lib/mtncloud/cli/commands/provisioning_licenses_command.rb +509 -0
- data/lib/mtncloud/cli/commands/provisioning_settings_command.rb +238 -0
- data/lib/mtncloud/cli/commands/recent_activity_command.rb +171 -0
- data/lib/mtncloud/cli/commands/remote.rb +1818 -0
- data/lib/mtncloud/cli/commands/reports_command.rb +724 -0
- data/lib/mtncloud/cli/commands/resource_pool_groups_command.rb +586 -0
- data/lib/mtncloud/cli/commands/rm_command.rb +14 -0
- data/lib/mtncloud/cli/commands/roles.rb +3120 -0
- data/lib/mtncloud/cli/commands/scale_thresholds.rb +103 -0
- data/lib/mtncloud/cli/commands/search_command.rb +184 -0
- data/lib/mtncloud/cli/commands/security_group_rules.rb +230 -0
- data/lib/mtncloud/cli/commands/security_groups.rb +1294 -0
- data/lib/mtncloud/cli/commands/security_package_types.rb +32 -0
- data/lib/mtncloud/cli/commands/security_packages.rb +84 -0
- data/lib/mtncloud/cli/commands/security_scans.rb +107 -0
- data/lib/mtncloud/cli/commands/self_service_command.rb +17 -0
- data/lib/mtncloud/cli/commands/server_devices_command.rb +207 -0
- data/lib/mtncloud/cli/commands/service_catalog_command.rb +1528 -0
- data/lib/mtncloud/cli/commands/service_plans_command.rb +895 -0
- data/lib/mtncloud/cli/commands/set_prompt_command.rb +51 -0
- data/lib/mtncloud/cli/commands/setup.rb +423 -0
- data/lib/mtncloud/cli/commands/shell.rb +717 -0
- data/lib/mtncloud/cli/commands/sleep_command.rb +43 -0
- data/lib/mtncloud/cli/commands/snapshots.rb +156 -0
- data/lib/mtncloud/cli/commands/source_command.rb +30 -0
- data/lib/mtncloud/cli/commands/ssl_verification_command.rb +47 -0
- data/lib/mtncloud/cli/commands/storage_datastores.rb +457 -0
- data/lib/mtncloud/cli/commands/storage_providers_command.rb +1401 -0
- data/lib/mtncloud/cli/commands/storage_server_types.rb +45 -0
- data/lib/mtncloud/cli/commands/storage_servers.rb +116 -0
- data/lib/mtncloud/cli/commands/storage_volume_types.rb +45 -0
- data/lib/mtncloud/cli/commands/storage_volumes.rb +236 -0
- data/lib/mtncloud/cli/commands/subnets_command.rb +819 -0
- data/lib/mtncloud/cli/commands/support_bundles_command.rb +606 -0
- data/lib/mtncloud/cli/commands/systems.rb +1203 -0
- data/lib/mtncloud/cli/commands/tasks.rb +1391 -0
- data/lib/mtncloud/cli/commands/tee_command.rb +14 -0
- data/lib/mtncloud/cli/commands/tenants_command.rb +315 -0
- data/lib/mtncloud/cli/commands/tokens_command.rb +391 -0
- data/lib/mtncloud/cli/commands/update_command.rb +46 -0
- data/lib/mtncloud/cli/commands/usage_command.rb +203 -0
- data/lib/mtncloud/cli/commands/user_groups_command.rb +512 -0
- data/lib/mtncloud/cli/commands/user_settings_command.rb +849 -0
- data/lib/mtncloud/cli/commands/user_sources_command.rb +1065 -0
- data/lib/mtncloud/cli/commands/users.rb +897 -0
- data/lib/mtncloud/cli/commands/vdi_allocations_command.rb +159 -0
- data/lib/mtncloud/cli/commands/vdi_apps_command.rb +317 -0
- data/lib/mtncloud/cli/commands/vdi_command.rb +359 -0
- data/lib/mtncloud/cli/commands/vdi_gateways_command.rb +290 -0
- data/lib/mtncloud/cli/commands/vdi_pools_command.rb +574 -0
- data/lib/mtncloud/cli/commands/version_command.rb +38 -0
- data/lib/mtncloud/cli/commands/view.rb +107 -0
- data/lib/mtncloud/cli/commands/virtual_images.rb +1362 -0
- data/lib/mtncloud/cli/commands/virtual_switches_command.rb +336 -0
- data/lib/mtncloud/cli/commands/whitelabel_settings_command.rb +653 -0
- data/lib/mtncloud/cli/commands/whoami.rb +323 -0
- data/lib/mtncloud/cli/commands/wiki_command.rb +448 -0
- data/lib/mtncloud/cli/commands/workflows.rb +1022 -0
- data/lib/mtncloud/cli/credentials.rb +482 -0
- data/lib/mtncloud/cli/dot_file.rb +180 -0
- data/lib/mtncloud/cli/error_handler.rb +307 -0
- data/lib/mtncloud/cli/errors.rb +53 -0
- data/lib/mtncloud/cli/expression_parser.rb +153 -0
- data/lib/mtncloud/cli/mixins/accounts_helper.rb +484 -0
- data/lib/mtncloud/cli/mixins/affinity_helper.rb +118 -0
- data/lib/mtncloud/cli/mixins/backups_helper.rb +200 -0
- data/lib/mtncloud/cli/mixins/deployments_helper.rb +163 -0
- data/lib/mtncloud/cli/mixins/execution_request_helper.rb +50 -0
- data/lib/mtncloud/cli/mixins/infrastructure_helper.rb +966 -0
- data/lib/mtncloud/cli/mixins/jobs_helper.rb +202 -0
- data/lib/mtncloud/cli/mixins/library_helper.rb +539 -0
- data/lib/mtncloud/cli/mixins/load_balancers_helper.rb +176 -0
- data/lib/mtncloud/cli/mixins/logs_helper.rb +131 -0
- data/lib/mtncloud/cli/mixins/monitoring_helper.rb +876 -0
- data/lib/mtncloud/cli/mixins/networks_helper.rb +62 -0
- data/lib/mtncloud/cli/mixins/operations_helper.rb +41 -0
- data/lib/mtncloud/cli/mixins/option_source_helper.rb +254 -0
- data/lib/mtncloud/cli/mixins/print_helper.rb +1631 -0
- data/lib/mtncloud/cli/mixins/processes_helper.rb +286 -0
- data/lib/mtncloud/cli/mixins/prompt_helper.rb +136 -0
- data/lib/mtncloud/cli/mixins/provisioning_helper.rb +2963 -0
- data/lib/mtncloud/cli/mixins/remote_helper.rb +139 -0
- data/lib/mtncloud/cli/mixins/rest_command.rb +994 -0
- data/lib/mtncloud/cli/mixins/secondary_rest_command.rb +700 -0
- data/lib/mtncloud/cli/mixins/storage_servers_helper.rb +93 -0
- data/lib/mtncloud/cli/mixins/storage_volumes_helper.rb +76 -0
- data/lib/mtncloud/cli/mixins/vdi_helper.rb +246 -0
- data/lib/mtncloud/cli/mixins/whoami_helper.rb +73 -0
- data/lib/mtncloud/cli/option_parser.rb +127 -0
- data/lib/mtncloud/cli/option_types.rb +1622 -0
- data/lib/mtncloud/cli/version.rb +6 -0
- data/lib/mtncloud/cli.rb +105 -0
- data/lib/mtncloud/currency.rb +184 -0
- data/lib/mtncloud/ext/hash.rb +109 -0
- data/lib/mtncloud/ext/nil_class.rb +5 -0
- data/lib/mtncloud/ext/rest_client.rb +37 -0
- data/lib/mtncloud/ext/string.rb +66 -0
- data/lib/mtncloud/formatters.rb +511 -0
- data/lib/mtncloud/logging.rb +185 -0
- data/lib/mtncloud/morpkg.rb +119 -0
- data/lib/mtncloud/rest_client.rb +104 -0
- data/lib/mtncloud/routes.rb +304 -0
- data/lib/mtncloud/terminal.rb +528 -0
- data/lib/mtncloud/util.rb +29 -0
- data/lib/mtncloud.rb +5 -0
- data/mtncloud-cli.gemspec +38 -0
- data/test/api/affinity_groups_interface_test.rb +43 -0
- data/test/api/clients_interface_test.rb +23 -0
- data/test/api/clouds_interface_test.rb +67 -0
- data/test/api/containers_interface_test.rb +68 -0
- data/test/api/host_vm_groups_interface_test.rb +35 -0
- data/test/api/instances_interface_test.rb +22 -0
- data/test/api/network_routers_interface_test.rb +22 -0
- data/test/api/systems_interface_test.rb +26 -0
- data/test/api/whoami_interface_test.rb +14 -0
- data/test/branding_test.rb +160 -0
- data/test/cli/access_token_test.rb +36 -0
- data/test/cli/affinity_groups_cloud_cluster_scope_test.rb +270 -0
- data/test/cli/affinity_groups_cluster_scope_test.rb +171 -0
- data/test/cli/affinity_groups_test.rb +57 -0
- data/test/cli/affinity_groups_violations_scope_test.rb +141 -0
- data/test/cli/affinity_helper_test.rb +367 -0
- data/test/cli/auth_test.rb +88 -0
- data/test/cli/backups_test.rb +212 -0
- data/test/cli/cli_test.rb +48 -0
- data/test/cli/clients_test.rb +45 -0
- data/test/cli/clusters_uuid_test.rb +146 -0
- data/test/cli/containers_test.rb +92 -0
- data/test/cli/distributed_workers_test.rb +68 -0
- data/test/cli/help_test.rb +25 -0
- data/test/cli/host_vm_groups_cluster_scope_test.rb +187 -0
- data/test/cli/host_vm_groups_test.rb +63 -0
- data/test/cli/infrastructure_helper_cluster_resolver_test.rb +250 -0
- data/test/cli/instances_test.rb +37 -0
- data/test/cli/man_test.rb +14 -0
- data/test/cli/migrations_test.rb +39 -0
- data/test/cli/network_routers_test.rb +65 -0
- data/test/cli/remote_test.rb +89 -0
- data/test/cli/roles_test.rb +47 -0
- data/test/cli/shell_test.rb +81 -0
- data/test/cli/storage_volumes_test.rb +79 -0
- data/test/cli/systems_test.rb +206 -0
- data/test/cli/version_test.rb +23 -0
- data/test/cli/view_test.rb +55 -0
- data/test/cli/whoami_test.rb +17 -0
- data/test/mtncloud_test.rb +16 -0
- data/test/test_case.rb +342 -0
- data/test/test_config.rb +137 -0
- data/test/test_data_helper.rb +97 -0
- metadata +807 -0
|
@@ -0,0 +1,2963 @@
|
|
|
1
|
+
require 'mtncloud/cli/mixins/print_helper'
|
|
2
|
+
require 'mtncloud/cli/option_types'
|
|
3
|
+
# Mixin for MtnCloud::Cli command classes
|
|
4
|
+
# Provides common methods for provisioning instances
|
|
5
|
+
module MtnCloud::Cli::ProvisioningHelper
|
|
6
|
+
|
|
7
|
+
def self.included(klass)
|
|
8
|
+
klass.send :include, MtnCloud::Cli::PrintHelper
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def api_client
|
|
12
|
+
raise "#{self.class} has not defined @api_client" if @api_client.nil?
|
|
13
|
+
@api_client
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def instances_interface
|
|
17
|
+
@api_client.instances
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def apps_interface
|
|
21
|
+
@api_client.apps
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def servers_interface
|
|
25
|
+
@api_client.servers
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def options_interface
|
|
29
|
+
@api_client.options
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def instance_types_interface
|
|
33
|
+
@api_client.instance_types
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def instance_type_layouts_interface
|
|
37
|
+
@api_client.library_layouts
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def provision_types_interface
|
|
41
|
+
api_client.provision_types
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def clouds_interface
|
|
45
|
+
@api_client.clouds
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def cloud_datastores_interface
|
|
49
|
+
@api_client.cloud_datastores
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def datastores_interface
|
|
53
|
+
@api_client.datastores
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def accounts_interface
|
|
57
|
+
@api_client.accounts
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def datastores_interface
|
|
61
|
+
@api_client.datastores
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def get_available_groups(params = {}, refresh=false)
|
|
65
|
+
if !@available_groups || refresh
|
|
66
|
+
option_results = options_interface.options_for_source('groups', params)
|
|
67
|
+
@available_groups = option_results['data'].collect {|it|
|
|
68
|
+
{"id" => it["value"], "name" => it["name"], "value" => it["value"]}
|
|
69
|
+
}
|
|
70
|
+
end
|
|
71
|
+
#puts "get_available_groups() rtn: #{@available_groups.inspect}"
|
|
72
|
+
return @available_groups
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def get_available_clouds(group_id, params = {}, refresh=false)
|
|
76
|
+
if !group_id
|
|
77
|
+
option_results = options_interface.options_for_source('clouds', params.merge({'default' => 'false'}))
|
|
78
|
+
return option_results['data'].collect {|it|
|
|
79
|
+
{"id" => it["value"], "name" => it["name"], "value" => it["value"], "zoneTypeId" => it["zoneTypeId"]}
|
|
80
|
+
}
|
|
81
|
+
end
|
|
82
|
+
group = find_group_by_id_for_provisioning(group_id)
|
|
83
|
+
if !group
|
|
84
|
+
return []
|
|
85
|
+
end
|
|
86
|
+
if !group["clouds"] || refresh
|
|
87
|
+
option_results = options_interface.options_for_source('clouds', params.merge({groupId: group_id}))
|
|
88
|
+
group["clouds"] = option_results['data'].collect {|it|
|
|
89
|
+
{"id" => it["value"], "name" => it["name"], "value" => it["value"], "zoneTypeId" => it["zoneTypeId"]}
|
|
90
|
+
}
|
|
91
|
+
end
|
|
92
|
+
return group["clouds"]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def get_available_accounts(refresh=false)
|
|
96
|
+
if !@available_accounts || refresh
|
|
97
|
+
# @available_accounts = accounts_interface.list()['accounts']
|
|
98
|
+
@available_accounts = options_interface.options_for_source("allTenants", {})['data'].collect {|it|
|
|
99
|
+
{"name" => it["name"], "value" => it["value"], "id" => it["value"]}
|
|
100
|
+
}
|
|
101
|
+
end
|
|
102
|
+
@available_accounts
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def get_available_plans(refresh=false)
|
|
106
|
+
if !@available_plans || refresh
|
|
107
|
+
@available_plans = instances_interface.search_plans['searchPlans'].collect {|it|
|
|
108
|
+
{"name" => it["name"], "value" => it["id"]}
|
|
109
|
+
}
|
|
110
|
+
end
|
|
111
|
+
@available_plans
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def find_group_by_id_for_provisioning(val)
|
|
115
|
+
groups = get_available_groups()
|
|
116
|
+
group = groups.find {|it| it["id"].to_s == val.to_s }
|
|
117
|
+
if !group
|
|
118
|
+
print_red_alert "Group not found by id #{val}"
|
|
119
|
+
exit 1
|
|
120
|
+
end
|
|
121
|
+
return group
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def find_group_by_name_for_provisioning(val)
|
|
125
|
+
groups = get_available_groups()
|
|
126
|
+
group = groups.find {|it| it["name"].to_s.downcase == val.to_s.downcase }
|
|
127
|
+
if !group
|
|
128
|
+
print_red_alert "Group not found by name #{val}"
|
|
129
|
+
exit 1
|
|
130
|
+
end
|
|
131
|
+
return group
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def find_group_by_name_or_id_for_provisioning(val)
|
|
135
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
|
136
|
+
return find_group_by_id_for_provisioning(val)
|
|
137
|
+
else
|
|
138
|
+
return find_group_by_name_for_provisioning(val)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def find_cloud_by_id_for_provisioning(group_id, val)
|
|
143
|
+
clouds = get_available_clouds(group_id)
|
|
144
|
+
cloud = clouds.find {|it| it["id"].to_s == val.to_s }
|
|
145
|
+
if !cloud
|
|
146
|
+
print_red_alert "Cloud not found by id #{val}"
|
|
147
|
+
exit 1
|
|
148
|
+
end
|
|
149
|
+
return cloud
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def find_cloud_by_name_for_provisioning(group_id, val)
|
|
153
|
+
clouds = get_available_clouds(group_id)
|
|
154
|
+
cloud = clouds.find {|it| it["name"].to_s.downcase == val.to_s.downcase }
|
|
155
|
+
if !cloud
|
|
156
|
+
print_red_alert "Cloud not found by name #{val}"
|
|
157
|
+
exit 1
|
|
158
|
+
end
|
|
159
|
+
return cloud
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def find_cloud_by_name_or_id_for_provisioning(group_id, val)
|
|
163
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
|
164
|
+
return find_cloud_by_id_for_provisioning(group_id, val)
|
|
165
|
+
else
|
|
166
|
+
return find_cloud_by_name_for_provisioning(group_id, val)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def find_instance_type_by_id(id)
|
|
171
|
+
begin
|
|
172
|
+
json_response = instance_types_interface.get(id.to_i)
|
|
173
|
+
return json_response['instanceType']
|
|
174
|
+
rescue RestClient::Exception => e
|
|
175
|
+
if e.response && e.response.code == 404
|
|
176
|
+
print_red_alert "Instance Type not found by id #{id}"
|
|
177
|
+
return nil
|
|
178
|
+
else
|
|
179
|
+
raise e
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def find_instance_type_by_code(code)
|
|
185
|
+
results = instance_types_interface.list({code: code})
|
|
186
|
+
instance_types = results['instanceTypes']
|
|
187
|
+
if instance_types.empty?
|
|
188
|
+
print_red_alert "Instance Type not found by code #{code}"
|
|
189
|
+
return nil
|
|
190
|
+
end
|
|
191
|
+
if instance_types.size() > 1
|
|
192
|
+
print as_pretty_table(instance_types, [:id,:name,:code], {color:red})
|
|
193
|
+
print_red_alert "Try using ID instead"
|
|
194
|
+
return nil
|
|
195
|
+
end
|
|
196
|
+
# return instance_types[0]
|
|
197
|
+
# fetch by ID to get full details
|
|
198
|
+
# could also use ?details-true with search
|
|
199
|
+
return find_instance_type_by_id(instance_types[0]['id'])
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def find_instance_type_by_name(name)
|
|
203
|
+
results = instance_types_interface.list({name: name})
|
|
204
|
+
instance_types = results['instanceTypes']
|
|
205
|
+
if instance_types.empty?
|
|
206
|
+
print_red_alert "Instance Type not found by name #{name}"
|
|
207
|
+
return nil
|
|
208
|
+
end
|
|
209
|
+
if instance_types.size() > 1
|
|
210
|
+
print as_pretty_table(instance_types, [:id,:name,:code], {color:red})
|
|
211
|
+
print_red_alert "Try using ID instead"
|
|
212
|
+
return nil
|
|
213
|
+
end
|
|
214
|
+
# return instance_types[0]
|
|
215
|
+
# fetch by ID to get full details
|
|
216
|
+
# could also use ?details-true with search
|
|
217
|
+
return find_instance_type_by_id(instance_types[0]['id'])
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def find_instance_type_by_name_or_id(val)
|
|
221
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
|
222
|
+
return find_instance_type_by_id(val)
|
|
223
|
+
else
|
|
224
|
+
return find_instance_type_by_name(val)
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
def find_instance_by_name_or_id(val, include_tenants=false)
|
|
229
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
|
230
|
+
return find_instance_by_id(val)
|
|
231
|
+
else
|
|
232
|
+
return find_instance_by_name(val, include_tenants)
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def find_instance_by_id(id)
|
|
237
|
+
begin
|
|
238
|
+
json_response = instances_interface.get(id.to_i)
|
|
239
|
+
return json_response['instance']
|
|
240
|
+
rescue RestClient::Exception => e
|
|
241
|
+
if e.response && e.response.code == 404
|
|
242
|
+
print_red_alert "Instance not found by id #{id}"
|
|
243
|
+
exit 1
|
|
244
|
+
else
|
|
245
|
+
raise e
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def find_instance_by_name(name, include_tenants=false)
|
|
251
|
+
params = {name: name.to_s}
|
|
252
|
+
params['includeTenants'] = true if include_tenants
|
|
253
|
+
instances = instances_interface.list(params)['instances']
|
|
254
|
+
if instances.empty?
|
|
255
|
+
print_red_alert "Instance not found by name #{name}"
|
|
256
|
+
exit 1
|
|
257
|
+
elsif instances.size > 1
|
|
258
|
+
print_red_alert "Multiple Instances exist with the name '#{name}'"
|
|
259
|
+
puts_error as_pretty_table(instances, [:id, :name], {color:red})
|
|
260
|
+
print_red_alert "Try using ID instead"
|
|
261
|
+
print_error reset,"\n"
|
|
262
|
+
exit 1
|
|
263
|
+
end
|
|
264
|
+
return instances[0]
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def parse_instance_id_list(id_list)
|
|
268
|
+
parse_id_list(id_list).collect do |instance_id|
|
|
269
|
+
find_instance_by_name_or_id(instance_id)['id']
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
## resources
|
|
274
|
+
|
|
275
|
+
# todo: crud and /api/options for resources
|
|
276
|
+
|
|
277
|
+
def parse_resource_id_list(id_list)
|
|
278
|
+
parse_id_list(id_list).collect do |resource_id|
|
|
279
|
+
#find_resource_by_name_or_id(resource_id)['id']
|
|
280
|
+
resource_id
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
## apps
|
|
285
|
+
|
|
286
|
+
def find_app_by_id(id)
|
|
287
|
+
app_results = apps_interface.get(id.to_i)
|
|
288
|
+
if app_results['app'].empty?
|
|
289
|
+
print_red_alert "App not found by id #{id}"
|
|
290
|
+
exit 1
|
|
291
|
+
end
|
|
292
|
+
return app_results['app']
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def find_app_by_name(name)
|
|
296
|
+
app_results = apps_interface.list({name: name})
|
|
297
|
+
apps = app_results['apps']
|
|
298
|
+
if apps.empty?
|
|
299
|
+
print_red_alert "App not found by name #{name}"
|
|
300
|
+
exit 1
|
|
301
|
+
elsif apps.size > 1
|
|
302
|
+
print_red_alert "#{apps.size} apps exist with the name #{name}. Try using id instead"
|
|
303
|
+
exit 1
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
return app_results['apps'][0]
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def find_app_by_name_or_id(val)
|
|
310
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
|
311
|
+
return find_app_by_id(val)
|
|
312
|
+
else
|
|
313
|
+
return find_app_by_name(val)
|
|
314
|
+
end
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
## servers
|
|
318
|
+
|
|
319
|
+
def find_server_by_id(id)
|
|
320
|
+
begin
|
|
321
|
+
json_response = servers_interface.get(id.to_i)
|
|
322
|
+
return json_response['server']
|
|
323
|
+
rescue RestClient::Exception => e
|
|
324
|
+
if e.response && e.response.code == 404
|
|
325
|
+
print_red_alert "Server not found by id #{id}"
|
|
326
|
+
exit 1
|
|
327
|
+
else
|
|
328
|
+
raise e
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
def find_server_by_name(name)
|
|
334
|
+
results = servers_interface.list({name: name})
|
|
335
|
+
if results['servers'].empty?
|
|
336
|
+
print_red_alert "Server not found by name #{name}"
|
|
337
|
+
exit 1
|
|
338
|
+
elsif results['servers'].size > 1
|
|
339
|
+
print_red_alert "Multiple Servers exist with the name '#{name}'"
|
|
340
|
+
puts_error as_pretty_table(results['servers'], [:id, :name], {color:red})
|
|
341
|
+
print_red_alert "Try using ID instead"
|
|
342
|
+
exit 1
|
|
343
|
+
end
|
|
344
|
+
return results['servers'][0]
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
def find_server_by_name_or_id(val)
|
|
348
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
|
349
|
+
return find_server_by_id(val)
|
|
350
|
+
else
|
|
351
|
+
return find_server_by_name(val)
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def parse_server_id_list(id_list)
|
|
356
|
+
parse_id_list(id_list).collect do |server_id|
|
|
357
|
+
find_server_by_name_or_id(server_id)['id']
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
## hosts is the same as servers, just says 'Host' instead of 'Server'
|
|
362
|
+
|
|
363
|
+
def find_host_by_id(id)
|
|
364
|
+
begin
|
|
365
|
+
json_response = servers_interface.get(id.to_i)
|
|
366
|
+
return json_response['server']
|
|
367
|
+
rescue RestClient::Exception => e
|
|
368
|
+
if e.response && e.response.code == 404
|
|
369
|
+
print_red_alert "Host not found by id #{id}"
|
|
370
|
+
exit 1
|
|
371
|
+
else
|
|
372
|
+
raise e
|
|
373
|
+
end
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def find_host_by_name(name)
|
|
378
|
+
results = servers_interface.list({name: name})
|
|
379
|
+
if results['servers'].empty?
|
|
380
|
+
print_red_alert "Host not found by name #{name}"
|
|
381
|
+
exit 1
|
|
382
|
+
elsif results['servers'].size > 1
|
|
383
|
+
print_red_alert "#{results['servers'].size} hosts exist with the name #{name}. Try using id instead"
|
|
384
|
+
exit 1
|
|
385
|
+
end
|
|
386
|
+
return results['servers'][0]
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def find_host_by_name_or_id(val)
|
|
390
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
|
391
|
+
return find_host_by_id(val)
|
|
392
|
+
else
|
|
393
|
+
return find_host_by_name(val)
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
def parse_host_id_list(id_list)
|
|
398
|
+
parse_id_list(id_list).collect do |host_id|
|
|
399
|
+
find_host_by_name_or_id(host_id)['id']
|
|
400
|
+
end
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
def find_instance_type_layout_by_id(layout_id, id)
|
|
404
|
+
json_results = instance_type_layouts_interface.get(layout_id, id)
|
|
405
|
+
if json_results['instanceTypeLayout'].empty?
|
|
406
|
+
print_red_alert "Instance type layout not found by id #{id}"
|
|
407
|
+
exit 1
|
|
408
|
+
end
|
|
409
|
+
json_results['instanceTypeLayout']
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
def find_workflow_by_name_or_id(val)
|
|
413
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
|
414
|
+
return find_workflow_by_id(val)
|
|
415
|
+
else
|
|
416
|
+
return find_workflow_by_name(val)
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
def find_workflow_by_id(id)
|
|
421
|
+
begin
|
|
422
|
+
json_response = @task_sets_interface.get(id.to_i)
|
|
423
|
+
return json_response['taskSet']
|
|
424
|
+
rescue RestClient::Exception => e
|
|
425
|
+
if e.response && e.response.code == 404
|
|
426
|
+
print_red_alert "Workflow not found by id #{id}"
|
|
427
|
+
else
|
|
428
|
+
raise e
|
|
429
|
+
end
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
def find_workflow_by_name(name)
|
|
434
|
+
workflows = @task_sets_interface.get({name: name.to_s})['taskSets']
|
|
435
|
+
if workflows.empty?
|
|
436
|
+
print_red_alert "Workflow not found by name #{name}"
|
|
437
|
+
return nil
|
|
438
|
+
elsif workflows.size > 1
|
|
439
|
+
print_red_alert "#{workflows.size} workflows by name #{name}"
|
|
440
|
+
print_workflows_table(workflows, {color: red})
|
|
441
|
+
print reset,"\n\n"
|
|
442
|
+
return nil
|
|
443
|
+
else
|
|
444
|
+
return workflows[0]
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
def find_cloud_resource_pool_by_name_or_id(cloud_id, val)
|
|
449
|
+
(val.to_s =~ /\A\d{1,}\Z/) ? find_cloud_resource_pool_by_id(cloud_id, val) : find_cloud_resource_pool_by_name(cloud_id, val)
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
def get_provision_type_for_zone_type(zone_type_id)
|
|
453
|
+
clouds_interface.cloud_type(zone_type_id)['zoneType']['provisionTypes'].first rescue nil
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
# prompts user for all the configuartion options for a particular instance
|
|
457
|
+
# returns payload of data for a new instance
|
|
458
|
+
def prompt_new_instance(options={})
|
|
459
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
|
460
|
+
#puts "prompt_new_instance() #{options}"
|
|
461
|
+
print reset # clear colors
|
|
462
|
+
options[:options] ||= {}
|
|
463
|
+
# provisioning with blueprint can lock fields
|
|
464
|
+
locked_fields = options[:locked_fields] || []
|
|
465
|
+
# Group
|
|
466
|
+
default_group = find_group_by_name_or_id_for_provisioning(options[:default_group] || @active_group_id) if options[:default_group] || @active_group_id
|
|
467
|
+
|
|
468
|
+
group_id = nil
|
|
469
|
+
group = options[:group] ? find_group_by_name_or_id_for_provisioning(options[:group]) : nil
|
|
470
|
+
if group
|
|
471
|
+
group_id = group["id"]
|
|
472
|
+
else
|
|
473
|
+
# print_red_alert "Group not found or specified!"
|
|
474
|
+
# exit 1
|
|
475
|
+
group_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'type' => 'select', 'fieldLabel' => 'Group', 'selectOptions' => get_available_groups(), 'required' => true, 'description' => 'Select Group.', 'defaultValue' => (default_group ? default_group['name'] : nil)}],options[:options],api_client,{})
|
|
476
|
+
group_id = group_prompt['group']
|
|
477
|
+
end
|
|
478
|
+
|
|
479
|
+
# Cloud
|
|
480
|
+
cloud_id = nil
|
|
481
|
+
cloud = options[:cloud] ? find_cloud_by_name_or_id_for_provisioning(group_id, options[:cloud]) : nil
|
|
482
|
+
if cloud
|
|
483
|
+
cloud_id = cloud["id"]
|
|
484
|
+
else
|
|
485
|
+
# print_red_alert "Cloud not specified!"
|
|
486
|
+
# exit 1
|
|
487
|
+
available_clouds = get_available_clouds(group_id)
|
|
488
|
+
cloud_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'cloud', 'type' => 'select', 'fieldLabel' => 'Cloud', 'selectOptions' => get_available_clouds(group_id), 'required' => true, 'description' => 'Select Cloud.', 'defaultValue' => options[:default_cloud] ? options[:default_cloud] : nil}],options[:options],api_client,{groupId: group_id})
|
|
489
|
+
cloud_id = cloud_prompt['cloud']
|
|
490
|
+
cloud = available_clouds.find {|it| it['value'] == cloud_id}
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
cloud_type = clouds_interface.cloud_type(cloud['zoneTypeId'])
|
|
494
|
+
|
|
495
|
+
# Instance Type
|
|
496
|
+
instance_type_code = nil
|
|
497
|
+
if options[:instance_type_code]
|
|
498
|
+
instance_type_code = options[:instance_type_code]
|
|
499
|
+
else
|
|
500
|
+
instance_type_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'type' => 'select', 'fieldLabel' => 'Type', 'optionSource' => 'instanceTypes', 'required' => true, 'description' => 'Select Instance Type.'}],options[:options],api_client,{groupId: group_id, cloudId: cloud_id, restrictProvisionType:true}, no_prompt, true)
|
|
501
|
+
instance_type_code = instance_type_prompt['type']
|
|
502
|
+
end
|
|
503
|
+
if instance_type_code.to_s =~ /\A\d{1,}\Z/
|
|
504
|
+
instance_type = find_instance_type_by_id(instance_type_code)
|
|
505
|
+
else
|
|
506
|
+
instance_type = find_instance_type_by_code(instance_type_code)
|
|
507
|
+
end
|
|
508
|
+
exit 1 if !instance_type
|
|
509
|
+
|
|
510
|
+
# Instance Name
|
|
511
|
+
instance_name = nil
|
|
512
|
+
if options[:instance_name]
|
|
513
|
+
options[:options]['name'] = options[:instance_name]
|
|
514
|
+
elsif options[:options]['instance'] && options[:options]['instance']['name']
|
|
515
|
+
options[:options]['name'] = options[:options]['instance']['name']
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
while instance_name.nil? do
|
|
519
|
+
name_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Instance Name', 'type' => 'text', 'required' => options[:name_required], 'defaultValue' => options[:default_name]}], options[:options])
|
|
520
|
+
name = name_prompt['name']
|
|
521
|
+
if name.nil? && !options[:name_required]
|
|
522
|
+
break
|
|
523
|
+
else
|
|
524
|
+
if instances_interface.list({name: name})['instances'].empty?
|
|
525
|
+
instance_name = name
|
|
526
|
+
else
|
|
527
|
+
print_red_alert "Name must be unique, #{name} already exists"
|
|
528
|
+
options[:options].delete('name')
|
|
529
|
+
exit 1 if no_prompt
|
|
530
|
+
if options[:default_name] == name
|
|
531
|
+
options[:default_name] += '-2'
|
|
532
|
+
end
|
|
533
|
+
end
|
|
534
|
+
end
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
# config
|
|
538
|
+
config = {}
|
|
539
|
+
=begin
|
|
540
|
+
if cloud_type['code'] == 'amazon' && (cloud['config'] || {})['isVpc'] == 'false' && (cloud['config'] || {})['vpc'] == ''
|
|
541
|
+
config['isEC2'] = true
|
|
542
|
+
else
|
|
543
|
+
config['isEC2'] = false
|
|
544
|
+
if cloud_type['code'] == 'amazon' && (cloud['config'] || {})['isVpc'] == 'true' && (cloud['config'] || {})['vpc'] != ''
|
|
545
|
+
config['isVpcSelectable'] = false
|
|
546
|
+
config['resourcePoolId'] = cloud['config']['vpc']
|
|
547
|
+
else
|
|
548
|
+
config['isVpcSelectable'] = true
|
|
549
|
+
end
|
|
550
|
+
end
|
|
551
|
+
=end
|
|
552
|
+
|
|
553
|
+
payload = {
|
|
554
|
+
'zoneId' => cloud_id,
|
|
555
|
+
# 'siteId' => siteId,
|
|
556
|
+
'instance' => {
|
|
557
|
+
'name' => instance_name,
|
|
558
|
+
'cloud' => cloud['name'],
|
|
559
|
+
'site' => {
|
|
560
|
+
'id' => group_id
|
|
561
|
+
},
|
|
562
|
+
'type' => instance_type_code,
|
|
563
|
+
'instanceType' => {
|
|
564
|
+
'code' => instance_type_code
|
|
565
|
+
}
|
|
566
|
+
},
|
|
567
|
+
'config' => config
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
# allow arbitrary -O values passed by the user
|
|
571
|
+
if options[:options]
|
|
572
|
+
arbitrary_options = (options[:options] || {}).reject {|k,v| k.is_a?(Symbol) }
|
|
573
|
+
# remove some things that are being prompted for
|
|
574
|
+
arbitrary_options.delete('group')
|
|
575
|
+
arbitrary_options.delete('cloud')
|
|
576
|
+
arbitrary_options.delete('type')
|
|
577
|
+
arbitrary_options.delete('name')
|
|
578
|
+
#arbitrary_options.delete('version')
|
|
579
|
+
arbitrary_options.delete('layout')
|
|
580
|
+
arbitrary_options.delete('servicePlan')
|
|
581
|
+
arbitrary_options.delete('description')
|
|
582
|
+
arbitrary_options.delete('environment')
|
|
583
|
+
arbitrary_options.delete('instanceContext')
|
|
584
|
+
arbitrary_options.delete('tags')
|
|
585
|
+
# these are used by prompt_network_interfaces
|
|
586
|
+
arbitrary_options.delete('networkInterface')
|
|
587
|
+
(2..10).each {|i| arbitrary_options.delete('networkInterface' + i.to_s) }
|
|
588
|
+
# these are used by prompt_volumes
|
|
589
|
+
arbitrary_options.delete('rootVolume')
|
|
590
|
+
arbitrary_options.delete('dataVolume')
|
|
591
|
+
(2..10).each {|i| arbitrary_options.delete('dataVolume' + i.to_s) }
|
|
592
|
+
arbitrary_options.delete('lockedFields')
|
|
593
|
+
# arbitrary_options.delete('ports')
|
|
594
|
+
arbitrary_options.delete('marketplacePublisher')
|
|
595
|
+
arbitrary_options.delete('marketplaceOffer')
|
|
596
|
+
arbitrary_options.delete('marketplaceSku')
|
|
597
|
+
arbitrary_options.delete('marketplaceVersion')
|
|
598
|
+
payload.deep_merge!(arbitrary_options)
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
# Description
|
|
602
|
+
if options[:description]
|
|
603
|
+
options[:options]['description'] = options[:description]
|
|
604
|
+
end
|
|
605
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false, 'defaultValue' => options[:default_description]}], options[:options])
|
|
606
|
+
payload['instance']['description'] = v_prompt['description'] if !v_prompt['description'].empty?
|
|
607
|
+
|
|
608
|
+
# Environment
|
|
609
|
+
if options[:environment]
|
|
610
|
+
options[:options]['environment'] = options[:environment]
|
|
611
|
+
elsif options[:options]['instanceContext'] && !options[:options]['environment']
|
|
612
|
+
options[:options]['environment'] = options[:options]['instanceContext']
|
|
613
|
+
end
|
|
614
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'environment', 'fieldLabel' => 'Environment', 'type' => 'select', 'required' => false, 'selectOptions' => get_available_environments(), 'defaultValue' => options[:default_environment]}], options[:options])
|
|
615
|
+
payload['instance']['instanceContext'] = v_prompt['environment'] if !v_prompt['environment'].empty?
|
|
616
|
+
|
|
617
|
+
# Labels (used to be called tags)
|
|
618
|
+
unless options[:skip_labels_prompt]
|
|
619
|
+
if options[:labels]
|
|
620
|
+
payload['instance']['labels'] = options[:labels].is_a?(Array) ? options[:labels] : options[:labels].to_s.split(',').collect {|it| it.to_s.strip }.compact.uniq
|
|
621
|
+
else
|
|
622
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'labels', 'fieldLabel' => 'Labels', 'type' => 'text', 'required' => false, 'defaultValue' => options[:default_labels]}], options[:options])
|
|
623
|
+
payload['instance']['labels'] = v_prompt['labels'].split(',').collect {|it| it.to_s.strip }.compact.uniq if !v_prompt['labels'].empty?
|
|
624
|
+
end
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
# Version and Layout
|
|
628
|
+
layout_id = nil
|
|
629
|
+
if locked_fields.include?('instance.layout.id')
|
|
630
|
+
layout_id = options[:options]['instance']['layout'] rescue options[:options]['layout']
|
|
631
|
+
if layout_id.is_a?(Hash)
|
|
632
|
+
layout_id = layout_id['id'] || layout_id['code'] || layout_id['name']
|
|
633
|
+
end
|
|
634
|
+
else
|
|
635
|
+
layout_id = nil
|
|
636
|
+
if options[:layout]
|
|
637
|
+
layout_id = options[:layout]
|
|
638
|
+
# elsif options[:options]['layout']
|
|
639
|
+
# layout_id = options[:options]['layout']
|
|
640
|
+
end
|
|
641
|
+
if layout_id.is_a?(Hash)
|
|
642
|
+
layout_id = layout_id['id'] || layout_id['code'] || layout_id['name']
|
|
643
|
+
end
|
|
644
|
+
if layout_id.nil?
|
|
645
|
+
version_value = nil
|
|
646
|
+
default_layout_value = nil
|
|
647
|
+
if options[:version]
|
|
648
|
+
version_value = options[:version]
|
|
649
|
+
elsif options[:options]['version']
|
|
650
|
+
version_value = options[:options]['version']
|
|
651
|
+
else
|
|
652
|
+
available_versions = options_interface.options_for_source('instanceVersions',{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id']})['data']
|
|
653
|
+
# filter versions with no layouts.. api should probably do that too eh?
|
|
654
|
+
available_versions.reject! { |available_version| available_version["layouts"].nil? || available_version["layouts"].empty? }
|
|
655
|
+
default_version_value = payload['instance']['version'] ? payload['instance']['version'] : payload['version']
|
|
656
|
+
#default_layout_value = options[:layout]
|
|
657
|
+
if default_layout_value.nil?
|
|
658
|
+
default_layout_value = payload['instance']['layout'] ? payload['instance']['layout'] : payload['layout']
|
|
659
|
+
end
|
|
660
|
+
if default_layout_value && default_layout_value.is_a?(Hash)
|
|
661
|
+
default_layout_value = default_layout_value['id']
|
|
662
|
+
end
|
|
663
|
+
# JD: version is always nil because it is not stored in the blueprint or config !!
|
|
664
|
+
# so for now, infer the version from the layout
|
|
665
|
+
# requires api 3.6.2 to get "layouts" from /options/versions
|
|
666
|
+
if default_layout_value && default_version_value.to_s.empty?
|
|
667
|
+
available_versions.each do |available_version|
|
|
668
|
+
if available_version["layouts"]
|
|
669
|
+
selected_layout = available_version["layouts"].find {|it| it["value"].to_s == default_layout_value.to_s || it["id"].to_s == default_layout_value.to_s || it["code"].to_s == default_layout_value.to_s }
|
|
670
|
+
if selected_layout
|
|
671
|
+
default_version_value = available_version["value"]
|
|
672
|
+
break
|
|
673
|
+
end
|
|
674
|
+
end
|
|
675
|
+
end
|
|
676
|
+
end
|
|
677
|
+
|
|
678
|
+
# do not require version if a layout is passed
|
|
679
|
+
version_value = default_version_value
|
|
680
|
+
version_is_required = default_layout_value.nil?
|
|
681
|
+
if default_layout_value.nil? && options[:options]["layout"].nil? && options[:always_prompt] != true
|
|
682
|
+
version_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'version', 'type' => 'select', 'fieldLabel' => 'Version', 'selectOptions' => available_versions, 'required' => version_is_required, 'skipSingleOption' => true, 'autoPickOption' => true, 'description' => 'Select which version of the instance type to be provisioned.', 'defaultValue' => default_version_value}],options[:options],api_client,{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id']})
|
|
683
|
+
version_value = version_prompt['version']
|
|
684
|
+
end
|
|
685
|
+
end
|
|
686
|
+
layout_id = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'layout', 'type' => 'select', 'fieldLabel' => 'Layout', 'optionSource' => 'layoutsForCloud', 'required' => true, 'description' => 'Select which configuration of the instance type to be provisioned.', 'defaultValue' => default_layout_value}],options[:options],api_client,{groupId: group_id, cloudId: cloud_id, instanceTypeId: instance_type['id'], version: version_value, creatable: true}, no_prompt, true)['layout']
|
|
687
|
+
end
|
|
688
|
+
end
|
|
689
|
+
|
|
690
|
+
# determine layout and provision_type
|
|
691
|
+
|
|
692
|
+
# layout = find_instance_type_layout_by_id(instance_type['id'], layout_id.to_i)
|
|
693
|
+
layout = (instance_type['instanceTypeLayouts'] || []).find {|it|
|
|
694
|
+
it['id'].to_s == layout_id.to_s || it['code'].to_s == layout_id.to_s || it['name'].to_s == layout_id.to_s
|
|
695
|
+
}
|
|
696
|
+
if !layout
|
|
697
|
+
print_red_alert "Layout not found by id #{layout_id}"
|
|
698
|
+
exit 1
|
|
699
|
+
end
|
|
700
|
+
layout_id = layout['id']
|
|
701
|
+
payload['instance']['layout'] = {'id' => layout['id'], 'code' => layout['code']}
|
|
702
|
+
|
|
703
|
+
# need to GET provision type for optionTypes, and other settings...
|
|
704
|
+
provision_type_code = layout['provisionTypeCode'] || layout['provisionType']['code']
|
|
705
|
+
provision_type = nil
|
|
706
|
+
if provision_type_code
|
|
707
|
+
provision_type = provision_types_interface.list({code:provision_type_code})['provisionTypes'][0]
|
|
708
|
+
if provision_type.nil?
|
|
709
|
+
print_red_alert "Provision Type not found by code #{provision_type_code}"
|
|
710
|
+
exit 1
|
|
711
|
+
end
|
|
712
|
+
else
|
|
713
|
+
provision_type = get_provision_type_for_zone_type(cloud['zoneType']['id'])
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
# build config option types
|
|
717
|
+
option_type_list = []
|
|
718
|
+
if !layout['optionTypes'].nil? && !layout['optionTypes'].empty?
|
|
719
|
+
option_type_list += layout['optionTypes']
|
|
720
|
+
end
|
|
721
|
+
if !instance_type['optionTypes'].nil? && !instance_type['optionTypes'].empty?
|
|
722
|
+
option_type_list += instance_type['optionTypes']
|
|
723
|
+
end
|
|
724
|
+
|
|
725
|
+
api_params = {groupId: group_id, cloudId: cloud_id, zoneId: cloud_id, instanceTypeId: instance_type['id'], version: version_value}
|
|
726
|
+
|
|
727
|
+
pool_id = nil
|
|
728
|
+
resource_pool = nil
|
|
729
|
+
service_plan = nil
|
|
730
|
+
|
|
731
|
+
prompt_service_plan = -> {
|
|
732
|
+
service_plans_json = instances_interface.service_plans({zoneId: cloud_id, layoutId: layout['id'], siteId: group_id}.merge(resource_pool.nil? ? {} : {'poolId' => resource_pool['id'], 'resourcePoolId' => resource_pool['id']}))
|
|
733
|
+
service_plans = service_plans_json["plans"]
|
|
734
|
+
if locked_fields.include?('plan.id')
|
|
735
|
+
plan_id = options[:options]['plan']['id'] rescue nil
|
|
736
|
+
if plan_id.nil?
|
|
737
|
+
plan_id = options[:options]['instance']['plan']['id'] rescue nil
|
|
738
|
+
end
|
|
739
|
+
service_plan = service_plans.find {|sp| sp['id'] == plan_id }
|
|
740
|
+
else
|
|
741
|
+
service_plan = service_plans.find {|sp| sp['id'] == options[:service_plan].to_i} if options[:service_plan]
|
|
742
|
+
|
|
743
|
+
if !service_plan
|
|
744
|
+
service_plans_dropdown = service_plans.collect {|sp| {'name' => sp["name"], 'value' => sp["id"], 'code' => sp['code']} } # already sorted
|
|
745
|
+
default_plan = nil
|
|
746
|
+
if payload['plan']
|
|
747
|
+
default_plan = payload['plan']
|
|
748
|
+
elsif payload['instance'] && payload['instance']['plan']
|
|
749
|
+
default_plan = payload['instance']['plan']
|
|
750
|
+
end
|
|
751
|
+
|
|
752
|
+
if options[:default_plan] && service_plans_dropdown.find {|sp| [sp["name"], sp["value"].to_s, sp["code"]].include?(options[:default_plan].to_s)}
|
|
753
|
+
default_plan_value = options[:default_plan]
|
|
754
|
+
else
|
|
755
|
+
default_plan_value = options[:default_plan] || (default_plan.is_a?(Hash) ? default_plan['id'] : default_plan)
|
|
756
|
+
end
|
|
757
|
+
plan_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'servicePlan', 'type' => 'select', 'fieldLabel' => 'Plan', 'selectOptions' => service_plans_dropdown, 'required' => true, 'description' => 'Choose the appropriately sized plan for this instance', 'defaultValue' => default_plan_value}],options[:options], api_client, {}, no_prompt, true)
|
|
758
|
+
plan_id = plan_prompt['servicePlan']
|
|
759
|
+
service_plan = service_plans.find {|sp| sp["id"] == plan_id.to_i }
|
|
760
|
+
if !service_plan
|
|
761
|
+
print_red_alert "Plan not found by id #{plan_id}"
|
|
762
|
+
exit 1
|
|
763
|
+
end
|
|
764
|
+
end
|
|
765
|
+
#todo: consolidate these, instances api looks for instance.plan.id and apps looks for plan.id
|
|
766
|
+
if options[:for_app]
|
|
767
|
+
payload['plan'] = {'id' => service_plan["id"], 'code' => service_plan["code"], 'name' => service_plan["name"]}
|
|
768
|
+
else
|
|
769
|
+
payload['instance']['plan'] = {'id' => service_plan["id"], 'code' => service_plan["code"], 'name' => service_plan["name"]}
|
|
770
|
+
end
|
|
771
|
+
end
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
prompt_resource_pool = -> {
|
|
775
|
+
# prompt for resource pool
|
|
776
|
+
if locked_fields.include?('config.resourcePoolId')
|
|
777
|
+
pool_id = payload['config']['resourcePoolId'] rescue nil
|
|
778
|
+
elsif locked_fields.include?('config.resourcePool')
|
|
779
|
+
pool_id = payload['config']['resourcePool'] rescue nil
|
|
780
|
+
elsif locked_fields.include?('config.azureResourceGroupId')
|
|
781
|
+
pool_id = payload['config']['azureResourceGroupId'] rescue nil
|
|
782
|
+
else
|
|
783
|
+
has_zone_pools = provision_type && provision_type["id"] && provision_type["hasZonePools"]
|
|
784
|
+
if has_zone_pools
|
|
785
|
+
# pluck out the resourcePoolId option type to prompt for
|
|
786
|
+
resource_pool_option_type = option_type_list.find {|opt| ['poolId','resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
|
|
787
|
+
option_type_list = option_type_list.reject {|opt| ['poolId','resourcePool','resourcePoolId','azureResourceGroupId'].include?(opt['fieldName']) }
|
|
788
|
+
|
|
789
|
+
resource_pool_options = options_interface.options_for_source('zonePools', {groupId: group_id, siteId: group_id, zoneId: cloud_id, cloudId: cloud_id, instanceTypeId: instance_type['id'], layoutId: layout["id"]}.merge(service_plan.nil? ? {} : {planId: service_plan["id"]}))['data']
|
|
790
|
+
if options[:resource_pool]
|
|
791
|
+
resource_pool = resource_pool_options.find {|opt| opt['value'] == options[:resource_pool].to_s || opt['value'] == "pool-#{options[:resource_pool]}"}
|
|
792
|
+
end
|
|
793
|
+
pool_required = provision_type["zonePoolRequired"]
|
|
794
|
+
# Should pool_id have the pool-,poolGroup- prefix or not?
|
|
795
|
+
use_pool_prefix = resource_pool_options.find {|opt| opt['value'].to_s.include?("pool") }
|
|
796
|
+
if resource_pool
|
|
797
|
+
pool_id = resource_pool['id'] # id or value?
|
|
798
|
+
else
|
|
799
|
+
if options[:default_resource_pool]
|
|
800
|
+
default_resource_pool = resource_pool_options.find {|rp| rp['id'] == options[:default_resource_pool]}
|
|
801
|
+
end
|
|
802
|
+
if use_pool_prefix && options[:options]['config'] && options[:options]['config']['resourcePoolId'] && !options[:options]['config']['resourcePoolId'].to_s.include?("pool")
|
|
803
|
+
options[:options]['config']['resourcePoolId'] = "pool-" + options[:options]['config']['resourcePoolId'].to_s
|
|
804
|
+
end
|
|
805
|
+
resource_pool_option_type ||= {'fieldContext' => 'config', 'fieldName' => 'resourcePoolId', 'type' => 'select', 'fieldLabel' => 'Resource Pool', 'selectOptions' => resource_pool_options, 'required' => pool_required, 'skipSingleOption' => true, 'description' => 'Select resource pool.', 'defaultValue' => default_resource_pool ? default_resource_pool['name'] : nil}
|
|
806
|
+
resource_pool_prompt = MtnCloud::Cli::OptionTypes.prompt([resource_pool_option_type],options[:options],api_client,{}, no_prompt, true)
|
|
807
|
+
resource_pool_prompt.deep_compact!
|
|
808
|
+
payload.deep_merge!(resource_pool_prompt)
|
|
809
|
+
# this results in the layout, not the resourcePool for some reason...
|
|
810
|
+
#resource_pool = MtnCloud::Cli::OptionTypes.get_last_select()
|
|
811
|
+
if resource_pool_option_type['fieldContext'] && resource_pool_prompt[resource_pool_option_type['fieldContext']]
|
|
812
|
+
pool_id = resource_pool_prompt[resource_pool_option_type['fieldContext']][resource_pool_option_type['fieldName']]
|
|
813
|
+
elsif resource_pool_prompt[resource_pool_option_type['fieldName']]
|
|
814
|
+
pool_id = resource_pool_prompt[resource_pool_option_type['fieldName']]
|
|
815
|
+
end
|
|
816
|
+
resource_pool ||= resource_pool_options.find {|it| it['value'].to_s == pool_id.to_s}
|
|
817
|
+
end
|
|
818
|
+
end
|
|
819
|
+
end
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
prompt_provision_options = -> {
|
|
823
|
+
if !provision_type.nil? && !provision_type['optionTypes'].nil? && !provision_type['optionTypes'].empty?
|
|
824
|
+
option_type_list += provision_type['optionTypes'].reject {|it| (it['fieldGroup'] || '').downcase == 'provisiontype'}
|
|
825
|
+
provision_config_payload = MtnCloud::Cli::OptionTypes.prompt(provision_type['optionTypes'].reject {|it| (it['fieldGroup'] || '').downcase != 'provisiontype'}, options[:options], @api_client, api_params, no_prompt, true)
|
|
826
|
+
payload.deep_merge!(provision_config_payload)
|
|
827
|
+
end
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
if ['openstack', 'huawei', 'opentelekom'].include?(cloud_type['zoneType']['code'])
|
|
831
|
+
prompt_resource_pool.call
|
|
832
|
+
prompt_provision_options.call
|
|
833
|
+
prompt_service_plan.call
|
|
834
|
+
else
|
|
835
|
+
prompt_service_plan.call
|
|
836
|
+
prompt_provision_options.call
|
|
837
|
+
prompt_resource_pool.call
|
|
838
|
+
end
|
|
839
|
+
|
|
840
|
+
# remove host selection for kubernetes
|
|
841
|
+
if resource_pool
|
|
842
|
+
payload['config']['poolProviderType'] = resource_pool['providerType'] if resource_pool['providerType']
|
|
843
|
+
if resource_pool['providerType'] == 'kubernetes'
|
|
844
|
+
option_type_list = option_type_list.reject {|opt| ['provisionServerId'].include?(opt['fieldName'])}
|
|
845
|
+
end
|
|
846
|
+
|
|
847
|
+
# add selectable datastores
|
|
848
|
+
# no longer use the plan datastores info, always load from data-stores api instead
|
|
849
|
+
# note: this modifies service_plan in place with 'datastores' and 'autoOptions'
|
|
850
|
+
if options[:select_datastore]
|
|
851
|
+
if provision_type['hasDatastore']
|
|
852
|
+
datastore_params = {'zoneId' => cloud_id, 'siteId' => group_id, 'resourcePoolId' => resource_pool['id']}
|
|
853
|
+
load_service_plan_datastores(service_plan, provision_type, datastore_params)
|
|
854
|
+
end
|
|
855
|
+
end
|
|
856
|
+
end
|
|
857
|
+
|
|
858
|
+
# plan_info has this property already..
|
|
859
|
+
# has_datastore = provision_type && provision_type["id"] && provision_type["hasDatastore"]
|
|
860
|
+
# service_plan['hasDatastore'] = has_datastore
|
|
861
|
+
|
|
862
|
+
# set root volume name if has mounts
|
|
863
|
+
mounts = (layout['mounts'] || []).reject {|it| !it['canPersist']}
|
|
864
|
+
if mounts.count > 0
|
|
865
|
+
options[:root_volume_name] = mounts[0]['shortName']
|
|
866
|
+
end
|
|
867
|
+
|
|
868
|
+
# prompt for volumes
|
|
869
|
+
if locked_fields.include?('volumes')
|
|
870
|
+
payload['volumes'] = options[:options]['volumes'] if options[:options]['volumes']
|
|
871
|
+
else
|
|
872
|
+
volumes = prompt_volumes(service_plan, provision_type, options, api_client, {zoneId: cloud_id, layoutId: layout['id'], siteId: group_id})
|
|
873
|
+
if !volumes.empty?
|
|
874
|
+
payload['volumes'] = volumes
|
|
875
|
+
end
|
|
876
|
+
end
|
|
877
|
+
|
|
878
|
+
# plan customizations
|
|
879
|
+
plan_opts = prompt_service_plan_options(service_plan, options, api_client, {zoneId: cloud_id, layoutId: layout['id'], siteId: group_id})
|
|
880
|
+
if plan_opts && !plan_opts.empty?
|
|
881
|
+
payload['servicePlanOptions'] = plan_opts
|
|
882
|
+
end
|
|
883
|
+
|
|
884
|
+
# prompt networks
|
|
885
|
+
if locked_fields.include?('networks')
|
|
886
|
+
# payload['networkInterfaces'] = options[:options]['networkInterfaces'] if options[:options]['networkInterfaces']
|
|
887
|
+
else
|
|
888
|
+
if provision_type && provision_type["hasNetworks"]
|
|
889
|
+
# prompt for network interfaces (if supported)
|
|
890
|
+
begin
|
|
891
|
+
network_interfaces = prompt_network_interfaces(cloud_id, provision_type["id"], pool_id, options.merge({:api_params => payload['config']}))
|
|
892
|
+
if !network_interfaces.empty?
|
|
893
|
+
payload['networkInterfaces'] = network_interfaces
|
|
894
|
+
end
|
|
895
|
+
rescue RestClient::Exception => e
|
|
896
|
+
print yellow,"Unable to load network options. Proceeding...",reset,"\n"
|
|
897
|
+
print_rest_exception(e, options) if MtnCloud::Logging.debug?
|
|
898
|
+
end
|
|
899
|
+
end
|
|
900
|
+
end
|
|
901
|
+
|
|
902
|
+
# Security Groups
|
|
903
|
+
# look for securityGroups option type... this is old and goofy
|
|
904
|
+
sg_option_type = option_type_list.find {|opt| ((opt['code'] == 'provisionType.amazon.securityId') || (opt['fieldName'] == 'securityId' || opt['name'] == 'securityId')) }
|
|
905
|
+
option_type_list = option_type_list.reject {|opt| ((opt['code'] == 'provisionType.amazon.securityId') || (opt['fieldName'] == 'securityId' || opt['name'] == 'securityId')) }
|
|
906
|
+
if locked_fields.include?('securityGroups')
|
|
907
|
+
# payload['securityGroups'] = options[:options]['securityGroups'] if options[:options]['securityGroups']
|
|
908
|
+
else
|
|
909
|
+
# prompt for multiple security groups
|
|
910
|
+
# ok.. seed data has changed and serverTypes do not have this optionType anymore...
|
|
911
|
+
if sg_option_type.nil?
|
|
912
|
+
if provision_type && (provision_type["code"] == 'amazon')
|
|
913
|
+
sg_option_type = {'fieldContext' => 'config', 'fieldName' => 'securityId', 'type' => 'select', 'fieldLabel' => 'Security Group', 'optionSource' => 'amazonSecurityGroup', 'optionSourceType' => 'amazon', 'required' => true, 'description' => 'Select security group.', 'defaultValue' => options[:default_security_group]}
|
|
914
|
+
end
|
|
915
|
+
end
|
|
916
|
+
sg_api_params = {zoneId: cloud_id, poolId: pool_id}
|
|
917
|
+
# The amazon plugin uses a new optionSource options/amazon/awsPluginEc2SecurityGroup
|
|
918
|
+
# which expects parameter config.resourcePoolId=pool-ID
|
|
919
|
+
if sg_option_type
|
|
920
|
+
if sg_option_type['optionSource'] == 'awsPluginEc2SecurityGroup'
|
|
921
|
+
if pool_id
|
|
922
|
+
sg_api_params[:config] ||= {}
|
|
923
|
+
sg_api_params[:config][:resourcePoolId] = pool_id
|
|
924
|
+
end
|
|
925
|
+
# convert multiSelect to select to make prompt_security_groups() work
|
|
926
|
+
# though we should should be able to skip the prompt_security_groups and use multiSelect instead
|
|
927
|
+
sg_option_type['type'] = 'select' if sg_option_type['type'] == 'multiSelect'
|
|
928
|
+
sg_option_type['type'] = 'typeahead' if sg_option_type['type'] == 'multiTypeahead'
|
|
929
|
+
sg_option_type['fieldLabel'] = 'Security Group' if sg_option_type['fieldLabel'] == 'Security Groups'
|
|
930
|
+
sg_option_type['required'] = true
|
|
931
|
+
end
|
|
932
|
+
end
|
|
933
|
+
has_security_groups = !!sg_option_type
|
|
934
|
+
if options[:security_groups]
|
|
935
|
+
available_security_groups = []
|
|
936
|
+
if sg_option_type && sg_option_type['optionSource']
|
|
937
|
+
sg_option_results = options_interface.options_for_source(sg_option_type['optionSource'], sg_api_params, sg_option_type['optionSourceType'])
|
|
938
|
+
available_security_groups = sg_option_results['data'].collect do |it|
|
|
939
|
+
{"id" => it["value"] || it["id"], "name" => it["name"], "value" => it["value"] || it["id"]}
|
|
940
|
+
end
|
|
941
|
+
end
|
|
942
|
+
# work with id or names, API expects ids though.
|
|
943
|
+
payload['securityGroups'] = options[:security_groups].collect {|sg_id|
|
|
944
|
+
found_sg = available_security_groups.find {|it| sg_id && (sg_id.to_s == it['id'].to_s || sg_id.to_s == it['name'].to_s) }
|
|
945
|
+
if found_sg.nil?
|
|
946
|
+
print_red_alert "Security group not found by name or id '#{sg_id}'"
|
|
947
|
+
exit 1
|
|
948
|
+
end
|
|
949
|
+
{'id' => found_sg['id']}
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
elsif has_security_groups
|
|
953
|
+
do_prompt_sg = true
|
|
954
|
+
if options[:default_security_groups]
|
|
955
|
+
payload['securityGroups'] = options[:default_security_groups]
|
|
956
|
+
security_groups_value = options[:default_security_groups].collect {|sg| sg['id'] }.join(',') rescue options[:default_security_groups]
|
|
957
|
+
# do_prompt_sg = (!no_prompt && MtnCloud::Cli::OptionTypes.confirm("Modify security groups? (#{security_groups_value})", {:default => false}))
|
|
958
|
+
do_prompt_sg = (!no_prompt && MtnCloud::Cli::OptionTypes.confirm("Modify security groups?", {:default => false}))
|
|
959
|
+
end
|
|
960
|
+
if do_prompt_sg
|
|
961
|
+
security_groups_array = prompt_security_groups(sg_option_type, sg_api_params, options)
|
|
962
|
+
if !security_groups_array.empty?
|
|
963
|
+
payload['securityGroups'] = security_groups_array.collect {|sg_id| {'id' => sg_id} }
|
|
964
|
+
end
|
|
965
|
+
end
|
|
966
|
+
end
|
|
967
|
+
end
|
|
968
|
+
|
|
969
|
+
# prompt for option types
|
|
970
|
+
api_params['config'] = payload['config'] if payload['config']
|
|
971
|
+
api_params['poolId'] = payload['config']['resourcePoolId'] if payload['config'] && payload['config']['resourcePoolId']
|
|
972
|
+
api_params['resourcePoolId'] = api_params['poolId']
|
|
973
|
+
# some option sources expect networkIntefaces passed as networkInterfaceIds[] eg. oraclecloudAvailabilityDomains
|
|
974
|
+
if payload['networkInterfaces']
|
|
975
|
+
begin
|
|
976
|
+
api_params['networkInterfaceIds[]'] = payload['networkInterfaces'].collect {|it| it['network']['id'] }
|
|
977
|
+
rescue => netex
|
|
978
|
+
MtnCloud::Logging::DarkPrinter.puts "Unable to parse networkInterfaces parameter" if MtnCloud::Logging.debug?
|
|
979
|
+
end
|
|
980
|
+
end
|
|
981
|
+
|
|
982
|
+
# set option type defaults from config
|
|
983
|
+
if options[:default_config]
|
|
984
|
+
options[:default_config].each do |k,v|
|
|
985
|
+
if v && !(v.kind_of?(Array) && v.empty?)
|
|
986
|
+
option_type = option_type_list.find {|ot| ot['fieldContext'] == 'config' && ot['fieldName'] == k}
|
|
987
|
+
option_type['defaultValue'] = v if option_type
|
|
988
|
+
end
|
|
989
|
+
end
|
|
990
|
+
end
|
|
991
|
+
|
|
992
|
+
option_type_list += [
|
|
993
|
+
{'fieldName' => 'userGroup.id', 'fieldLabel' => 'User Group', 'fieldGroup' => 'User Config', 'type' => 'select', 'optionSource' => 'userGroups', 'displayOrder' => 0, 'fieldContext' => 'instance'},
|
|
994
|
+
{'fieldName' => 'hostName', 'fieldLabel' => 'Hostname', 'fieldGroup' => 'Advanced', 'type' => 'string', 'displayOrder' => 1},
|
|
995
|
+
{'fieldName' => 'networkDomain.id', 'fieldLabel' => 'Domain', 'fieldGroup' => 'Advanced', 'type' => 'select', 'optionSource' => 'networkDomains', 'displayOrder' => 2, 'fieldContext' => 'instance'},
|
|
996
|
+
{'fieldName' => 'timezone', 'fieldLabel' => 'Time Zone', 'fieldGroup' => 'Advanced', 'type' => 'select', 'optionSource' => 'timezones', 'displayOrder' => 3, 'fieldContext' => 'config'}
|
|
997
|
+
]
|
|
998
|
+
|
|
999
|
+
if instance_type['hasAutoScale']
|
|
1000
|
+
option_type_list += [
|
|
1001
|
+
{'fieldName' => 'layoutSize', 'fieldLabel' => 'Scale Factor', 'fieldGroup' => 'Advanced', 'type' => 'number', 'defaultValue' => 1, 'displayOrder' => 0},
|
|
1002
|
+
]
|
|
1003
|
+
end
|
|
1004
|
+
|
|
1005
|
+
instance_config_payload = MtnCloud::Cli::OptionTypes.prompt(option_type_list.reject {|ot| ot['type'] == 'exposedPorts'}, options[:options], @api_client, api_params, no_prompt, true)
|
|
1006
|
+
payload.deep_merge!(instance_config_payload)
|
|
1007
|
+
|
|
1008
|
+
# prompt for exposed ports
|
|
1009
|
+
if payload['ports'].nil?
|
|
1010
|
+
# need a way to know if the instanceType even supports this.
|
|
1011
|
+
# the default ports come from the node type, under layout['containerTypes']
|
|
1012
|
+
ports = prompt_exposed_ports(options)
|
|
1013
|
+
if !ports.empty?
|
|
1014
|
+
payload['ports'] = ports
|
|
1015
|
+
end
|
|
1016
|
+
end
|
|
1017
|
+
|
|
1018
|
+
# prompt for environment variables
|
|
1019
|
+
evars = prompt_evars(options)
|
|
1020
|
+
if !evars.empty?
|
|
1021
|
+
payload['evars'] = evars
|
|
1022
|
+
end
|
|
1023
|
+
|
|
1024
|
+
# metadata tags
|
|
1025
|
+
# metadata_tag_key = 'metadata'
|
|
1026
|
+
metadata_tag_key = 'tags'
|
|
1027
|
+
if !options[:metadata]
|
|
1028
|
+
if options[:options]['metadata'].is_a?(Array)
|
|
1029
|
+
options[:metadata] = options[:options]['metadata']
|
|
1030
|
+
end
|
|
1031
|
+
if options[:options]['tags'].is_a?(Array)
|
|
1032
|
+
options[:metadata] = options[:options]['tags']
|
|
1033
|
+
end
|
|
1034
|
+
end
|
|
1035
|
+
if options[:metadata]
|
|
1036
|
+
metadata = []
|
|
1037
|
+
if options[:metadata] == "[]" || options[:metadata] == "null"
|
|
1038
|
+
metadata = []
|
|
1039
|
+
elsif options[:metadata].is_a?(Array)
|
|
1040
|
+
metadata = options[:metadata]
|
|
1041
|
+
else
|
|
1042
|
+
# parse string into format name:value, name:value
|
|
1043
|
+
# merge IDs from current metadata
|
|
1044
|
+
# todo: should allow quoted semicolons..
|
|
1045
|
+
metadata = options[:metadata].split(",").select {|it| !it.to_s.empty? }
|
|
1046
|
+
metadata = metadata.collect do |it|
|
|
1047
|
+
metadata_pair = it.split(":")
|
|
1048
|
+
if metadata_pair.size < 2 && it.include?("=")
|
|
1049
|
+
metadata_pair = it.split("=")
|
|
1050
|
+
end
|
|
1051
|
+
row = {}
|
|
1052
|
+
row['name'] = metadata_pair[0].to_s.strip
|
|
1053
|
+
row['value'] = metadata_pair[1].to_s.strip
|
|
1054
|
+
row
|
|
1055
|
+
end
|
|
1056
|
+
end
|
|
1057
|
+
payload[metadata_tag_key] = metadata
|
|
1058
|
+
else
|
|
1059
|
+
# prompt for metadata tags
|
|
1060
|
+
metadata = prompt_metadata(options)
|
|
1061
|
+
if !metadata.empty?
|
|
1062
|
+
payload[metadata_tag_key] = metadata
|
|
1063
|
+
end
|
|
1064
|
+
end
|
|
1065
|
+
|
|
1066
|
+
# Fix any hugepages option type is using on/off which
|
|
1067
|
+
if payload['config']
|
|
1068
|
+
if payload['config']['hugepages'] == "off"
|
|
1069
|
+
payload['config'].delete('hugepages')
|
|
1070
|
+
end
|
|
1071
|
+
end
|
|
1072
|
+
|
|
1073
|
+
return payload
|
|
1074
|
+
end
|
|
1075
|
+
|
|
1076
|
+
# This recreates the behavior of multi_disk.js
|
|
1077
|
+
# returns array of volumes based on service plan options (plan_info)
|
|
1078
|
+
def prompt_volumes(plan_info, provision_type, options={}, api_client=nil, api_params={})
|
|
1079
|
+
#puts "Configure Volumes:"
|
|
1080
|
+
# return [] if plan_info['noDisks']
|
|
1081
|
+
|
|
1082
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
|
1083
|
+
volumes = []
|
|
1084
|
+
plan_size = 0
|
|
1085
|
+
if plan_info['maxStorage'].to_i > 0
|
|
1086
|
+
plan_size = plan_info['maxStorage'].to_i / (1024 * 1024 * 1024)
|
|
1087
|
+
end
|
|
1088
|
+
root_storage_types = []
|
|
1089
|
+
if plan_info['rootStorageTypes']
|
|
1090
|
+
plan_info['rootStorageTypes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }.each do |opt|
|
|
1091
|
+
if !opt.nil?
|
|
1092
|
+
root_storage_types << {'name' => opt['name'], 'value' => opt['id']}
|
|
1093
|
+
end
|
|
1094
|
+
end
|
|
1095
|
+
end
|
|
1096
|
+
|
|
1097
|
+
storage_types = []
|
|
1098
|
+
if plan_info['storageTypes']
|
|
1099
|
+
plan_info['storageTypes'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }.each do |opt|
|
|
1100
|
+
if !opt.nil?
|
|
1101
|
+
storage_types << {'name' => opt['name'], 'value' => opt['id']}
|
|
1102
|
+
end
|
|
1103
|
+
end
|
|
1104
|
+
end
|
|
1105
|
+
|
|
1106
|
+
datastore_options = []
|
|
1107
|
+
if plan_info['supportsAutoDatastore']
|
|
1108
|
+
if plan_info['autoOptions']
|
|
1109
|
+
plan_info['autoOptions'].each do |opt|
|
|
1110
|
+
if !opt.nil?
|
|
1111
|
+
datastore_options << {'name' => opt['name'], 'value' => opt['id']}
|
|
1112
|
+
end
|
|
1113
|
+
end
|
|
1114
|
+
end
|
|
1115
|
+
end
|
|
1116
|
+
if plan_info['datastores']
|
|
1117
|
+
plan_info['datastores'].each do |k, v|
|
|
1118
|
+
v.each do |opt|
|
|
1119
|
+
if !opt.nil?
|
|
1120
|
+
k = 'datastores' if k == 'store'
|
|
1121
|
+
k = 'clusters' if k == 'cluster'
|
|
1122
|
+
datastore_options << {'name' => "#{k}: #{opt['name']}", 'value' => opt['id']}
|
|
1123
|
+
end
|
|
1124
|
+
end
|
|
1125
|
+
end
|
|
1126
|
+
end
|
|
1127
|
+
# api does not always return datastores, so go get them if needed..
|
|
1128
|
+
if plan_info['hasDatastore'] && datastore_options.empty?
|
|
1129
|
+
option_results = options_interface.options_for_source('datastores', api_params)
|
|
1130
|
+
option_results['data'].each do |it|
|
|
1131
|
+
datastore_options << {"id" => it["value"] || it["id"], "name" => it["name"], "value" => it["value"] || it["id"]}
|
|
1132
|
+
end
|
|
1133
|
+
end
|
|
1134
|
+
storage_profiles = []
|
|
1135
|
+
if provision_type['storageProfiles']
|
|
1136
|
+
storage_profiles = provision_type['storageProfiles'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }.collect {|it| {'name' => it['name'], 'value' => it['code'], 'isDefault' => it['isDefault']} }
|
|
1137
|
+
end
|
|
1138
|
+
|
|
1139
|
+
#puts "Configure Root Volume"
|
|
1140
|
+
|
|
1141
|
+
field_context = "rootVolume"
|
|
1142
|
+
|
|
1143
|
+
volume_label = options[:root_volume_name] || 'root'
|
|
1144
|
+
volume = {
|
|
1145
|
+
'id' => -1,
|
|
1146
|
+
'rootVolume' => true,
|
|
1147
|
+
'name' => volume_label,
|
|
1148
|
+
'size' => plan_size,
|
|
1149
|
+
'sizeId' => nil,
|
|
1150
|
+
'storageType' => nil,
|
|
1151
|
+
'datastoreId' => nil
|
|
1152
|
+
}
|
|
1153
|
+
if options[:options] && options[:options]['volumes'] && options[:options]['volumes'][0]
|
|
1154
|
+
volume = options[:options]['volumes'][0]
|
|
1155
|
+
end
|
|
1156
|
+
|
|
1157
|
+
if root_storage_types.empty?
|
|
1158
|
+
# this means there's no configuration, just send a single root volume to the server
|
|
1159
|
+
storage_type_id = nil
|
|
1160
|
+
storage_type = nil
|
|
1161
|
+
else
|
|
1162
|
+
default_storage_type = root_storage_types.find {|t| t['value'].to_s == (volume['typeId'] || volume['storageType']).to_s}
|
|
1163
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageType', 'type' => 'select', 'fieldLabel' => 'Root Storage Type', 'selectOptions' => root_storage_types, 'required' => true, 'defaultFirstOption' => true, 'skipSingleOption' => true, 'description' => 'Choose a storage type.', 'defaultValue' => default_storage_type ? default_storage_type['name'] : volume['storageType']}], options[:options])
|
|
1164
|
+
storage_type_id = v_prompt[field_context]['storageType']
|
|
1165
|
+
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
|
1166
|
+
volume['storageType'] = storage_type_id
|
|
1167
|
+
end
|
|
1168
|
+
|
|
1169
|
+
# sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
|
|
1170
|
+
root_custom_size_options = []
|
|
1171
|
+
if plan_info['rootCustomSizeOptions'] && plan_info['rootCustomSizeOptions'][storage_type_id.to_s]
|
|
1172
|
+
plan_info['rootCustomSizeOptions'][storage_type_id.to_s].each do |opt|
|
|
1173
|
+
if !opt.nil?
|
|
1174
|
+
root_custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
|
1175
|
+
end
|
|
1176
|
+
end
|
|
1177
|
+
end
|
|
1178
|
+
|
|
1179
|
+
if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customLabel']
|
|
1180
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Root Volume Label', 'required' => true, 'description' => 'Enter a volume label.', 'defaultValue' => volume['name']}], options[:options])
|
|
1181
|
+
volume['name'] = v_prompt[field_context]['name']
|
|
1182
|
+
end
|
|
1183
|
+
if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customSize']
|
|
1184
|
+
# provision_type['rootDiskSizeKnown'] == false means size cannot be changed
|
|
1185
|
+
if provision_type['rootDiskSizeKnown'] == false
|
|
1186
|
+
# volume['size'] = plan_size if plan_size.to_i != 0
|
|
1187
|
+
else
|
|
1188
|
+
if root_custom_size_options.empty?
|
|
1189
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'size', 'type' => 'number', 'fieldLabel' => 'Root Volume Size (GB)', 'required' => true, 'description' => 'Enter a volume size (GB).', 'defaultValue' => volume['size']}], options[:options])
|
|
1190
|
+
volume['size'] = v_prompt[field_context]['size']
|
|
1191
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
|
1192
|
+
else
|
|
1193
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => 'Root Volume Size', 'selectOptions' => root_custom_size_options, 'required' => true, 'description' => 'Choose a volume size.', 'defaultValue' => volume['sizeId']}], options[:options])
|
|
1194
|
+
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
|
1195
|
+
volume['size'] = nil #volume.delete('size')
|
|
1196
|
+
end
|
|
1197
|
+
end
|
|
1198
|
+
# root volume storage controller mount input is disabled in the UI.
|
|
1199
|
+
# if plan_info['customizeVolume'] # && storage_type['customStorageController']
|
|
1200
|
+
# cmp = prompt_volume_controller_mount_point(volumes, field_context, volume_index, volume, plan_info, provision_type, options, server)
|
|
1201
|
+
# volume['controllerMountPoint'] = cmp if !cmp.to_s.empty?
|
|
1202
|
+
# end
|
|
1203
|
+
else
|
|
1204
|
+
# might need different logic here ? =o
|
|
1205
|
+
#volume['size'] = plan_size
|
|
1206
|
+
#volume['sizeId'] = nil #volume.delete('sizeId')
|
|
1207
|
+
end
|
|
1208
|
+
|
|
1209
|
+
if !datastore_options.empty? && !provision_type['disableRootDatastore']
|
|
1210
|
+
default_datastore = datastore_options.find {|ds| ds['value'].to_s == volume['datastoreId'].to_s}
|
|
1211
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'datastoreId', 'type' => 'select', 'fieldLabel' => 'Root Datastore', 'selectOptions' => datastore_options, 'required' => true, 'description' => 'Choose a datastore.', 'defaultValue' => default_datastore ? default_datastore['name'] : volume['datastoreId']}], options[:options])
|
|
1212
|
+
volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
|
1213
|
+
end
|
|
1214
|
+
if !storage_profiles.empty?
|
|
1215
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageProfile', 'type' => 'select', 'fieldLabel' => 'Root Storage Profile', 'selectOptions' => storage_profiles, 'required' => false, 'description' => 'Choose a storage profile.'}], options[:options])
|
|
1216
|
+
volume['storageProfile'] = v_prompt[field_context]['storageProfile'] if v_prompt[field_context] && !v_prompt[field_context]['storageProfile'].to_s.empty?
|
|
1217
|
+
end
|
|
1218
|
+
|
|
1219
|
+
volumes << volume
|
|
1220
|
+
|
|
1221
|
+
if plan_info['addVolumes']
|
|
1222
|
+
volume_index = 1
|
|
1223
|
+
has_another_volume = (options[:options] && options[:options]["dataVolume#{volume_index}"]) || (options[:options] && options[:options]['volumes'] && options[:options]['volumes'][volume_index])
|
|
1224
|
+
add_another_volume = has_another_volume || (!no_prompt && MtnCloud::Cli::OptionTypes.confirm("Add data volume?", {:default => (options[:defaultAddFirstDataVolume] == true && volume_index == 1)}))
|
|
1225
|
+
while add_another_volume do
|
|
1226
|
+
#puts "Configure Data #{volume_index} Volume"
|
|
1227
|
+
|
|
1228
|
+
field_context = "dataVolume#{volume_index}"
|
|
1229
|
+
|
|
1230
|
+
#volume_label = (volume_index == 1 ? 'data' : "data #{volume_index}")
|
|
1231
|
+
volume_label = "data-#{volume_index}"
|
|
1232
|
+
volume = {
|
|
1233
|
+
#'id' => -1,
|
|
1234
|
+
'rootVolume' => false,
|
|
1235
|
+
'name' => volume_label,
|
|
1236
|
+
'size' => plan_size,
|
|
1237
|
+
'sizeId' => nil,
|
|
1238
|
+
'storageType' => nil,
|
|
1239
|
+
'datastoreId' => nil
|
|
1240
|
+
}
|
|
1241
|
+
if options[:options] && options[:options]['volumes'] && options[:options]['volumes'][volume_index]
|
|
1242
|
+
volume = options[:options]['volumes'][volume_index]
|
|
1243
|
+
end
|
|
1244
|
+
|
|
1245
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageType', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Storage Type", 'selectOptions' => storage_types, 'required' => true, 'defaultFirstOption' => true, 'skipSingleOption' => true, 'description' => 'Choose a storage type.', 'defaultValue' => volume['storageType']}], options[:options])
|
|
1246
|
+
storage_type_id = v_prompt[field_context]['storageType']
|
|
1247
|
+
volume['storageType'] = storage_type_id
|
|
1248
|
+
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
|
1249
|
+
|
|
1250
|
+
# sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
|
|
1251
|
+
custom_size_options = []
|
|
1252
|
+
if plan_info['customSizeOptions'] && plan_info['customSizeOptions'][storage_type_id.to_s]
|
|
1253
|
+
plan_info['customSizeOptions'][storage_type_id.to_s].each do |opt|
|
|
1254
|
+
if !opt.nil?
|
|
1255
|
+
custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
|
1256
|
+
end
|
|
1257
|
+
end
|
|
1258
|
+
end
|
|
1259
|
+
|
|
1260
|
+
if plan_info['customizeVolume'] && storage_type['customLabel']
|
|
1261
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "Disk #{volume_index} Volume Label", 'required' => true, 'description' => 'Enter a volume label.', 'defaultValue' => volume['name']}], options[:options])
|
|
1262
|
+
volume['name'] = v_prompt[field_context]['name']
|
|
1263
|
+
end
|
|
1264
|
+
if plan_info['customizeVolume'] && storage_type['customSize']
|
|
1265
|
+
if custom_size_options.empty?
|
|
1266
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'size', 'type' => 'number', 'fieldLabel' => "Disk #{volume_index} Volume Size (GB)", 'required' => true, 'description' => 'Enter a volume size (GB).', 'defaultValue' => volume['size']}], options[:options])
|
|
1267
|
+
volume['size'] = v_prompt[field_context]['size']
|
|
1268
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
|
1269
|
+
else
|
|
1270
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Volume Size", 'selectOptions' => custom_size_options, 'required' => true, 'description' => 'Choose a volume size.', 'defaultValue' => volume['sizeId']}], options[:options])
|
|
1271
|
+
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
|
1272
|
+
volume['size'] = nil #volume.delete('size')
|
|
1273
|
+
end
|
|
1274
|
+
else
|
|
1275
|
+
# might need different logic here ? =o
|
|
1276
|
+
volume['size'] = plan_size
|
|
1277
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
|
1278
|
+
end
|
|
1279
|
+
#todo: Pass in virtual_image to prompt based on its storage_controllers (and volume configuration)
|
|
1280
|
+
if plan_info['customizeVolume'] # && storage_type['customStorageController']
|
|
1281
|
+
cmp = prompt_volume_controller_mount_point(volumes, field_context, volume_index, volume, plan_info, provision_type, options, nil)
|
|
1282
|
+
volume['controllerMountPoint'] = cmp if !cmp.to_s.empty?
|
|
1283
|
+
end
|
|
1284
|
+
if !datastore_options.empty?
|
|
1285
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'datastoreId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Datastore", 'selectOptions' => datastore_options, 'required' => true, 'description' => 'Choose a datastore.', 'defaultValue' => volume['datastoreId']}], options[:options])
|
|
1286
|
+
volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
|
1287
|
+
end
|
|
1288
|
+
if !storage_profiles.empty?
|
|
1289
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageProfile', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Storage Profile", 'selectOptions' => storage_profiles, 'required' => false, 'description' => 'Choose a storage profile.'}], options[:options])
|
|
1290
|
+
volume['storageProfile'] = v_prompt[field_context]['storageProfile'] if v_prompt[field_context] && !v_prompt[field_context]['storageProfile'].to_s.empty?
|
|
1291
|
+
end
|
|
1292
|
+
|
|
1293
|
+
volumes << volume
|
|
1294
|
+
|
|
1295
|
+
volume_index += 1
|
|
1296
|
+
if options[:options] && options[:options]['volumes'] && options[:options]['volumes'][volume_index]
|
|
1297
|
+
add_another_volume = true
|
|
1298
|
+
elsif plan_info['maxDisk'] && volume_index >= plan_info['maxDisk']
|
|
1299
|
+
# todo: should maxDisk check consider the root volume too?
|
|
1300
|
+
add_another_volume = false
|
|
1301
|
+
else
|
|
1302
|
+
has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
|
|
1303
|
+
add_another_volume = has_another_volume || (!no_prompt && MtnCloud::Cli::OptionTypes.confirm("Add another data volume?", {:default => false}))
|
|
1304
|
+
end
|
|
1305
|
+
|
|
1306
|
+
end
|
|
1307
|
+
|
|
1308
|
+
end
|
|
1309
|
+
|
|
1310
|
+
return volumes
|
|
1311
|
+
end
|
|
1312
|
+
|
|
1313
|
+
|
|
1314
|
+
# This recreates the behavior of multi_disk.js
|
|
1315
|
+
# returns array of volumes based on service plan options (plan_info)
|
|
1316
|
+
def prompt_resize_volumes(current_volumes, plan_info, provision_type, options={}, server=nil)
|
|
1317
|
+
#puts "Configure Volumes:"
|
|
1318
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
|
1319
|
+
|
|
1320
|
+
current_root_volume = current_volumes[0]
|
|
1321
|
+
|
|
1322
|
+
volumes = []
|
|
1323
|
+
|
|
1324
|
+
plan_size = nil
|
|
1325
|
+
if plan_info['maxStorage'].to_i > 0
|
|
1326
|
+
plan_size = plan_info['maxStorage'].to_i / (1024 * 1024 * 1024)
|
|
1327
|
+
end
|
|
1328
|
+
|
|
1329
|
+
root_storage_types = []
|
|
1330
|
+
if plan_info['rootStorageTypes']
|
|
1331
|
+
plan_info['rootStorageTypes'].each do |opt|
|
|
1332
|
+
if !opt.nil?
|
|
1333
|
+
root_storage_types << {'name' => opt['name'], 'value' => opt['id']}
|
|
1334
|
+
end
|
|
1335
|
+
end
|
|
1336
|
+
end
|
|
1337
|
+
|
|
1338
|
+
storage_types = []
|
|
1339
|
+
if plan_info['storageTypes']
|
|
1340
|
+
plan_info['storageTypes'].each do |opt|
|
|
1341
|
+
if !opt.nil?
|
|
1342
|
+
storage_types << {'name' => opt['name'], 'value' => opt['id']}
|
|
1343
|
+
end
|
|
1344
|
+
end
|
|
1345
|
+
end
|
|
1346
|
+
|
|
1347
|
+
# no longer use the plan datastores info, always load from data-stores api instead
|
|
1348
|
+
# note: this modifies service_plan in place with 'datastores' and 'autoOptions'
|
|
1349
|
+
group_id = cloud_id = options['siteId']
|
|
1350
|
+
cloud_id = options['zoneId']
|
|
1351
|
+
server_resource_pool_id = server ? (server['resourcePoolId'] || (server['resourcePool'] ? server['resourcePool']['id'] : nil)) : nil
|
|
1352
|
+
resource_pool_id = options['resourcePoolId'] || server_resource_pool_id
|
|
1353
|
+
if provision_type['hasDatastore']
|
|
1354
|
+
datastore_params = {'zoneId' => cloud_id, 'siteId' => group_id, 'resourcePoolId' => resource_pool_id}
|
|
1355
|
+
load_service_plan_datastores(plan_info, provision_type, datastore_params)
|
|
1356
|
+
end
|
|
1357
|
+
datastore_options = []
|
|
1358
|
+
if plan_info['supportsAutoDatastore']
|
|
1359
|
+
if plan_info['autoOptions']
|
|
1360
|
+
plan_info['autoOptions'].each do |opt|
|
|
1361
|
+
if !opt.nil?
|
|
1362
|
+
datastore_options << {'name' => opt['name'], 'value' => opt['id']}
|
|
1363
|
+
end
|
|
1364
|
+
end
|
|
1365
|
+
end
|
|
1366
|
+
end
|
|
1367
|
+
if plan_info['datastores']
|
|
1368
|
+
plan_info['datastores'].each do |k, v|
|
|
1369
|
+
v.each do |opt|
|
|
1370
|
+
if !opt.nil?
|
|
1371
|
+
datastore_options << {'name' => "#{k}: #{opt['name']}", 'value' => opt['id']}
|
|
1372
|
+
end
|
|
1373
|
+
end
|
|
1374
|
+
end
|
|
1375
|
+
end
|
|
1376
|
+
storage_profiles = []
|
|
1377
|
+
if provision_type['storageProfiles']
|
|
1378
|
+
storage_profiles = provision_type['storageProfiles'].sort {|x,y| x['displayOrder'] <=> y['displayOrder'] }.collect {|it| {'name' => it['name'], 'value' => it['code'], 'isDefault' => it['isDefault']} }
|
|
1379
|
+
end
|
|
1380
|
+
#puts "Configure Root Volume"
|
|
1381
|
+
|
|
1382
|
+
field_context = "rootVolume"
|
|
1383
|
+
storage_type = nil
|
|
1384
|
+
storage_type_id = nil
|
|
1385
|
+
if root_storage_types.empty?
|
|
1386
|
+
# this means there's no configuration, just send a single root volume to the server
|
|
1387
|
+
storage_type_id = nil
|
|
1388
|
+
storage_type = nil
|
|
1389
|
+
else
|
|
1390
|
+
#v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageType', 'type' => 'select', 'fieldLabel' => 'Root Storage Type', 'selectOptions' => root_storage_types, 'required' => true, 'defaultFirstOption' => true, 'skipSingleOption' => true, 'description' => 'Choose a storage type.'}], options[:options])
|
|
1391
|
+
#storage_type_id = v_prompt[field_context]['storageType']
|
|
1392
|
+
storage_type_id = (current_root_volume['typeId'] || current_root_volume['storageType'] || (current_root_volume['type']['id'] rescue nil))
|
|
1393
|
+
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
|
1394
|
+
end
|
|
1395
|
+
|
|
1396
|
+
# sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
|
|
1397
|
+
root_custom_size_options = []
|
|
1398
|
+
if plan_info['rootCustomSizeOptions'] && plan_info['rootCustomSizeOptions'][storage_type_id.to_s]
|
|
1399
|
+
plan_info['rootCustomSizeOptions'][storage_type_id.to_s].each do |opt|
|
|
1400
|
+
if !opt.nil?
|
|
1401
|
+
root_custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
|
1402
|
+
end
|
|
1403
|
+
end
|
|
1404
|
+
end
|
|
1405
|
+
volume = {
|
|
1406
|
+
'id' => current_root_volume['id'],
|
|
1407
|
+
'rootVolume' => true,
|
|
1408
|
+
'name' => current_root_volume['name'],
|
|
1409
|
+
'size' => get_volume_size(current_root_volume) || plan_size,
|
|
1410
|
+
'sizeId' => nil,
|
|
1411
|
+
'storageType' => storage_type_id,
|
|
1412
|
+
'datastoreId' => current_root_volume['datastoreId']
|
|
1413
|
+
}
|
|
1414
|
+
if !current_root_volume['controllerMountPoint'].to_s.empty?
|
|
1415
|
+
volume['controllerMountPoint'] = current_root_volume['controllerMountPoint']
|
|
1416
|
+
end
|
|
1417
|
+
if !current_root_volume['storageProfile'].to_s.empty?
|
|
1418
|
+
volume['storageProfile'] = current_root_volume['storageProfile']
|
|
1419
|
+
end
|
|
1420
|
+
if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customLabel']
|
|
1421
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Root Volume Label', 'required' => true, 'description' => 'Enter a volume label.', 'defaultValue' => volume['name']}], options[:options])
|
|
1422
|
+
volume['name'] = v_prompt[field_context]['name']
|
|
1423
|
+
end
|
|
1424
|
+
if plan_info['rootDiskCustomizable'] && storage_type && storage_type['customSize']
|
|
1425
|
+
# provision_type['rootDiskSizeKnown'] == false means size cannot be changed
|
|
1426
|
+
if provision_type['rootDiskSizeKnown'] == false
|
|
1427
|
+
# volume['size'] = plan_size if plan_size.to_i != 0
|
|
1428
|
+
else
|
|
1429
|
+
if root_custom_size_options.empty?
|
|
1430
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'size', 'type' => 'number', 'fieldLabel' => 'Root Volume Size (GB)', 'required' => true, 'description' => 'Enter a volume size (GB).', 'defaultValue' => volume['size']}], options[:options])
|
|
1431
|
+
volume['size'] = v_prompt[field_context]['size']
|
|
1432
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
|
1433
|
+
else
|
|
1434
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => 'Root Volume Size', 'selectOptions' => root_custom_size_options, 'required' => true, 'description' => 'Choose a volume size.'}], options[:options])
|
|
1435
|
+
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
|
1436
|
+
volume['size'] = nil #volume.delete('size')
|
|
1437
|
+
end
|
|
1438
|
+
end
|
|
1439
|
+
else
|
|
1440
|
+
# might need different logic here ? =o
|
|
1441
|
+
# volume['size'] = plan_size
|
|
1442
|
+
# volume['sizeId'] = nil #volume.delete('sizeId')
|
|
1443
|
+
end
|
|
1444
|
+
# if !datastore_options.empty?
|
|
1445
|
+
# v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'datastoreId', 'type' => 'select', 'fieldLabel' => 'Root Datastore', 'selectOptions' => datastore_options, 'required' => true, 'description' => 'Choose a datastore.'}], options[:options])
|
|
1446
|
+
# volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
|
1447
|
+
# end
|
|
1448
|
+
if !storage_profiles.empty?
|
|
1449
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageProfile', 'type' => 'select', 'fieldLabel' => 'Root Storage Profile', 'selectOptions' => storage_profiles, 'required' => false, 'description' => 'Choose a storage profile.', 'defaultValue' => volume['storageProfile']}], options[:options])
|
|
1450
|
+
volume['storageProfile'] = v_prompt[field_context]['storageProfile'] if v_prompt[field_context] && !v_prompt[field_context]['storageProfile'].to_s.empty?
|
|
1451
|
+
end
|
|
1452
|
+
volumes << volume
|
|
1453
|
+
|
|
1454
|
+
# modify or delete existing data volumes
|
|
1455
|
+
(1..(current_volumes.size-1)).each do |volume_index|
|
|
1456
|
+
current_volume = current_volumes[volume_index]
|
|
1457
|
+
if current_volume
|
|
1458
|
+
|
|
1459
|
+
field_context = "dataVolume#{volume_index}"
|
|
1460
|
+
|
|
1461
|
+
action_options = [{'name' => 'Modify', 'value' => 'modify'}, {'name' => 'Keep', 'value' => 'keep'}, {'name' => 'Delete', 'value' => 'delete'}]
|
|
1462
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'action', 'type' => 'select', 'fieldLabel' => "Modify/Keep/Delete volume '#{current_volume['name']}'", 'selectOptions' => action_options, 'required' => true, 'defaultValue' => 'keep', 'description' => 'Modify, Keep or Delete existing data volume?'}], options[:options])
|
|
1463
|
+
volume_action = v_prompt[field_context]['action']
|
|
1464
|
+
|
|
1465
|
+
if volume_action == 'delete'
|
|
1466
|
+
# deleted volume is just excluded from post params
|
|
1467
|
+
next
|
|
1468
|
+
elsif volume_action == 'keep'
|
|
1469
|
+
volume = {
|
|
1470
|
+
'id' => current_volume['id'].to_i,
|
|
1471
|
+
'rootVolume' => false,
|
|
1472
|
+
'name' => current_volume['name'],
|
|
1473
|
+
'size' => get_volume_size(current_volume) || plan_size,
|
|
1474
|
+
'sizeId' => nil,
|
|
1475
|
+
'storageType' => (current_volume['typeId'] || current_volume['storageType'] || (current_volume['type']['id'] rescue nil)),
|
|
1476
|
+
'datastoreId' => current_volume['datastoreId']
|
|
1477
|
+
}
|
|
1478
|
+
if !current_volume['controllerMountPoint'].to_s.empty?
|
|
1479
|
+
volume['controllerMountPoint'] = current_volume['controllerMountPoint']
|
|
1480
|
+
end
|
|
1481
|
+
if !current_volume['storageProfile'].to_s.empty?
|
|
1482
|
+
volume['storageProfile'] = current_volume['storageProfile']
|
|
1483
|
+
end
|
|
1484
|
+
volumes << volume
|
|
1485
|
+
else
|
|
1486
|
+
# v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageType', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Storage Type", 'selectOptions' => storage_types, 'required' => true, 'skipSingleOption' => true, 'description' => 'Choose a storage type.'}], options[:options])
|
|
1487
|
+
# storage_type_id = v_prompt[field_context]['storageType']
|
|
1488
|
+
storage_type_id = (current_volume['typeId'] || current_volume['storageType'] || (current_volume['type']['id'] rescue nil))
|
|
1489
|
+
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
|
1490
|
+
# sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
|
|
1491
|
+
custom_size_options = []
|
|
1492
|
+
if plan_info['customSizeOptions'] && plan_info['customSizeOptions'][storage_type_id.to_s]
|
|
1493
|
+
plan_info['customSizeOptions'][storage_type_id.to_s].each do |opt|
|
|
1494
|
+
if !opt.nil?
|
|
1495
|
+
custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
|
1496
|
+
end
|
|
1497
|
+
end
|
|
1498
|
+
end
|
|
1499
|
+
|
|
1500
|
+
volume = {
|
|
1501
|
+
'id' => current_volume['id'].to_i,
|
|
1502
|
+
'rootVolume' => false,
|
|
1503
|
+
'name' => current_volume['name'],
|
|
1504
|
+
'size' => get_volume_size(current_volume) || plan_size,
|
|
1505
|
+
'sizeId' => nil,
|
|
1506
|
+
'storageType' => (current_volume['typeId'] || current_volume['storageType'] || (current_volume['type']['id'] rescue current_volume['type'])),
|
|
1507
|
+
'datastoreId' => current_volume['datastoreId']
|
|
1508
|
+
}
|
|
1509
|
+
if !current_volume['controllerMountPoint'].to_s.empty?
|
|
1510
|
+
volume['controllerMountPoint'] = current_volume['controllerMountPoint']
|
|
1511
|
+
end
|
|
1512
|
+
if !current_volume['storageProfile'].to_s.empty?
|
|
1513
|
+
volume['storageProfile'] = current_volume['storageProfile']
|
|
1514
|
+
end
|
|
1515
|
+
if plan_info['customizeVolume'] && storage_type['customLabel']
|
|
1516
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "Disk #{volume_index} Volume Label", 'required' => true, 'description' => 'Enter a volume label.', 'defaultValue' => volume['name']}], options[:options])
|
|
1517
|
+
volume['name'] = v_prompt[field_context]['name']
|
|
1518
|
+
end
|
|
1519
|
+
if plan_info['customizeVolume'] && storage_type['customSize']
|
|
1520
|
+
if custom_size_options.empty?
|
|
1521
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'size', 'type' => 'number', 'fieldLabel' => "Disk #{volume_index} Volume Size (GB)", 'required' => true, 'description' => 'Enter a volume size (GB).', 'defaultValue' => volume['size']}], options[:options])
|
|
1522
|
+
volume['size'] = v_prompt[field_context]['size']
|
|
1523
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
|
1524
|
+
else
|
|
1525
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Volume Size", 'selectOptions' => custom_size_options, 'required' => true, 'description' => 'Choose a volume size.'}], options[:options])
|
|
1526
|
+
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
|
1527
|
+
volume['size'] = nil #volume.delete('size')
|
|
1528
|
+
end
|
|
1529
|
+
else
|
|
1530
|
+
# might need different logic here ? =o
|
|
1531
|
+
# volume['size'] = plan_size
|
|
1532
|
+
# volume['sizeId'] = nil #volume.delete('sizeId')
|
|
1533
|
+
end
|
|
1534
|
+
# if plan_info['customizeVolume'] # && storage_type['customStorageController']
|
|
1535
|
+
# cmp = prompt_volume_controller_mount_point(volumes, field_context, volume_index, volume, plan_info, provision_type, options, server)
|
|
1536
|
+
# volume['controllerMountPoint'] = cmp if !cmp.to_s.empty?
|
|
1537
|
+
# end
|
|
1538
|
+
# if !datastore_options.empty?
|
|
1539
|
+
# v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'datastoreId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Datastore", 'selectOptions' => datastore_options, 'required' => true, 'description' => 'Choose a datastore.'}], options[:options])
|
|
1540
|
+
# volume['datastoreId'] = v_prompt[field_context]['datastoreId']
|
|
1541
|
+
# end
|
|
1542
|
+
if !storage_profiles.empty?
|
|
1543
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageProfile', 'type' => 'select', 'fieldLabel' => 'Root Storage Profile', 'selectOptions' => storage_profiles, 'required' => false, 'description' => 'Choose a storage profile.', 'defaultValue' => current_volume['storageProfile']}], options[:options])
|
|
1544
|
+
volume['storageProfile'] = v_prompt[field_context]['storageProfile'] if v_prompt[field_context] && !v_prompt[field_context]['storageProfile'].to_s.empty?
|
|
1545
|
+
end
|
|
1546
|
+
|
|
1547
|
+
volumes << volume
|
|
1548
|
+
|
|
1549
|
+
end
|
|
1550
|
+
|
|
1551
|
+
end
|
|
1552
|
+
end
|
|
1553
|
+
|
|
1554
|
+
|
|
1555
|
+
if plan_info['addVolumes']
|
|
1556
|
+
volume_index = current_volumes.size
|
|
1557
|
+
has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
|
|
1558
|
+
add_another_volume = has_another_volume || (!no_prompt && MtnCloud::Cli::OptionTypes.confirm("Add data volume?", {:default => false}))
|
|
1559
|
+
while add_another_volume do
|
|
1560
|
+
#puts "Configure Data #{volume_index} Volume"
|
|
1561
|
+
previous_volume = volumes.last
|
|
1562
|
+
default_storage_type_id = (previous_volume['typeId'] || previous_volume['storageType'] || (previous_volume['type']['id'] rescue previous_volume['type']))
|
|
1563
|
+
storage_type_match = storage_types.find {|type| type['value'] == default_storage_type_id}
|
|
1564
|
+
default_storage_type = storage_type_match ? (storage_type_match['name'] || storage_type_match['value']) : nil
|
|
1565
|
+
field_context = "dataVolume#{volume_index}"
|
|
1566
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'defaultValue' => default_storage_type, 'fieldContext' => field_context, 'fieldName' => 'storageType', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Storage Type", 'selectOptions' => storage_types, 'required' => true, 'defaultFirstOption' => true, 'skipSingleOption' => true, 'description' => 'Choose a storage type.'}], options[:options])
|
|
1567
|
+
storage_type_id = v_prompt[field_context]['storageType']
|
|
1568
|
+
storage_type = plan_info['storageTypes'].find {|i| i['id'] == storage_type_id.to_i }
|
|
1569
|
+
|
|
1570
|
+
# sometimes the user chooses sizeId from a list of size options (AccountPrice) and other times it is free form
|
|
1571
|
+
custom_size_options = []
|
|
1572
|
+
if plan_info['customSizeOptions'] && plan_info['customSizeOptions'][storage_type_id.to_s]
|
|
1573
|
+
plan_info['customSizeOptions'][storage_type_id.to_s].each do |opt|
|
|
1574
|
+
if !opt.nil?
|
|
1575
|
+
custom_size_options << {'name' => opt['value'], 'value' => opt['key']}
|
|
1576
|
+
end
|
|
1577
|
+
end
|
|
1578
|
+
end
|
|
1579
|
+
|
|
1580
|
+
#volume_label = (volume_index == 1 ? 'data' : "data #{volume_index}")
|
|
1581
|
+
volume_label = "data-#{volume_index}"
|
|
1582
|
+
volume = {
|
|
1583
|
+
'id' => -1,
|
|
1584
|
+
'rootVolume' => false,
|
|
1585
|
+
'name' => volume_label,
|
|
1586
|
+
'size' => plan_size,
|
|
1587
|
+
'sizeId' => nil,
|
|
1588
|
+
'storageType' => storage_type_id,
|
|
1589
|
+
'datastoreId' => nil
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
if plan_info['customizeVolume'] && storage_type['customLabel']
|
|
1593
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "Disk #{volume_index} Volume Label", 'required' => true, 'description' => 'Enter a volume label.', 'defaultValue' => volume_label}], options[:options])
|
|
1594
|
+
volume['name'] = v_prompt[field_context]['name']
|
|
1595
|
+
end
|
|
1596
|
+
if plan_info['customizeVolume'] && storage_type['customSize']
|
|
1597
|
+
if custom_size_options.empty?
|
|
1598
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'size', 'type' => 'number', 'fieldLabel' => "Disk #{volume_index} Volume Size (GB)", 'required' => true, 'description' => 'Enter a volume size (GB).', 'defaultValue' => volume['size']}], options[:options])
|
|
1599
|
+
volume['size'] = v_prompt[field_context]['size']
|
|
1600
|
+
volume['sizeId'] = nil #volume.delete('sizeId')
|
|
1601
|
+
else
|
|
1602
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'sizeId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Volume Size", 'selectOptions' => custom_size_options, 'required' => true, 'description' => 'Choose a volume size.'}], options[:options])
|
|
1603
|
+
volume['sizeId'] = v_prompt[field_context]['sizeId']
|
|
1604
|
+
volume['size'] = nil #volume.delete('size')
|
|
1605
|
+
end
|
|
1606
|
+
else
|
|
1607
|
+
# might need different logic here ? =o
|
|
1608
|
+
# volume['size'] = plan_size
|
|
1609
|
+
# volume['sizeId'] = nil #volume.delete('sizeId')
|
|
1610
|
+
end
|
|
1611
|
+
if plan_info['customizeVolume'] # && storage_type['customStorageController']
|
|
1612
|
+
cmp = prompt_volume_controller_mount_point(volumes, field_context, volume_index, volume, plan_info, provision_type, options, server)
|
|
1613
|
+
volume['controllerMountPoint'] = cmp if !cmp.to_s.empty?
|
|
1614
|
+
end
|
|
1615
|
+
if !datastore_options.empty?
|
|
1616
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'datastoreId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Datastore", 'selectOptions' => datastore_options, 'required' => true, 'description' => 'Choose a datastore.', 'defaultValue' => current_root_volume['datastoreId']}], options[:options])
|
|
1617
|
+
volume['datastoreId'] = v_prompt[field_context]['datastoreId'] unless v_prompt[field_context]['datastoreId'].to_s.empty?
|
|
1618
|
+
end
|
|
1619
|
+
if !storage_profiles.empty?
|
|
1620
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'storageProfile', 'type' => 'select', 'fieldLabel' => 'Root Storage Profile', 'selectOptions' => storage_profiles, 'required' => false, 'description' => 'Choose a storage profile.'}], options[:options])
|
|
1621
|
+
volume['storageProfile'] = v_prompt[field_context]['storageProfile'] if v_prompt[field_context] && !v_prompt[field_context]['storageProfile'].to_s.empty?
|
|
1622
|
+
end
|
|
1623
|
+
|
|
1624
|
+
volumes << volume
|
|
1625
|
+
|
|
1626
|
+
# todo: should maxDisk check consider the root volume too?
|
|
1627
|
+
if plan_info['maxDisk'] && volume_index >= plan_info['maxDisk']
|
|
1628
|
+
add_another_volume = false
|
|
1629
|
+
else
|
|
1630
|
+
volume_index += 1
|
|
1631
|
+
has_another_volume = options[:options] && options[:options]["dataVolume#{volume_index}"]
|
|
1632
|
+
add_another_volume = has_another_volume || (!no_prompt && MtnCloud::Cli::OptionTypes.confirm("Add another data volume?", {default:false}))
|
|
1633
|
+
end
|
|
1634
|
+
|
|
1635
|
+
end
|
|
1636
|
+
|
|
1637
|
+
end
|
|
1638
|
+
|
|
1639
|
+
return volumes
|
|
1640
|
+
end
|
|
1641
|
+
|
|
1642
|
+
# loads datastores and modifies service_plan in place
|
|
1643
|
+
# populating datastores: {datastores: [],clusters: []}, supportsAutoDatastore: true, autoOptions: []
|
|
1644
|
+
def load_service_plan_datastores(service_plan, provision_type, params)
|
|
1645
|
+
begin
|
|
1646
|
+
selectable_datastores = datastores_interface.list(params)
|
|
1647
|
+
service_plan['datastores'] = {'clusters' => [], 'datastores' => []}
|
|
1648
|
+
['clusters', 'datastores'].each do |type|
|
|
1649
|
+
service_plan['datastores'][type] ||= []
|
|
1650
|
+
selectable_datastores[type].reject { |ds| service_plan['datastores'][type].find {|it| it['id'] == ds['id']} }.each { |ds|
|
|
1651
|
+
service_plan['datastores'][type] << ds
|
|
1652
|
+
}
|
|
1653
|
+
end
|
|
1654
|
+
rescue => error
|
|
1655
|
+
MtnCloud::Logging::DarkPrinter.puts "Unable to load available data-stores, using datastores option source instead." if MtnCloud::Logging.debug?
|
|
1656
|
+
end
|
|
1657
|
+
|
|
1658
|
+
if provision_type && provision_type['supportsAutoDatastore']
|
|
1659
|
+
service_plan['supportsAutoDatastore'] = true
|
|
1660
|
+
service_plan['autoOptions'] ||= []
|
|
1661
|
+
if service_plan['datastores'] && service_plan['datastores']['clusters']
|
|
1662
|
+
if service_plan['datastores']['clusters'].count > 0 && !service_plan['autoOptions'].find {|it| it['id'] == 'autoCluster'}
|
|
1663
|
+
service_plan['autoOptions'] << {'id' => 'autoCluster', 'name' => 'Auto - Cluster'}
|
|
1664
|
+
end
|
|
1665
|
+
else
|
|
1666
|
+
service_plan['autoOptions'] << {'id' => 'autoCluster', 'name' => 'Auto - Cluster'}
|
|
1667
|
+
end
|
|
1668
|
+
if service_plan['datastores'] && service_plan['datastores']['datastores']
|
|
1669
|
+
if service_plan['datastores']['datastores'].count > 0 && !service_plan['autoOptions'].find {|it| it['id'] == 'auto'}
|
|
1670
|
+
service_plan['autoOptions'] << {'id' => 'auto', 'name' => 'Auto - Datastore'}
|
|
1671
|
+
end
|
|
1672
|
+
else
|
|
1673
|
+
service_plan['autoOptions'] << {'id' => 'auto', 'name' => 'Auto - Datastore'}
|
|
1674
|
+
end
|
|
1675
|
+
end
|
|
1676
|
+
return service_plan
|
|
1677
|
+
end
|
|
1678
|
+
|
|
1679
|
+
def get_volume_size(volume)
|
|
1680
|
+
if volume['size'].to_i > 0
|
|
1681
|
+
volume['size']
|
|
1682
|
+
elsif volume['maxStorage'].to_i > 0
|
|
1683
|
+
volume['maxStorage'].to_i / (1024**3)
|
|
1684
|
+
else
|
|
1685
|
+
nil
|
|
1686
|
+
end
|
|
1687
|
+
end
|
|
1688
|
+
|
|
1689
|
+
def prompt_volume_controller_mount_point(volumes, field_context, volume_index, volume, plan_info, provision_type, options={}, server=nil)
|
|
1690
|
+
begin
|
|
1691
|
+
# The /api/provision-types has always returned all the controllerTypes, yay
|
|
1692
|
+
# It did not return hasStorageControllers: true|false though, so fallback to checking if controllerTypes.size > 0.
|
|
1693
|
+
# has_storage_controllers = provision_type['hasStorageControllers'] || ['vmware'].include?(provision_type['code'])
|
|
1694
|
+
# storage_controller_types = has_storage_controllers ? options_interface.options_for_source('storageControllerTypes',{provisionTypeId:provision_type['id']})['data'] : []
|
|
1695
|
+
storage_controller_types = provision_type['controllerTypes']
|
|
1696
|
+
has_storage_controllers = provision_type['hasStorageControllers'] || (storage_controller_types && !storage_controller_types.empty?)
|
|
1697
|
+
storage_controllers = server ? server['controllers'] : []
|
|
1698
|
+
if has_storage_controllers
|
|
1699
|
+
# existing storage controllers from server
|
|
1700
|
+
storage_controller_options = []
|
|
1701
|
+
storage_controller_options.push({'name' => 'Auto', 'value' => 'auto'})
|
|
1702
|
+
storage_controller_options.push({'name' => 'New', 'value' => -1})
|
|
1703
|
+
storage_controllers.each_with_index do |sc, index|
|
|
1704
|
+
# storage_controller_options.push({'name' => sc['name'], 'value' => sc['id']})
|
|
1705
|
+
# API did not always return controller busNumber so extract from the volume mountPoint if needed
|
|
1706
|
+
if sc['busNumber'].nil?
|
|
1707
|
+
matching_volume = volumes.find {|v| v['controllerMountPoint'] && v['controllerMountPoint'].split(':')[0] == sc['id'].to_s }
|
|
1708
|
+
if matching_volume
|
|
1709
|
+
sc['busNumber'] = matching_volume['controllerMountPoint'].split(":")[1]
|
|
1710
|
+
end
|
|
1711
|
+
end
|
|
1712
|
+
sct = storage_controller_types.find { |t| t['id'] == sc['type']['id'] }
|
|
1713
|
+
storage_controller_options.push({'name' => "#{sct['category'].to_s.upcase rescue ''} #{sc['busNumber'] || index}", 'value' => sc['id']})
|
|
1714
|
+
end if storage_controllers
|
|
1715
|
+
# The controller mount point specification for this volume in the format: `id:busNumber:typeId:unitNumber"`
|
|
1716
|
+
# For new storage controllers the id is passed as -1, so an example value would be: `"-1:1:6:0"` which translates to id: -1 (new), busNumber: 1, storage controller type id: 6 (SCSI VMware Paravirtual), unit number: 0.
|
|
1717
|
+
# Split -O dataVolume1.controllerMountPoint="-1:1:6:0" into its components.
|
|
1718
|
+
controller_mount_point = ""
|
|
1719
|
+
controller_id, bus_number, controller_type_id, unit_number = nil, nil, nil, nil
|
|
1720
|
+
if options[:options][field_context] && options[:options][field_context]['controllerMountPoint']
|
|
1721
|
+
parts = options[:options][field_context]['controllerMountPoint'].split(":").collect {|it| it.to_s.strip }
|
|
1722
|
+
controller_id, bus_number, controller_type_id, unit_number = parts[0],parts[1],parts[2],parts[3]
|
|
1723
|
+
# if we dont have every part then clear the options value so it prompt down below
|
|
1724
|
+
if controller_id.to_s.empty? || bus_number.to_s.empty? || controller_type_id.to_s.empty? || unit_number.to_s.empty?
|
|
1725
|
+
options[:options][field_context].delete('controllerMountPoint')
|
|
1726
|
+
end
|
|
1727
|
+
end
|
|
1728
|
+
# Select Storage Controller, auto, new or existing
|
|
1729
|
+
# Choose Existing or Add a new controller which requires selecting type selecting type.
|
|
1730
|
+
if !controller_id.to_s.empty?
|
|
1731
|
+
controller_id = controller_id
|
|
1732
|
+
else
|
|
1733
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'controllerId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Storage Controller #{volume_index}", 'selectOptions' => storage_controller_options, 'required' => true, 'description' => 'Choose a storage controller.', 'defaultValue' => (volume['controllerId'] || 'auto') }], options[:options])
|
|
1734
|
+
controller_id = v_prompt[field_context]['controllerId']
|
|
1735
|
+
end
|
|
1736
|
+
skip_controller_mount_point = false
|
|
1737
|
+
if controller_id.to_s == 'auto'
|
|
1738
|
+
# auto just means omit controllerMountPoint
|
|
1739
|
+
skip_controller_mount_point = true
|
|
1740
|
+
elsif controller_id.to_i < 1
|
|
1741
|
+
# -1 (or anything but a positive integer) means new controller
|
|
1742
|
+
controller_id = -1
|
|
1743
|
+
elsif controller_id
|
|
1744
|
+
controller_id = controller_id.to_i
|
|
1745
|
+
end
|
|
1746
|
+
if skip_controller_mount_point
|
|
1747
|
+
# skip mount point parameter
|
|
1748
|
+
# volume.delete('controllerMountPoint')
|
|
1749
|
+
# volume.delete('controllerId')
|
|
1750
|
+
return nil
|
|
1751
|
+
else
|
|
1752
|
+
storage_controller_type = nil
|
|
1753
|
+
storage_controller = nil
|
|
1754
|
+
# New Controller?
|
|
1755
|
+
if controller_id == -1
|
|
1756
|
+
#[field_context]['controllerTypeId'] controller_type_id = unless controller_type_id.to_s.empty?
|
|
1757
|
+
storage_controller_type_options = storage_controller_types.sort {|a,b| a['displayOrder'].to_i <=> b['displayOrder'].to_i}.collect {|it| {"name" => it["name"], "value" => it["id"]}}
|
|
1758
|
+
if !controller_type_id.to_s.empty?
|
|
1759
|
+
options[:options][field_context]['controllerTypeId'] = controller_type_id
|
|
1760
|
+
end
|
|
1761
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'controllerTypeId', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Storage Controller Type", 'selectOptions' => storage_controller_type_options, 'required' => true, 'description' => 'Choose a storage controller type.'}], options[:options])
|
|
1762
|
+
controller_type_id = v_prompt[field_context]['controllerTypeId']
|
|
1763
|
+
# find the selected controller type
|
|
1764
|
+
storage_controller_type = storage_controller_types.find {|it| it['id'] == controller_type_id }
|
|
1765
|
+
if storage_controller_type.nil?
|
|
1766
|
+
raise_command_error("Storage controller type not found for id #{controller_type_id}")
|
|
1767
|
+
end
|
|
1768
|
+
storage_controller = {'id' => -1, 'type' => {'id' => storage_controller_type['id']}}
|
|
1769
|
+
max_devices = storage_controller_type['maxDevices'] || 1
|
|
1770
|
+
reserved_bus_numbers = storage_controllers.select {|it| it['category'] == storage_controller_type['category'] }.collect {|it| it['busNumber'].to_s}.uniq
|
|
1771
|
+
bus_number = bus_number.to_i || 0
|
|
1772
|
+
while true
|
|
1773
|
+
if !reserved_bus_numbers.include?(bus_number.to_s)
|
|
1774
|
+
break
|
|
1775
|
+
else
|
|
1776
|
+
next_bus_number = bus_number + 1
|
|
1777
|
+
if next_bus_number >= max_devices
|
|
1778
|
+
MtnCloud::Logging::DarkPrinter.puts "Failed to find an available bus number!"
|
|
1779
|
+
break
|
|
1780
|
+
end
|
|
1781
|
+
bus_number = next_bus_number
|
|
1782
|
+
end
|
|
1783
|
+
end
|
|
1784
|
+
storage_controller['busNumber'] = bus_number.to_s
|
|
1785
|
+
storage_controller['name'] = "#{storage_controller_type['category'].to_s.upcase} #{bus_number}"
|
|
1786
|
+
# storage_controller['unitNumber'] = "null"
|
|
1787
|
+
# add new controller to the list
|
|
1788
|
+
storage_controllers.push(storage_controller)
|
|
1789
|
+
else
|
|
1790
|
+
# existing controller
|
|
1791
|
+
# controller_type_id = controller_type_id
|
|
1792
|
+
# find the selected controller type
|
|
1793
|
+
storage_controller = storage_controllers.find {|it| it['id'] == controller_id.to_i }
|
|
1794
|
+
if storage_controller.nil?
|
|
1795
|
+
raise_command_error("Storage controller type not found for id #{controller_type_id}")
|
|
1796
|
+
end
|
|
1797
|
+
end
|
|
1798
|
+
# Choose Controller Mount Point
|
|
1799
|
+
mount_point_options = []
|
|
1800
|
+
controller_list = storage_controllers
|
|
1801
|
+
# only show the selected controller
|
|
1802
|
+
controller_list = [storage_controller]
|
|
1803
|
+
controller_list.each do |sc|
|
|
1804
|
+
sct = storage_controller_types.find { |t| t['id'] == sc['type']['id'] }
|
|
1805
|
+
category = sct['category']
|
|
1806
|
+
max_devices = sct['maxDevices'] || 1
|
|
1807
|
+
matching_type_ids = storage_controller_types.select { |t| t['category'] == category }.collect {|t| t['id'] }
|
|
1808
|
+
# find available unit numbers by reversing the controllerMountPoint to find matching types, blarghhh
|
|
1809
|
+
reserved_unit_numbers = (volumes || []).collect {|v|
|
|
1810
|
+
if !v['controllerMountPoint'].to_s.empty?
|
|
1811
|
+
parts = v['controllerMountPoint'].split(":")
|
|
1812
|
+
vol_controller_id = parts[0]
|
|
1813
|
+
vol_bus_number = parts[1]
|
|
1814
|
+
vol_sct_id = parts[2]
|
|
1815
|
+
vol_unit_number = parts[3]
|
|
1816
|
+
if matching_type_ids.include?(vol_sct_id.to_i)
|
|
1817
|
+
vol_unit_number.to_i
|
|
1818
|
+
else
|
|
1819
|
+
nil
|
|
1820
|
+
end
|
|
1821
|
+
else
|
|
1822
|
+
nil
|
|
1823
|
+
end
|
|
1824
|
+
}.compact.uniq
|
|
1825
|
+
(0..(max_devices - 1)).each do |index|
|
|
1826
|
+
cmp_value = [sc['id'],sc['busNumber'],sct['id'],index].join(":")
|
|
1827
|
+
if reserved_unit_numbers.include?(index)
|
|
1828
|
+
#mount_point_options << {'name' => "#{category.to_s.upcase} #{sc['busNumber']}:#{index}", 'value' => cmp_value}
|
|
1829
|
+
else
|
|
1830
|
+
mount_point_options << {'name' => "#{category.to_s.upcase} #{sc['busNumber']}:#{index}", 'value' => cmp_value}
|
|
1831
|
+
end
|
|
1832
|
+
end
|
|
1833
|
+
end
|
|
1834
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'controllerMountPoint', 'type' => 'select', 'fieldLabel' => "Disk #{volume_index} Controller Mount Point", 'selectOptions' => mount_point_options, 'required' => true, 'description' => 'Choose a storage controller mount point.'}], options[:options])
|
|
1835
|
+
controller_mount_point = v_prompt[field_context]['controllerMountPoint']
|
|
1836
|
+
# build controllerMountPoint parameter as "id:busNumber:typeId:unitNumber"
|
|
1837
|
+
#controller_mount_point = [controller_id, bus_number, controller_type_id, unit_number].collect {|it| it.to_s.strip}.join(":")
|
|
1838
|
+
# volume['controllerMountPoint'] = controller_mount_point
|
|
1839
|
+
return controller_mount_point
|
|
1840
|
+
end
|
|
1841
|
+
else
|
|
1842
|
+
# storage controllers not supported, carry on then
|
|
1843
|
+
end
|
|
1844
|
+
rescue => e
|
|
1845
|
+
raise e
|
|
1846
|
+
MtnCloud::Cli::ErrorHandler.new(my_terminal.stderr).handle_error(e) if MtnCloud::Logging.debug?
|
|
1847
|
+
MtnCloud::Logging::DarkPrinter.puts "Failed to prompt for storage controller. Proceeding..."
|
|
1848
|
+
end
|
|
1849
|
+
end
|
|
1850
|
+
|
|
1851
|
+
# This recreates the behavior of multi_networks.js
|
|
1852
|
+
# This is used by both `instances add` and `hosts add`
|
|
1853
|
+
# returns array of networkInterfaces based on provision type and cloud settings
|
|
1854
|
+
def prompt_network_interfaces(zone_id, provision_type_id, pool_id, options={})
|
|
1855
|
+
#puts "Configure Networks:"
|
|
1856
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
|
1857
|
+
network_interfaces = []
|
|
1858
|
+
api_params = {zoneId: zone_id, provisionTypeId: provision_type_id}.merge(options[:api_params] || {})
|
|
1859
|
+
if pool_id
|
|
1860
|
+
api_params[:poolId] = pool_id
|
|
1861
|
+
end
|
|
1862
|
+
|
|
1863
|
+
zone_network_options_json = api_client.options.options_for_source('zoneNetworkOptions', api_params)
|
|
1864
|
+
# puts "zoneNetworkOptions JSON"
|
|
1865
|
+
# puts JSON.pretty_generate(zone_network_options_json)
|
|
1866
|
+
zone_network_data = zone_network_options_json['data'] || {}
|
|
1867
|
+
networks = zone_network_data['networks']
|
|
1868
|
+
network_groups = zone_network_data['networkGroups']
|
|
1869
|
+
if network_groups
|
|
1870
|
+
networks = network_groups + networks
|
|
1871
|
+
end
|
|
1872
|
+
network_subnets = zone_network_data['networkSubnets']
|
|
1873
|
+
if network_subnets
|
|
1874
|
+
networks += network_subnets
|
|
1875
|
+
end
|
|
1876
|
+
network_interface_types = (zone_network_data['networkTypes'] || []).sort { |x,y| x['displayOrder'] <=> y['displayOrder'] }
|
|
1877
|
+
enable_network_type_selection = (zone_network_data['enableNetworkTypeSelection'] == 'on' || zone_network_data['enableNetworkTypeSelection'] == true)
|
|
1878
|
+
has_networks = zone_network_data["hasNetworks"] == true
|
|
1879
|
+
max_networks = (zone_network_data["maxNetworks"].to_i > 0) ? zone_network_data["maxNetworks"].to_i : nil
|
|
1880
|
+
|
|
1881
|
+
# skip unless provision type supports networks
|
|
1882
|
+
if !has_networks
|
|
1883
|
+
return nil
|
|
1884
|
+
end
|
|
1885
|
+
|
|
1886
|
+
# no networks available, shouldn't happen
|
|
1887
|
+
if networks.empty?
|
|
1888
|
+
return network_interfaces
|
|
1889
|
+
end
|
|
1890
|
+
|
|
1891
|
+
network_options = []
|
|
1892
|
+
networks.each do |opt|
|
|
1893
|
+
if !opt.nil?
|
|
1894
|
+
network_options << {'name' => opt['name'], 'value' => opt['id']}
|
|
1895
|
+
end
|
|
1896
|
+
end
|
|
1897
|
+
|
|
1898
|
+
network_interface_type_options = []
|
|
1899
|
+
network_interface_types.each do |opt|
|
|
1900
|
+
if !opt.nil?
|
|
1901
|
+
network_interface_type_options << {'name' => opt['name'], 'value' => opt['id']}
|
|
1902
|
+
end
|
|
1903
|
+
end
|
|
1904
|
+
|
|
1905
|
+
interface_index = 0
|
|
1906
|
+
add_another_interface = true
|
|
1907
|
+
while add_another_interface do
|
|
1908
|
+
# if !no_prompt
|
|
1909
|
+
# if interface_index == 0
|
|
1910
|
+
# puts "Configure Network Interface"
|
|
1911
|
+
# else
|
|
1912
|
+
# puts "Configure Network Interface #{interface_index+1}"
|
|
1913
|
+
# end
|
|
1914
|
+
# end
|
|
1915
|
+
|
|
1916
|
+
# networkInterfaces may be passed as objects from blueprints or via -O networkInterfaces='[]'
|
|
1917
|
+
field_context = interface_index == 0 ? "networkInterface" : "networkInterface#{interface_index+1}"
|
|
1918
|
+
network_interface = {}
|
|
1919
|
+
if options[:options] && options[:options]['networkInterfaces'] && options[:options]['networkInterfaces'][interface_index]
|
|
1920
|
+
network_interface = options[:options]['networkInterfaces'][interface_index]
|
|
1921
|
+
end
|
|
1922
|
+
|
|
1923
|
+
default_network_id = network_interface['networkId'] || network_interface['id']
|
|
1924
|
+
if default_network_id.nil? && network_interface['network'].is_a?(Hash) && network_interface['network']['id']
|
|
1925
|
+
default_network_id = network_interface['network']['id']
|
|
1926
|
+
end
|
|
1927
|
+
# JD: this for cluster or server prompting perhaps?
|
|
1928
|
+
# because zoneNetworkOptions already returns foramt like "id": "network-1"
|
|
1929
|
+
if !default_network_id || !default_network_id.to_s.include?("-")
|
|
1930
|
+
if network_interface['network'] && network_interface['network']['id']
|
|
1931
|
+
if network_interface['network']['subnet']
|
|
1932
|
+
default_network_id = "subnet-#{network_interface['network']['subnet']}"
|
|
1933
|
+
elsif network_interface['network']['group']
|
|
1934
|
+
default_network_id = "networkGroup-#{network_interface['network']['group']}"
|
|
1935
|
+
else
|
|
1936
|
+
default_network_id = "network-#{network_interface['network']['id']}"
|
|
1937
|
+
end
|
|
1938
|
+
end
|
|
1939
|
+
end
|
|
1940
|
+
|
|
1941
|
+
default_network_value = (network_options.find {|n| n['value'] == default_network_id} || {})['name']
|
|
1942
|
+
|
|
1943
|
+
# choose network
|
|
1944
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'networkId', 'type' => 'select', 'fieldLabel' => "Network", 'selectOptions' => network_options, 'required' => true, 'skipSingleOption' => false, 'description' => 'Choose a network for this interface.', 'defaultValue' => default_network_value}], options[:options], api_client, {}, no_prompt, true)
|
|
1945
|
+
network_interface['network'] = {}
|
|
1946
|
+
network_interface['network']['id'] = v_prompt[field_context]['networkId'].to_s
|
|
1947
|
+
selected_network = networks.find {|it| it["id"].to_s == network_interface['network']['id'] }
|
|
1948
|
+
#network_options.reject! {|it| it['value'] == v_prompt[field_context]['networkId']}
|
|
1949
|
+
|
|
1950
|
+
if !selected_network
|
|
1951
|
+
print_red_alert "Network not found by id #{network_interface['network']['id']}!"
|
|
1952
|
+
exit 1
|
|
1953
|
+
end
|
|
1954
|
+
|
|
1955
|
+
# choose network interface type
|
|
1956
|
+
if enable_network_type_selection && !network_interface_type_options.empty?
|
|
1957
|
+
default_interface_type_value = (network_interface_type_options.find {|t| t['value'].to_s == network_interface['networkInterfaceTypeId'].to_s} || {})['name']
|
|
1958
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'networkInterfaceTypeId', 'type' => 'select', 'fieldLabel' => "Network Interface Type", 'selectOptions' => network_interface_type_options, 'required' => true, 'skipSingleOption' => true, 'description' => 'Choose a network interface type.', 'defaultValue' => default_interface_type_value}], options[:options])
|
|
1959
|
+
network_interface['networkInterfaceTypeId'] = v_prompt[field_context]['networkInterfaceTypeId'].to_i
|
|
1960
|
+
selected_network_interface_type = network_interface_types.find {|it| it["id"] == network_interface['networkInterfaceTypeId']}
|
|
1961
|
+
end
|
|
1962
|
+
|
|
1963
|
+
# determine if IP can/should be specified for selected network
|
|
1964
|
+
ip_flags = determine_ip_requirements(selected_network)
|
|
1965
|
+
ip_available = ip_flags[:ip_available]
|
|
1966
|
+
ip_required = ip_flags[:ip_required]
|
|
1967
|
+
|
|
1968
|
+
# Prompt for IP input when static assignment is allowed or an IP is explicitly required
|
|
1969
|
+
if ip_available || ip_required
|
|
1970
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'ipAddress', 'type' => 'text', 'fieldLabel' => "IP Address", 'required' => ip_required, 'description' => 'Enter an IP for this network interface. x.x.x.x', 'defaultValue' => network_interface['ipAddress']}], options[:options])
|
|
1971
|
+
if v_prompt[field_context] && !v_prompt[field_context]['ipAddress'].to_s.empty?
|
|
1972
|
+
network_interface['ipAddress'] = v_prompt[field_context]['ipAddress']
|
|
1973
|
+
end
|
|
1974
|
+
end
|
|
1975
|
+
|
|
1976
|
+
if ip_required == false && network_interface['ipAddress'] == nil && selected_network['dhcpServer'] == true
|
|
1977
|
+
network_interface['ipMode'] = 'dhcp'
|
|
1978
|
+
elsif network_interface['ipAddress']
|
|
1979
|
+
network_interface['ipMode'] = 'static'
|
|
1980
|
+
end
|
|
1981
|
+
|
|
1982
|
+
# prompt for virtual interfaces if supported by the selected network interface type
|
|
1983
|
+
virtual_interfaces = prompt_virtual_interfaces(
|
|
1984
|
+
selected_network_interface_type,
|
|
1985
|
+
networks,
|
|
1986
|
+
network_options,
|
|
1987
|
+
field_context,
|
|
1988
|
+
interface_index,
|
|
1989
|
+
options,
|
|
1990
|
+
no_prompt
|
|
1991
|
+
)
|
|
1992
|
+
virtual_interfaces ||= []
|
|
1993
|
+
network_interface['networkInterfaces'] = virtual_interfaces unless virtual_interfaces.empty?
|
|
1994
|
+
|
|
1995
|
+
# append the interface
|
|
1996
|
+
network_interfaces << network_interface
|
|
1997
|
+
interface_index += 1
|
|
1998
|
+
if options[:options] && options[:options]['networkInterfaces'] && options[:options]['networkInterfaces'][interface_index]
|
|
1999
|
+
add_another_interface = true
|
|
2000
|
+
elsif (max_networks && network_interfaces.size >= max_networks) || network_options.count == 0
|
|
2001
|
+
add_another_interface = false
|
|
2002
|
+
else
|
|
2003
|
+
has_another_interface = options[:options] && options[:options]["networkInterface#{interface_index+1}"]
|
|
2004
|
+
add_another_interface = has_another_interface || (!no_prompt && MtnCloud::Cli::OptionTypes.confirm("Add another network interface?", {:default => false}))
|
|
2005
|
+
end
|
|
2006
|
+
|
|
2007
|
+
end
|
|
2008
|
+
|
|
2009
|
+
return network_interfaces
|
|
2010
|
+
|
|
2011
|
+
end
|
|
2012
|
+
|
|
2013
|
+
# determine if IP can/should be specified for selected network
|
|
2014
|
+
def determine_ip_requirements(selected_network)
|
|
2015
|
+
ip_available = selected_network['allowStaticOverride'] != false
|
|
2016
|
+
ip_required = true
|
|
2017
|
+
if selected_network['id'].to_s.include?('networkGroup')
|
|
2018
|
+
ip_available = false
|
|
2019
|
+
ip_required = false
|
|
2020
|
+
elsif selected_network['pool']
|
|
2021
|
+
ip_required = false
|
|
2022
|
+
elsif selected_network['dhcpServer']
|
|
2023
|
+
ip_required = false
|
|
2024
|
+
end
|
|
2025
|
+
{ip_available: ip_available, ip_required: ip_required}
|
|
2026
|
+
end
|
|
2027
|
+
|
|
2028
|
+
# Prompt for virtual interfaces if supported by the selected network interface type
|
|
2029
|
+
def prompt_virtual_interfaces(selected_network_interface_type, networks, network_options, field_context, interface_index, options, no_prompt)
|
|
2030
|
+
return [] unless selected_network_interface_type && selected_network_interface_type['hasVirtualInterfaces']
|
|
2031
|
+
|
|
2032
|
+
virtual_interfaces = []
|
|
2033
|
+
# gather virtual interface types for the selected network interface type
|
|
2034
|
+
network_interface_types = selected_network_interface_type['virtualInterfaces'] || []
|
|
2035
|
+
return [] if network_interface_types.empty?
|
|
2036
|
+
|
|
2037
|
+
network_interface_type_options = []
|
|
2038
|
+
network_interface_types.each do |opt|
|
|
2039
|
+
next if opt.nil?
|
|
2040
|
+
network_interface_type_options << {'name' => opt['name'], 'value' => opt['id']}
|
|
2041
|
+
end
|
|
2042
|
+
|
|
2043
|
+
# Preconfigured virtual interfaces passed in options
|
|
2044
|
+
prespecified = false
|
|
2045
|
+
preconfigured_vi = []
|
|
2046
|
+
if options[:options]
|
|
2047
|
+
if options[:options]['networkInterfaces'] &&
|
|
2048
|
+
options[:options]['networkInterfaces'][interface_index]
|
|
2049
|
+
preconfigured_vi = options[:options]['networkInterfaces'][interface_index]['networkInterfaces'] || []
|
|
2050
|
+
prespecified = true
|
|
2051
|
+
end
|
|
2052
|
+
if options[:options][field_context].is_a?(Hash) && !options[:options][field_context].empty?
|
|
2053
|
+
prespecified = true
|
|
2054
|
+
end
|
|
2055
|
+
end
|
|
2056
|
+
|
|
2057
|
+
vi_index = 0
|
|
2058
|
+
has_another = false
|
|
2059
|
+
# Process any pre-configured virtual interfaces first, then prompt for additional ones.
|
|
2060
|
+
if preconfigured_vi[vi_index]
|
|
2061
|
+
has_another = true
|
|
2062
|
+
elsif options[:options] && options[:options][field_context] && !options[:options][field_context].empty?
|
|
2063
|
+
has_another = options[:options][field_context]['virtualInterface'] || false
|
|
2064
|
+
end
|
|
2065
|
+
confirm_message = prespecified ? "Add virtual network interface? (under prespecified interface #{interface_index})": "Add virtual network interface?"
|
|
2066
|
+
|
|
2067
|
+
add_another = has_another || (!no_prompt && MtnCloud::Cli::OptionTypes.confirm(confirm_message, {default:false}))
|
|
2068
|
+
while add_another
|
|
2069
|
+
vi_field_context = vi_index == 0 ? "virtualInterface" : "virtualInterface#{vi_index+1}"
|
|
2070
|
+
vi = preconfigured_vi[vi_index] ? preconfigured_vi[vi_index].dup : {}
|
|
2071
|
+
|
|
2072
|
+
# Determine default network for this virtual interface
|
|
2073
|
+
default_network_id = vi['networkId'] || (vi['network'] && vi['network']['id'])
|
|
2074
|
+
default_network_name = (network_options.find {|n| n['value'] == default_network_id} || {})['name']
|
|
2075
|
+
|
|
2076
|
+
# Choose network
|
|
2077
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt(
|
|
2078
|
+
[{
|
|
2079
|
+
'fieldContext' => "#{field_context}.#{vi_field_context}",
|
|
2080
|
+
'fieldName' => 'networkId',
|
|
2081
|
+
'type' => 'select',
|
|
2082
|
+
'fieldLabel' => "Virtual Network",
|
|
2083
|
+
'selectOptions' => network_options,
|
|
2084
|
+
'required' => true,
|
|
2085
|
+
'skipSingleOption' => false,
|
|
2086
|
+
'description' => 'Choose a network for this virtual interface.',
|
|
2087
|
+
'defaultValue' => default_network_name
|
|
2088
|
+
}],
|
|
2089
|
+
options[:options],
|
|
2090
|
+
nil,
|
|
2091
|
+
{},
|
|
2092
|
+
no_prompt,
|
|
2093
|
+
true
|
|
2094
|
+
)
|
|
2095
|
+
vi['network'] ||= {}
|
|
2096
|
+
vi['network']['id'] = v_prompt[field_context][vi_field_context]['networkId'].to_s
|
|
2097
|
+
|
|
2098
|
+
# determine / prompt interface type for virtual interface
|
|
2099
|
+
default_interface_type_id = vi['networkInterfaceTypeId'] ||
|
|
2100
|
+
(vi['networkInterfaceType'] && vi['networkInterfaceType']['id'])
|
|
2101
|
+
default_interface_type_name =
|
|
2102
|
+
(network_interface_type_options.find { |t| t['value'].to_s == default_interface_type_id.to_s } || {})['name']
|
|
2103
|
+
type_prompt = MtnCloud::Cli::OptionTypes.prompt(
|
|
2104
|
+
[{
|
|
2105
|
+
'fieldContext' => "#{field_context}.#{vi_field_context}",
|
|
2106
|
+
'fieldName' => 'networkInterfaceTypeId',
|
|
2107
|
+
'type' => 'select',
|
|
2108
|
+
'fieldLabel' => "Virtual Network Interface Type",
|
|
2109
|
+
'selectOptions' => network_interface_type_options,
|
|
2110
|
+
'required' => true,
|
|
2111
|
+
'skipSingleOption' => true,
|
|
2112
|
+
'description' => 'Choose a network interface type.',
|
|
2113
|
+
'defaultValue' => default_interface_type_name
|
|
2114
|
+
}],
|
|
2115
|
+
options[:options]
|
|
2116
|
+
)
|
|
2117
|
+
vi['networkInterfaceTypeId'] = type_prompt[field_context][vi_field_context]['networkInterfaceTypeId'].to_i
|
|
2118
|
+
|
|
2119
|
+
# IP logic
|
|
2120
|
+
selected_network = networks.find {|n| n['id'].to_s == vi['network']['id'] }
|
|
2121
|
+
if selected_network
|
|
2122
|
+
ip_flags = determine_ip_requirements(selected_network)
|
|
2123
|
+
if ip_flags[:ip_available] || ip_flags[:ip_required]
|
|
2124
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt(
|
|
2125
|
+
[{
|
|
2126
|
+
'fieldContext' => "#{field_context}.#{vi_field_context}",
|
|
2127
|
+
'fieldName' => 'ipAddress',
|
|
2128
|
+
'type' => 'text',
|
|
2129
|
+
'fieldLabel' => "IP Address for Virtual Interface",
|
|
2130
|
+
'required' => ip_flags[:ip_required],
|
|
2131
|
+
'description' => 'Enter an IP for this virtual interface.',
|
|
2132
|
+
'defaultValue' => vi['ipAddress']
|
|
2133
|
+
}],
|
|
2134
|
+
options[:options]
|
|
2135
|
+
)
|
|
2136
|
+
if v_prompt[field_context][vi_field_context] && !v_prompt[field_context][vi_field_context]['ipAddress'].to_s.empty?
|
|
2137
|
+
vi['ipAddress'] = v_prompt[field_context][vi_field_context]['ipAddress']
|
|
2138
|
+
vi['ipMode'] = 'static'
|
|
2139
|
+
elsif ip_flags[:ip_required] == false && selected_network['dhcpServer']
|
|
2140
|
+
vi['ipMode'] = 'dhcp'
|
|
2141
|
+
end
|
|
2142
|
+
end
|
|
2143
|
+
end
|
|
2144
|
+
|
|
2145
|
+
virtual_interfaces << vi
|
|
2146
|
+
vi_index += 1
|
|
2147
|
+
|
|
2148
|
+
has_another = false
|
|
2149
|
+
confirm_message = prespecified ? "Add another virtual network interface? (under prespecified interface #{interface_index})": "Add another virtual network interface?"
|
|
2150
|
+
if preconfigured_vi[vi_index]
|
|
2151
|
+
has_another = true
|
|
2152
|
+
elsif options[:options] && options[:options][field_context]
|
|
2153
|
+
has_another = options[:options][field_context]["virtualInterface#{vi_index+1}"] && !options[:options][field_context]["virtualInterface#{vi_index+1}"].empty?
|
|
2154
|
+
end
|
|
2155
|
+
add_another = has_another || (!no_prompt && MtnCloud::Cli::OptionTypes.confirm(confirm_message,{default:false}))
|
|
2156
|
+
end
|
|
2157
|
+
virtual_interfaces
|
|
2158
|
+
end
|
|
2159
|
+
|
|
2160
|
+
# Prompts user for environment variables for new instance
|
|
2161
|
+
# returns array of evar objects {id: null, name: "VAR", value: "somevalue"}
|
|
2162
|
+
def prompt_evars(options={})
|
|
2163
|
+
#puts "Configure Environment Variables:"
|
|
2164
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
|
2165
|
+
evars = []
|
|
2166
|
+
evar_index = 0
|
|
2167
|
+
has_another_evar = options[:options] && options[:options]["evar#{evar_index}"]
|
|
2168
|
+
add_another_evar = has_another_evar || (!no_prompt && MtnCloud::Cli::OptionTypes.confirm("Add an environment variable?", {default: false}))
|
|
2169
|
+
while add_another_evar do
|
|
2170
|
+
field_context = "evar#{evar_index}"
|
|
2171
|
+
evar = {}
|
|
2172
|
+
evar['id'] = nil
|
|
2173
|
+
evar_label = evar_index == 0 ? "ENV" : "ENV [#{evar_index+1}]"
|
|
2174
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "#{evar_label} Name", 'required' => true, 'description' => 'Environment Variable Name.', 'defaultValue' => evar['name']}], options[:options])
|
|
2175
|
+
evar['name'] = v_prompt[field_context]['name']
|
|
2176
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'value', 'type' => 'text', 'fieldLabel' => "#{evar_label} Value", 'required' => true, 'description' => 'Environment Variable Value', 'defaultValue' => evar['value']}], options[:options])
|
|
2177
|
+
evar['value'] = v_prompt[field_context]['value']
|
|
2178
|
+
evars << evar
|
|
2179
|
+
evar_index += 1
|
|
2180
|
+
has_another_evar = options[:options] && options[:options]["evar#{evar_index}"]
|
|
2181
|
+
add_another_evar = has_another_evar || (!no_prompt && MtnCloud::Cli::OptionTypes.confirm("Add another environment variable?", {default: false}))
|
|
2182
|
+
end
|
|
2183
|
+
|
|
2184
|
+
return evars
|
|
2185
|
+
end
|
|
2186
|
+
|
|
2187
|
+
# Converts metadata tags array into a string like "name:value, foo:bar"
|
|
2188
|
+
def format_metadata(tags)
|
|
2189
|
+
if tags.nil? || tags.empty?
|
|
2190
|
+
""
|
|
2191
|
+
elsif tags.instance_of?(Array)
|
|
2192
|
+
tags.collect {|tag| "#{tag['name']}: #{tag['value']}" }.sort.join(", ")
|
|
2193
|
+
elsif tags.instance_of?(Hash)
|
|
2194
|
+
tags.collect {|k,v| "#{k}: #{v}" }.sort.join(", ")
|
|
2195
|
+
else
|
|
2196
|
+
tags.to_s
|
|
2197
|
+
end
|
|
2198
|
+
end
|
|
2199
|
+
|
|
2200
|
+
# Parses metadata tags object (string) into an array
|
|
2201
|
+
def parse_metadata(val)
|
|
2202
|
+
metadata = nil
|
|
2203
|
+
if val
|
|
2204
|
+
if val == "[]" || val == "null"
|
|
2205
|
+
metadata = []
|
|
2206
|
+
elsif val.is_a?(Array)
|
|
2207
|
+
metadata = val
|
|
2208
|
+
else
|
|
2209
|
+
# parse string into format name:value, name:value
|
|
2210
|
+
# merge IDs from current metadata
|
|
2211
|
+
# todo: should allow quoted semicolons..
|
|
2212
|
+
metadata_list = val.to_s.split(",").select {|it| !it.to_s.empty? }
|
|
2213
|
+
metadata_list = metadata_list.collect do |it|
|
|
2214
|
+
metadata_pair = it.include?(":") ? it.split(":") : it.split("=")
|
|
2215
|
+
row = {}
|
|
2216
|
+
row['name'] = metadata_pair[0].to_s.strip
|
|
2217
|
+
row['value'] = metadata_pair[1].to_s.strip
|
|
2218
|
+
# hacky way to set masked flag to true of false to (masked) in the value itself
|
|
2219
|
+
if(row['value'].include?("(masked)"))
|
|
2220
|
+
row['value'] = row['value'].gsub("(masked)", "").strip
|
|
2221
|
+
row['masked'] = true
|
|
2222
|
+
end
|
|
2223
|
+
if(row['value'].include?("(unmasked)"))
|
|
2224
|
+
row['value'] = row['value'].gsub("(unmasked)", "").strip
|
|
2225
|
+
row['masked'] = false
|
|
2226
|
+
end
|
|
2227
|
+
row
|
|
2228
|
+
end
|
|
2229
|
+
metadata = metadata_list
|
|
2230
|
+
end
|
|
2231
|
+
end
|
|
2232
|
+
return metadata
|
|
2233
|
+
end
|
|
2234
|
+
|
|
2235
|
+
# Prompts user for environment variables for new instance
|
|
2236
|
+
# returns array of metadata objects {id: null, name: "MYTAG", value: "myvalue"}
|
|
2237
|
+
def prompt_metadata(options={})
|
|
2238
|
+
#puts "Configure Environment Variables:"
|
|
2239
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
|
2240
|
+
metadata_array = []
|
|
2241
|
+
metadata_index = 0
|
|
2242
|
+
# Keep Current Tags (foo:bar,hello:world)
|
|
2243
|
+
# this is used by clone()
|
|
2244
|
+
if options[:current_tags] && !options[:current_tags].empty?
|
|
2245
|
+
current_tags_string = options[:current_tags].collect { |tag| tag['name'].to_s + '=' + tag['value'].to_s }.join(', ')
|
|
2246
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'keepExistingTags', 'type' => 'checkbox', 'fieldLabel' => "Keep existing metadata tags (#{current_tags_string}) ?", 'required' => true, 'description' => 'Whether or not to keep existing metadata tags', 'defaultValue' => true}], options[:options])
|
|
2247
|
+
if ['on','true','1',''].include?(v_prompt['keepExistingTags'].to_s.downcase)
|
|
2248
|
+
options[:current_tags].each do |tag|
|
|
2249
|
+
current_tag = tag.clone
|
|
2250
|
+
current_tag.delete('id')
|
|
2251
|
+
metadata_array << current_tag
|
|
2252
|
+
end
|
|
2253
|
+
end
|
|
2254
|
+
end
|
|
2255
|
+
has_another_metadata = options[:options] && options[:options]["metadata#{metadata_index}"]
|
|
2256
|
+
add_another_metadata = has_another_metadata || (!no_prompt && MtnCloud::Cli::OptionTypes.confirm("Add a metadata tag?", {default: false}))
|
|
2257
|
+
while add_another_metadata do
|
|
2258
|
+
field_context = "metadata#{metadata_index}"
|
|
2259
|
+
metadata = {}
|
|
2260
|
+
#metadata['id'] = nil
|
|
2261
|
+
metadata_label = metadata_index == 0 ? "Metadata Tag" : "Metadata Tag [#{metadata_index+1}]"
|
|
2262
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "#{metadata_label} Name", 'required' => true, 'description' => 'Metadata Tag Name.', 'defaultValue' => metadata['name']}], options[:options])
|
|
2263
|
+
# todo: metadata.type ?
|
|
2264
|
+
metadata['name'] = v_prompt[field_context]['name']
|
|
2265
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'value', 'type' => 'text', 'fieldLabel' => "#{metadata_label} Value", 'required' => true, 'description' => 'Metadata Tag Value', 'defaultValue' => metadata['value']}], options[:options])
|
|
2266
|
+
metadata['value'] = v_prompt[field_context]['value']
|
|
2267
|
+
metadata_array << metadata
|
|
2268
|
+
metadata_index += 1
|
|
2269
|
+
has_another_metadata = options[:options] && options[:options]["metadata#{metadata_index}"]
|
|
2270
|
+
add_another_metadata = has_another_metadata || (!no_prompt && MtnCloud::Cli::OptionTypes.confirm("Add another metadata tag?", {default: false}))
|
|
2271
|
+
end
|
|
2272
|
+
|
|
2273
|
+
return metadata_array
|
|
2274
|
+
end
|
|
2275
|
+
|
|
2276
|
+
def prompt_security_groups(sg_option_type, api_params, options)
|
|
2277
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
|
2278
|
+
security_groups_array = []
|
|
2279
|
+
sg_required = sg_option_type['required']
|
|
2280
|
+
sg_index = 0
|
|
2281
|
+
add_another_sg = sg_required || (!no_prompt && MtnCloud::Cli::OptionTypes.confirm("Add a security group?", {default: false}))
|
|
2282
|
+
while add_another_sg do
|
|
2283
|
+
cur_sg_option_type = sg_option_type.merge({'required' => (sg_index == 0 ? sg_required : false)})
|
|
2284
|
+
if sg_index == 0 && !options[:default_security_group].nil?
|
|
2285
|
+
cur_sg_option_type['defaultValue'] = options[:default_security_group]
|
|
2286
|
+
end
|
|
2287
|
+
field_context = cur_sg_option_type['fieldContext']
|
|
2288
|
+
field_name = cur_sg_option_type['fieldName']
|
|
2289
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([cur_sg_option_type], options[:options], api_client, api_params)
|
|
2290
|
+
has_another_sg = false
|
|
2291
|
+
if field_context
|
|
2292
|
+
if v_prompt[field_context] && !v_prompt[field_context][field_name].to_s.empty?
|
|
2293
|
+
security_groups_array << v_prompt[field_context][field_name]
|
|
2294
|
+
end
|
|
2295
|
+
has_another_sg = options[:options] && options[:options][field_context] && options[:options][field_context]["#{field_name}#{sg_index+2}"]
|
|
2296
|
+
else
|
|
2297
|
+
if !v_prompt[field_name].to_s.empty?
|
|
2298
|
+
security_groups_array << v_prompt[field_name]
|
|
2299
|
+
end
|
|
2300
|
+
has_another_sg = options[:options] && options[:options]["#{field_name}#{sg_index+2}"]
|
|
2301
|
+
end
|
|
2302
|
+
add_another_sg = has_another_sg || (!no_prompt && MtnCloud::Cli::OptionTypes.confirm("Add another security group?", {default: false}))
|
|
2303
|
+
sg_index += 1
|
|
2304
|
+
end
|
|
2305
|
+
|
|
2306
|
+
return security_groups_array
|
|
2307
|
+
end
|
|
2308
|
+
|
|
2309
|
+
# Prompts user for load balancer settings
|
|
2310
|
+
# returns Hash of parameters like {loadBalancerId: "-1", etc}
|
|
2311
|
+
def prompt_instance_load_balancer(instance, default_lb_id, options)
|
|
2312
|
+
#puts "Configure Environment Variables:"
|
|
2313
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
|
2314
|
+
payload = {}
|
|
2315
|
+
api_params = {}
|
|
2316
|
+
if instance['id']
|
|
2317
|
+
api_params['instanceId'] = instance['id']
|
|
2318
|
+
end
|
|
2319
|
+
if instance['zone']
|
|
2320
|
+
api_params['zoneId'] = instance['zone']['id']
|
|
2321
|
+
elsif instance['cloud']
|
|
2322
|
+
api_params['zoneId'] = instance['cloud']['id']
|
|
2323
|
+
end
|
|
2324
|
+
if instance['group']
|
|
2325
|
+
api_params['siteId'] = instance['group']['id']
|
|
2326
|
+
elsif instance['site']
|
|
2327
|
+
api_params['siteId'] = instance['site']['id']
|
|
2328
|
+
end
|
|
2329
|
+
if instance['plan']
|
|
2330
|
+
api_params['planId'] = instance['plan']['id']
|
|
2331
|
+
end
|
|
2332
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'loadBalancerId', 'type' => 'select', 'fieldLabel' => "Load Balancer", 'optionSource' => 'loadBalancers', 'required' => true, 'description' => 'Select Load Balancer for instance', 'defaultValue' => default_lb_id || ''}], options[:options], api_client, api_params)
|
|
2333
|
+
lb_id = v_prompt['loadBalancerId']
|
|
2334
|
+
payload['loadBalancerId'] = lb_id
|
|
2335
|
+
|
|
2336
|
+
# todo: finish implmenting this
|
|
2337
|
+
|
|
2338
|
+
# loadBalancerId
|
|
2339
|
+
# loadBalancerProxyProtocol
|
|
2340
|
+
# loadBalancerName
|
|
2341
|
+
# loadBalancerDescription
|
|
2342
|
+
# loadBalancerSslCert
|
|
2343
|
+
# loadBalancerScheme
|
|
2344
|
+
|
|
2345
|
+
return payload
|
|
2346
|
+
end
|
|
2347
|
+
|
|
2348
|
+
def prompt_cluster_load_balancer(cluster, options, can_use_kubevip)
|
|
2349
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'loadBalancerTypeId', 'type' => 'select', 'fieldLabel' => "Load Balancer", 'optionSource' => 'loadBalancerTypes', 'required' => false, 'description' => 'Select Load Balancer for Cluster', 'defaultValue' => '', 'excludeKubevip' => !can_use_kubevip}], options[:options], api_client, cluster)
|
|
2350
|
+
lb_type_id = v_prompt['loadBalancerTypeId']
|
|
2351
|
+
|
|
2352
|
+
if lb_type_id.empty?
|
|
2353
|
+
return false
|
|
2354
|
+
end
|
|
2355
|
+
|
|
2356
|
+
return lb_type_id
|
|
2357
|
+
end
|
|
2358
|
+
|
|
2359
|
+
|
|
2360
|
+
# reject old option types that now come from the selected service plan
|
|
2361
|
+
# these will eventually get removed from the associated optionTypes
|
|
2362
|
+
def reject_service_plan_option_types(option_types)
|
|
2363
|
+
option_types.reject {|opt|
|
|
2364
|
+
['cpuCount', 'memorySize', 'memory'].include?(opt['fieldName'])
|
|
2365
|
+
}
|
|
2366
|
+
end
|
|
2367
|
+
|
|
2368
|
+
def get_available_environments(refresh=false)
|
|
2369
|
+
if !@available_environments || refresh
|
|
2370
|
+
begin
|
|
2371
|
+
option_results = options_interface.options_for_source('environments',{})
|
|
2372
|
+
@available_environments = option_results['data'].collect {|it|
|
|
2373
|
+
{"code" => (it["code"] || it["value"]), "name" => it["name"], "value" => it["value"]}
|
|
2374
|
+
}
|
|
2375
|
+
rescue RestClient::Exception => e
|
|
2376
|
+
# if e.response && e.response.code == 404
|
|
2377
|
+
MtnCloud::Logging::DarkPrinter.puts "Unable to determine available environments, using default options" if MtnCloud::Logging.debug?
|
|
2378
|
+
@available_environments = get_static_environments()
|
|
2379
|
+
# else
|
|
2380
|
+
# raise e
|
|
2381
|
+
# end
|
|
2382
|
+
end
|
|
2383
|
+
end
|
|
2384
|
+
return @available_environments
|
|
2385
|
+
end
|
|
2386
|
+
|
|
2387
|
+
def get_static_environments
|
|
2388
|
+
[{'name' => 'Dev', 'value' => 'dev'}, {'name' => 'Test', 'value' => 'qa'}, {'name' => 'Staging', 'value' => 'staging'}, {'name' => 'Production', 'value' => 'production'}]
|
|
2389
|
+
end
|
|
2390
|
+
|
|
2391
|
+
def add_perms_options(opts, options, excludes = [])
|
|
2392
|
+
if !excludes.include?('groups')
|
|
2393
|
+
opts.on('--group-access-all [on|off]', String, "Toggle Access for all groups.") do |val|
|
|
2394
|
+
options[:groupAccessAll] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
|
2395
|
+
end
|
|
2396
|
+
opts.on('--group-access LIST', Array, "Group Access, comma separated list of group IDs.") do |list|
|
|
2397
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
|
2398
|
+
options[:groupAccessList] = []
|
|
2399
|
+
else
|
|
2400
|
+
options[:groupAccessList] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
2401
|
+
end
|
|
2402
|
+
end
|
|
2403
|
+
if !excludes.include?('groupDefaults')
|
|
2404
|
+
opts.on('--group-defaults LIST', Array, "Group Default Selection, comma separated list of group IDs") do |list|
|
|
2405
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
|
2406
|
+
options[:groupDefaultsList] = []
|
|
2407
|
+
else
|
|
2408
|
+
options[:groupDefaultsList] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
2409
|
+
end
|
|
2410
|
+
end
|
|
2411
|
+
end
|
|
2412
|
+
end
|
|
2413
|
+
|
|
2414
|
+
if !excludes.include?('plans')
|
|
2415
|
+
opts.on('--plan-access-all [on|off]', String, "Toggle Access for all service plans.") do |val|
|
|
2416
|
+
options[:planAccessAll] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
|
|
2417
|
+
end
|
|
2418
|
+
opts.on('--plan-access LIST', Array, "Service Plan Access, comma separated list of plan IDs.") do |list|
|
|
2419
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
|
2420
|
+
options[:planAccessList] = []
|
|
2421
|
+
else
|
|
2422
|
+
options[:planAccessList] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
2423
|
+
end
|
|
2424
|
+
end
|
|
2425
|
+
opts.on('--plan-defaults LIST', Array, "Plan Default Selection, comma separated list of plan IDs") do |list|
|
|
2426
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
|
2427
|
+
options[:planDefaultsList] = []
|
|
2428
|
+
else
|
|
2429
|
+
options[:planDefaultsList] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
2430
|
+
end
|
|
2431
|
+
end
|
|
2432
|
+
end
|
|
2433
|
+
|
|
2434
|
+
if !excludes.include?('visibility')
|
|
2435
|
+
opts.on('--visibility VISIBILITY', String, "Visibility [private|public]") do |val|
|
|
2436
|
+
options[:visibility] = val
|
|
2437
|
+
end
|
|
2438
|
+
end
|
|
2439
|
+
|
|
2440
|
+
if !excludes.include?('tenants')
|
|
2441
|
+
opts.on('--tenants LIST', Array, "Tenant Access, comma separated list of account IDs") do |list|
|
|
2442
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
|
2443
|
+
options[:tenants] = []
|
|
2444
|
+
else
|
|
2445
|
+
options[:tenants] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
|
2446
|
+
end
|
|
2447
|
+
end
|
|
2448
|
+
end
|
|
2449
|
+
end
|
|
2450
|
+
|
|
2451
|
+
def prompt_permissions(options, excludes = [])
|
|
2452
|
+
all_groups = nil
|
|
2453
|
+
group_access = nil
|
|
2454
|
+
all_plans = nil
|
|
2455
|
+
plan_access = nil
|
|
2456
|
+
permissions = {}
|
|
2457
|
+
|
|
2458
|
+
# Group Access
|
|
2459
|
+
unless excludes.include?('groups')
|
|
2460
|
+
if !options[:groupAccessAll].nil?
|
|
2461
|
+
all_groups = options[:groupAccessAll]
|
|
2462
|
+
end
|
|
2463
|
+
|
|
2464
|
+
if !options[:groupAccessList].empty?
|
|
2465
|
+
group_access = options[:groupAccessList].collect {|site_id|
|
|
2466
|
+
found_group = find_group_by_name_or_id_for_provisioning(site_id)
|
|
2467
|
+
return 1, "group not found by #{site_id}" if found_group.nil?
|
|
2468
|
+
{'id' => found_group['id']}
|
|
2469
|
+
} || []
|
|
2470
|
+
elsif !options[:no_prompt] && !all_groups
|
|
2471
|
+
available_groups = options[:available_groups] || get_available_groups
|
|
2472
|
+
|
|
2473
|
+
if available_groups.empty?
|
|
2474
|
+
#print_red_alert "No available groups"
|
|
2475
|
+
#exit 1
|
|
2476
|
+
elsif available_groups.count > 1
|
|
2477
|
+
available_groups.unshift({"id" => '0', "name" => "All", "value" => "all"})
|
|
2478
|
+
|
|
2479
|
+
# default to all
|
|
2480
|
+
group_id = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'type' => 'select', 'fieldLabel' => 'Group Access', 'selectOptions' => available_groups, 'required' => false, 'description' => 'Add Group Access.'}], options[:options], @api_client, {})['group']
|
|
2481
|
+
|
|
2482
|
+
if !group_id.nil?
|
|
2483
|
+
if group_id == 'all'
|
|
2484
|
+
all_groups = true
|
|
2485
|
+
else
|
|
2486
|
+
group_access = (excludes.include?('groupDefaults') ? [{'id' => group_id}] : [{'id' => group_id, 'default' => MtnCloud::Cli::OptionTypes.confirm("Set '#{available_groups.find{|it| it['value'] == group_id}['name']}' as default?", {:default => false})}])
|
|
2487
|
+
end
|
|
2488
|
+
available_groups = available_groups.reject {|it| it['value'] == group_id}
|
|
2489
|
+
|
|
2490
|
+
while !group_id.nil? && !available_groups.empty? && MtnCloud::Cli::OptionTypes.confirm("Add another group access?", {:default => false})
|
|
2491
|
+
group_id = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'type' => 'select', 'fieldLabel' => 'Group Access', 'selectOptions' => available_groups, 'required' => false, 'description' => 'Add Group Access.'}], options[:options], @api_client, {})['group']
|
|
2492
|
+
|
|
2493
|
+
if !group_id.nil?
|
|
2494
|
+
if group_id == 'all'
|
|
2495
|
+
all_groups = true
|
|
2496
|
+
else
|
|
2497
|
+
group_access ||= []
|
|
2498
|
+
group_access << (excludes.include?('groupDefaults') ? {'id' => group_id} : {'id' => group_id, 'default' => MtnCloud::Cli::OptionTypes.confirm("Set '#{available_groups.find{|it| it['value'] == group_id}['name']}' as default?", {:default => false})})
|
|
2499
|
+
end
|
|
2500
|
+
available_groups = available_groups.reject {|it| it['value'] == group_id}
|
|
2501
|
+
end
|
|
2502
|
+
end
|
|
2503
|
+
end
|
|
2504
|
+
end
|
|
2505
|
+
end
|
|
2506
|
+
end
|
|
2507
|
+
|
|
2508
|
+
# Plan Access
|
|
2509
|
+
unless excludes.include?('plans')
|
|
2510
|
+
if !options[:planAccessAll].nil?
|
|
2511
|
+
all_plans = options[:planAccessAll]
|
|
2512
|
+
end
|
|
2513
|
+
|
|
2514
|
+
if !options[:planAccessList].empty?
|
|
2515
|
+
plan_access = options[:planAccessList].collect {|plan_id| {'id' => plan_id.to_i}}
|
|
2516
|
+
elsif !options[:no_prompt]
|
|
2517
|
+
available_plans = options[:available_plans] || get_available_plans
|
|
2518
|
+
|
|
2519
|
+
if available_plans.empty?
|
|
2520
|
+
#print_red_alert "No available plans"
|
|
2521
|
+
#exit 1
|
|
2522
|
+
elsif !available_plans.empty? && !options[:no_prompt]
|
|
2523
|
+
available_plans.unshift({"id" => '0', "name" => "All", "value" => "all"})
|
|
2524
|
+
|
|
2525
|
+
# default to all
|
|
2526
|
+
plan_id = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'plan', 'type' => 'select', 'fieldLabel' => 'Service Plan Access', 'selectOptions' => available_plans, 'required' => false, 'description' => 'Add Service Plan Access.'}], options[:options], @api_client, {})['plan']
|
|
2527
|
+
|
|
2528
|
+
if !plan_id.nil?
|
|
2529
|
+
if plan_id == 'all'
|
|
2530
|
+
all_plans = true
|
|
2531
|
+
else
|
|
2532
|
+
plan_access = [{'id' => plan_id, 'default' => MtnCloud::Cli::OptionTypes.confirm("Set '#{available_plans.find{|it| it['value'] == plan_id}['name']}' as default?", {:default => false})}]
|
|
2533
|
+
end
|
|
2534
|
+
|
|
2535
|
+
available_plans = available_plans.reject {|it| it['value'] == plan_id}
|
|
2536
|
+
|
|
2537
|
+
while !plan_id.nil? && !available_plans.empty? && MtnCloud::Cli::OptionTypes.confirm("Add another service plan access?", {:default => false})
|
|
2538
|
+
plan_id = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'plan', 'type' => 'select', 'fieldLabel' => 'Service Plan Access', 'selectOptions' => available_plans, 'required' => false, 'description' => 'Add Service Plan Access.'}], options[:options], @api_client, {})['plan']
|
|
2539
|
+
|
|
2540
|
+
if !plan_id.nil?
|
|
2541
|
+
if plan_id == 'all'
|
|
2542
|
+
all_plans = true
|
|
2543
|
+
else
|
|
2544
|
+
plan_access ||= []
|
|
2545
|
+
plan_access << {'id' => plan_id, 'default' => MtnCloud::Cli::OptionTypes.confirm("Set '#{available_plans.find{|it| it['value'] == plan_id}['name']}' as default?", {:default => false})}
|
|
2546
|
+
end
|
|
2547
|
+
available_plans = available_plans.reject {|it| it['value'] == plan_id}
|
|
2548
|
+
end
|
|
2549
|
+
end
|
|
2550
|
+
end
|
|
2551
|
+
end
|
|
2552
|
+
end
|
|
2553
|
+
end
|
|
2554
|
+
|
|
2555
|
+
unless excludes.include?('resource')
|
|
2556
|
+
resource_perms = {}
|
|
2557
|
+
resource_perms['all'] = all_groups if !all_groups.nil?
|
|
2558
|
+
resource_perms['sites'] = group_access if !group_access.nil?
|
|
2559
|
+
resource_perms['allPlans'] = all_plans if !all_plans.nil?
|
|
2560
|
+
resource_perms['plans'] = plan_access if !plan_access.nil?
|
|
2561
|
+
permissions['resourcePermissions'] = resource_perms
|
|
2562
|
+
end
|
|
2563
|
+
|
|
2564
|
+
available_accounts = get_available_accounts() #.collect {|it| {'name' => it['name'], 'value' => it['id']}}
|
|
2565
|
+
accounts = []
|
|
2566
|
+
|
|
2567
|
+
# Prompts for multi tenant
|
|
2568
|
+
if available_accounts.count > 1
|
|
2569
|
+
visibility = options[:visibility]
|
|
2570
|
+
unless excludes.include?('visibility')
|
|
2571
|
+
if !visibility && !options[:no_prompt]
|
|
2572
|
+
visibility = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'visibility', 'fieldLabel' => 'Tenant Permissions Visibility', 'type' => 'select', 'defaultValue' => 'private', 'required' => true, 'selectOptions' => [{'name' => 'Private', 'value' => 'private'},{'name' => 'Public', 'value' => 'public'}]}], options[:options], @api_client, {})['visibility']
|
|
2573
|
+
end
|
|
2574
|
+
permissions['resourcePool'] = {'visibility' => visibility} if visibility
|
|
2575
|
+
end
|
|
2576
|
+
|
|
2577
|
+
# Tenants
|
|
2578
|
+
default_stores = []
|
|
2579
|
+
default_targets = []
|
|
2580
|
+
unless excludes.include?('tenants')
|
|
2581
|
+
if !options[:tenants].nil?
|
|
2582
|
+
accounts = options[:tenants].collect {|id| id.to_i}
|
|
2583
|
+
elsif !options[:no_prompt]
|
|
2584
|
+
account_id = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'account', 'type' => 'select', 'fieldLabel' => 'Add Tenant', 'selectOptions' => available_accounts, 'required' => false, 'description' => 'Add Tenant Permissions.'}], options[:options], @api_client, {})['account']
|
|
2585
|
+
|
|
2586
|
+
unless account_id.nil?
|
|
2587
|
+
accounts << account_id
|
|
2588
|
+
available_accounts = available_accounts.reject {|it| it['value'] == account_id}
|
|
2589
|
+
|
|
2590
|
+
# Prompt default store / target
|
|
2591
|
+
if options[:for_datastore]
|
|
2592
|
+
if MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'defaultTarget', 'type' => 'checkbox', 'fieldLabel' => 'Default', 'required' => false, 'description' => 'Designate as Default Store.', 'defaultValue' => false}], options[:options].merge({:checkbox_as_boolean => true}), @api_client, {})['defaultTarget']
|
|
2593
|
+
default_targets << account_id
|
|
2594
|
+
end
|
|
2595
|
+
if MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'defaultStore', 'type' => 'checkbox', 'fieldLabel' => 'Image Target', 'required' => false, 'description' => 'Designate as Image Target.', 'defaultValue' => false}], options[:options].merge({:checkbox_as_boolean => true}), @api_client, {})['defaultStore']
|
|
2596
|
+
default_stores << account_id
|
|
2597
|
+
end
|
|
2598
|
+
end
|
|
2599
|
+
|
|
2600
|
+
while !available_accounts.empty? && (account_id = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'account', 'type' => 'select', 'fieldLabel' => 'Add Another Tenant', 'selectOptions' => available_accounts, 'required' => false, 'description' => 'Add Tenant Permissions.'}], options[:options], @api_client, {})['account'])
|
|
2601
|
+
if !account_id.nil?
|
|
2602
|
+
accounts << account_id
|
|
2603
|
+
available_accounts = available_accounts.reject {|it| it['value'] == account_id}
|
|
2604
|
+
|
|
2605
|
+
# Prompt default store / target
|
|
2606
|
+
if options[:for_datastore]
|
|
2607
|
+
if MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'defaultTarget', 'type' => 'checkbox', 'fieldLabel' => 'Default', 'required' => false, 'description' => 'Designate as Default Store.', 'defaultValue' => false}], options[:options].merge({:checkbox_as_boolean => true}), @api_client, {})['defaultTarget']
|
|
2608
|
+
default_targets << account_id
|
|
2609
|
+
end
|
|
2610
|
+
if MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'defaultStore', 'type' => 'checkbox', 'fieldLabel' => 'Image Target', 'required' => false, 'description' => 'Designate as Image Target.', 'defaultValue' => false}], options[:options].merge({:checkbox_as_boolean => true}), @api_client, {})['defaultStore']
|
|
2611
|
+
default_stores << account_id
|
|
2612
|
+
end
|
|
2613
|
+
end
|
|
2614
|
+
end
|
|
2615
|
+
end
|
|
2616
|
+
end
|
|
2617
|
+
end
|
|
2618
|
+
if options[:for_datastore]
|
|
2619
|
+
permissions['tenantPermissions'] = accounts.collect {|it| {'id' => it, 'defaultStore' => default_stores.include?(it), 'defaultTarget' => default_targets.include?(it)}}
|
|
2620
|
+
else
|
|
2621
|
+
permissions['tenantPermissions'] = {'accounts' => accounts}
|
|
2622
|
+
end
|
|
2623
|
+
end
|
|
2624
|
+
end
|
|
2625
|
+
permissions
|
|
2626
|
+
end
|
|
2627
|
+
|
|
2628
|
+
def prompt_permissions_v2(options, excludes = [])
|
|
2629
|
+
perms = prompt_permissions(options, excludes)
|
|
2630
|
+
rtn = {}
|
|
2631
|
+
rtn['visibility'] = perms['resourcePool']['visibility'] if !perms['resourcePool'].nil? && !excludes.include?('visibility')
|
|
2632
|
+
rtn['tenants'] = ((perms['tenantPermissions'] || {})['accounts'] || []).collect {|it| {'id' => it}}
|
|
2633
|
+
rtn
|
|
2634
|
+
end
|
|
2635
|
+
|
|
2636
|
+
def print_permissions(permissions, excludes = [])
|
|
2637
|
+
if permissions.nil?
|
|
2638
|
+
print_h2 "Permissions"
|
|
2639
|
+
print yellow,"No permissions found.",reset,"\n"
|
|
2640
|
+
else
|
|
2641
|
+
if !permissions['resourcePermissions'].nil?
|
|
2642
|
+
if !excludes.include?('groups')
|
|
2643
|
+
print_h2 "Group Access"
|
|
2644
|
+
|
|
2645
|
+
if excludes.include?('groupDefaults')
|
|
2646
|
+
groups = []
|
|
2647
|
+
groups << 'All' if permissions['resourcePermissions']['all']
|
|
2648
|
+
groups += permissions['resourcePermissions']['sites'].collect {|it| it['name']} if permissions['resourcePermissions']['sites']
|
|
2649
|
+
|
|
2650
|
+
if groups.count > 0
|
|
2651
|
+
print cyan,"#{groups.join(', ')}".center(20)
|
|
2652
|
+
else
|
|
2653
|
+
print yellow,"No group access",reset,"\n"
|
|
2654
|
+
end
|
|
2655
|
+
print "\n"
|
|
2656
|
+
else
|
|
2657
|
+
rows = []
|
|
2658
|
+
if permissions['resourcePermissions']['all']
|
|
2659
|
+
rows.push({group: 'All'})
|
|
2660
|
+
end
|
|
2661
|
+
if permissions['resourcePermissions']['sites']
|
|
2662
|
+
permissions['resourcePermissions']['sites'].each do |site|
|
|
2663
|
+
rows.push({group: site['name'], default: site['default'] ? 'Yes' : ''})
|
|
2664
|
+
end
|
|
2665
|
+
end
|
|
2666
|
+
if rows.empty?
|
|
2667
|
+
print yellow,"No group access",reset,"\n"
|
|
2668
|
+
else
|
|
2669
|
+
columns = [:group, :default]
|
|
2670
|
+
print cyan
|
|
2671
|
+
print as_pretty_table(rows, columns)
|
|
2672
|
+
end
|
|
2673
|
+
end
|
|
2674
|
+
end
|
|
2675
|
+
|
|
2676
|
+
if !excludes.include?('plans')
|
|
2677
|
+
print_h2 "Plan Access"
|
|
2678
|
+
rows = []
|
|
2679
|
+
if permissions['resourcePermissions']['allPlans']
|
|
2680
|
+
rows.push({plan: 'All'})
|
|
2681
|
+
end
|
|
2682
|
+
if permissions['resourcePermissions']['plans']
|
|
2683
|
+
permissions['resourcePermissions']['plans'].each do |plan|
|
|
2684
|
+
rows.push({plan: plan['name'], default: plan['default'] ? 'Yes' : ''})
|
|
2685
|
+
end
|
|
2686
|
+
end
|
|
2687
|
+
if rows.empty?
|
|
2688
|
+
print yellow,"No plan access",reset,"\n"
|
|
2689
|
+
else
|
|
2690
|
+
columns = [:plan, :default]
|
|
2691
|
+
print cyan
|
|
2692
|
+
print as_pretty_table(rows, columns)
|
|
2693
|
+
end
|
|
2694
|
+
end
|
|
2695
|
+
|
|
2696
|
+
if !excludes.include?('tenants')
|
|
2697
|
+
if !permissions['tenantPermissions'].nil?
|
|
2698
|
+
print_h2 "Tenant Permissions"
|
|
2699
|
+
if !permissions['resourcePool'].nil?
|
|
2700
|
+
print cyan
|
|
2701
|
+
print "Visibility: #{permissions['resourcePool']['visibility'].to_s.capitalize}".center(20)
|
|
2702
|
+
print "\n"
|
|
2703
|
+
end
|
|
2704
|
+
if !permissions['tenantPermissions'].nil?
|
|
2705
|
+
print cyan
|
|
2706
|
+
print "Accounts: #{permissions['tenantPermissions']['accounts'].join(', ')}".center(20)
|
|
2707
|
+
print "\n"
|
|
2708
|
+
end
|
|
2709
|
+
end
|
|
2710
|
+
end
|
|
2711
|
+
print "\n"
|
|
2712
|
+
end
|
|
2713
|
+
end
|
|
2714
|
+
end
|
|
2715
|
+
|
|
2716
|
+
|
|
2717
|
+
## Exposed Ports component
|
|
2718
|
+
|
|
2719
|
+
def load_balance_protocols_dropdown
|
|
2720
|
+
[
|
|
2721
|
+
{'name' => 'None', 'value' => ''},
|
|
2722
|
+
{'name' => 'HTTP', 'value' => 'HTTP'},
|
|
2723
|
+
{'name' => 'HTTPS', 'value' => 'HTTPS'},
|
|
2724
|
+
{'name' => 'TCP', 'value' => 'TCP'}
|
|
2725
|
+
]
|
|
2726
|
+
end
|
|
2727
|
+
|
|
2728
|
+
# Prompts user for ports array
|
|
2729
|
+
# returns array of port objects
|
|
2730
|
+
def prompt_exposed_ports(options={}, api_client=nil, api_params={})
|
|
2731
|
+
#puts "Configure ports:"
|
|
2732
|
+
passed_ports = ((options[:options] && options[:options]["ports"]) ? options[:options]["ports"] : nil)
|
|
2733
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
|
2734
|
+
# skip prompting?
|
|
2735
|
+
if no_prompt
|
|
2736
|
+
return passed_ports
|
|
2737
|
+
end
|
|
2738
|
+
# value already given
|
|
2739
|
+
if passed_ports.is_a?(Array)
|
|
2740
|
+
return passed_ports
|
|
2741
|
+
end
|
|
2742
|
+
|
|
2743
|
+
# prompt for ports
|
|
2744
|
+
ports = []
|
|
2745
|
+
port_index = 0
|
|
2746
|
+
has_another_port = options[:options] && options[:options]["ports"]
|
|
2747
|
+
add_another_port = has_another_port || (!no_prompt && MtnCloud::Cli::OptionTypes.confirm("Add an exposed port?", {default:false}))
|
|
2748
|
+
while add_another_port do
|
|
2749
|
+
field_context = port_index == 0 ? "ports" : "ports#{port_index}"
|
|
2750
|
+
|
|
2751
|
+
port = {}
|
|
2752
|
+
port_label = port_index == 0 ? "Port" : "Port [#{port_index+1}]"
|
|
2753
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "#{port_label} Name", 'required' => false, 'description' => 'Choose a name for this port.', 'defaultValue' => port['name']}], options[:options])
|
|
2754
|
+
port['name'] = v_prompt[field_context]['name']
|
|
2755
|
+
|
|
2756
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'port', 'type' => 'number', 'fieldLabel' => "#{port_label} Number", 'required' => true, 'description' => 'A port number. eg. 8001', 'defaultValue' => (port['port'] ? port['port'].to_i : nil)}], options[:options])
|
|
2757
|
+
port['port'] = v_prompt[field_context]['port']
|
|
2758
|
+
|
|
2759
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'lb', 'type' => 'select', 'fieldLabel' => "#{port_label} LB", 'required' => false, 'selectOptions' => load_balance_protocols_dropdown, 'description' => 'Choose a load balance protocol.', 'defaultValue' => port['lb']}], options[:options])
|
|
2760
|
+
# port['loadBalanceProtocol'] = v_prompt[field_context]['lb']
|
|
2761
|
+
port['lb'] = v_prompt[field_context]['lb']
|
|
2762
|
+
|
|
2763
|
+
ports << port
|
|
2764
|
+
port_index += 1
|
|
2765
|
+
has_another_port = options[:options] && options[:options]["ports#{port_index}"]
|
|
2766
|
+
add_another_port = has_another_port || (!no_prompt && MtnCloud::Cli::OptionTypes.confirm("Add another exposed port?", {default:false}))
|
|
2767
|
+
end
|
|
2768
|
+
|
|
2769
|
+
|
|
2770
|
+
return ports
|
|
2771
|
+
end
|
|
2772
|
+
|
|
2773
|
+
def prompt_service_plan_options(plan_info, options={}, api_client=nil, api_params={}, instance=nil)
|
|
2774
|
+
plan_opts = {}
|
|
2775
|
+
# provisioning with blueprint can lock fields
|
|
2776
|
+
locked_fields = options[:locked_fields] || []
|
|
2777
|
+
if options[:options]['servicePlanOptions']
|
|
2778
|
+
plan_opts = options[:options]['servicePlanOptions']
|
|
2779
|
+
end
|
|
2780
|
+
default_max_cores = plan_info['maxCores'].to_i != 0 ? plan_info['maxCores'] : 1
|
|
2781
|
+
default_cores_per_socket = plan_info['coresPerSocket'].to_i != 0 ? plan_info['coresPerSocket'] : 1
|
|
2782
|
+
default_max_memory = plan_info['maxMemory'].to_i != 0 ? plan_info['maxMemory'] : nil
|
|
2783
|
+
# use defaults from the instance/server
|
|
2784
|
+
if instance
|
|
2785
|
+
default_max_cores = instance["maxCores"] if instance["maxCores"]
|
|
2786
|
+
default_cores_per_socket = instance["coresPerSocket"] if instance["coresPerSocket"]
|
|
2787
|
+
default_max_memory = instance["maxMemory"] if instance["maxMemory"]
|
|
2788
|
+
end
|
|
2789
|
+
# Core Count
|
|
2790
|
+
if plan_info["customCores"]
|
|
2791
|
+
if locked_fields.include?('servicePlanOptions.maxCores')
|
|
2792
|
+
if options[:options]['servicePlanOptions'] && options[:options]['servicePlanOptions']['maxCores']
|
|
2793
|
+
plan_opts['maxCores'] = options[:options]['servicePlanOptions']['maxCores'].to_i
|
|
2794
|
+
end
|
|
2795
|
+
else
|
|
2796
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => 'servicePlanOptions', 'fieldName' => 'maxCores', 'type' => 'number', 'fieldLabel' => "Core Count", 'required' => true, 'defaultValue' => default_max_cores, 'description' => "Customize service plan options Core Count"}], options[:options])
|
|
2797
|
+
if v_prompt['servicePlanOptions'] && v_prompt['servicePlanOptions']['maxCores']
|
|
2798
|
+
plan_opts['maxCores'] = v_prompt['servicePlanOptions']['maxCores'].to_i
|
|
2799
|
+
end
|
|
2800
|
+
end
|
|
2801
|
+
end
|
|
2802
|
+
# Cores Per Socket
|
|
2803
|
+
if plan_info["customCoresPerSocket"]
|
|
2804
|
+
if locked_fields.include?('servicePlanOptions.coresPerSocket')
|
|
2805
|
+
if options[:options]['servicePlanOptions'] && options[:options]['servicePlanOptions']['coresPerSocket']
|
|
2806
|
+
plan_opts['coresPerSocket'] = options[:options]['servicePlanOptions']['coresPerSocket'].to_i
|
|
2807
|
+
end
|
|
2808
|
+
else
|
|
2809
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldContext' => 'servicePlanOptions', 'fieldName' => 'coresPerSocket', 'type' => 'number', 'fieldLabel' => "Cores Per Socket", 'required' => true, 'defaultValue' => default_cores_per_socket, 'description' => "Customize service plan options Cores Per Socket"}], options[:options])
|
|
2810
|
+
if v_prompt['servicePlanOptions'] && v_prompt['servicePlanOptions']['coresPerSocket']
|
|
2811
|
+
plan_opts['coresPerSocket'] = v_prompt['servicePlanOptions']['coresPerSocket'].to_i
|
|
2812
|
+
end
|
|
2813
|
+
end
|
|
2814
|
+
end
|
|
2815
|
+
# Memory
|
|
2816
|
+
if plan_info["customMaxMemory"]
|
|
2817
|
+
if locked_fields.include?('servicePlanOptions.maxMemory')
|
|
2818
|
+
if options[:options]['servicePlanOptions'] && options[:options]['servicePlanOptions']['maxMemory']
|
|
2819
|
+
plan_opts['maxMemory'] = options[:options]['servicePlanOptions']['maxMemory'].to_i
|
|
2820
|
+
end
|
|
2821
|
+
else
|
|
2822
|
+
if options[:options]['servicePlanOptions'] && options[:options]['servicePlanOptions']['maxMemory']
|
|
2823
|
+
plan_opts['maxMemory'] = options[:options]['servicePlanOptions']['maxMemory'].to_i
|
|
2824
|
+
else
|
|
2825
|
+
# prompt for "memoryMB" field as MB or "memoryGB" in GB
|
|
2826
|
+
# always convert maxMemory to bytes
|
|
2827
|
+
if plan_info["memorySizeType"] == "MB" || options[:options]["memoryMB"]
|
|
2828
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'memoryMB', 'type' => 'text', 'fieldLabel' => "Memory (MB)", 'required' => true, 'defaultValue' => default_max_memory ? (default_max_memory / (1024 * 1024)) : nil, 'description' => "Customize service plan options Memory (MB). Value is in megabytes."}], options[:options])
|
|
2829
|
+
if v_prompt['memoryMB'].to_s != ""
|
|
2830
|
+
plan_opts['maxMemory'] = v_prompt['memoryMB'].to_i * 1024 * 1024
|
|
2831
|
+
end
|
|
2832
|
+
else
|
|
2833
|
+
v_prompt = MtnCloud::Cli::OptionTypes.prompt([{'fieldName' => 'memoryGB', 'type' => 'text', 'fieldLabel' => "Memory (GB)", 'required' => true, 'defaultValue' => default_max_memory ? (default_max_memory / (1024 * 1024 * 1024)) : nil, 'description' => "Customize service plan options Memory (GB). Value is in gigabytes."}], options[:options])
|
|
2834
|
+
if v_prompt['memoryGB'].to_s != ""
|
|
2835
|
+
plan_opts['maxMemory'] = v_prompt['memoryGB'].to_i * 1024 * 1024 * 1024
|
|
2836
|
+
end
|
|
2837
|
+
end
|
|
2838
|
+
# remove transient memory field just used for prompting for MB or GB
|
|
2839
|
+
plan_opts.delete("memoryMB")
|
|
2840
|
+
plan_opts.delete("memoryGB")
|
|
2841
|
+
end
|
|
2842
|
+
end
|
|
2843
|
+
end
|
|
2844
|
+
return plan_opts
|
|
2845
|
+
end
|
|
2846
|
+
|
|
2847
|
+
def format_instance_status(instance, return_color=cyan)
|
|
2848
|
+
out = ""
|
|
2849
|
+
status_string = instance['status'].to_s
|
|
2850
|
+
if status_string == 'running'
|
|
2851
|
+
out << "#{green}#{status_string.upcase}#{return_color}"
|
|
2852
|
+
elsif status_string == 'provisioning'
|
|
2853
|
+
out << "#{cyan}#{status_string.upcase}#{return_color}"
|
|
2854
|
+
elsif status_string == 'stopped' or status_string == 'failed'
|
|
2855
|
+
out << "#{red}#{status_string.upcase}#{return_color}"
|
|
2856
|
+
else
|
|
2857
|
+
out << "#{yellow}#{status_string.upcase}#{return_color}"
|
|
2858
|
+
end
|
|
2859
|
+
out
|
|
2860
|
+
end
|
|
2861
|
+
|
|
2862
|
+
def format_instance_connection_string(instance)
|
|
2863
|
+
if !instance['connectionInfo'].nil? && instance['connectionInfo'].empty? == false
|
|
2864
|
+
connection_string = "#{instance['connectionInfo'][0]['ip']}:#{instance['connectionInfo'][0]['port']}"
|
|
2865
|
+
end
|
|
2866
|
+
end
|
|
2867
|
+
|
|
2868
|
+
def format_app_status(app, return_color=cyan)
|
|
2869
|
+
out = ""
|
|
2870
|
+
status_string = app['status'] || app['appStatus'] || ''
|
|
2871
|
+
if status_string == 'running'
|
|
2872
|
+
out = "#{green}#{status_string.upcase}#{return_color}"
|
|
2873
|
+
elsif status_string == 'provisioning'
|
|
2874
|
+
out = "#{cyan}#{status_string.upcase}#{cyan}"
|
|
2875
|
+
elsif status_string == 'stopped' or status_string == 'failed'
|
|
2876
|
+
out = "#{red}#{status_string.upcase}#{return_color}"
|
|
2877
|
+
elsif status_string == 'unknown'
|
|
2878
|
+
out = "#{yellow}#{status_string.upcase}#{return_color}"
|
|
2879
|
+
elsif status_string == 'warning' && app['instanceCount'].to_i == 0
|
|
2880
|
+
# show this instead of WARNING
|
|
2881
|
+
out = "#{cyan}EMPTY#{return_color}"
|
|
2882
|
+
else
|
|
2883
|
+
out = "#{yellow}#{status_string.upcase}#{return_color}"
|
|
2884
|
+
end
|
|
2885
|
+
out
|
|
2886
|
+
end
|
|
2887
|
+
|
|
2888
|
+
def format_container_status(container, return_color=cyan)
|
|
2889
|
+
out = ""
|
|
2890
|
+
status_string = container['status'].to_s
|
|
2891
|
+
if status_string == 'running'
|
|
2892
|
+
out << "#{green}#{status_string.upcase}#{return_color}"
|
|
2893
|
+
elsif status_string == 'provisioning'
|
|
2894
|
+
out << "#{cyan}#{status_string.upcase}#{return_color}"
|
|
2895
|
+
elsif status_string == 'stopped' or status_string == 'failed'
|
|
2896
|
+
out << "#{red}#{status_string.upcase}#{return_color}"
|
|
2897
|
+
else
|
|
2898
|
+
out << "#{yellow}#{status_string.upcase}#{return_color}"
|
|
2899
|
+
end
|
|
2900
|
+
out
|
|
2901
|
+
end
|
|
2902
|
+
|
|
2903
|
+
def format_container_connection_string(container)
|
|
2904
|
+
if !container['ports'].nil? && container['ports'].empty? == false
|
|
2905
|
+
connection_string = "#{container['ip']}:#{container['ports'][0]['external']}"
|
|
2906
|
+
else
|
|
2907
|
+
# eh? more logic needed here i think, see taglib morph:containerLocationMenu
|
|
2908
|
+
connection_string = "#{container['ip']}"
|
|
2909
|
+
end
|
|
2910
|
+
end
|
|
2911
|
+
|
|
2912
|
+
def format_instance_container_display_name(instance, plural=false)
|
|
2913
|
+
#<span class="info-label">${[null,'docker'].contains(instance.layout?.provisionType?.code) ? 'Containers' : 'Virtual Machines'}:</span> <span class="info-value">${instance.containers?.size()}</span>
|
|
2914
|
+
v = plural ? "Containers" : "Container"
|
|
2915
|
+
if instance && instance['layout'] && instance['layout'].key?("provisionTypeCode")
|
|
2916
|
+
if [nil, 'docker'].include?(instance['layout']["provisionTypeCode"])
|
|
2917
|
+
v = plural ? "Virtual Machines" : "Virtual Machine"
|
|
2918
|
+
end
|
|
2919
|
+
end
|
|
2920
|
+
return v
|
|
2921
|
+
end
|
|
2922
|
+
|
|
2923
|
+
def format_blueprint_type(type_code)
|
|
2924
|
+
return type_code.to_s # just show it as is
|
|
2925
|
+
if type_code.to_s.empty?
|
|
2926
|
+
type_code = "morpheus"
|
|
2927
|
+
end
|
|
2928
|
+
if type_code.to_s.downcase == "arm"
|
|
2929
|
+
"ARM"
|
|
2930
|
+
else
|
|
2931
|
+
return type_code.to_s.capitalize
|
|
2932
|
+
end
|
|
2933
|
+
end
|
|
2934
|
+
|
|
2935
|
+
def parse_blueprint_type(type_code)
|
|
2936
|
+
return type_code.to_s # just use it as is
|
|
2937
|
+
# if type_code.to_s.empty?
|
|
2938
|
+
# type_code = "morpheus"
|
|
2939
|
+
# end
|
|
2940
|
+
if type_code.to_s.downcase == "arm"
|
|
2941
|
+
"arm"
|
|
2942
|
+
elsif type_code.to_s.downcase == "cloudformation"
|
|
2943
|
+
type_code = "cloudFormation"
|
|
2944
|
+
else
|
|
2945
|
+
return type_code.to_s.downcase
|
|
2946
|
+
end
|
|
2947
|
+
end
|
|
2948
|
+
|
|
2949
|
+
def format_snapshot_status(snapshot, return_color=cyan)
|
|
2950
|
+
out = ""
|
|
2951
|
+
status_string = snapshot['status'].to_s
|
|
2952
|
+
if status_string == 'complete'
|
|
2953
|
+
out << "#{green}#{status_string.upcase}#{return_color}"
|
|
2954
|
+
elsif status_string == 'creating'
|
|
2955
|
+
out << "#{cyan}#{status_string.upcase}#{return_color}"
|
|
2956
|
+
elsif status_string == 'failed'
|
|
2957
|
+
out << "#{red}#{status_string.upcase}#{return_color}"
|
|
2958
|
+
else
|
|
2959
|
+
out << "#{yellow}#{status_string.upcase}#{return_color}"
|
|
2960
|
+
end
|
|
2961
|
+
out
|
|
2962
|
+
end
|
|
2963
|
+
end
|