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
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: c8074c5d41cd8ca2aa6f199a0b85f22f7c2b8d3647b2788604d42424b7abbd9b
         | 
| 4 | 
            +
              data.tar.gz: 8176b21a71b63466b537ca4d43933e06411ae374cbb159ab451f4e37042299e5
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 05414d569b3e9d323ca0ebf0ff86778e9656f84b92af1a2e6520e826351dc444eb1c6d6721ef7137ffbe603be703832dcd15f4e14c31f28005b6de7c2cc454f8
         | 
| 7 | 
            +
              data.tar.gz: fca09ddb93cf6cc58401d1652803a61d220fe9999427a931b0fed515c5a8e0a2933013299323722739a7f65c9b9b42edffe4a62972cad85e9b5651a4fcded2df
         | 
    
        data/Dockerfile
    CHANGED
    
    
| @@ -950,6 +950,14 @@ class Morpheus::APIClient | |
| 950 950 | 
             
                Morpheus::NetworkServerGroupsInterface.new(common_interface_options).setopts(@options)
         | 
| 951 951 | 
             
              end
         | 
| 952 952 |  | 
| 953 | 
            +
              def network_server_services
         | 
| 954 | 
            +
                Morpheus::NetworkServerServicesInterface.new(common_interface_options).setopts(@options)
         | 
| 955 | 
            +
              end
         | 
| 956 | 
            +
             | 
| 957 | 
            +
              def network_resource_types
         | 
| 958 | 
            +
                Morpheus::NetworkResourceTypesInterface.new(common_interface_options).setopts(@options)
         | 
| 959 | 
            +
              end
         | 
| 960 | 
            +
             | 
| 953 961 | 
             
              def network_edge_clusters
         | 
| 954 962 | 
             
                Morpheus::NetworkEdgeClustersInterface.new(common_interface_options).setopts(@options)
         | 
| 955 963 | 
             
              end
         | 
| @@ -1002,6 +1010,9 @@ class Morpheus::APIClient | |
| 1002 1010 | 
             
                Morpheus::EmailTemplatesInterface.new(common_interface_options).setopts(@options)
         | 
| 1003 1011 | 
             
              end
         | 
| 1004 1012 |  | 
| 1013 | 
            +
              def library_operating_systems
         | 
| 1014 | 
            +
                Morpheus::LibraryOperatingSystemsInterface.new(common_interface_options).setopts(@options)
         | 
| 1015 | 
            +
              end
         | 
| 1005 1016 |  | 
| 1006 1017 | 
             
              def rest(endpoint)
         | 
| 1007 1018 | 
             
                Morpheus::RestInterface.new(common_interface_options).setopts(@options.merge({base_path: "#{@base_url}/api/#{endpoint}"}))
         | 
| @@ -25,6 +25,13 @@ class Morpheus::ApplianceSettingsInterface < Morpheus::APIClient | |
| 25 25 | 
             
                execute(opts)
         | 
| 26 26 | 
             
              end
         | 
| 27 27 |  | 
| 28 | 
            +
              def locales(params={})
         | 
| 29 | 
            +
                url = "#{base_path}/locales"
         | 
| 30 | 
            +
                headers = { params: params, authorization: "Bearer #{@access_token}" }
         | 
| 31 | 
            +
                opts = {method: :get, url: url, headers: headers}
         | 
| 32 | 
            +
                execute(opts)
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
             | 
| 28 35 | 
             
              def maintenance(params={}, payload={})
         | 
| 29 36 | 
             
                url = "#{base_path}/maintenance"
         | 
| 30 37 | 
             
                headers = { params: params, authorization: "Bearer #{@access_token}" }
         | 
| @@ -228,6 +228,12 @@ class Morpheus::ClustersInterface < Morpheus::APIClient | |
| 228 228 | 
             
                execute(method: :get, url: url, headers: headers)
         | 
| 229 229 | 
             
              end
         | 
| 230 230 |  | 
| 231 | 
            +
              def get_container_group(cluster_id, resource_type, id, params={})
         | 
| 232 | 
            +
                url = "#{base_path}/#{cluster_id}/#{resource_type}s/#{id}"
         | 
| 233 | 
            +
                headers = { params: params, authorization: "Bearer #{@access_token}" }
         | 
| 234 | 
            +
                execute(method: :get, url: url, headers: headers)
         | 
| 235 | 
            +
              end
         | 
| 236 | 
            +
             | 
| 231 237 | 
             
              def restart_container_group(id, container_group_id, resource_type, params={})
         | 
| 232 238 | 
             
                url = "#{base_path}/#{id}/#{resource_type}s/#{container_group_id}/restart"
         | 
| 233 239 | 
             
                headers = { params: params, authorization: "Bearer #{@access_token}" }
         | 
| @@ -259,12 +265,24 @@ class Morpheus::ClustersInterface < Morpheus::APIClient | |
| 259 265 | 
             
                execute(method: :get, url: url, headers: headers)
         | 
