class Morpheus::Cli::Clouds

Public Class Methods

new() click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 18
def initialize()
  # @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
end

Public Instance Methods

_get(id, params, options={}) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 156
def _get(id, params, options={})
  cloud = nil
  if id.to_s !~ /\A\d{1,}\Z/
    cloud = find_cloud_by_name_or_id(id)
    id = cloud['id']
  end
  @clouds_interface.setopts(options)
  if options[:dry_run]
    print_dry_run @clouds_interface.dry.get(id.to_i, params)
    return
  end
  json_response = @clouds_interface.get(id, params)
  render_response(json_response, options, 'zone') do
    cloud = json_response['zone']
    cloud_stats = cloud['stats']
    # serverCounts moved to zone.stats.serverCounts
    server_counts = nil
    if cloud_stats
      server_counts = cloud_stats['serverCounts']
    else
      server_counts = json_response['serverCounts'] # legacy
    end
    #cloud_type = cloud_type_for_id(cloud['zoneTypeId'])
    print_h1 "Cloud Details"
    print cyan
    description_cols = {
      "ID" => 'id',
      "Name" => 'name',
      # "Type" => lambda {|it| cloud_type ? cloud_type['name'] : '' },
      "Type" => lambda {|it| it['zoneType'] ? it['zoneType']['name'] : '' },
      "Code" => 'code',
      "Location" => 'location',
      "Labels" => lambda {|it| format_list(it['labels'], '') rescue '' },
      "Region Code" => 'regionCode',
      "Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
      "Groups" => lambda {|it| it['groups'].collect {|g| g.instance_of?(Hash) ? g['name'] : g.to_s }.join(', ') },
      #"Owner" => lambda {|it| it['owner'].instance_of?(Hash) ? it['owner']['name'] : it['ownerId'] },
      "Tenant" => lambda {|it| it['account'].instance_of?(Hash) ? it['account']['name'] : it['accountId'] },
      "Enabled" => lambda {|it| format_boolean(it['enabled']) },
      "Last Sync" => lambda {|it| format_local_dt(it['lastSync']) },
      "Sync Duration" => lambda {|it| format_duration_milliseconds(it['lastSyncDuration']).to_s },
      "Status" => lambda {|it| format_cloud_status(it) },
    }
    print_description_list(description_cols, cloud)

    print_h2 "Cloud Servers"
    print cyan
    if server_counts
      print "Container Hosts: #{server_counts['containerHost']}".center(20)
      print "Hypervisors: #{server_counts['hypervisor']}".center(20)
      print "Bare Metal: #{server_counts['baremetal']}".center(20)
      print "Virtual Machines: #{server_counts['vm']}".center(20)
      print "Unmanaged: #{server_counts['unmanaged']}".center(20)
      print "\n"
    end
    print reset,"\n"
  end
  return 0, nil
