morpheus-cli 7.0.7 → 8.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +11 -0
- data/lib/morpheus/api/appliance_settings_interface.rb +7 -0
- data/lib/morpheus/api/clusters_interface.rb +25 -0
- data/lib/morpheus/api/datastores_interface.rb +6 -0
- data/lib/morpheus/api/library_operating_systems_interface.rb +63 -0
- data/lib/morpheus/api/processes_interface.rb +17 -5
- data/lib/morpheus/api/virtual_images_interface.rb +6 -0
- data/lib/morpheus/cli/commands/appliance_settings_command.rb +21 -2
- data/lib/morpheus/cli/commands/apps.rb +1 -1
- data/lib/morpheus/cli/commands/backup_jobs_command.rb +50 -17
- data/lib/morpheus/cli/commands/backups_command.rb +36 -9
- data/lib/morpheus/cli/commands/clouds.rb +1 -1
- data/lib/morpheus/cli/commands/clusters.rb +380 -6
- data/lib/morpheus/cli/commands/hosts.rb +3 -0
- data/lib/morpheus/cli/commands/instances.rb +33 -4
- data/lib/morpheus/cli/commands/library_container_types_command.rb +6 -0
- data/lib/morpheus/cli/commands/library_operating_systems_command.rb +671 -0
- data/lib/morpheus/cli/commands/license.rb +11 -1
- data/lib/morpheus/cli/commands/processes_command.rb +71 -1
- data/lib/morpheus/cli/commands/setup.rb +32 -18
- data/lib/morpheus/cli/commands/virtual_images.rb +66 -8
- data/lib/morpheus/cli/mixins/print_helper.rb +4 -2
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +35 -8
- data/lib/morpheus/cli/option_types.rb +3 -0
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/formatters.rb +12 -0
- metadata +5 -3
| @@ -13,18 +13,20 @@ class Morpheus::Cli::Clusters | |
| 13 13 | 
             
              register_subcommands :upgrade_cluster
         | 
| 14 14 | 
             
              register_subcommands :list_volumes, :remove_volume
         | 
| 15 15 | 
             
              register_subcommands :list_namespaces, :get_namespace, :add_namespace, :update_namespace, :remove_namespace
         | 
| 16 | 
            -
              register_subcommands :list_containers, :remove_container, :restart_container
         | 
| 16 | 
            +
              register_subcommands :list_containers, :remove_container, :restart_container, :get_container
         | 
| 17 17 | 
             
              register_subcommands :list_deployments, :remove_deployment, :restart_deployment
         | 
| 18 18 | 
             
              register_subcommands :list_stateful_sets, :remove_stateful_set, :restart_stateful_set
         | 
| 19 19 | 
             
              register_subcommands :list_pods, :remove_pod, :restart_pod
         | 
| 20 20 | 
             
              register_subcommands :list_jobs, :remove_job
         | 
| 21 21 | 
             
              register_subcommands :list_services, :remove_service
         | 
| 22 | 
            -
              register_subcommands :list_datastores, :get_datastore, :update_datastore
         | 
| 22 | 
            +
              register_subcommands :list_datastores, :get_datastore, :update_datastore, :add_datastore, :remove_datastore
         | 
| 23 23 | 
             
              register_subcommands :update_permissions
         | 
| 24 24 | 
             
              register_subcommands :api_config, :view_api_token, :view_kube_config
         | 
| 25 25 | 
             
              register_subcommands :wiki, :update_wiki
         | 
| 26 26 | 
             
              register_subcommands :apply_template
         | 
| 27 27 | 
             
              register_subcommands :refresh
         | 
| 28 | 
            +
              register_subcommands :list_replicasets, :list_daemonsets, :list_endpoints, :list_ingresses, :list_policies, :list_volumes, :list_volume_claims, :list_config_maps, :list_secrets
         | 
| 29 | 
            +
              register_subcommands :get_pod, :get_deployment, :get_replicaset, :get_daemonset, :get_endpoint, :get_ingress, :get_policy, :get_volume_claim, :get_volume, :get_config_map, :get_secret, :get_stateful_set, :get_job, :get_service
         | 
| 28 30 |  | 
| 29 31 | 
             
              def connect(opts)
         | 
| 30 32 | 
             
                @api_client = establish_remote_appliance_connection(opts)
         | 
| @@ -32,6 +34,7 @@ class Morpheus::Cli::Clusters | |
| 32 34 | 
             
                @groups_interface = @api_client.groups
         | 
| 33 35 | 
             
                @cluster_layouts_interface = @api_client.library_cluster_layouts
         | 
| 34 36 | 
             
                @security_groups_interface = @api_client.security_groups
         | 
| 37 | 
            +
                @datastores_interface = @api_client.datastores
         | 
| 35 38 | 
             
                #@security_group_rules_interface = @api_client.security_group_rules
         | 
| 36 39 | 
             
                @cloud_resource_pools_interface = @api_client.cloud_resource_pools
         | 
| 37 40 | 
             
                @resource_pool_groups_interface = @api_client.resource_pool_groups
         | 
| @@ -220,6 +223,7 @@ class Morpheus::Cli::Clusters | |
| 220 223 | 
             
                      "Cloud" => lambda { |it| it['zone']['name'] },
         | 
| 221 224 | 
             
                      "Location" => lambda { |it| it['location'] },
         | 
| 222 225 | 
             
                      "Layout" => lambda { |it| it['layout'] ? it['layout']['name'] : ''},
         | 
| 226 | 
            +
                      "Integrations" => lambda {|it| format_name_and_id(it['integrations']) },
         | 
| 223 227 | 
             
                      "API Url" => 'serviceUrl',
         | 
| 224 228 | 
             
                      "Visibility" => lambda { |it| it['visibility'].to_s.capitalize },
         | 
| 225 229 | 
             
                      #"Groups" => lambda {|it| it['groups'].collect {|g| g.instance_of?(Hash) ? g['name'] : g.to_s }.join(', ') },
         | 