| 260 266 | 
             
              end
         | 
| 261 267 |  | 
| 268 | 
            +
              def create_datastore(id, payload)
         | 
| 269 | 
            +
                url = "#{base_path}/#{id}/data-stores"
         | 
| 270 | 
            +
                headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
         | 
| 271 | 
            +
                execute(method: :post, url: url, headers: headers, payload: payload.to_json)
         | 
| 272 | 
            +
              end
         | 
| 273 | 
            +
             | 
| 262 274 | 
             
              def update_datastore(id, datastore_id, payload)
         | 
| 263 275 | 
             
                url = "#{base_path}/#{id}/datastores/#{datastore_id}"
         | 
| 264 276 | 
             
                headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
         | 
| 265 277 | 
             
                execute(method: :put, url: url, headers: headers, payload: payload.to_json)
         | 
| 266 278 | 
             
              end
         | 
| 267 279 |  | 
| 280 | 
            +
              def destroy_datastore(id, datastore_id, params={})
         | 
| 281 | 
            +
                url = "#{base_path}/#{id}/datastores/#{datastore_id}"
         | 
| 282 | 
            +
                headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
         | 
| 283 | 
            +
                execute(method: :delete, url: url, headers: headers)
         | 
| 284 | 
            +
              end
         | 
| 285 | 
            +
             | 
| 268 286 | 
             
              def wiki(id, params)
         | 
| 269 287 | 
             
                url = "#{@base_url}/api/clusters/#{id}/wiki"
         | 
| 270 288 | 
             
                headers = { params: params, authorization: "Bearer #{@access_token}" }
         | 
| @@ -320,4 +338,11 @@ class Morpheus::ClustersInterface < Morpheus::APIClient | |
| 320 338 | 
             
                opts = {method: :get, url: url, headers: headers}
         | 
| 321 339 | 
             
                execute(opts)
         | 
| 322 340 | 
             
              end
         | 
| 341 | 
            +
             | 
| 342 | 
            +
              def list_resources(id, resources, params={})
         | 
| 343 | 
            +
                url = "#{base_path}/#{id}/#{resources}"
         | 
| 344 | 
            +
                headers = { params: params, authorization: "Bearer #{@access_token}" }
         | 
| 345 | 
            +
                execute(method: :get, url: url, headers: headers)
         | 
| 346 | 
            +
              end
         | 
| 347 | 
            +
             | 
| 323 348 | 
             
            end
         | 
| @@ -12,4 +12,10 @@ class Morpheus::DatastoresInterface < Morpheus::APIClient | |
| 12 12 | 
             
                execute(method: :get, url: url, headers: headers)
         | 
| 13 13 | 
             
              end
         | 
| 14 14 |  | 
| 15 | 
            +
              def types(params={})
         | 
| 16 | 
            +
                url = "/api/data-store-types"
         | 
| 17 | 
            +
                headers = { params: params, authorization: "Bearer #{@access_token}" }
         | 
| 18 | 
            +
                opts = {method: :get, url: url, headers: headers}
         | 
| 19 | 
            +
                execute(opts)
         | 
| 20 | 
            +
              end
         | 
| 15 21 | 
             
            end
         | 
| @@ -0,0 +1,63 @@ | |
| 1 | 
            +
            require 'morpheus/api/api_client'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class Morpheus::LibraryOperatingSystemsInterface < Morpheus::APIClient
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              def list_os_types(params={})
         | 
| 6 | 
            +
                url = "#{@base_url}/api/library/operating-systems/os-types"
         | 
| 7 | 
            +
                params['pageConfig'] = { sort:'owner,name', order:'desc,asc' }
         | 
| 8 | 
            +
                headers = { params: params, authorization: "Bearer #{@access_token}" }
         | 
| 9 | 
            +
                opts = {method: :get, url: url, headers: headers}
         | 
| 10 | 
            +
                execute(opts)
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              def get(id, params={})
         | 
| 14 | 
            +
                raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
         | 
| 15 | 
            +
                url = "#{@base_url}/api/library/operating-systems/os-types/#{id}"
         | 
| 16 | 
            +
                headers = { params: params, authorization: "Bearer #{@access_token}" }
         | 
| 17 | 
            +
                opts = {method: :get, url: url, headers: headers}
         | 
| 18 | 
            +
                execute(opts)
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              def update(id, payload)
         | 
| 22 | 
            +
                url = "#{@base_url}/api/library/operating-systems/#{id}"
         | 
| 23 | 
            +
                headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
         | 
| 24 | 
            +
                opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
         | 
| 25 | 
            +
                execute(opts)
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              def get_image(id, params={})
         | 
| 29 | 
            +
                raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
         | 
| 30 | 
            +
                url = "#{@base_url}/api/library/operating-systems/os-types/images/#{id}"
         | 