end
add(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 216
def add(args)
  options = {}
  params = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[name] --group GROUP --type TYPE")
    opts.on( '-g', '--group GROUP', "Group Name" ) do |val|
      params[:group] = val
    end
    opts.on( '-t', '--type TYPE', "Cloud Type" ) do |val|
      params[:zone_type] = val
    end
    opts.on( '-d', '--description DESCRIPTION', "Description (optional)" ) do |desc|
      params[:description] = desc
    end
    opts.on( '--certificate-provider CODE', String, "Certificate Provider. Default is 'internal'" ) do |val|
      params[:certificate_provider] = val
    end
    opts.on('--costing-mode VALUE', String, "Costing Mode can be off,costing,full, Default is off." ) do |val|
      options[:options]['costingMode'] = val
    end
    opts.on('--credential VALUE', String, "Credential ID or \"local\"" ) do |val|
      options[:options]['credential'] = val
    end
    opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
      options[:options]['labels'] = parse_labels(val)
    end

    build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
  end
  optparse.parse!(args)
  # if args.count < 1
  #   puts optparse
  #   exit 1
  # end
  connect(options)

  begin
    payload = nil
    if options[:payload]
      payload = options[:payload]
      payload.deep_merge!({'zone' => parse_passed_options(options)})
    else
      cloud_payload = {name: args[0], description: params[:description]}
      cloud_payload.deep_merge!(parse_passed_options(options))
      # use active group by default
      params[:group] ||= @active_group_id

      # Group
      group_id = nil
      group = params[:group] ? find_group_by_name_or_id_for_provisioning(params[:group]) : nil
      if group
        group_id = group["id"]
      else
        # print_red_alert "Group not found or specified!"
        # exit 1
        #groups_dropdown = @groups_interface.list({})['groups'].collect {|it| {'name' => it["name"], 'value' => it["id"]} }
        group_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'group', 'type' => 'select', 'fieldLabel' => 'Group', 'optionSource' => 'groups', 'required' => true, 'description' => 'Select Group.'}],options[:options],@api_client,{})
        group_id = group_prompt['group']
      end
      cloud_payload['groupId'] = group_id
      # todo: pass groups as an array instead

      # Cloud Name
      if args[0]
        cloud_payload[:name] = args[0]
        options[:options]['name'] = args[0] # to skip prompt
      elsif !options[:no_prompt]
        # name_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true}], options[:options])
        # cloud_payload[:name] = name_prompt['name']
      end

      # Cloud Type
      cloud_type = nil
      if params[:zone_type]
        cloud_type = cloud_type_for_name(params[:zone_type])
      elsif !options[:no_prompt]
        # print_red_alert "Cloud Type not found or specified!"
        # exit 1
        cloud_types_dropdown = cloud_types_for_dropdown
        cloud_type_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'type' => 'select', 'fieldLabel' => 'Cloud Type', 'selectOptions' => cloud_types_dropdown, 'required' => true, 'description' => 'Select Cloud Type.'}],options[:options],@api_client,{})
        cloud_type_code = cloud_type_prompt['type']
        cloud_type = cloud_type_for_name(cloud_type_code) # this does work
      end
      if !cloud_type
        print_red_alert "A cloud type is required."
        exit 1
      end
      cloud_payload[:zoneType] = {code: cloud_type['code']}

      cloud_payload['config'] ||= {}
      if params[:certificate_provider]
        cloud_payload['config']['certificateProvider'] = params[:certificate_provider]
      else
        cloud_payload['config']['certificateProvider'] = 'internal'
      end

      all_option_types = add_cloud_option_types(cloud_type)

      params = Morpheus::Cli::OptionTypes.prompt(all_option_types, options[:options], @api_client, {zoneTypeId: cloud_type['id']})
      # some optionTypes have fieldContext='zone', so move those to the root level of the zone payload
      if params['zone'].is_a?(Hash)
        cloud_payload.deep_merge!(params.delete('zone'))
      end
      cloud_payload.deep_merge!(params)
      payload = {zone: cloud_payload}
    end
    @clouds_interface.setopts(options)
    if options[:dry_run]
      print_dry_run @clouds_interface.dry.create(payload)
      return
    end
    json_response = @clouds_interface.create(payload)
    cloud = json_response['zone']
    if options[:json]
      puts as_json(json_response, options)
    else
      get([cloud['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
    end
    return 0
  rescue RestClient::Exception => e
    print_rest_exception(e, options)
    exit 1
  end
end
apply_security_groups(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 705
def apply_security_groups(args)
  options = {}
  clear_or_secgroups_specified = false
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[name] [-s] [--clear]")
    opts.on( '-c', '--clear', "Clear all security groups" ) do
      options[:securityGroupIds] = []
      clear_or_secgroups_specified = true
    end
    opts.on( '-s', '--secgroups SECGROUPS', "Apply the specified comma separated security group ids" ) do |secgroups|
      options[:securityGroupIds] = secgroups.split(",")
      clear_or_secgroups_specified = true
    end
    build_common_options(opts, options, [:json, :dry_run, :remote])
  end
  optparse.parse!(args)
  if !clear_or_secgroups_specified
    puts optparse
    exit
  end
  connect(options)
  begin
    cloud = find_cloud_by_name_or_id(args[0])
    @clouds_interface.setopts(options)
    if options[:dry_run]
      print_dry_run @clouds_interface.dry.apply_security_groups(cloud['id'])
      return
    end
    json_response = @clouds_interface.apply_security_groups(cloud['id'], options)
    if options[:json]
      print JSON.pretty_generate(json_response)
      print "\n"
      return
    end
    security_groups([args[0]])
  rescue RestClient::Exception => e
    print_rest_exception(e, options)
    exit 1
  end
end
connect(opts) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 22
def connect(opts)
  @api_client = establish_remote_appliance_connection(opts)
  @clouds_interface = @api_client.clouds
  @groups_interface = @api_client.groups
  @active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
end
count(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 107
def count(args)
  options = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[options]")
    build_common_options(opts, options, [:query, :remote, :dry_run])
    opts.footer = "Get the number of clouds."
  end
  optparse.parse!(args)
  connect(options)
  begin
    params = {}
    params.merge!(parse_list_options(options))
    @clouds_interface.setopts(options)
    if options[:dry_run]
      print_dry_run @clouds_interface.dry.list(params)
      return
    end
    json_response = @clouds_interface.list(params)
    # print number only
    if json_response['meta'] && json_response['meta']['total']
      print cyan, json_response['meta']['total'], reset, "\n"
    else
      print yellow, "unknown", reset, "\n"
    end
  rescue RestClient::Exception => e
    print_rest_exception(e, options)
    exit 1
  end
end
firewall_disable(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 592
def firewall_disable(args)
  options = {}
  clear_or_secgroups_specified = false
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[name]")
    build_common_options(opts, options, [:json, :dry_run, :remote])
  end
  optparse.parse!(args)
  if args.count < 1
    puts optparse
    return
  end
  connect(options)
  begin
    cloud = find_cloud_by_name_or_id(args[0])
    @clouds_interface.setopts(options)
    if options[:dry_run]
      print_dry_run @clouds_interface.dry.firewall_disable(cloud['id'])
      return
    end
    json_response = @clouds_interface.firewall_disable(cloud['id'])
    if options[:json]
      print JSON.pretty_generate(json_response)
      print "\n"
      return
    end
    security_groups([args[0]])
  rescue RestClient::Exception => e
    print_rest_exception(e, options)
    exit 1
  end
end
firewall_enable(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 625
def firewall_enable(args)
  options = {}
  clear_or_secgroups_specified = false
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[name]")
    build_common_options(opts, options, [:json, :dry_run, :remote])
  end
  optparse.parse!(args)
  if args.count < 1
    puts optparse
    return
  end
  connect(options)
  begin
    cloud = find_cloud_by_name_or_id(args[0])
    @clouds_interface.setopts(options)
    if options[:dry_run]
      print_dry_run @clouds_interface.dry.firewall_enable(cloud['id'])
      return
    end
    json_response = @clouds_interface.firewall_enable(cloud['id'])
    if options[:json]
      print JSON.pretty_generate(json_response)
      print "\n"
      return
    end
    security_groups([args[0]])
  rescue RestClient::Exception => e
    print_rest_exception(e, options)
    exit 1
  end
end
get(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 137
def get(args)
  options = {}
  params = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[name]")
    build_standard_list_options(opts, options)
    opts.footer = "Get details about a cloud.\n" +
                  "[name] is required. This is the name or id of a cloud."
  end
  optparse.parse!(args)
  verify_args!(args:args, optparse:optparse, min:1)
  connect(options)
  params.merge!(parse_query_options(options))
  id_list = parse_id_list(args)
  return run_command_for_each_arg(id_list) do |arg|
    _get(arg, params, options)
  end
end
handle(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 29
def handle(args)
  handle_subcommand(args)
end
list(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 33
def list(args)
  options={}
  params = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage()
    opts.on( '-g', '--group GROUP', "Group Name" ) do |group|
      options[:group] = group
    end
    opts.on( '-t', '--type TYPE', "Cloud Type" ) do |val|
      options[:zone_type] = val
    end
    opts.on('-l', '--labels LABEL', String, "Filter by labels, can match any of the values") do |val|
      add_query_parameter(params, 'labels', parse_labels(val))
    end
    opts.on('--all-labels LABEL', String, "Filter by labels, must match all of the values") do |val|
      add_query_parameter(params, 'allLabels', parse_labels(val))
    end
    build_standard_list_options(opts, options)
    opts.footer = "List clouds."
  end
  optparse.parse!(args)
  connect(options)
  # verify_args!(args:args, optparse:optparse, count:0)
  if args.count > 0
    options[:phrase] = args.join(" ")
  end
  begin
    if options[:zone_type]
      cloud_type = cloud_type_for_name(options[:zone_type])
      params[:type] = cloud_type['code']
    end
    if !options[:group].nil?
      group = find_group_by_name(options[:group])
      if !group.nil?
        params['groupId'] = group['id']
      end
    end

    params.merge!(parse_list_options(options))
    @clouds_interface.setopts(options)
    if options[:dry_run]
      print_dry_run @clouds_interface.dry.list(params)
      return 0
    end

    json_response = @clouds_interface.list(params)
    render_response(json_response, options, 'zones') do
      clouds = json_response['zones']
      title = "Morpheus Clouds"
      subtitles = []
      if group
        subtitles << "Group: #{group['name']}".strip
      end
      if cloud_type
        subtitles << "Type: #{cloud_type['name']}".strip
      end
      subtitles += parse_list_subtitles(options)
      print_h1 title, subtitles
      if clouds.empty?
        print cyan,"No clouds found.",reset,"\n"
      else          
        columns = cloud_list_column_definitions(options).upcase_keys!
        print as_pretty_table(clouds, columns, options)
        print_results_pagination(json_response)
      end
      print reset,"\n"
    end
    return 0, nil
  rescue RestClient::Exception => e
    print_rest_exception(e, options)
    exit 1
  end
end
refresh(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 484
def refresh(args)
  options = {}
  query_params = {}
  params = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[cloud] [options]")
    opts.on( '-m', '--mode [daily|costing]', "Refresh Mode. Use this to run the daily or costing jobs instead of the default hourly refresh." ) do |val|
      query_params[:mode] = val
    end
    opts.on( '--rebuild [on|off]', "Rebuild invoices for period. Only applies to mode=costing." ) do |val|
      query_params[:rebuild] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
    end
    opts.on( '--period PERIOD', "Period in the format YYYYMM to process invoices for. Default is the current period. Only applies to mode=costing." ) do |val|
      query_params[:period] = val.to_s
    end
    opts.on( '-f', '--force', "Force refresh. Useful if the cloud is disabled." ) do
      query_params[:force] = 'true'
    end
    build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
    opts.footer = "Refresh a cloud." + "\n" +
                  "[cloud] is required. This is the name or id of a cloud."
  end
  optparse.parse!(args)
  if args.count != 1
    raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
  end
  connect(options)
  begin
    cloud = find_cloud_by_name_or_id(args[0])
    return 1 if cloud.nil?
    passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
    payload = nil
    if options[:payload]
      payload = options[:payload]
      payload.deep_merge!(passed_options) unless passed_options.empty?
    else
      payload = {}
      payload.deep_merge!(passed_options) unless passed_options.empty?
    end
    @clouds_interface.setopts(options)
    if options[:dry_run]
      print_dry_run @clouds_interface.dry.refresh(cloud['id'], query_params, payload)
      return
    end
    json_response = @clouds_interface.refresh(cloud['id'], query_params, payload)
    if options[:json]
      puts as_json(json_response, options)
    else
      print_green_success "Refreshing cloud #{cloud['name']}..."
      #get([cloud['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
    end
    return 0
  rescue RestClient::Exception => e
    print_rest_exception(e, options)
    exit 1
  end
end
remove(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 440
def remove(args)
  options = {}
  query_params = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[name]")
    opts.on('--remove-resources [on|off]', ['on','off'], "Remove Associated Resources. Default is off.") do |val|
      query_params[:removeResources] = val.nil? ? 'on' : val
    end
    opts.on( '-f', '--force', "Force Remove" ) do
      query_params[:force] = 'on'
    end
    build_common_options(opts, options, [:auto_confirm, :quiet, :json, :dry_run, :remote])
  end
  optparse.parse!(args)
  if args.count < 1
    puts optparse
    return
  end
  connect(options)
  begin
    cloud = find_cloud_by_name_or_id(args[0])
    unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the cloud #{cloud['name']}?")
      exit
    end
    @clouds_interface.setopts(options)
    if options[:dry_run]
      print_dry_run @clouds_interface.dry.destroy(cloud['id'], query_params)
      return 0
    end
    json_response = @clouds_interface.destroy(cloud['id'], query_params)
    if options[:json]
      print JSON.pretty_generate(json_response)
      print "\n"
    elsif !options[:quiet]
      print_green_success "Removed cloud #{cloud['name']}"
      #list([])
    end
    return 0
  rescue RestClient::Exception => e
    print_rest_exception(e, options)
    exit 1
  end
end
security_groups(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 658
def security_groups(args)
  options = {}
  clear_or_secgroups_specified = false
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[name]")
    build_common_options(opts, options, [:json, :dry_run, :remote])
  end
  optparse.parse!(args)
  if args.count < 1
    puts optparse
    return
  end
  connect(options)
  begin
    cloud = find_cloud_by_name_or_id(args[0])
    zone_id = cloud['id']
    @clouds_interface.setopts(options)
    if options[:dry_run]
      print_dry_run @clouds_interface.dry.security_groups(zone_id)
      return
    end
    json_response = @clouds_interface.security_groups(zone_id)
    if options[:json]
      print JSON.pretty_generate(json_response)
      print "\n"
      return
    end
    securityGroups = json_response['securityGroups']
    print_h1 "Morpheus Security Groups for Cloud: #{cloud['name']}"
    print cyan
    print_description_list({"Firewall Enabled" => lambda {|it| format_boolean it['firewallEnabled'] } }, json_response)
    if securityGroups.empty?
      print yellow,"\n","No security groups currently applied.",reset,"\n"
    else
      print "\n"
      securityGroups.each do |securityGroup|
        print cyan, "=  #{securityGroup['id']} (#{securityGroup['name']}) - (#{securityGroup['description']})\n"
      end
    end
    print reset,"\n"

  rescue RestClient::Exception => e
    print_rest_exception(e, options)
    exit 1
  end
end
sync(args) click to toggle source

not exposed yet, refresh should be all that’s needed.

# File lib/morpheus/cli/commands/clouds.rb, line 543
def sync(args)
  options = {}
  query_params = {}
  params = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[name] [options]")
    opts.on( '-f', '--force', "Force Delete" ) do
      query_params[:force] = 'true'
    end
    build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
    opts.footer = "Sync a cloud." + "\n" +
                  "[cloud] is required. This is the name or id of a cloud."
  end
  optparse.parse!(args)
  if args.count != 1
    raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args}\n#{optparse}"
  end
  connect(options)
  begin
    cloud = find_cloud_by_name_or_id(args[0])
    return 1 if cloud.nil?
    passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
    payload = nil
    if options[:payload]
      payload = options[:payload]
      payload.deep_merge!(passed_options) unless passed_options.empty?
    else
      payload = {}
      payload.deep_merge!(passed_options) unless passed_options.empty?
    end
    @clouds_interface.setopts(options)
    if options[:dry_run]
      print_dry_run @clouds_interface.dry.sync(cloud['id'], query_params, payload)
      return
    end
    json_response = @clouds_interface.sync(cloud['id'], query_params, payload)
    if options[:json]
      puts as_json(json_response, options)
    else
      print_green_success "Syncing cloud #{cloud['name']}..."
      #get([cloud['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
    end
    return 0
  rescue RestClient::Exception => e
    print_rest_exception(e, options)
    exit 1
  end
end
type(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 793
  def type(args)
    options={}
    params = {}
    optparse = Morpheus::Cli::OptionParser.new do |opts|
      opts.banner = subcommand_usage("[type]")
      build_standard_get_options(opts, options)
            opts.footer = <<-EOT
Get details about a cloud type.
[type] is required. This is the name or id of cloud type.
EOT
    end
    optparse.parse!(args)
    verify_args!(args:args, optparse:optparse, count:1)
    connect(options)
    # construct request
    params.merge!(parse_query_options(options))
    id = args[0]
    cloud_type = nil
    if id.to_s !~ /\A\d{1,}\Z/
      cloud_type = cloud_type_for_name_or_id(id)
      if cloud_type.nil?
        raise_command_error "cloud type not found for name or code '#{id}'"
      end
      id = cloud_type['id']
    end
    # execute request
    @clouds_interface.setopts(options)
    if options[:dry_run]
      print_dry_run @clouds_interface.dry.cloud_type(id.to_i)
      return 0
    end
    json_response = @clouds_interface.cloud_type(id.to_i)
    # render response
    render_response(json_response, options, 'zoneType') do
      cloud_type = json_response['zoneType']
      print_h1 "Cloud Type", [], options
      print cyan
      #columns = rest_type_column_definitions(options)
      columns = {
        "ID" => 'id',
        "Name" => 'name',
        "Code" => 'code',
        "Enabled" => lambda {|it| format_boolean it['enabled'] },
        "Provision" => lambda {|it| format_boolean it['provision'] },
        "Auto Capacity" => lambda {|it| format_boolean it['autoCapacity'] },
        # "Migration Target" => lambda {|it| format_boolean it['migrationTarget'] },
        "Datastores" => lambda {|it| format_boolean it['hasDatastores'] },
        "Networks" => lambda {|it| format_boolean it['hasNetworks'] },
        "Resource Pools" => lambda {|it| format_boolean it['hasResourcePools'] },
        "Security Groups" => lambda {|it| format_boolean it['hasSecurityGroups'] },
        "Containers" => lambda {|it| format_boolean it['hasContainers'] },
        "Bare Metal" => lambda {|it| format_boolean it['hasBareMetal'] },
        "Services" => lambda {|it| format_boolean it['hasServices'] },
        "Functions" => lambda {|it| format_boolean it['hasFunctions'] },
        "Jobs" => lambda {|it| format_boolean it['hasJobs'] },
        "Discovery" => lambda {|it| format_boolean it['hasDiscovery'] },
        "Cloud Init" => lambda {|it| format_boolean it['hasCloudInit'] },
        "Folders" => lambda {|it| format_boolean it['hasFolders'] },
        "Floating Ips" => lambda {|it| format_boolean it['hasFloatingIps'] },
        # "Marketplace" => lambda {|it| format_boolean it['hasMarketplace'] },
        "Public Cloud" => lambda {|it| format_boolean(it['cloud'] == 'public') },
      }
      print_description_list(columns, cloud_type, options)
      # Option Types
      option_types = cloud_type['optionTypes']
      if option_types && option_types.size > 0
        print_h2 "Option Types", options
        print format_option_types_table(option_types, options, "zone")
      end
      print reset,"\n"
    end
  end
types(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 746
  def types(args)
    options={}
    params = {}
    optparse = Morpheus::Cli::OptionParser.new do |opts|
      opts.banner = subcommand_usage("[search]")
      build_standard_list_options(opts, options)
      opts.footer = <<-EOT
List cloud types.
EOT
    end
    optparse.parse!(args)
    connect(options)

    if args.count > 0
      options[:phrase] = args.join(" ")
    end
    params.merge!(parse_list_options(options))
    @clouds_interface.setopts(options)
    if options[:dry_run]
      print_dry_run @clouds_interface.dry.cloud_types({})
      return 0
    end
    json_response = @clouds_interface.cloud_types(params)
      
    render_response(json_response, options, 'zoneTypes') do
      cloud_types = json_response['zoneTypes']
      subtitles = []        
      subtitles += parse_list_subtitles(options)
      print_h1 "Morpheus Cloud Types", subtitles, options
      if cloud_types.empty?
        print cyan,"No cloud types found.",reset,"\n"
      else
        print cyan
        cloud_types = cloud_types.select {|it| it['enabled'] }
        rows = cloud_types.collect do |cloud_type|
          {id: cloud_type['id'], name: cloud_type['name'], code: cloud_type['code']}
        end
        #print "\n"
        columns = [:id, :name, :code]
        columns = options[:include_fields] if options[:include_fields]
        print as_pretty_table(rows, columns, options)
        print_results_pagination(json_response)
        print reset,"\n"
      end
    end
  end
update(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 341
def update(args)
  options = {}
  params = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[name] [options]")
    # opts.on( '-g', '--group GROUP', "Group Name" ) do |val|
    #   params[:group] = val
    # end
    # opts.on( '-t', '--type TYPE', "Cloud Type" ) do |val|
    #   params[:zone_type] = val
    # end
    # opts.on( '-d', '--description DESCRIPTION', "Description (optional)" ) do |desc|
    #   params[:description] = desc
    # end
    opts.on('-l', '--labels [LIST]', String, "Labels") do |val|
      options[:options]['labels'] = parse_labels(val)
    end
    opts.on('--costing-mode VALUE', String, "Costing Mode can be off, costing, or full. Default is off." ) do |val|
      options[:options]['costingMode'] = val
    end
    opts.on('--credential VALUE', String, "Credential ID or \"local\"" ) do |val|
      options[:options]['credential'] = val
    end
    opts.on('--default-cloud-logos', "Reset logos to default cloud logos, removing any custom logo and dark logo" ) do
      options[:options]['defaultCloudLogos'] = true
    end
    
    build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
  end
  optparse.parse!(args)
  if args.count < 1
    puts optparse
    exit 1
  end
  connect(options)
  begin
    cloud = find_cloud_by_name_or_id(args[0])
    return 1 if cloud.nil?
    payload = nil
    if options[:payload]
      payload = options[:payload]
      # support -O OPTION switch on top of --payload
      if options[:options]
        payload['zone'] ||= {}
        payload['zone'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) })
      end
    else
      cloud_type = cloud_type_for_id(cloud['zoneTypeId'])
      cloud_payload = {}
      all_option_types = update_cloud_option_types(cloud_type)
      #params = Morpheus::Cli::OptionTypes.no_prompt(all_option_types, options[:options], @api_client, {zoneId: cloud['id'], zoneTypeId: cloud_type['id']})
      params = options[:options] || {}

      # Credentials (ideally only if value passed in and name can be parsed)
      if options[:options]['credential']
        credential_code = "credential"
        credential_option_type = {'code' => credential_code, 'fieldName' => credential_code, 'fieldLabel' => 'Credentials', 'type' => 'select', 'optionSource' => 'credentials', 'description' => 'Enter an existing credential ID or choose "local"', 'defaultValue' => "local", 'required' => true}
        # supported_credential_types = ['username-keypair', 'username-password', 'username-password-keypair'].compact.flatten.join(",").split(",").collect {|it| it.strip }
        credential_params = {"new" => false, "zoneId" => cloud['id']}
        credential_value = Morpheus::Cli::OptionTypes.select_prompt(credential_option_type, @api_client, credential_params, true, options[:options][credential_code])
        if !credential_value.to_s.empty?
          if credential_value == "local"
            params[credential_code] = {"type" => credential_value}
          elsif credential_value.to_s =~ /\A\d{1,}\Z/
            params[credential_code] = {"id" => credential_value.to_i}
          end
        end
      end
      if params.empty?
        raise_command_error "Specify at least one option to update.\n#{optparse}"
      end
      # some optionTypes have fieldContext='zone', so move those to the root level of the zone payload
      if params['zone'].is_a?(Hash)
        cloud_payload.merge!(params.delete('zone'))
      end
      if params.key?('labels')
        params['labels'] = parse_labels(params['labels'])
      end
      cloud_payload.merge!(params)
      payload = {zone: cloud_payload}
    end
    @clouds_interface.setopts(options)
    if options[:dry_run]
      print_dry_run @clouds_interface.dry.update(cloud['id'], payload)
      return
    end
    json_response = @clouds_interface.update(cloud['id'], payload)
    if options[:json]
      puts as_json(json_response, options)
    else
      get([cloud['id']] + (options[:remote] ? ["-r",options[:remote]] : []))
    end
    return 0
  rescue RestClient::Exception => e
    print_rest_exception(e, options)
    exit 1
  end
end
update_wiki(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 975
def update_wiki(args)
  options = {}
  params = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[cloud] [options]")
    build_option_type_options(opts, options, update_wiki_page_option_types)
    opts.on('--file FILE', "File containing the wiki content. This can be used instead of --content") do |filename|
      full_filename = File.expand_path(filename)
      if File.exist?(full_filename)
        params['content'] = File.read(full_filename)
      else
        print_red_alert "File not found: #{full_filename}"
        return 1
      end
      # use the filename as the name by default.
      if !params['name']
        params['name'] = File.basename(full_filename)
      end
    end
    opts.on(nil, '--clear', "Clear current page content") do |val|
      params['content'] = ""
    end
    build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
  end
  optparse.parse!(args)
  if args.count != 1
    puts_error  "#{Morpheus::Terminal.angry_prompt}wrong number of arguments. Expected 1 and received #{args.count} #{args.inspect}\n#{optparse}"
    return 1
  end
  connect(options)

  begin
    cloud = find_cloud_by_name_or_id(args[0])
    return 1 if cloud.nil?
    # construct payload
    passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
    payload = nil
    if options[:payload]
      payload = options[:payload]
      payload.deep_merge!({'page' => passed_options}) unless passed_options.empty?
    else
      payload = {
        'page' => {
        }
      }
      # allow arbitrary -O options
      payload.deep_merge!({'page' => passed_options}) unless passed_options.empty?
      # prompt for options
      #params = Morpheus::Cli::OptionTypes.prompt(update_wiki_page_option_types, options[:options], @api_client, options[:params])
      #params = passed_options
      params.deep_merge!(passed_options)

      if params.empty?
        raise_command_error "Specify at least one option to update.\n#{optparse}"
      end

      payload.deep_merge!({'page' => params}) unless params.empty?
    end
    @clouds_interface.setopts(options)
    if options[:dry_run]
      print_dry_run @clouds_interface.dry.update_wiki(cloud["id"], payload)
      return
    end
    json_response = @clouds_interface.update_wiki(cloud["id"], payload)

    if options[:json]
      puts as_json(json_response, options)
    else
      print_green_success "Updated wiki page for cloud #{cloud['name']}"
      wiki([cloud['id']])
    end
    return 0
  rescue RestClient::Exception => e
    print_rest_exception(e, options)
    exit 1
  end
end
view_wiki(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 944
def view_wiki(args)
  params = {}
  options = {}
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[id]")
    build_common_options(opts, options, [:dry_run, :remote])
    opts.footer = "View cloud wiki page in a web browser" + "\n" +
                  "[cloud] is required. This is the name or id of a cloud."
  end
  optparse.parse!(args)
  if args.count != 1
    raise_command_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.join(' ')}\n#{optparse}"
  end
  connect(options)
  begin
    cloud = find_cloud_by_name_or_id(args[0])
    return 1 if cloud.nil?

    link = "#{@appliance_url}/login/oauth-redirect?access_token=#{@access_token}\\&redirectUri=/infrastructure/clouds/#{cloud['id']}#!wiki"

    if options[:dry_run]
      puts Morpheus::Util.open_url_command(link)
      return 0
    end
    return Morpheus::Util.open_url(link)
  rescue RestClient::Exception => e
    print_rest_exception(e, options)
    exit 1
  end
end
wiki(args) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 866
def wiki(args)
  options = {}
  params = {}
  open_wiki_link = false
  optparse = Morpheus::Cli::OptionParser.new do |opts|
    opts.banner = subcommand_usage("[cloud]")
    opts.on('--view', '--view', "View wiki page in web browser.") do
      open_wiki_link = true
    end
    build_common_options(opts, options, [:json, :dry_run, :remote])
    opts.footer = "View wiki page details for a cloud." + "\n" +
                  "[cloud] is required. This is the name or id of a cloud."
  end
  optparse.parse!(args)
  if args.count != 1
    puts_error  "#{Morpheus::Terminal.angry_prompt}wrong number of arguments. Expected 1 and received #{args.count} #{args.inspect}\n#{optparse}"
    return 1
  end
  connect(options)

  begin
    cloud = find_cloud_by_name_or_id(args[0])
    return 1 if cloud.nil?


    @clouds_interface.setopts(options)
    if options[:dry_run]
      print_dry_run @clouds_interface.dry.wiki(cloud["id"], params)
      return
    end
    json_response = @clouds_interface.wiki(cloud["id"], params)
    page = json_response['page']

    render_result = render_with_format(json_response, options, 'page')
    return 0 if render_result

    if page

      # my_terminal.exec("wiki get #{page['id']}")

      print_h1 "Cloud Wiki Page: #{cloud['name']}"
      # print_h1 "Wiki Page Details"
      print cyan

      print_description_list({
        "Page ID" => 'id',
        "Name" => 'name',
        #"Category" => 'category',
        #"Ref Type" => 'refType',
        #"Ref ID" => 'refId',
        #"Owner" => lambda {|it| it['account'] ? it['account']['name'] : '' },
        "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
        "Created By" => lambda {|it| it['createdBy'] ? it['createdBy']['username'] : '' },
        "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
        "Updated By" => lambda {|it| it['updatedBy'] ? it['updatedBy']['username'] : '' }
      }, page)
      print reset,"\n"

      print_h2 "Page Content"
      print cyan, page['content'], reset, "\n"

    else
      print "\n"
      print cyan, "No wiki page found.", reset, "\n"
    end
    print reset,"\n"

    if open_wiki_link
      return view_wiki([args[0]])
    end

    return 0
  rescue RestClient::Exception => e
    print_rest_exception(e, options)
    exit 1
  end
end

Private Instance Methods

add_cloud_option_types(cloud_type) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 1169
def add_cloud_option_types(cloud_type)
  # note: Type is selected before this
  tmp_option_types = [
    #{'fieldName' => 'zoneType.code', 'fieldLabel' => 'Image Type', 'type' => 'select', 'selectOptions' => cloud_types_for_dropdown, 'required' => true, 'description' => 'Cloud Type.', 'displayOrder' => 0},
    {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
    {'fieldName' => 'code', 'fieldLabel' => 'Code', 'type' => 'text', 'required' => false, 'displayOrder' => 2},
    {'shorthand' => '-l', 'optionalValue' => true, 'fieldName' => 'labels', 'fieldLabel' => 'Labels', 'type' => 'text', 'required' => false, 'processValue' => lambda {|val| parse_labels(val) }, 'displayOrder' => 3},
    {'fieldName' => 'location', 'fieldLabel' => 'Location', 'type' => 'text', 'required' => false, 'displayOrder' => 4},
    {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'},{'name' => 'Public', 'value' => 'public'}], 'required' => false, 'description' => 'Visibility', 'category' => 'permissions', 'defaultValue' => 'private', 'displayOrder' => 5},
    {'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'required' => false, 'defaultValue' => true, 'displayOrder' => 6},
    {'fieldName' => 'autoRecoverPowerState', 'fieldLabel' => 'Automatically Power On VMs', 'type' => 'checkbox', 'required' => false, 'defaultValue' => false, 'displayOrder' => 7}
  ]

  # TODO: Account

  # Details (zoneType.optionTypes)

  if cloud_type && cloud_type['optionTypes']
    if !cloud_type['optionTypes'].find {|opt| opt['type'] == 'credential'}
      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}
      cloud_type['optionTypes'].select {|opt| ['username', 'password', 'serviceUsername', 'servicePassword'].include?(opt['fieldName'])}.each {|opt| opt['localCredential'] = true}
    end
    # adjust displayOrder to put these at the end
    #tmp_option_types = tmp_option_types + cloud_type['optionTypes']
    cloud_type['optionTypes'].each do |opt|
      # temp fix for typo
      opt['optionSource'] = 'credentials' if opt['optionSource'] == 'credentials,'
      tmp_option_types << opt.merge({'displayOrder' => opt['displayOrder'].to_i + 100})
    end
  end

  # TODO:
  # Advanced Options
  ## (a whole bunch needed here)

  # Provisioning Options

  ## PROXY (dropdown)
  ## BYPASS PROXY FOR APPLIANCE URL (checkbox)
  ## USER DATA LINUX (code)

  return tmp_option_types
end
cloud_list_column_definitions(options) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 1155
def cloud_list_column_definitions(options)
  {
    "ID" => 'id',
    "Name" => 'name',
    "Type" => lambda {|it| it['zoneType'] ? it['zoneType']['name'] : '' },
    "Labels" => lambda {|it| format_list(it['labels'], '', 3) rescue '' },
    "Location" => 'location',
    "Region Code" => lambda {|it| it['regionCode'] },
    "Groups" => lambda {|it| (it['groups'] || []).collect {|g| g.instance_of?(Hash) ? g['name'] : g.to_s }.join(', ') },
    "Servers" => lambda {|it| it['serverCount'] },
    "Status" => lambda {|it| format_cloud_status(it) },
  }
end
cloud_types_for_dropdown() click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 1217
def cloud_types_for_dropdown
  @clouds_interface.cloud_types({max:1000, shallow:true})['zoneTypes'].select {|it| it['enabled'] }.collect {|it| {'name' => it['name'], 'value' => it['code']} }
end
format_cloud_status(cloud, return_color=cyan) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 1221
def format_cloud_status(cloud, return_color=cyan)
  out = ""
  status_string = cloud['status']
  if cloud['enabled'] == false
    out << "#{red}DISABLED#{return_color}"
  elsif status_string.nil? || status_string.empty? || status_string == "unknown"
    out << "#{white}UNKNOWN#{return_color}"
  elsif status_string == 'ok'
    out << "#{green}#{status_string.upcase}#{return_color}"
  elsif status_string == 'syncing' || status_string == 'initializing' || status_string == 'removing'
    out << "#{yellow}#{status_string.upcase}#{return_color}"
  else
    out << "#{red}#{status_string ? status_string.upcase : 'N/A'}#{cloud['statusMessage'] ? "#{return_color} - #{cloud['statusMessage']}" : ''}#{return_color}"
  end
  out
end
get_cloud_type_credential_types(cloud_type_code) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 1246
def get_cloud_type_credential_types(cloud_type_code)
  case cloud_type_code
  when "amazon", "alibaba"
    ['access-key-secret']
  when "azure","azurestack"
    ['client-id-secret']
  when "google"
    ['email-private-key']
  when "softlayer"
    ['username-api-key']
  when "digitalocean"
    ['username-api-key']
  else
    ['username-password']
  end
end
update_cloud_option_types(cloud_type) click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 1213
def update_cloud_option_types(cloud_type)
  add_cloud_option_types(cloud_type).collect {|it| it['required'] = false; it }
end
update_wiki_page_option_types() click to toggle source
# File lib/morpheus/cli/commands/clouds.rb, line 1238
def update_wiki_page_option_types
  [
    {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => false, 'displayOrder' => 1, 'description' => 'The name of the wiki page for this instance. Default is the instance name.'},
    #{'fieldName' => 'category', 'fieldLabel' => 'Category', 'type' => 'text', 'required' => false, 'displayOrder' => 2},
    {'fieldName' => 'content', 'fieldLabel' => 'Content', 'type' => 'textarea', 'required' => false, 'displayOrder' => 3, 'description' => 'The content (markdown) of the wiki page.'}
  ]
end