| @@ -228,6 +232,8 @@ class Morpheus::Cli::Clusters | |
| 228 232 | 
             
                      "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
         | 
| 229 233 | 
             
                      "Created By" => lambda {|it| it['createdBy'] ? it['createdBy']['username'] : '' },
         | 
| 230 234 | 
             
                      "Enabled" => lambda { |it| format_boolean(it['enabled']) },
         | 
| 235 | 
            +
                      "Managed" => lambda { |it| format_boolean(it['managed']) },
         | 
| 236 | 
            +
                      "Auto Power On VMs" => lambda { |it| format_boolean(it['autoRecoverPowerState']) },
         | 
| 231 237 | 
             
                      "Status" => lambda { |it| format_cluster_status(it) }
         | 
| 232 238 | 
             
                  }
         | 
| 233 239 | 
             
                  print_description_list(description_cols, cluster)
         | 
| @@ -796,12 +802,18 @@ class Morpheus::Cli::Clusters | |
| 796 802 | 
             
                  opts.on('--managed [on|off]', String, "Can be used to enable / disable managed cluster. Default is on") do |val|
         | 
| 797 803 | 
             
                    options[:managed] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
         | 
| 798 804 | 
             
                  end
         | 
| 805 | 
            +
                  opts.on('--autoRecoverPowerState [on|off]', String, "Automatically Power On VMs") do |val|
         | 
| 806 | 
            +
                    options[:autoRecoverPowerState] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
         | 
| 807 | 
            +
                  end
         | 
| 799 808 | 
             
                  opts.on( nil, '--refresh', "Refresh cluster" ) do
         | 
| 800 809 | 
             
                    options[:refresh] = true
         | 
| 801 810 | 
             
                  end
         | 
| 802 811 | 
             
                  opts.on("--tenant ACCOUNT", String, "Account ID or Name" ) do |val|
         | 
| 803 812 | 
             
                    options[:tenant] = val
         | 
| 804 813 | 
             
                  end
         | 
| 814 | 
            +
                  opts.on('--integrations [LIST]', Array, "Updates Cluster Integration(s), comma separated list of integration IDs") do |list|
         | 
| 815 | 
            +
                    options[:integrations] = list ? list.collect {|it| it.to_s.strip.to_i } : []
         | 
| 816 | 
            +
                  end
         | 
| 805 817 | 
             
                  build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
         | 
| 806 818 | 
             
                  opts.footer = "Update a cluster.\n" +
         | 
| 807 819 | 
             
                                "[cluster] is required. This is the name or id of an existing cluster."
         | 
| @@ -831,15 +843,18 @@ class Morpheus::Cli::Clusters | |
| 831 843 | 
             
                  else
         | 
| 832 844 | 
             
                    cluster = find_cluster_by_name_or_id(args[0])
         | 
| 833 845 | 
             
                    cluster_payload = {}
         | 
| 846 | 
            +
                    cluster_payload.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) })
         | 
| 834 847 | 
             
                    cluster_payload['name'] = options[:name] if !options[:name].empty?
         | 
| 835 848 | 
             
                    cluster_payload['description'] = options[:description] if !options[:description].empty?
         | 
| 836 849 | 
             
                    cluster_payload['labels'] = options[:labels] if !options[:labels].nil?
         | 
| 837 850 | 
             
                    cluster_payload['enabled'] = options[:active] if !options[:active].nil?
         | 
| 838 851 | 
             
                    cluster_payload['managed'] = options[:managed] if !options[:managed].nil?
         | 
| 852 | 
            +
                    cluster_payload['autoRecoverPowerState'] = options[:autoRecoverPowerState] if !options[:autoRecoverPowerState].nil?
         | 
| 839 853 | 
             
                    cluster_payload['serviceUrl'] = options[:apiUrl] if !options[:apiUrl].nil?
         | 
| 840 854 | 
             
                    cluster_payload['serviceToken'] = options[:apiToken] if !options[:apiToken].nil?
         | 
| 841 855 | 
             
                    cluster_payload['refresh'] = options[:refresh] if options[:refresh] == true
         | 
| 842 856 | 
             
                    cluster_payload['tenant'] = options[:tenant] if !options[:tenant].nil?
         | 
| 857 | 
            +
                    cluster_payload['integrations'] = options[:integrations] if !options[:integrations].nil?
         | 
| 843 858 | 
             
                    payload = {"cluster" => cluster_payload}
         | 
| 844 859 | 
             
                  end
         | 
| 845 860 |  | 
| @@ -847,10 +862,9 @@ class Morpheus::Cli::Clusters | |
| 847 862 | 
             
                    print_red_alert "No clusters available for update"
         | 
| 848 863 | 
             
                    exit 1
         | 
| 849 864 | 
             
                  end
         | 
| 850 | 
            -
             | 
| 851 | 
            -
                  if  | 
| 852 | 
            -
                     | 
| 853 | 
            -
                    exit 1
         | 
| 865 | 
            +
                  
         | 
| 866 | 
            +
                  if payload['cluster'].empty?
         | 
| 867 | 
            +
                    raise_command_error "Specify at least one option to update.\n#{optparse}"
         | 
| 854 868 | 
             
                  end
         | 
| 855 869 |  | 
| 856 870 | 
             
                  @clusters_interface.setopts(options)
         | 
| @@ -2205,6 +2219,7 @@ class Morpheus::Cli::Clusters | |
| 2205 2219 | 
             
                        :id, :status, :name, :cpu, :memory, :storage
         | 
| 2206 2220 | 
             
                    ]
         | 
| 2207 2221 | 
             
                    print as_pretty_table(rows, columns, options)
         | 
| 2222 | 
            +
                    print_results_pagination(json_response)
         | 
| 2208 2223 | 
             
                  end
         | 
| 2209 2224 | 
             
                  print reset,"\n"
         | 
| 2210 2225 | 
             
                  return 0
         | 
| @@ -2214,6 +2229,43 @@ class Morpheus::Cli::Clusters | |
| 2214 2229 | 
             
                end
         | 
| 2215 2230 | 
             
              end
         | 
| 2216 2231 |  | 
| 2232 | 
            +
              def _get_container_group(args, options, resource_type)
         | 
| 2233 | 
            +
                begin
         | 
| 2234 | 
            +
                  cluster = find_cluster_by_name_or_id(args[0])
         | 
| 2235 | 
            +
                  id = args[1]
         | 
| 2236 | 
            +
                  return 1 if cluster.nil?
         | 
| 2237 | 
            +
             | 
| 2238 | 
            +
                  params = {}
         | 
| 2239 | 
            +
                  params.merge!(parse_list_options(options))
         | 
| 2240 | 
            +
                  params['resourceLevel'] = options[:resourceLevel] if !options[:resourceLevel].nil?
         | 
| 2241 | 
            +
                  @clusters_interface.setopts(options)
         | 
| 2242 | 
            +
                  if options[:dry_run]
         | 
| 2243 | 
            +
                    print_dry_run @clusters_interface.dry.get_container_group(cluster['id'], resource_type, id, params)
         | 
| 2244 | 
            +
                    return
         | 
| 2245 | 
            +
                  end
         | 
| 2246 | 
            +
                  container_group = @clusters_interface.get_container_group(cluster['id'], resource_type, id, params)['resource']
         | 
| 2247 | 
            +
             | 
| 2248 | 
            +
                  render_result = render_with_format(container_group, options, 'containers')
         | 
| 2249 | 
            +
                  return 0 if render_result
         | 
| 2250 | 
            +
                  resource_is = options['title'] ? options['title'].capitalize : resource_type.capitalize
         | 
| 2251 | 
            +
                  title = "Morpheus Cluster #{cluster['name']}: #{resource_is}"
         | 
| 2252 | 
            +
                  print_h1 title
         | 
| 2253 | 
            +
                  print cyan
         | 
| 2254 | 
            +
                  description_cols = {
         | 
| 2255 | 
            +
                      "ID" => 'id',
         | 
| 2256 | 
            +
                      "Name" => 'name',
         | 
| 2257 | 
            +
                      "Status" => 'status',
         | 
| 2258 | 
            +
                      "metadata" => lambda { |it| as_json(it['metadata']) }
         | 
| 2259 | 
            +
                  }
         | 
| 2260 | 
            +
                  print_description_list(description_cols, container_group)
         | 
| 2261 | 
            +
                  print reset,"\n"
         | 
| 2262 | 
            +
                  return 0
         | 
| 2263 | 
            +
                rescue RestClient::Exception => e
         | 
| 2264 | 
            +
                  print_rest_exception(e, options)
         | 
| 2265 | 
            +
                  exit 1
         | 
| 2266 | 
            +
                end
         | 
| 2267 | 
            +
              end
         | 
| 2268 | 
            +
             | 
| 2217 2269 | 
             
              def _remove_container_group(args, options, resource_type)
         | 
| 2218 2270 | 
             
                begin
         | 
| 2219 2271 | 
             
                  cluster = find_cluster_by_name_or_id(args[0])
         | 
| @@ -2321,6 +2373,26 @@ class Morpheus::Cli::Clusters | |
| 2321 2373 | 
             
                _list_container_groups(args, options,resource_type)
         | 
| 2322 2374 | 
             
              end
         | 
| 2323 2375 |  | 
| 2376 | 
            +
              def get_deployment(args)
         | 
| 2377 | 
            +
                resource_type = 'deployment'
         | 
| 2378 | 
            +
                options = {}
         | 
| 2379 | 
            +
                optparse = Morpheus::Cli::OptionParser.new do |opts|
         | 
| 2380 | 
            +
                  opts.banner = subcommand_usage( "[cluster]")
         | 
| 2381 | 
            +
                  opts.on("--resource-level LEVEL", String, "Resource Level") do |val|
         | 
| 2382 | 
            +
                    options[:resourceLevel] = val.to_s
         | 
| 2383 | 
            +
                  end
         | 
| 2384 | 
            +
                  build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
         | 
| 2385 | 
            +
                  opts.footer = "get #{resource_type} for a cluster.\n" +
         | 
| 2386 | 
            +
                      "[cluster] and [#{resource_type}] is required. This is the name or id of an existing cluster, and the id of the #{resource_type}"
         | 
| 2387 | 
            +
                end
         | 
| 2388 | 
            +
                optparse.parse!(args)
         | 
| 2389 | 
            +
                if args.count != 2
         | 
| 2390 | 
            +
                  raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
         | 
| 2391 | 
            +
                end
         | 
| 2392 | 
            +
                connect(options)
         | 
| 2393 | 
            +
                _get_container_group(args, options, resource_type)
         | 
| 2394 | 
            +
              end
         | 
| 2395 | 
            +
             | 
| 2324 2396 | 
             
              def remove_deployment(args)
         | 
| 2325 2397 | 
             
                resource_type = 'deployment'
         | 
| 2326 2398 | 
             
                options = {}
         | 
| @@ -2439,6 +2511,26 @@ class Morpheus::Cli::Clusters | |
| 2439 2511 | 
             
                _list_container_groups(args, options, resource_type)
         | 
| 2440 2512 | 
             
              end
         | 
| 2441 2513 |  | 
| 2514 | 
            +
              def get_pod(args)
         | 
| 2515 | 
            +
                resource_type = 'pod'
         | 
| 2516 | 
            +
                options = {}
         | 
| 2517 | 
            +
                optparse = Morpheus::Cli::OptionParser.new do |opts|
         | 
| 2518 | 
            +
                  opts.banner = subcommand_usage( "[cluster]")
         | 
| 2519 | 
            +
                  opts.on("--resource-level LEVEL", String, "Resource Level") do |val|
         | 
| 2520 | 
            +
                    options[:resourceLevel] = val.to_s
         | 
| 2521 | 
            +
                  end
         | 