| 31 | 
            +
                headers = { params: params, authorization: "Bearer #{@access_token}" }
         | 
| 32 | 
            +
                opts = {method: :get, url: url, headers: headers}
         | 
| 33 | 
            +
                execute(opts)
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              def create_image(payload)
         | 
| 37 | 
            +
                url = "#{@base_url}/api/library/operating-systems/os-types/create-image"
         | 
| 38 | 
            +
                headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
         | 
| 39 | 
            +
                opts = {method: :post, url: url, headers: headers, payload: payload.to_json}
         | 
| 40 | 
            +
                execute(opts)
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
              def create(payload)
         | 
| 44 | 
            +
                url = "#{@base_url}/api/library/operating-systems"
         | 
| 45 | 
            +
                headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
         | 
| 46 | 
            +
                opts = {method: :post, url: url, headers: headers, payload: payload.to_json}
         | 
| 47 | 
            +
                execute(opts)
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
              def destroy_image(id, payload={})
         | 
| 51 | 
            +
                url = "#{@base_url}/api/library/operating-systems/os-types/images/#{id}"
         | 
| 52 | 
            +
                headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
         | 
| 53 | 
            +
                opts = {method: :delete, url: url, headers: headers, payload: payload.to_json}
         | 
| 54 | 
            +
                execute(opts)
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              def destroy(id, payload={})
         | 
| 58 | 
            +
                url = "#{@base_url}/api/library/operating-systems/#{id}"
         | 
| 59 | 
            +
                headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
         | 
| 60 | 
            +
                opts = {method: :delete, url: url, headers: headers, payload: payload.to_json}
         | 
| 61 | 
            +
                execute(opts)
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
            end
         | 
| @@ -2,8 +2,12 @@ require 'morpheus/api/api_client' | |
| 2 2 |  | 
| 3 3 | 
             
            class Morpheus::ProcessesInterface < Morpheus::APIClient
         | 
| 4 4 |  | 
| 5 | 
            +
              def base_path
         | 
| 6 | 
            +
                "/api/processes"
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 5 9 | 
             
              def list(params={})
         | 
| 6 | 
            -
                url =  | 
| 10 | 
            +
                url = base_path
         | 
| 7 11 | 
             
                headers = { params: params, authorization: "Bearer #{@access_token}" }
         | 
| 8 12 | 
             
                opts = {method: :get, url: url, headers: headers}
         | 
| 9 13 | 
             
                execute(opts)
         | 
| @@ -11,18 +15,26 @@ class Morpheus::ProcessesInterface < Morpheus::APIClient | |
| 11 15 |  | 
| 12 16 | 
             
              def get(id, params={})
         | 
| 13 17 | 
             
                raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
         | 
| 14 | 
            -
                url = "#{ | 
| 18 | 
            +
                url = "#{base_path}/#{CGI::escape(id.to_s)}"
         | 
| 15 19 | 
             
                headers = { params: params, authorization: "Bearer #{@access_token}" }
         | 
| 16 20 | 
             
                opts = {method: :get, url: url, headers: headers}
         | 
| 17 21 | 
             
                execute(opts)
         | 
| 18 22 | 
             
              end
         | 
| 19 23 |  | 
| 20 | 
            -
              def get_event( | 
| 21 | 
            -
                raise "#{self.class}.get() passed a blank id!" if  | 
| 22 | 
            -
                url = "#{ | 
| 24 | 
            +
              def get_event(event_id, params={})
         | 
| 25 | 
            +
                raise "#{self.class}.get() passed a blank event id!" if event_id.to_s == ''
         | 
| 26 | 
            +
                url = "#{base_path}/events/#{CGI::escape(event_id.to_s)}"
         | 
| 23 27 | 
             
                headers = { params: params, authorization: "Bearer #{@access_token}" }
         | 
| 24 28 | 
             
                opts = {method: :get, url: url, headers: headers}
         | 
| 25 29 | 
             
                execute(opts)
         | 
| 26 30 | 
             
              end
         | 
| 27 31 |  | 
| 32 | 
            +
              def retry(id, payload={}, params={}, headers={})
         | 
| 33 | 
            +
                execute(method: :post, url: "#{base_path}/#{CGI::escape(id.to_s)}/retry", params: params, payload: payload, headers: headers)
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              def cancel(id, payload={}, params={}, headers={})
         | 
| 37 | 
            +
                execute(method: :post, url: "#{base_path}/#{CGI::escape(id.to_s)}/cancel", params: params, payload: payload, headers: headers)
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
             | 
| 28 40 | 
             
            end
         | 
| @@ -44,6 +44,12 @@ class Morpheus::VirtualImagesInterface < Morpheus::APIClient | |
| 44 44 | 
             
                execute(method: :put, url: url, headers: headers, payload: payload.to_json)
         | 
| 45 45 | 
             
              end
         | 
| 46 46 |  | 
| 47 | 
            +
              def convert(id, payload)
         | 
| 48 | 
            +
                url = "#{@base_url}/api/virtual-images/#{id}/convert"
         | 
| 49 | 
            +
                headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
         | 
| 50 | 
            +
                execute(method: :post, url: url, headers: headers, payload: payload.to_json)
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 47 53 | 
             
              def destroy(id, params={})
         | 
| 48 54 | 
             
                url = "#{@base_url}/api/virtual-images/#{id}"
         | 
| 49 55 | 
             
                headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
         | 
| @@ -7,7 +7,7 @@ class Morpheus::Cli::ApplianceSettingsCommand | |
| 7 7 | 
             
              set_command_name :'appliance-settings'
         | 
| 8 8 |  | 
| 9 9 | 
             
              register_subcommands :get, :update, :toggle_maintenance, :'reindex'
         | 
| 10 | 
            -
             | 
| 10 | 
            +
             | 
| 11 11 | 
             
              set_default_subcommand :get
         | 
| 12 12 |  | 
| 13 13 | 
             
              def connect(opts)
         | 
| @@ -33,7 +33,7 @@ class Morpheus::Cli::ApplianceSettingsCommand | |
| 33 33 | 
             
                  raise_command_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args}\n#{optparse}"
         | 
