morpheus-cli 5.2.0 → 5.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4f4b5a29dcfa1a915ab2d3fed9ad07197d2a760758b2bc3b76e72cf6899c4372
4
- data.tar.gz: 59c981a5aede057b69e08f5c717d27c884bdd64aed84fb81361b35291b3aaf72
3
+ metadata.gz: 4409a856333a1b2957649aac67f62677b943706754ebc810c614fa5f879b120d
4
+ data.tar.gz: bb968663da852f4ea631fc9b0c89c115f6fb1067049585953c33b7c24e4b284a
5
5
  SHA512:
6
- metadata.gz: 678ff7f73923c9883968ee8bba29b8d75d5464a4899ca812477ce943b25f758c74f187a481c781500928206c4d540d5153f858ee4e2242cfb24cc2604be1602d
7
- data.tar.gz: c27881081abb71b05eceb4857280f51a4f838e9a568658baa34385afe7fc2b86be61eb31a070a4e3a9381000337ceb9b11f58fe8572fff8066882225133742ba
6
+ metadata.gz: 2be204c65dd3c2a35ce5ac7170e70a2297aa34ee1348db2fc736a5915a2678c0c45361269a801db228f202e27dcdcfaaf69afc7f49d9eded429c16d5381dd28f
7
+ data.tar.gz: a5018a327ae43078e4661c1c3744e75b6cc1adfc8854ca09d99a0a47f8e0678d2f8914b46d724bd8189011b13a42f2ac5779b3980611af1655cdebc4393a3e53
data/.gitignore CHANGED
@@ -21,3 +21,4 @@ tmp
21
21
  *.a
22
22
  mkmf.log
23
23
  .DS_Store
24
+ .idea
@@ -530,9 +530,10 @@ class Morpheus::Cli::Hosts
530
530
  puts records_as_csv([json_response['server']], options)
531
531
  return 0
532
532
  end
533
- server = json_response['server']
533
+ server = json_response['server'] || json_response['host'] || {}
534
534
  #stats = server['stats'] || json_response['stats'] || {}
535
535
  stats = json_response['stats'] || {}
536
+ tags = server['tags'] || server['metadata']
536
537
  title = "Host Details"
537
538
  print_h1 title, [], options
538
539
  print cyan
@@ -541,6 +542,7 @@ class Morpheus::Cli::Hosts
541
542
  "Name" => 'name',
542
543
  "Hostname" => 'hostname',
543
544
  "Description" => 'description',
545
+ "Tags" => lambda {|it| tags ? format_metadata(tags) : '' },
544
546
  "Owner" => lambda {|it| it['owner'] ? it['owner']['username'] : '' },
545
547
  "Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
546
548
  #"Group" => lambda {|it| it['group'] ? it['group']['name'] : '' },
@@ -564,6 +566,7 @@ class Morpheus::Cli::Hosts
564
566
  # server_columns.delete("Tenant") if multi_tenant != true
565
567
  server_columns.delete("Cost") if server['hourlyCost'].to_f == 0
566
568
  server_columns.delete("Price") if server['hourlyPrice'].to_f == 0 || server['hourlyPrice'] == server['hourlyCost']
569
+ server_columns.delete("Tags") if tags.nil? || tags.empty?
567
570
 
568
571
  print_description_list(server_columns, server)
569
572
 
@@ -990,6 +993,19 @@ class Morpheus::Cli::Hosts
990
993
  opts.on('--power-schedule-type ID', String, "Power Schedule Type ID") do |val|
991
994
  params['powerScheduleType'] = val == "null" ? nil : val
992
995
  end
996
+ opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
997
+ options[:tags] = val
998
+ end
999
+ opts.on('--metadata LIST', String, "Alias for --tags.") do |val|
1000
+ options[:tags] = val
1001
+ end
1002
+ opts.add_hidden_option('--metadata')
1003
+ opts.on('--add-tags TAGS', String, "Add Tags in the format 'name:value, name:value'. This will only add/update tags.") do |val|
1004
+ options[:add_tags] = val
1005
+ end
1006
+ opts.on('--remove-tags TAGS', String, "Remove Tags in the format 'name, name:value'. This removes tags, the :value component is optional and must match if passed.") do |val|
1007
+ options[:remove_tags] = val
1008
+ end
993
1009
  # opts.on('--created-by ID', String, "Created By User ID") do |val|