| 2522 | 
            +
                  build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
         | 
| 2523 | 
            +
                  opts.footer = "get #{resource_type} for a cluster.\n" +
         | 
| 2524 | 
            +
                      "[cluster] and [#{resource_type}] is required. This is the name or id of an existing cluster, and the id of the #{resource_type}"
         | 
| 2525 | 
            +
                end
         | 
| 2526 | 
            +
                optparse.parse!(args)
         | 
| 2527 | 
            +
                if args.count != 2
         | 
| 2528 | 
            +
                  raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
         | 
| 2529 | 
            +
                end
         | 
| 2530 | 
            +
                connect(options)
         | 
| 2531 | 
            +
                _get_container_group(args, options, resource_type)
         | 
| 2532 | 
            +
              end
         | 
| 2533 | 
            +
             | 
| 2442 2534 | 
             
              def remove_pod(args)
         | 
| 2443 2535 | 
             
                resource_type = 'pod'
         | 
| 2444 2536 | 
             
                options = {}
         | 
| @@ -2908,6 +3000,130 @@ class Morpheus::Cli::Clusters | |
| 2908 3000 | 
             
                end
         | 
| 2909 3001 | 
             
              end
         | 
| 2910 3002 |  | 
| 3003 | 
            +
              def add_datastore(args)
         | 
| 3004 | 
            +
                options = {}
         | 
| 3005 | 
            +
                optparse = Morpheus::Cli::OptionParser.new do |opts|
         | 
| 3006 | 
            +
                  opts.banner = subcommand_usage( "[cluster] [options]")
         | 
| 3007 | 
            +
                  build_option_type_options(opts, options, add_datastore_option_types)
         | 
| 3008 | 
            +
                  build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
         | 
| 3009 | 
            +
                  opts.footer = "Add datastore to a cluster.\n" +
         | 
| 3010 | 
            +
                    "[cluster] is required. This is the name or id of an existing cluster.\n" +
         | 
| 3011 | 
            +
                    "[name] is required. This is the name of the new datastore."
         | 
| 3012 | 
            +
                end
         | 
| 3013 | 
            +
             | 
| 3014 | 
            +
                optparse.parse!(args)
         | 
| 3015 | 
            +
                if args.count != 1 and args.count != 2
         | 
| 3016 | 
            +
                  raise_command_error "wrong number of arguments, expected 1-2 and got (#{args.count}) #{args}\n#{optparse}"
         | 
| 3017 | 
            +
                end
         | 
| 3018 | 
            +
                connect(options)
         | 
| 3019 | 
            +
             | 
| 3020 | 
            +
                begin
         | 
| 3021 | 
            +
                  cluster = find_cluster_by_name_or_id(args[0])
         | 
| 3022 | 
            +
                  return 1 if cluster.nil?
         | 
| 3023 | 
            +
                  if options[:payload]
         | 
| 3024 | 
            +
                    payload = options[:payload]
         | 
| 3025 | 
            +
                    # support -O OPTION switch on top of --payload
         | 
| 3026 | 
            +
                    if options[:options]
         | 
| 3027 | 
            +
                      payload ||= {}
         | 
| 3028 | 
            +
                      payload.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) })
         | 
| 3029 | 
            +
                    end
         | 
| 3030 | 
            +
                  else
         | 
| 3031 | 
            +
                    options[:params] ||= {}
         | 
| 3032 | 
            +
                    options[:params].merge!({:serverGroupId => cluster['id']})
         | 
| 3033 | 
            +
             | 
| 3034 | 
            +
                    datastore = Morpheus::Cli::OptionTypes.prompt(add_datastore_option_types, options[:options], @api_client, options[:params])
         | 
| 3035 | 
            +
             | 
| 3036 | 
            +
                    datastore_type = find_datastore_type_by_code(datastore['datastoreType'])
         | 
| 3037 | 
            +
                    datastore['datastoreType'] = {id:datastore_type['id']}
         | 
| 3038 | 
            +
             | 
| 3039 | 
            +
                    # datastore type options
         | 
| 3040 | 
            +
                    unless datastore_type['optionTypes'].empty?
         | 
| 3041 | 
            +
                      datastore.merge!(Morpheus::Cli::OptionTypes.prompt(datastore_type['optionTypes'], options[:options].deep_merge({:context_map => {'domain' => ''}, :checkbox_as_boolean => true}), @api_client, options[:params]))
         | 
| 3042 | 
            +
                    end
         | 
| 3043 | 
            +
             | 
| 3044 | 
            +
                    # perms
         | 
| 3045 | 
            +
                    perms = prompt_permissions(options.merge({:for_datastore => true}), ['plans', 'groupDefaults'])
         | 
| 3046 | 
            +
             | 
| 3047 | 
            +
                    datastore['resourcePermissions'] = perms['resourcePermissions'] unless perms['resourcePermissions'].nil?
         | 
| 3048 | 
            +
                    datastore['tenants'] = perms['tenantPermissions'] unless perms['tenantPermissions'].nil?
         | 
| 3049 | 
            +
                    datastore['visibility'] = perms['resourcePool']['visibility'] if !perms['resourcePool'].nil? && !perms['resourcePool']['visibility'].nil?
         | 
| 3050 | 
            +
             | 
| 3051 | 
            +
                    payload = {datastore:datastore}
         | 
| 3052 | 
            +
                  end
         | 
| 3053 | 
            +
             | 
| 3054 | 
            +
                  @clusters_interface.setopts(options)
         | 
| 3055 | 
            +
                  if options[:dry_run]
         | 
| 3056 | 
            +
                    print_dry_run @clusters_interface.dry.create_datastore(cluster['id'], payload)
         | 
| 3057 | 
            +
                    return
         | 
| 3058 | 
            +
                  end
         | 
| 3059 | 
            +
                  json_response = @clusters_interface.create_datastore(cluster['id'], payload)
         | 
| 3060 | 
            +
                  if options[:json]
         | 
| 3061 | 
            +
                    puts as_json(json_response)
         | 
| 3062 | 
            +
                  elsif json_response['success']
         | 
| 3063 | 
            +
                    if json_response['msg'] == nil
         | 
| 3064 | 
            +
                      print_green_success "Added datastore to cluster #{cluster['name']}"
         | 
| 3065 | 
            +
                    else
         | 
| 3066 | 
            +
                      print_green_success json_response['msg']
         | 
| 3067 | 
            +
                    end
         | 
| 3068 | 
            +
                  end
         | 
| 3069 | 
            +
                  return 0
         | 
| 3070 | 
            +
                rescue RestClient::Exception => e
         | 
| 3071 | 
            +
                  print_rest_exception(e, options)
         | 
| 3072 | 
            +
                  exit 1
         | 
| 3073 | 
            +
                end
         | 
| 3074 | 
            +
              end
         | 
| 3075 | 
            +
             | 
| 3076 | 
            +
              def remove_datastore(args)
         | 
| 3077 | 
            +
                params = {}
         | 
| 3078 | 
            +
                options = {}
         | 
| 3079 | 
            +
                optparse = Morpheus::Cli::OptionParser.new do |opts|
         | 
| 3080 | 
            +
                  opts.banner = subcommand_usage("[cluster] [datastore]")
         | 
| 3081 | 
            +
                  opts.on( '-f', '--force', "Force Delete" ) do
         | 
| 3082 | 
            +
                    params[:force] = 'on'
         | 
| 3083 | 
            +
                  end
         | 
| 3084 | 
            +
                  build_standard_remove_options(opts, options)
         | 
| 3085 | 
            +
                  opts.footer = "Delete a datastore from a cluster.\n" +
         | 
| 3086 | 
            +
                    "[cluster] is required. This is the name or id of an existing cluster.\n" +
         | 
| 3087 | 
            +
                    "[datastore] is required. This is the name or id of an existing datastore."
         | 
| 3088 | 
            +
                end
         | 
| 3089 | 
            +
                optparse.parse!(args)
         | 
| 3090 | 
            +
                verify_args!(args:args, optparse:optparse, count:2)
         | 
| 3091 | 
            +
                connect(options)
         | 
| 3092 | 
            +
                params.merge!(parse_query_options(options))
         | 
| 3093 | 
            +
             | 
| 3094 | 
            +
                cluster = find_cluster_by_name_or_id(args[0])
         | 
| 3095 | 
            +
                return 1 if cluster.nil?
         | 
| 3096 | 
            +
             | 
| 3097 | 
            +
                datastore_id = args[1]
         | 
| 3098 | 
            +
                if datastore_id.empty?
         | 
| 3099 | 
            +
                  raise_command_error "missing required worker parameter"
         | 
| 3100 | 
            +
                end
         | 
| 3101 | 
            +
             | 
| 3102 | 
            +
                datastore = find_datastore_by_name_or_id(cluster['id'], datastore_id)
         | 
| 3103 | 
            +
                if datastore.nil?
         | 
| 3104 | 
            +
                  print_red_alert "Datastore not found for '#{datastore_id}'"
         | 
| 3105 | 
            +
                  return 1
         | 
| 3106 | 
            +
                end
         | 
| 3107 | 
            +
                unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to remove the cluster datastore '#{datastore['name'] || datastore['id']}'?", options)
         | 
| 3108 | 
            +
                  return 9, "aborted command"
         | 
| 3109 | 
            +
                end
         | 
| 3110 | 
            +
             | 
| 3111 | 
            +
                @clusters_interface.setopts(options)
         | 
| 3112 | 
            +
                if options[:dry_run]
         | 
| 3113 | 
            +
                  print_dry_run @clusters_interface.dry.destroy_datastore(cluster['id'], datastore['id'], params)
         | 
| 3114 | 
            +
                  return
         | 
| 3115 | 
            +
                end
         | 
| 3116 | 
            +
                json_response = @clusters_interface.destroy_datastore(cluster['id'], datastore['id'], params)
         | 
| 3117 | 
            +
                render_response(json_response, options) do
         | 
| 3118 | 
            +
                  msg = "Datastore #{datastore['name']} is being removed from cluster #{cluster['name']}..."
         | 
| 3119 | 
            +
                  if json_response['msg']
         | 
| 3120 | 
            +
                    msg = json_response['msg']
         | 
| 3121 | 
            +
                  end
         | 
| 3122 | 
            +
                  print_green_success msg
         | 
| 3123 | 
            +
                end
         | 
| 3124 | 
            +
                return 0, nil
         | 
| 3125 | 
            +
              end
         | 
| 3126 | 
            +
             | 
| 2911 3127 | 
             
              def update_datastore(args)
         | 
| 2912 3128 | 
             
                options = {}
         | 
| 2913 3129 | 
             
                optparse = Morpheus::Cli::OptionParser.new do |opts|
         | 
| @@ -3970,6 +4186,25 @@ class Morpheus::Cli::Clusters | |
| 3970 4186 | 
             
                json_results['datastores'].empty? ? nil : json_results['datastores'][0]
         | 
| 3971 4187 | 
             
              end
         | 
| 3972 4188 |  | 
| 4189 | 
            +
              def find_datastore_type_by_code_or_id(val)
         | 
| 4190 | 
            +
                (val.to_s =~ /\A\d{1,}\Z/) ? find_datastore_type_by_id(val) : find_datastore_type_by_code(val)
         | 
| 4191 | 
            +
              end
         | 
| 4192 | 
            +
             | 
| 4193 | 
            +
              def find_datastore_type_by_id(id)
         | 
| 4194 | 
            +
                get_datastore_types.find { |it| it['id'] == id }
         | 
| 4195 | 
            +
              end
         | 
| 4196 | 
            +
             | 
| 4197 | 
            +
              def find_datastore_type_by_code(code)
         | 
| 4198 | 
            +
                get_datastore_types.find { |it| it['code'].downcase == code.downcase }
         | 