| 34 34 | 
             
                  return 1
         | 
| 35 35 | 
             
                end
         | 
| 36 | 
            -
             | 
| 36 | 
            +
             | 
| 37 37 | 
             
                begin
         | 
| 38 38 | 
             
                  @appliance_settings_interface.setopts(options)
         | 
| 39 39 |  | 
| @@ -220,6 +220,25 @@ class Morpheus::Cli::ApplianceSettingsCommand | |
| 220 220 | 
             
                  opts.on("--stats-retainment-period DAYS", Integer, "Stats retainment period. The number of days stats should be available. Can be 30, 60, or 90.") do |val|
         | 
| 221 221 | 
             
                    params['statsRetainmentPeriod'] = val.to_i
         | 
| 222 222 | 
             
                  end
         | 
| 223 | 
            +
                  opts.on("--cloud-sync-interval-seconds SECONDS", Integer, "Cloud sync interval in seconds") do |val|
         | 
| 224 | 
            +
                    params['cloudSyncIntervalSeconds'] = val.to_i
         | 
| 225 | 
            +
                  end
         | 
| 226 | 
            +
                  opts.on("--cluster-sync-interval-seconds SECONDS", Integer, "Cluster sync interval in seconds") do |val|
         | 
| 227 | 
            +
                    params['clusterSyncIntervalSeconds'] = val.to_i
         | 
| 228 | 
            +
                  end
         | 
| 229 | 
            +
                  opts.on("--usage-retainment-period DAYS", Integer, "Retainment period for usage records") do |val|
         | 
| 230 | 
            +
                    params['usageRetainmentPeriod'] = val.to_i
         | 
| 231 | 
            +
                  end
         | 
| 232 | 
            +
                  opts.on("--invoice-retainment-period DAYS", Integer, "Retainment period for invoice records") do |val|
         | 
| 233 | 
            +
                    params['invoiceRetainmentPeriod'] = val.to_i
         | 
| 234 | 
            +
                  end
         | 
| 235 | 
            +
                  opts.on("--max-option-list-size NUMBER", Integer, "Max option list size (x10^3)") do |val|
         | 
| 236 | 
            +
                    params['maxOptionListSize'] = val.to_i
         | 
| 237 | 
            +
                  end
         | 
| 238 | 
            +
                  opts.on("--default-locale STRING", String, "Default locale for the appliance") do |val|
         | 
| 239 | 
            +
                    params['defaultLocale'] = val == 'null' ? nil : val
         | 
| 240 | 
            +
                  end
         | 
| 241 | 
            +
             | 
| 223 242 | 
             
                  build_common_options(opts, options, [:json, :payload, :dry_run, :quiet, :remote])
         | 
| 224 243 | 
             
                end
         | 
| 225 244 |  | 
| @@ -16,6 +16,8 @@ class Morpheus::Cli::BackupJobsCommand | |
| 16 16 | 
             
                @api_client = establish_remote_appliance_connection(opts)
         | 
| 17 17 | 
             
                @backups_interface = @api_client.backups
         | 
| 18 18 | 
             
                @backup_jobs_interface = @api_client.backup_jobs
         | 
| 19 | 
            +
                @backup_settings_interface = @api_client.backup_settings
         | 
| 20 | 
            +
                @options_interface = @api_client.options
         | 
| 19 21 | 
             
              end
         | 
| 20 22 |  | 
| 21 23 | 
             
              def handle(args)
         | 
| @@ -107,6 +109,9 @@ EOT | |
| 107 109 | 
             
                  columns = backup_job_column_definitions
         | 
| 108 110 | 
             
                  columns.delete("Provider") if backup_job['backupProvider'].nil?
         | 