994
1010
  # params['createdById'] = val
995
1011
  # end
@@ -1008,6 +1024,18 @@ class Morpheus::Cli::Hosts
1008
1024
  new_group = nil
1009
1025
  passed_options = options[:options] ? options[:options].reject {|k,v| k.is_a?(Symbol) } : {}
1010
1026
  params.deep_merge!(passed_options) unless passed_options.empty?
1027
+ # metadata tags
1028
+ if options[:tags]
1029
+ params['tags'] = parse_metadata(options[:tags])
1030
+ else
1031
+ # params['tags'] = prompt_metadata(options)
1032
+ end
1033
+ if options[:add_tags]
1034
+ params['addTags'] = parse_metadata(options[:add_tags])
1035
+ end
1036
+ if options[:remove_tags]
1037
+ params['removeTags'] = parse_metadata(options[:remove_tags])
1038
+ end
1011
1039
  payload = nil
1012
1040
  if options[:payload]
1013
1041
  payload = options[:payload]
@@ -1919,7 +1947,8 @@ class Morpheus::Cli::Hosts
1919
1947
  snapshot_column_definitions = {
1920
1948
  "ID" => lambda {|it| it['id'] },
1921
1949
  "Name" => lambda {|it| it['name'] },
1922
- "Description" => lambda {|it| it['snapshotType'] ? (it['snapshotType']['name'] || it['snapshotType']['code']) : '' },
1950
+ "Description" => lambda {|it| it['description'] },
1951
+ # "Type" => lambda {|it| it['snapshotType'] },
1923
1952
  "Date Created" => lambda {|it| format_local_dt(it['snapshotCreated']) },
1924
1953
  "Status" => lambda {|it| format_snapshot_status(it) }
1925
1954
  }
@@ -459,17 +459,58 @@ class Morpheus::Cli::Instances
459
459
  options[:instance_name] = args[0]
460
460
  end
461
461
 
462
- # use active group by default
463
- options[:group] ||= @active_group_id
464
- options[:select_datastore] = true
465
- options[:name_required] = true
466
462
  begin
467
463
  payload = nil
468
464
  if options[:payload]
469
465
  payload = options[:payload]
470
466
  # support -O OPTION switch on top of --payload
471
467
  payload.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
468
+ # obviously should support every option that prompt supports on top of -- payload as well
469
+ # group, cloud and type for now
470
+ # todo: also support :layout, service_plan, :resource_pool, etc.
471
+ group = nil
472
+ if options[:group]
473
+ group = find_group_by_name_or_id_for_provisioning(options[:group])
474
+ if group.nil?
475
+ return 1, "group not found by #{options[:group]}"
476
+ end
477
+ #payload["siteId"] = group["id"]
478
+ payload.deep_merge!({"instance" => {"site" => {"id" => group["id"]} } })
479
+ end
480
+ if options[:cloud]
481
+ group_id = group ? group["id"] : ((payload["instance"] && payload["instance"]["site"].is_a?(Hash)) ? payload["instance"]["site"]["id"] : nil)
482
+ cloud = find_cloud_by_name_or_id_for_provisioning(group_id, options[:cloud])
483
+ if cloud.nil?
484
+ return 1, "cloud not found by #{options[:cloud]}"
485
+ end
486
+ payload["zoneId"] = cloud["id"]
487
+ payload.deep_merge!({"instance" => {"cloud" => cloud["name"] } })
488
+ end
489
+ if options[:cloud]
490
+ group_id = group ? group["id"] : ((payload["instance"] && payload["instance"]["site"].is_a?(Hash)) ? payload["instance"]["site"]["id"] : nil)
491
+ cloud = find_cloud_by_name_or_id_for_provisioning(group_id, options[:cloud])
492
+ if cloud.nil?
493
+ return 1, "cloud not found by #{options[:cloud]}"
494
+ end
495
+ payload["zoneId"] = cloud["id"]
496
+ payload.deep_merge!({"instance" => {"cloud" => cloud["name"] } })
497
+ end
498
+ if options[:instance_type_code]
499
+ # should just use find_instance_type_by_name_or_id
500
+ # note that the api actually will match name name or code
501
+ instance_type = (options[:instance_type_code].to_s =~ /\A\d{1,}\Z/) ? find_instance_type_by_id(options[:instance_type_code]) : find_instance_type_by_code(options[:instance_type_code])
502
+ if instance_type.nil?
503
+ return 1, "instance type not found by #{options[:cloud]}"
504
+ end
505
+ payload.deep_merge!({"instance" => {"type" => instance_type["code"] } })
506
+ payload.deep_merge!({"instance" => {"instanceType" => {"code" => instance_type["code"]} } })
507
+ end
508
+
472
509
  else