| 4199 | 
            +
              end
         | 
| 4200 | 
            +
             | 
| 4201 | 
            +
              def get_datastore_types(refresh=false)
         | 
| 4202 | 
            +
                if !@datastore_types || refresh
         | 
| 4203 | 
            +
                  @datastore_types = @datastores_interface.types()['datastoreTypes']
         | 
| 4204 | 
            +
                end
         | 
| 4205 | 
            +
                @datastore_types
         | 
| 4206 | 
            +
              end
         | 
| 4207 | 
            +
             | 
| 3973 4208 | 
             
              def find_job_by_name_or_id(cluster_id, val)
         | 
| 3974 4209 | 
             
                if val.to_s =~ /\A\d{1,}\Z/
         | 
| 3975 4210 | 
             
                  params = {jobId: val.to_i}
         | 
| @@ -4275,6 +4510,14 @@ class Morpheus::Cli::Clusters | |
| 4275 4510 | 
             
                end
         | 
| 4276 4511 | 
             
              end
         | 
| 4277 4512 |  | 
| 4513 | 
            +
              def add_datastore_option_types
         | 
| 4514 | 
            +
                [
         | 
| 4515 | 
            +
                  {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
         | 
| 4516 | 
            +
                  {'fieldName' => 'datastoreType', 'fieldLabel' => 'Type', 'type' => 'select', 'optionSource' => 'datastoreTypes', 'description' => 'Choose a datastore type.', 'required' => true, 'displayOrder' => 2},
         | 
| 4517 | 
            +
                  {'fieldName' => 'active', 'fieldLabel' => 'Active', 'type' => 'checkbox', 'required' => true, 'displayOrder' => 3, 'defaultValue' => true},
         | 
| 4518 | 
            +
                ]
         | 
| 4519 | 
            +
              end
         | 
| 4520 | 
            +
             | 
| 4278 4521 | 
             
              def prompt_resource_pool(group, cloud, service_plan, provision_type, options)
         | 
| 4279 4522 | 
             
                resource_pool = nil
         | 
| 4280 4523 |  | 
| @@ -4451,4 +4694,135 @@ class Morpheus::Cli::Clusters | |
| 4451 4694 | 
             
                  exit 1
         | 
| 4452 4695 | 
             
                end
         | 
| 4453 4696 | 
             
              end
         | 
| 4697 | 
            +
             | 
| 4698 | 
            +
              def list_replicasets(args)
         | 
| 4699 | 
            +
                _list_resources(args, 'replicaset')
         | 
| 4700 | 
            +
              end
         | 
| 4701 | 
            +
             | 
| 4702 | 
            +
              def get_replicaset(args)
         | 
| 4703 | 
            +
                _get_resource(args, 'replicaset')
         | 
| 4704 | 
            +
              end
         | 
| 4705 | 
            +
             | 
| 4706 | 
            +
              def list_daemonsets(args)
         | 
| 4707 | 
            +
                _list_resources(args, 'daemonset')
         | 
| 4708 | 
            +
              end
         | 
| 4709 | 
            +
             | 
| 4710 | 
            +
              def get_daemonset(args)
         | 
| 4711 | 
            +
                _get_resource(args, 'daemonset')
         | 
| 4712 | 
            +
              end
         | 
| 4713 | 
            +
             | 
| 4714 | 
            +
             | 
| 4715 | 
            +
              def list_endpoints(args)
         | 
| 4716 | 
            +
                _list_resources(args, 'endpoint')
         | 
| 4717 | 
            +
              end
         | 
| 4718 | 
            +
             | 
| 4719 | 
            +
              def get_endpoint(args)
         | 
| 4720 | 
            +
                _get_resource(args, 'endpoint')
         | 
| 4721 | 
            +
              end
         | 
| 4722 | 
            +
             | 
| 4723 | 
            +
              def list_ingresses(args)
         | 
| 4724 | 
            +
                _list_resources(args, 'ingresse')
         | 
| 4725 | 
            +
              end
         | 
| 4726 | 
            +
             | 
| 4727 | 
            +
              def get_ingress(args)
         | 
| 4728 | 
            +
                _get_resource(args, 'ingresse', {'title' => 'ingress'})
         | 
| 4729 | 
            +
              end
         | 
| 4730 | 
            +
             | 
| 4731 | 
            +
              def list_policies(args)
         | 
| 4732 | 
            +
                _list_resources(args, 'policie')
         | 
| 4733 | 
            +
              end
         | 
| 4734 | 
            +
             | 
| 4735 | 
            +
              def get_policy(args)
         | 
| 4736 | 
            +
                _get_resource(args, 'policie', {'title' => 'policy'})
         | 
| 4737 | 
            +
              end
         | 
| 4738 | 
            +
             | 
| 4739 | 
            +
              def list_volume_claims(args)
         | 
| 4740 | 
            +
                _list_resources(args, 'volumeclaim')
         | 
| 4741 | 
            +
              end
         | 
| 4742 | 
            +
             | 
| 4743 | 
            +
              def get_volume_claim(args)
         | 
| 4744 | 
            +
                _get_resource(args, 'volumeclaim')
         | 
| 4745 | 
            +
              end
         | 
| 4746 | 
            +
             | 
| 4747 | 
            +
              def list_volumes(args)
         | 
| 4748 | 
            +
                _list_resources(args, 'volume')
         | 
| 4749 | 
            +
              end
         | 
| 4750 | 
            +
             | 
| 4751 | 
            +
              def get_volume(args)
         | 
| 4752 | 
            +
                _get_resource(args, 'volume')
         | 
| 4753 | 
            +
              end
         | 
| 4754 | 
            +
             | 
| 4755 | 
            +
             | 
| 4756 | 
            +
              def list_config_maps(args)
         | 
| 4757 | 
            +
                _list_resources(args, 'configmap')
         | 
| 4758 | 
            +
              end
         | 
| 4759 | 
            +
             | 
| 4760 | 
            +
              def get_config_map(args)
         | 
| 4761 | 
            +
                _get_resource(args, 'configmap')
         | 
| 4762 | 
            +
              end
         | 
| 4763 | 
            +
             | 
| 4764 | 
            +
              def list_secrets(args)
         | 
| 4765 | 
            +
                _list_resources(args, 'secret')
         | 
| 4766 | 
            +
              end
         | 
| 4767 | 
            +
             | 
| 4768 | 
            +
              def get_secret(args)
         | 
| 4769 | 
            +
                _get_resource(args, 'secret')
         | 
| 4770 | 
            +
              end
         | 
| 4771 | 
            +
             | 
| 4772 | 
            +
              def get_container(args)
         | 
| 4773 | 
            +
                _get_resource(args, 'container')
         | 
| 4774 | 
            +
              end
         | 
| 4775 | 
            +
             | 
| 4776 | 
            +
              def get_stateful_set(args)
         | 
| 4777 | 
            +
                _get_resource(args, 'statefulset')
         | 
| 4778 | 
            +
             | 
| 4779 | 
            +
              end
         | 
| 4780 | 
            +
             | 
| 4781 | 
            +
              def get_job(args)
         | 
| 4782 | 
            +
                _get_resource(args, 'job')
         | 
| 4783 | 
            +
              end
         | 
| 4784 | 
            +
             | 
| 4785 | 
            +
              def get_service(args)
         | 
| 4786 | 
            +
                _get_resource(args, 'service')
         | 
| 4787 | 
            +
              end
         | 
| 4788 | 
            +
             | 
| 4789 | 
            +
              private
         | 
| 4790 | 
            +
             | 
| 4791 | 
            +
              def _get_resource(args, resource_type, options = {})
         | 
| 4792 | 
            +
                optparse = Morpheus::Cli::OptionParser.new do |opts|
         | 
| 4793 | 
            +
                  opts.banner = subcommand_usage("[cluster] [id]")
         | 
| 4794 | 
            +
                  opts.on("--resource-level LEVEL", String, "Resource Level") do |val|
         | 
| 4795 | 
            +
                    options[:resourceLevel] = val.to_s
         | 
| 4796 | 
            +
                  end
         | 
| 4797 | 
            +
                  build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
         | 
| 4798 | 
            +
                  opts.footer = "get #{resource_type} for a cluster.\n" +
         | 
| 4799 | 
            +
                                "[cluster] and [#{resource_type}] is required. This is the name or id of an existing cluster, and the id of the #{resource_type}"
         | 
| 4800 | 
            +
                end
         | 
| 4801 | 
            +
                optparse.parse!(args)
         | 
| 4802 | 
            +
                
         | 
| 4803 | 
            +
                if args.count != 2
         | 
| 4804 | 
            +
                  raise_command_error "wrong number of arguments, expected 2 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
         | 
| 4805 | 
            +
                end
         | 
| 4806 | 
            +
             | 
| 4807 | 
            +
                connect(options)
         | 
| 4808 | 
            +
                _get_container_group(args, options, resource_type)
         | 
| 4809 | 
            +
              end
         | 
| 4810 | 
            +
             | 
| 4811 | 
            +
              def _list_resources(args, resource_type, options = {})
         | 
| 4812 | 
            +
                optparse = Morpheus::Cli::OptionParser.new do |opts|
         | 
| 4813 | 
            +
                  opts.banner = subcommand_usage( "[cluster]")
         | 
| 4814 | 
            +
                  opts.on("--resource-level LEVEL", String, "Resource Level") do |val|
         | 
| 4815 | 
            +
                    options[:resourceLevel] = val.to_s
         | 
| 4816 | 
            +
                  end
         | 
| 4817 | 
            +
                  build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
         | 
| 4818 | 
            +
                  opts.footer = "List #{resource_type}s for a cluster.\n" +
         | 
| 4819 | 
            +
                      "[cluster] is required. This is the name or id of an existing cluster."
         | 
| 4820 | 
            +
                end
         | 
| 4821 | 
            +
                optparse.parse!(args)
         | 
| 4822 | 
            +
                if args.count != 1
         | 
| 4823 | 
            +
                  raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
         | 
| 4824 | 
            +
                end
         | 
| 4825 | 
            +
                connect(options)
         | 
| 4826 | 
            +
                _list_container_groups(args, options, resource_type)
         | 
| 4827 | 
            +
              end
         | 
| 4454 4828 | 
             
            end
         | 
| @@ -1009,6 +1009,9 @@ class Morpheus::Cli::Hosts | |
| 1009 1009 | 
             
                  opts.on('--ssh-password VALUE', String, "SSH Password") do |val|
         | 
| 1010 1010 | 
             
                    params['sshPassword'] = val == "null" ? nil : val
         | 
| 1011 1011 | 
             
                  end
         | 
| 1012 | 
            +
                  opts.on('--ssh-key-pair ID', String, "SSH Key Pair ID") do |val|
         | 
| 1013 | 
            +
                    params['sshKeyPair'] = val == "null" ? nil : {"id" => val.to_i}
         | 
| 1014 | 
            +
                  end
         | 
| 1012 1015 | 
             
                  opts.on('--power-schedule-type ID', String, "Power Schedule Type ID") do |val|
         | 
| 1013 1016 | 
             
                    params['powerScheduleType'] = val == "null" ? nil : val
         | 
| 1014 1017 | 
             
                  end
         | 
| @@ -2746,6 +2746,9 @@ class Morpheus::Cli::Instances | |
| 2746 2746 | 
             
                options = {}
         | 
| 2747 2747 | 
             
                optparse = Morpheus::Cli::OptionParser.new do |opts|
         | 
| 2748 2748 | 
             
                  opts.banner = subcommand_usage("[instance]")
         | 
| 2749 | 
            +
                  opts.on('--include-network-interfaces','--include-network-interfaces', "Populate payload networkInterfaces with current interfaces") do
         | 
| 2750 | 
            +
                    options[:include_nics] = true
         | 
| 2751 | 
            +
                  end
         | 
| 2749 2752 | 
             
                  build_standard_update_options(opts, options)
         | 
| 2750 2753 | 
             
                end
         | 
| 2751 2754 | 
             
                optparse.parse!(args)
         | 
| @@ -2775,11 +2778,17 @@ class Morpheus::Cli::Instances | |
| 2775 2778 | 
             
                  plan_id = instance['plan']['id']
         | 
| 2776 2779 | 
             
                  resource_pool_id = instance['config']['resourcePoolId'] if instance['config']
         | 
| 2777 2780 | 
             
                  current_plan_name = instance['plan']['name']
         | 
| 2778 | 
            -
                  current_interfaces = get_instance_interfaces(instance)
         | 
| 2779 | 
            -
                  if current_interfaces != false 
         | 
| 2780 | 
            -
                    payload['networkInterfaces'] = current_interfaces
         | 
| 2781 | 
            -
                  end
         | 
| 2782 2781 |  | 
| 2782 | 
            +
                  # JD: networkInterfaces should not be needed but pre 7.0.8/8.0.0 the API does expect it to be passed
         | 
| 2783 | 
            +
                  # However if the instance has more than one server this creates duplicate nics and breaks things
         | 
| 2784 | 
            +
                  # so only continue to do it if the instance has just one server and remote version is pre 7.0.8
         | 
| 2785 | 
            +
                  # should also only do this if remote version < 7.0.8
         | 
| 2786 | 
            +
                  if options[:include_nics] || (!remote_version_gte("7.0.8") && instance['servers'] && instance['servers'].size == 1)
         | 
| 2787 | 
            +
                      current_interfaces = get_instance_interfaces(instance)
         | 
| 2788 | 
            +
                      if current_interfaces != false 
         | 
| 2789 | 
            +
                        payload['networkInterfaces'] = current_interfaces
         | 
| 2790 | 
            +
                      end
         | 
| 2791 | 
            +
                  end
         | 
| 2783 2792 |  | 
| 2784 2793 | 
             
                  # need to GET provision type for some settings...
         | 
| 2785 2794 | 
             
                  provision_type = @provision_types_interface.get(instance['layout']['provisionTypeId'])['provisionType']
         | 
| @@ -5576,6 +5585,8 @@ private | |
| 5576 5585 | 
             
                    details['interfaces'].each do |inter|
         | 
| 5577 5586 | 
             
                      interfaces.push(inter)
         | 
| 5578 5587 | 
             
                    end
         | 
| 5588 | 
            +
                    # only include the first one or it will create duplicates
         | 
| 5589 | 
            +
                    break
         | 
| 5579 5590 | 
             
                  end
         | 
| 5580 5591 | 
             
                  return interfaces
         | 
| 5581 5592 | 
             
                rescue
         | 
| @@ -5583,4 +5594,22 @@ private | |
| 5583 5594 | 
             
                end
         | 
| 5584 5595 | 
             
              end
         | 
| 5585 5596 |  | 
| 5597 | 
            +
              def remote_version_gte(required_version)
         | 
| 5598 | 
            +
                version = @remote_appliance[:build_version]
         | 
| 5599 | 
            +
                return false if version.nil?
         | 
| 5600 | 
            +
                version_numbers = version.split(".")
         | 
| 5601 | 
            +
                required_version_numbers = required_version.split(".")
         | 
| 5602 | 
            +
                result = true
         | 
| 5603 | 
            +
                required_version_numbers.each_with_index do |v, i|
         | 
| 5604 | 
            +
                  if version_numbers[i].to_i > v.to_i
         | 
| 5605 | 
            +
                    break
         | 
| 5606 | 
            +
                  elsif version_numbers[i].to_i < v.to_i
         | 
| 5607 | 
            +
                    result = false
         | 
| 5608 | 
            +
                    break
         | 
| 5609 | 
            +
                  else
         | 
| 5610 | 
            +
                    # keep going
         | 
| 5611 | 
            +
                  end
         | 
| 5612 | 
            +
                end
         | 
| 5613 | 
            +
                return result
         | 
| 5614 | 
            +
              end
         | 
| 5586 5615 | 
             
            end
         | 
| @@ -163,6 +163,9 @@ class Morpheus::Cli::LibraryContainerTypesCommand | |
| 163 163 | 
             
                    "Virtual Image" => lambda {|it| 
         | 
| 164 164 | 
             
                      it['virtualImage'] ? it['virtualImage']['name'] : ''
         | 
| 165 165 | 
             
                    },
         | 
| 166 | 
            +
                    "OsType" => lambda {|it| 
         | 
| 167 | 
            +
                      it['osType'] ? it['osType']['name'] : ''
         | 
| 168 | 
            +
                    },
         | 
| 166 169 | 
             
                    # "Category" => lambda {|it| it['category'].to_s.capitalize },
         | 
| 167 170 | 
             
                    # # "Logo" => lambda {|it| it['logo'].to_s },
         | 
| 168 171 | 
             
                    # "Visiblity" => lambda {|it| it['visibility'].to_s.capitalize },
         | 
| @@ -474,6 +477,9 @@ class Morpheus::Cli::LibraryContainerTypesCommand | |
| 474 477 | 
             
                  opts.on('--version VALUE', String, "Version") do |val|
         | 
| 475 478 | 
             
                    params['containerVersion'] = val
         | 
| 476 479 | 
             
                  end
         | 
| 480 | 
            +
                  opts.on('--osType VALUE', Integer, "OsType") do |val|
         | 
| 481 | 
            +
                    params['osTypeId'] = val
         | 
| 482 | 
            +
                  end
         | 
| 477 483 | 
             
                  # opts.on('--technology CODE', String, "Technology") do |val|
         | 
| 478 484 | 
             
                  #   params['provisionTypeCode'] = val
         | 
| 479 485 | 
             
                  # end
         |