| 109 111 | 
             
                  columns.delete("Repository") if backup_job['backupRepository'].nil?
         | 
| 112 | 
            +
                  columns.delete("Synthetic Full Enabled") if backup_job['syntheticFull'].nil?
         | 
| 113 | 
            +
                  columns.delete("Synthetic Full Schedule") if backup_job['syntheticFull'].nil?
         | 
| 114 | 
            +
                  columns.delete("Synthetic Full Next") if backup_job['syntheticFull'].nil?
         | 
| 110 115 | 
             
                  print_description_list(columns, backup_job)
         | 
| 111 116 | 
             
                  # print reset,"\n"
         | 
| 112 117 | 
             
                  print_h2 "Backups", options
         | 
| @@ -123,10 +128,10 @@ EOT | |
| 123 128 | 
             
              def add(args)
         | 
| 124 129 | 
             
                options = {}
         | 
| 125 130 | 
             
                params = {}
         | 
| 131 | 
            +
             | 
| 126 132 | 
             
                optparse = Morpheus::Cli::OptionParser.new do |opts|
         | 
| 127 133 | 
             
                  opts.banner = "Usage: #{prog_name} backups add-job [name]"
         | 
| 128 134 | 
             
                  build_option_type_options(opts, options, add_backup_job_option_types)
         | 
| 129 | 
            -
                  build_option_type_options(opts, options, add_backup_job_advanced_option_types)
         | 
| 130 135 | 
             
                  build_standard_add_options(opts, options)
         | 
| 131 136 | 
             
                  opts.footer = <<-EOT
         | 
| 132 137 | 
             
            Create a new backup job
         | 
| @@ -142,14 +147,23 @@ EOT | |
| 142 147 | 
             
                  payload.deep_merge!({'job' => parse_passed_options(options)})
         | 
| 143 148 | 
             
                else
         | 
| 144 149 | 
             
                  payload.deep_merge!({'job' => parse_passed_options(options)})
         | 
| 145 | 
            -
             | 
| 150 | 
            +
             | 
| 151 | 
            +
                  avail_job_types = @options_interface.options_for_source('backupJobTypes',{})['data']
         | 
| 152 | 
            +
                  if avail_job_types.empty?
         | 
| 153 | 
            +
                    raise_command_error "No available backup job types found"
         | 
| 154 | 
            +
                  else
         | 
| 155 | 
            +
                    params["jobTypeId"] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'jobTypeId', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => avail_job_types, 'defaultValue' => avail_job_types[0] ? avail_job_types[0]['name'] : nil, 'required' => true}], options[:options], @api_client)["jobTypeId"]
         | 
| 156 | 
            +
                  end
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                  v_prompt = Morpheus::Cli::OptionTypes.prompt(add_backup_job_option_types, options[:options], @api_client, options[:params])
         | 
| 146 159 | 
             
                  params.deep_merge!(v_prompt)
         | 
| 147 160 | 
             
                  if params['scheduleId'] == 'manual' || params['scheduleId'] == ''
         | 
| 148 161 | 
             
                    params['scheduleId'] = nil
         | 
| 149 162 | 
             
                  end
         | 
| 150 | 
            -
             | 
| 151 | 
            -
                   | 
| 152 | 
            -
                   | 
| 163 | 
            +
             | 
| 164 | 
            +
                  job_type_config = Morpheus::Cli::OptionTypes.prompt(add_backup_job_type_option_types("new", params["jobTypeId"], options), options[:options].deep_merge({ :context_map => { 'domain' => ''}}), @api_client, options[:params])
         | 
| 165 | 
            +
                  job_type_config.deep_compact!
         | 
| 166 | 
            +
                  params.deep_merge!(job_type_config)
         | 
| 153 167 | 
             
                  payload['job'].deep_merge!(params)
         | 
| 154 168 | 
             
                end
         | 
| 155 169 | 
             
                @backup_jobs_interface.setopts(options)
         | 
| @@ -173,7 +187,6 @@ EOT | |
| 173 187 | 
             
                optparse = Morpheus::Cli::OptionParser.new do |opts|
         | 
| 174 188 | 
             
                  opts.banner = "Usage: #{prog_name} backups update-job [job]"
         | 
| 175 189 | 
             
                  build_option_type_options(opts, options, update_backup_job_option_types)
         | 
| 176 | 
            -
                  build_option_type_options(opts, options, update_backup_job_advanced_option_types)
         | 
| 177 190 | 
             
                  build_standard_update_options(opts, options)
         | 
| 178 191 | 
             
                  opts.footer = <<-EOT
         | 
| 179 192 | 
             
            Update a backup job.
         | 
| @@ -197,7 +210,7 @@ EOT | |
| 197 210 | 
             
                    v_prompt['scheduleId'] = nil
         | 
| 198 211 | 
             
                  end
         | 
| 199 212 | 
             
                  params.deep_merge!(v_prompt)
         | 
| 200 | 
            -
                  advanced_config = Morpheus::Cli::OptionTypes.no_prompt( | 
| 213 | 
            +
                  advanced_config = Morpheus::Cli::OptionTypes.no_prompt(update_backup_job_type_option_types("new", get_object_value(backup_job, "jobType.id"), options[:params]), options[:options], @api_client, options[:params])
         | 
| 201 214 | 
             
                  advanced_config.deep_compact!
         | 
| 202 215 | 
             
                  params.deep_merge!(advanced_config)
         | 
| 203 216 | 
             
                  payload.deep_merge!({'job' => params})
         | 
| @@ -278,6 +291,9 @@ EOT | |
| 278 291 | 
             
                  "Schedule" => lambda {|it| it['schedule']['name'] rescue '' },
         | 
| 279 292 | 
             
                  "Next" => lambda {|it| format_local_dt(it['nextFire']) },
         | 
| 280 293 | 
             
                  "Retention Count" => lambda {|it| it['retentionCount'] rescue '' },
         | 
| 294 | 
            +
                  "Synthetic Full Enabled" => lambda {|it| it['syntheticFull']['enabled'] rescue ''},
         | 
| 295 | 
            +
                  "Synthetic Full Schedule" => lambda {|it| it['syntheticFull']['schedule']['name'] rescue ''},
         | 
| 296 | 
            +
                  "Synthetic Full Next" => lambda {|it|  format_local_dt(it['syntheticFull']['nextFire']) rescue ''},
         | 
| 281 297 | 
             
                  "Provider" => lambda {|it| it['backupProvider']['name'] rescue '' },
         | 
| 282 298 | 
             
                  "Repository" => lambda {|it| it['backupRepository']['name'] rescue '' },
         | 
| 283 299 | 
             
                  "Source" => lambda {|it| it['source'] },
         | 
| @@ -301,17 +317,34 @@ EOT | |
| 301 317 | 
             
              def add_backup_job_option_types
         | 
| 302 318 | 
             
                [
         | 
| 303 319 | 
             
                  {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
         | 
| 304 | 
            -
                  {'fieldName' => 'code', 'fieldLabel' => 'Code', 'type' => 'text', 'required' => false, 'displayOrder' => 2} | 
| 305 | 
            -
                  {'fieldName' => 'retentionCount', 'fieldLabel' => 'Retention Count', 'type' => 'number', 'displayOrder' => 3},
         | 
| 306 | 
            -
                  {'fieldName' => 'scheduleId', 'fieldLabel' => 'Schedule', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params| 
         | 
| 307 | 
            -
                    schedules = api_client.options.options_for_source('executeSchedules',{})['data']
         | 
| 308 | 
            -
                    [{"name" => "Manual", "value" => "manual"}] + schedules
         | 
| 309 | 
            -
                  }, 'displayOrder' => 4},
         | 
| 320 | 
            +
                  {'fieldName' => 'code', 'fieldLabel' => 'Code', 'type' => 'text', 'required' => false, 'displayOrder' => 2}
         | 
| 310 321 | 
             
                ]
         | 
| 311 322 | 
             
              end
         | 
| 312 323 |  | 
| 313 | 
            -
              def  | 
| 314 | 
            -
                []
         | 
| 324 | 
            +
              def add_backup_job_type_option_types(job_action, backup_job_type, options)
         | 
| 325 | 
            +
                backup_settings = @backup_settings_interface.get(options)["backupSettings"] || {}
         | 
| 326 | 
            +
                # get job defaults
         | 
| 327 | 
            +
                default_retention_count = options&.dig('backupJob', 'retentionCount') || get_object_value(backup_settings, "retentionCount")
         | 
| 328 | 
            +
                default_schedule = options&.dig('backupJob', 'scheduleTypeId') || get_object_value(backup_settings, "defaultSchedule.id")
         | 
| 329 | 
            +
                default_synthetic_enabled = options&.dig('backupJob', 'syntheticFullEnabled') || get_object_value(backup_settings, "defaultSyntheticFullBackupsEnabled")
         | 
| 330 | 
            +
                default_synthetic_schedule = options&.dig('backupJob', 'syntheticFullSchedule') || get_object_value(backup_settings, "defaultSyntheticFullBackupSchedule.id")
         | 
| 331 | 
            +
                job_input_params = {jobAction: job_action, id: backup_job_type}
         | 
| 332 | 
            +
                job_inputs = @options_interface.options_for_source('backupJobOptionTypes', job_input_params)['data']['optionTypes']
         | 
| 333 | 
            +
                job_inputs.each do | input |
         | 
| 334 | 
            +
                  # set input defaults from global settings
         | 
| 335 | 
            +
                  input['defaultValue'] = case input['fieldName']
         | 
| 336 | 
            +
                                          when "retentionCount"
         | 
| 337 | 
            +
                                            default_retention_count
         | 
| 338 | 
            +
                                          when "scheduleTypeId"
         | 
| 339 | 
            +
                                            default_schedule
         | 
| 340 | 
            +
                                          when "syntheticFullEnabled"
         | 
| 341 | 
            +
                                            default_synthetic_enabled
         | 
| 342 | 
            +
                                          when "syntheticFullSchedule"
         | 
| 343 | 
            +
                                            default_synthetic_schedule
         | 
| 344 | 
            +
                                          end
         | 
| 345 | 
            +
                end
         | 
| 346 | 
            +
             | 
| 347 | 
            +
                job_inputs
         | 
| 315 348 | 
             
              end
         | 
| 316 349 |  | 
| 317 350 | 
             
              def update_backup_job_option_types
         | 
| @@ -322,8 +355,8 @@ EOT | |
| 322 355 | 
             
                }
         | 
| 323 356 | 
             
              end
         | 
| 324 357 |  | 
| 325 | 
            -
              def  | 
| 326 | 
            -
                 | 
| 358 | 
            +
              def update_backup_job_type_option_types(job_action, backup_job_type, options)
         | 
| 359 | 
            +
                add_backup_job_type_option_types(job_action, backup_job_type, options).collect {|it|
         | 
| 327 360 | 
             
                  it.delete('required')
         | 
| 328 361 | 
             
                  it.delete('defaultValue')
         | 
| 329 362 | 
             
                  it
         | 
| @@ -22,6 +22,7 @@ class Morpheus::Cli::BackupsCommand | |
| 22 22 | 
             
                @backup_restores_interface = @api_client.backup_restores
         | 
| 23 23 | 
             
                @instances_interface = @api_client.instances
         | 
| 24 24 | 
             
                @servers_interface = @api_client.servers
         | 
| 25 | 
            +
                @options_interface = @api_client.options
         | 
| 25 26 | 
             
              end
         | 
| 26 27 |  | 
| 27 28 | 
             
              def handle(args)
         | 
| @@ -188,15 +189,6 @@ EOT | |
| 188 189 | 
             
                    params['jobAction'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'jobAction', 'fieldLabel' => 'Backup Job Type', 'type' => 'select', 'optionSource' => 'backupJobActions', 'required' => true, 'defaultValue' => 'new'}], options[:options], @api_client)['jobAction']
         | 
| 189 190 | 
             
                    if params['jobAction'] == 'new'
         | 
| 190 191 | 
             
                      params['jobName'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'jobName', 'fieldLabel' => 'Job Name', 'type' => 'text', 'required' => false, 'defaultValue' => nil}], options[:options], @api_client)['jobName']
         | 
| 191 | 
            -
                      default_retention_count = (create_results['backup'] && create_results['backup']['retentionCount']) ? create_results['backup']['retentionCount'] : ((create_results['backupSettings'] && create_results['backupSettings']['retentionCount']) ? create_results['backupSettings']['retentionCount'] : nil)
         | 
| 192 | 
            -
                      params['retentionCount'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'retentionCount', 'fieldLabel' => 'Retention Count', 'type' => 'number', 'required' => false, 'defaultValue' => default_retention_count}], options[:options], @api_client)['retentionCount']
         | 
| 193 | 
            -
                      params['jobSchedule'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'jobSchedule', 'fieldLabel' => 'Backup Schedule', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params| 
         | 
| 194 | 
            -
                        schedules = api_client.options.options_for_source('executeSchedules',{})['data']
         | 
| 195 | 
            -
                        [{"name" => "Manual", "value" => "manual"}] + schedules
         | 
| 196 | 
            -
                      }, 'required' => false}], options[:options], @api_client)['jobSchedule']
         | 
| 197 | 
            -
                      if params['jobSchedule'] == 'manual' || params['jobSchedule'] == ''
         | 
| 198 | 
            -
                        params.delete('jobSchedule')
         | 
| 199 | 
            -
                      end
         | 
| 200 192 | 
             
                    elsif params['jobAction'] == 'clone'
         | 
| 201 193 | 
             
                      params['jobId'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'jobId', 'fieldLabel' => 'Backup Job', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params| 
         | 
| 202 194 | 
             
                        @backup_jobs_interface.list({max:10000})['jobs'].collect {|backup_job|
         | 
| @@ -211,9 +203,20 @@ EOT | |
| 211 203 | 
             
                        }
         | 
| 212 204 | 
             
                      }, 'required' => true}], options[:options], @api_client)['jobId']
         | 
| 213 205 | 
             
                    end
         | 
| 206 | 
            +
             | 
| 207 | 
            +
                    # new job option types
         | 
| 208 | 
            +
                    job_inputs = build_backup_job_option_types(params['jobAction'], params['backupType'], create_results)
         | 
| 209 | 
            +
                    job_opt_parser = Morpheus::Cli::OptionParser.new do |opts|
         | 
| 210 | 
            +
                      build_option_type_options(opts, options, job_inputs)
         | 
| 211 | 
            +
                    end
         | 
| 212 | 
            +
                    job_opt_parser.parse!(args)
         | 
| 213 | 
            +
                    v_prompt = Morpheus::Cli::OptionTypes.prompt(job_inputs, options[:options].deep_merge({:context_map => {'domain' => 'backupJob'}}), @api_client)
         | 
| 214 | 
            +
                    v_prompt.deep_compact!.booleanize! # remove empty values and convert checkbox "on" and "off" to true and false
         | 
| 215 | 
            +
                    params.deep_merge!(v_prompt)
         | 
| 214 216 | 
             
                  end
         | 
| 215 217 | 
             
                  payload['backup'].deep_merge!(params)
         | 
| 216 218 | 
             
                end
         | 
| 219 | 
            +
                #options[:payload] = payload
         | 
| 217 220 | 
             
                execute_api(@backups_interface, :create, [], options, 'backup') do |json_response|
         | 
| 218 221 | 
             
                  backup = json_response['backup']
         | 
| 219 222 | 
             
                  print_green_success "Added backup #{backup['name']}"
         | 
| @@ -482,6 +485,30 @@ EOT | |
| 482 485 | 
             
              private
         | 
| 483 486 |  | 
| 484 487 | 
             
              ## Backups
         | 
| 488 | 
            +
              def build_backup_job_option_types(job_action, backup_type, config_opts)
         | 
| 489 | 
            +
                # get job defaults
         | 
| 490 | 
            +
                default_retention_count = config_opts.dig('backup', 'retentionCount') || config_opts.dig('backupSettings', 'retentionCount')
         | 
| 491 | 
            +
                default_schedule = config_opts.dig('backup', 'scheduleTypeId') || config_opts.dig('backup', 'backupJob', 'scheduleTypeId') || config_opts.dig('backupSettings', 'defaultBackupSchedule')
         | 
| 492 | 
            +
                default_synthetic_enabled = config_opts.dig('backup', 'backupJob', 'syntheticFullEnabled') || config_opts.dig('backupSettings', 'defaultSyntheticFullBackupsEnabled')
         | 
| 493 | 
            +
                default_synthetic_schedule = config_opts.dig('backup', 'backupJob', 'syntheticFullSchedule') || config_opts.dig('backupSettings', 'defaultSyntheticFullBackupSchedule')
         | 
| 494 | 
            +
                job_input_params = {jobAction: job_action, backupTypeCode: backup_type}
         | 
| 495 | 
            +
                job_inputs = @options_interface.options_for_source('backupJobOptionTypes', job_input_params)['data']['optionTypes']
         | 
| 496 | 
            +
                job_inputs.each do | input |
         | 
| 497 | 
            +
                  # set input defaults from global settings
         | 
| 498 | 
            +
                  input['defaultValue'] = case input['fieldName']
         | 
| 499 | 
            +
                  when "retentionCount"
         | 
| 500 | 
            +
                    default_retention_count
         | 
| 501 | 
            +
                  when "scheduleTypeId"
         | 
| 502 | 
            +
                    default_schedule
         | 
| 503 | 
            +
                  when "syntheticFullEnabled"
         | 
| 504 | 
            +
                    default_synthetic_enabled
         | 
| 505 | 
            +
                  when "syntheticFullSchedule"
         | 
| 506 | 
            +
                    default_synthetic_schedule
         | 
| 507 | 
            +
                  end
         | 
| 508 | 
            +
                end
         | 
| 509 | 
            +
             | 
| 510 | 
            +
                job_inputs
         | 
| 511 | 
            +
              end
         | 
| 485 512 |  | 
| 486 513 | 
             
              def backup_list_column_definitions()
         | 
| 487 514 | 
             
                {
         | 
| @@ -1183,7 +1183,7 @@ EOT | |
| 1183 1183 |  | 
| 1184 1184 | 
             
                # Details (zoneType.optionTypes)
         | 
| 1185 1185 |  | 
| 1186 | 
            -
                if cloud_type && cloud_type['optionTypes']
         | 
| 1186 | 
            +
                if cloud_type && cloud_type['optionTypes'] && cloud_type['code'] != 'standard'
         | 
| 1187 1187 | 
             
                  if !cloud_type['optionTypes'].find {|opt| opt['type'] == 'credential'}
         | 
| 1188 1188 | 
             
                    tmp_option_types << {'fieldName' => 'type', 'fieldLabel' => 'Credentials', 'type' => 'credential', 'optionSource' => 'credentials', 'required' => true, 'defaultValue' => 'local', 'config' => {'credentialTypes' => get_cloud_type_credential_types(cloud_type['code'])}, 'displayOrder' => 7}
         | 
| 1189 1189 | 
             
                    cloud_type['optionTypes'].select {|opt| ['username', 'password', 'serviceUsername', 'servicePassword'].include?(opt['fieldName'])}.each {|opt| opt['localCredential'] = true}
         |