510
+ # use active group by default
511
+ options[:group] ||= @active_group_id
512
+ options[:select_datastore] = true
513
+ options[:name_required] = true
473
514
  # prompt for all the instance configuration options
474
515
  # this provisioning helper method handles all (most) of the parsing and prompting
475
516
  # and it relies on the method to exit non-zero on error, like a bad CLOUD or TYPE value
@@ -562,16 +603,17 @@ class Morpheus::Cli::Instances
562
603
  opts.on('--group GROUP', String, "Group Name or ID") do |val|
563
604
  options[:group] = val
564
605
  end
565
- opts.on('--tags LIST', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
566
- options[:metadata] = val
606
+ opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
607
+ params['labels'] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
567
608
  end
568
- opts.on('--metadata LIST', String, "Metadata tags in the format 'ping=pong,flash=bang'") do |val|
569
- options[:metadata] = val
609
+ opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
610
+ options[:tags] = val
570
611
  end
571
- opts.add_hidden_option('--metadata')
572
- opts.on('--labels LIST', String, "Labels (keywords) in the format 'foo, bar'") do |val|
573
- # todo switch this from 'tags' to 'labels'
574
- params['tags'] = val.split(',').collect {|it| it.to_s.strip }.compact.uniq.join(',')
612
+ opts.on('--add-tags TAGS', String, "Add Tags in the format 'name:value, name:value'. This will only add/update tags.") do |val|
613
+ options[:add_tags] = val
614
+ end
615
+ opts.on('--remove-tags TAGS', String, "Remove Tags in the format 'name, name:value'. This removes tags, the :value component is optional and must match if passed.") do |val|
616
+ options[:remove_tags] = val
575
617
  end
576
618
  opts.on('--power-schedule-type ID', String, "Power Schedule Type ID") do |val|
577
619
  params['powerScheduleType'] = val == "null" ? nil : val
@@ -627,32 +669,17 @@ class Morpheus::Cli::Instances
627
669
  payload['instance']['site'] = {'id' => group['id']}
628
670
  end
629
671
  # metadata tags
630
- # if options[:options]['metadata'].is_a?(Array) && !options[:metadata]
631
- # options[:metadata] = options[:options]['metadata']
632
- # end
633
- if options[:metadata]
634
- metadata = []
635
- if options[:metadata] == "[]" || options[:metadata] == "null"
636
- payload['instance']['metadata'] = []
637
- elsif options[:metadata].is_a?(Array)
638
- payload['instance']['metadata'] = options[:metadata]
639
- else
640
- # parse string into format name:value, name:value
641
- # merge IDs from current metadata
642
- # todo: should allow quoted semicolons..
643
- metadata_list = options[:metadata].split(",").select {|it| !it.to_s.empty? }
644
- metadata_list = metadata_list.collect do |it|
645
- metadata_pair = it.split(":")
646
- if metadata_pair.size == 1 && it.include?("=")
647
- metadata_pair = it.split("=")
648
- end
649
- row = {}
650
- row['name'] = metadata_pair[0].to_s.strip
651
- row['value'] = metadata_pair[1].to_s.strip
652
- row
653
- end
654
- payload['instance']['metadata'] = metadata_list
655
- end
672
+ if options[:tags]
673
+ # api version 4.2.5 and later supports tags, older versions expect metadata
674
+ # todo: use tags instead like everywhere else
675
+ # payload['instance']['tags'] = parse_metadata(options[:tags])
676
+ payload['instance']['metadata'] = parse_metadata(options[:tags])
677
+ end
678
+ if options[:add_tags]
679
+ payload['instance']['addTags'] = parse_metadata(options[:add_tags])
680
+ end
681
+ if options[:remove_tags]
682
+ payload['instance']['removeTags'] = parse_metadata(options[:remove_tags])
656
683
  end
657
684
  if payload['instance'].empty? && params.empty? && options[:owner].nil?
658
685
  raise_command_error "Specify at least one option to update.\n#{optparse}"
@@ -1256,11 +1283,14 @@ class Morpheus::Cli::Instances
1256
1283
  # metadata tags used to be returned as metadata and are now returned as tags
1257
1284
  # the problem is tags is what we used to call Labels (keywords)
1258
1285
  # the api will change to tags and labels, so handle the old format as long as metadata is returned.
1259
- tags, labels = nil, nil
1260
- if instance.key?('metadata')
1261
- tags, labels = instance['metadata'], instance['tags']
1286
+ labels = nil
1287
+ tags = nil
1288
+ if instance.key?('labels')
1289
+ labels = instance['labels']
1290
+ tags = instance['tags']
1262
1291
  else
1263
- tags, labels = instance['tags'], instance['labels']
1292
+ labels = instance['tags']
1293
+ tags = instance['metadata']
1264
1294
  end
1265
1295
  # containers are fetched via separate api call
1266
1296
  containers = nil
@@ -1302,7 +1332,7 @@ class Morpheus::Cli::Instances
1302
1332
  # "Cost" => lambda {|it| it['hourlyCost'] ? format_money(it['hourlyCost'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
1303
1333
  # "Price" => lambda {|it| it['hourlyPrice'] ? format_money(it['hourlyPrice'], (it['currency'] || 'USD'), {sigdig:15}).to_s + ' per hour' : '' },
1304
1334
  "Environment" => 'instanceContext',
1305
- "Labels" => lambda {|it| it['tags'] ? it['tags'].join(',') : '' },
1335
+ "Labels" => lambda {|it| labels ? labels.join(',') : '' },
1306
1336
  "Tags" => lambda {|it| tags ? tags.collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
1307
1337
  "Owner" => lambda {|it|
1308
1338
  if it['owner']
@@ -3020,7 +3050,8 @@ EOT
3020
3050
  snapshot_column_definitions = {
3021
3051
  "ID" => lambda {|it| it['id'] },
3022
3052
  "Name" => lambda {|it| it['name'] },
3023
- "Description" => lambda {|it| it['snapshotType'] ? (it['snapshotType']['name'] || it['snapshotType']['code']) : '' },
3053
+ "Description" => lambda {|it| it['description'] },
3054
+ # "Type" => lambda {|it| it['snapshotType'] },
3024
3055
  "Date Created" => lambda {|it| format_local_dt(it['snapshotCreated']) },
3025
3056
  "Status" => lambda {|it| format_snapshot_status(it) }
3026
3057
  }
@@ -272,7 +272,7 @@ class Morpheus::Cli::InvoicesCommand
272
272
  {"ESTIMATE" => lambda {|it| format_boolean(it['estimate']) } },
273
273
  {"ACTIVE" => lambda {|it| format_boolean(it['active']) } },
274
274
  {"ITEMS" => lambda {|it| it['lineItems'].size rescue '' } },
275
- {"TAGS" => lambda {|it| it['metadata'] ? it['metadata'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' } },
275
+ {"TAGS" => lambda {|it| (it['metadata'] || it['tags']) ? (it['metadata'] || it['tags']).collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' } },
276
276
  ]
277
277
  if show_projects
278
278
  columns += [
@@ -438,7 +438,7 @@ EOT
438
438
  "Ref Start" => lambda {|it| format_dt(it['refStart']) },
439
439
  "Ref End" => lambda {|it| format_dt(it['refEnd']) },
440
440
  "Items" => lambda {|it| it['lineItems'].size rescue '' },
441
- "Tags" => lambda {|it| it['metadata'] ? it['metadata'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
441
+ "Tags" => lambda {|it| (it['metadata'] || it['tags']) ? (it['metadata'] || it['tags']).collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
442
442
  "Project ID" => lambda {|it| it['project'] ? it['project']['id'] : '' },
443
443
  "Project Name" => lambda {|it| it['project'] ? it['project']['name'] : '' },
444
444
  "Project Tags" => lambda {|it| it['project'] ? format_metadata(it['project']['tags']) : '' },
@@ -454,7 +454,8 @@ EOT
454
454
  description_cols.delete("Project Name")
455
455
  description_cols.delete("Project Tags")
456
456
  end
457
- if invoice['metadata'].nil? || invoice['metadata'].empty?
457
+ tags = (invoice['metadata'] || invoice['tags'])
458
+ if tags.nil? || tags.empty?
458
459
  description_cols.delete("Tags")
459
460
  end
460
461
  if !['ComputeServer','Instance','Container'].include?(invoice['refType'])
@@ -596,14 +596,12 @@ module Morpheus::Cli::ProvisioningHelper
596
596
  v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'environment', 'fieldLabel' => 'Environment', 'type' => 'select', 'required' => false, 'selectOptions' => get_available_environments()}], options[:options])
597
597
  payload['instance']['instanceContext'] = v_prompt['environment'] if !v_prompt['environment'].empty?
598
598
 
599
- # Labels (Provisioning API still refers to these as tags)
600
- # and tags (metadata tags) is called metadata.
601
- # todo: switch this from 'tags' to labels' when the api changes
599
+ # Labels (used to be called tags)
602
600
  if options[:labels]
603
- payload['instance']['tags'] = options[:labels].is_a?(Array) ? options[:labels] : options[:labels].to_s.split(',').collect {|it| it.to_s.strip }.compact.uniq
601
+ payload['instance']['labels'] = options[:labels].is_a?(Array) ? options[:labels] : options[:labels].to_s.split(',').collect {|it| it.to_s.strip }.compact.uniq
604
602
  else
605
603
  v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'labels', 'fieldLabel' => 'Labels', 'type' => 'text', 'required' => false}], options[:options])
606
- payload['instance']['tags'] = v_prompt['tags'].split(',').collect {|it| it.to_s.strip }.compact.uniq if !v_prompt['tags'].empty?
604
+ payload['instance']['labels'] = v_prompt['labels'].split(',').collect {|it| it.to_s.strip }.compact.uniq if !v_prompt['labels'].empty?
607
605
  end
608
606
 
609
607
  # Version and Layout
@@ -1693,6 +1691,15 @@ module Morpheus::Cli::ProvisioningHelper
1693
1691
  row = {}
1694
1692
  row['name'] = metadata_pair[0].to_s.strip
1695
1693
  row['value'] = metadata_pair[1].to_s.strip
1694
+ # hacky way to set masked flag to true of false to (masked) in the value itself
1695
+ if(row['value'].include?("(masked)"))
1696
+ row['value'] = row['value'].gsub("(masked)", "").strip
1697
+ row['masked'] = true
1698
+ end
1699
+ if(row['value'].include?("(unmasked)"))
1700
+ row['value'] = row['value'].gsub("(unmasked)", "").strip
1701
+ row['masked'] = false
1702
+ end
1696
1703
  row
1697
1704
  end
1698
1705
  metadata = metadata_list
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "5.2.0"
4
+ VERSION = "5.2.1"
5
5
  end
6
6
  end
@@ -299,7 +299,7 @@ EOT
299
299
  opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
300
300
  options[:tags] = val
301
301
  end
302
- opts.on('--add-tags TAGS', String, "Add Tags in the format 'name:value, name:value'. This will only add/update project tags.") do |val|
302
+ opts.on('--add-tags TAGS', String, "Add Tags in the format 'name:value, name:value'. This will only add/update tags.") do |val|
303
303
  options[:add_tags] = val
304
304
  end
305
305
  opts.on('--remove-tags TAGS', String, "Remove Tags in the format 'name, name:value'. This removes tags, the :value component is optional and must match if passed.") do |val|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: morpheus-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.0
4
+ version: 5.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Estes
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2020-11-10 00:00:00.000000000 Z
14
+ date: 2020-11-18 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler