morpheus-cli 8.0.11.1 → 8.0.12

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e612ece8267586e1ede25aaa18364ba1a6debc9d98a92201dff496038363a27
4
- data.tar.gz: e4f789f8b3b17a37d460de0833f65a3fa2f7599879a6162c617683eee9894163
3
+ metadata.gz: 30f5740960bec8ff3b96aa8e7da68862d310d4375fc7c48c11fd31841ac5310c
4
+ data.tar.gz: ae66b58b6702afeed4e30edc44b019a1e73e2ea11179f0ab6507edf250275977
5
5
  SHA512:
6
- metadata.gz: 75e8de5e4f8d83b2a37aed735e036b156d36eddf7eeba60b3bea20bc4b2e3e371222854dba2b0fd27a2aacef625ddddf7d6dfb8e486a700fc8e67cc1434c95fd
7
- data.tar.gz: 35c2a244ae0acb3d6187277b9650277dfe5c85349f7788ff8dc37c7bf341dfd4773e540c1ca68fabc5e726fa8aefec9eac42c7df6b7e11222561e84444784c84
6
+ metadata.gz: 795b92277a1dbc2ad7ec6a933469fcf0ab77f8c7e8d261b5502e218f3a72cfda0856bff14d94b043b4f3371ec2cbd89d8522df6c57b87477d75949e70b975436
7
+ data.tar.gz: cfdc201519632bf6f6b51155611b35ffe4c299733bda2c16c19109bae37174112439aa728ecebcff42c1646496060698952af332a444d7a32ab46b5e260789f7
data/Dockerfile CHANGED
@@ -1,5 +1,5 @@
1
1
  FROM ruby:2.7.5
2
2
 
3
- RUN gem install morpheus-cli -v 8.0.11.1
3
+ RUN gem install morpheus-cli -v 8.0.12
4
4
 
5
5
  ENTRYPOINT ["morpheus"]
@@ -1022,6 +1022,10 @@ class Morpheus::APIClient
1022
1022
  Morpheus::LibraryOperatingSystemsInterface.new(common_interface_options).setopts(@options)
1023
1023
  end
1024
1024
 
1025
+ def migrations
1026
+ Morpheus::MigrationsInterface.new(common_interface_options).setopts(@options)
1027
+ end
1028
+
1025
1029
  def rest(endpoint)
1026
1030
  Morpheus::RestInterface.new(common_interface_options).setopts(@options.merge({base_path: "#{@base_url}/api/#{endpoint}"}))
1027
1031
  end
@@ -0,0 +1,49 @@
1
+ require 'morpheus/api/rest_interface'
2
+
3
+ class Morpheus::MigrationsInterface < Morpheus::RestInterface
4
+
5
+ def base_path
6
+ "/api/migrations"
7
+ end
8
+
9
+ def source_clouds(params={}, headers={})
10
+ execute(method: :get, url: "#{base_path}/source-clouds", params: params, headers: headers)
11
+ end
12
+
13
+ def target_clouds(params={}, headers={})
14
+ execute(method: :get, url: "#{base_path}/target-clouds", params: params, headers: headers)
15
+ end
16
+
17
+ def source_servers(params={}, headers={})
18
+ execute(method: :get, url: "#{base_path}/source-servers", params: params, headers: headers)
19
+ end
20
+
21
+ def source_networks(params={}, headers={})
22
+ execute(method: :get, url: "#{base_path}/source-networks", params: params, headers: headers)
23
+ end
24
+
25
+ def target_networks(params={}, headers={})
26
+ execute(method: :get, url: "#{base_path}/target-networks", params: params, headers: headers)
27
+ end
28
+
29
+ def source_storage(params={}, headers={})
30
+ execute(method: :get, url: "#{base_path}/source-storage", params: params, headers: headers)
31
+ end
32
+
33
+ def target_storage(params={}, headers={})
34
+ execute(method: :get, url: "#{base_path}/target-storage", params: params, headers: headers)
35
+ end
36
+
37
+ # def target_pools(params={}, headers={})
38
+ # execute(method: :get, url: "#{base_path}/target-pools", params: params, headers: headers)
39
+ # end
40
+
41
+ # def target_groups(params={}, headers={})
42
+ # execute(method: :get, url: "#{base_path}/target-groups", params: params, headers: headers)
43
+ # end
44
+
45
+ def run(id, payload={}, params={}, headers={})
46
+ execute(method: :post, url: "#{base_path}/#{CGI::escape(id.to_s)}/run", params: params, payload: payload, headers: headers)
47
+ end
48
+
49
+ end
@@ -353,10 +353,9 @@ EOT
353
353
  out << "#{benchmark_name.ljust(30, ' ')}"
354
354
  # exit: 0
355
355
  exit_code = benchmark_record.exit_code
356
- bad_benchmark = benchmark_record.exit_code && benchmark_record.exit_code != 0
357
- if bad_benchmark
358
- out << "\texit: #{bad_benchmark.exit_code.to_s.ljust(2, ' ')}"
359
- out << "\terror: #{bad_benchmark.error.to_s.ljust(12, ' ')}"
356
+ if benchmark_record.exit_code && benchmark_record.exit_code != 0
357
+ out << "\texit: #{benchmark_record.exit_code.to_s.ljust(2, ' ')}"
358
+ out << "\terror: #{benchmark_record.error.to_s.ljust(12, ' ')}"
360
359
  else
361
360
  out << "\texit: 0 "
362
361
  end
@@ -4,6 +4,7 @@ class Morpheus::Cli::Clouds
4
4
  include Morpheus::Cli::CliCommand
5
5
  include Morpheus::Cli::InfrastructureHelper
6
6
  include Morpheus::Cli::ProvisioningHelper
7
+ include Morpheus::Cli::WhoamiHelper
7
8
 
8
9
  register_subcommands :list, :count, :get, :add, :update, :remove, :refresh, :security_groups, :apply_security_groups
9
10
  register_subcommands :types, :type
@@ -1250,12 +1251,7 @@ EOT
1250
1251
  optparse = Morpheus::Cli::OptionParser.new do |opts|
1251
1252
  opts.banner = subcommand_usage( "[cloud] [name] [options]")
1252
1253
  build_option_type_options(opts, options, add_cloud_affinity_group_option_types)
1253
- # opts.on('--refresh [SECONDS]', String, "Refresh until execution is complete. Default interval is #{default_refresh_interval} seconds.") do |val|
1254
- # options[:refresh_interval] = val.to_s.empty? ? default_refresh_interval : val.to_f
1255
- # end
1256
- # opts.on(nil, '--no-refresh', "Do not refresh" ) do
1257
- # options[:no_refresh] = true
1258
- # end
1254
+ add_perms_options(opts, options, ['plans'])
1259
1255
  build_standard_add_options(opts, options)
1260
1256
  opts.footer = "Add affinity group to a cloud.\n" +
1261
1257
  "[cloud] is required. This is the name or id of an existing cloud.\n" +
@@ -1294,10 +1290,10 @@ EOT
1294
1290
  # end
1295
1291
 
1296
1292
  # perms
1297
- perms = prompt_permissions(options.merge({:for_affinity_group => true}), ['plans', 'groupDefaults'])
1293
+ perms = prompt_permissions(options, is_master_account ? ['plans'] : ['plans', 'visibility', 'tenants'])
1298
1294
 
1299
- affinity_group['resourcePermissions'] = perms['resourcePermissions'] unless perms['resourcePermissions'].nil?
1300
- affinity_group['tenants'] = perms['tenantPermissions'] unless perms['tenantPermissions'].nil?
1295
+ affinity_group['resourcePermissions'] = perms['resourcePermissions'] unless perms['resourcePermissions'].empty?
1296
+ affinity_group['tenants'] = perms['tenantPermissions'] unless perms['tenantPermissions'].empty? || perms['tenantPermissions']['accounts'].empty?
1301
1297
  affinity_group['visibility'] = perms['resourcePool']['visibility'] if !perms['resourcePool'].nil? && !perms['resourcePool']['visibility'].nil?
1302
1298
 
1303
1299
  payload = {'affinityGroup' => affinity_group}
@@ -1337,10 +1333,8 @@ EOT
1337
1333
  options = {}
1338
1334
  optparse = Morpheus::Cli::OptionParser.new do |opts|
1339
1335
  opts.banner = subcommand_usage( "[cloud] [affinity group] [options]")
1340
- opts.on('--active [on|off]', String, "Enable affinity group") do |val|
1341
- options[:active] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
1342
- end
1343
- add_perms_options(opts, options, ['groupDefaults'])
1336
+ build_option_type_options(opts, options, update_cloud_affinity_group_option_types)
1337
+ add_perms_options(opts, options, ['plans'])
1344
1338
  build_standard_update_options(opts, options)
1345
1339
  opts.footer = "Update a cloud affinity group.\n" +
1346
1340
  "[cloud] is required. This is the name or id of an existing cloud.\n" +
@@ -1370,19 +1364,25 @@ EOT
1370
1364
  end
1371
1365
  else
1372
1366
  payload = {'affinityGroup' => {}}
1373
- payload['affinityGroup']['active'] = options[:active].nil? ? (Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'active', 'fieldLabel' => 'Active', 'type' => 'checkbox', 'description' => 'Active', 'defaultValue' => true}], options[:options], @api_client))['active'] == 'on' : options[:active]
1374
-
1375
- perms = prompt_permissions(options.merge({:available_plans => namespace_service_plans}), affinity_group['owner']['id'] == current_user['accountId'] ? ['plans', 'groupDefaults'] : ['plans', 'groupDefaults', 'visibility', 'tenants'])
1367
+ options[:params] ||= {}
1368
+ options[:params].merge!({:cloudId => cloud['id'],:zoneId => cloud['id']})
1369
+ option_types = update_cloud_affinity_group_option_types
1370
+ v_prompt = Morpheus::Cli::OptionTypes.no_prompt(option_types, options[:options], @api_client, options[:params])
1371
+ v_prompt.deep_compact!.booleanize!
1372
+ payload.deep_merge!({'affinityGroup' => v_prompt})
1373
+
1374
+ perms = prompt_permissions(options.merge({:no_prompt => true}), is_master_account ? ['plans'] : ['plans', 'visibility', 'tenants'])
1375
+
1376
1376
  perms_payload = {}
1377
- perms_payload['resourcePermissions'] = perms['resourcePermissions'] if !perms['resourcePermissions'].nil?
1378
- perms_payload['tenantPermissions'] = perms['tenantPermissions'] if !perms['tenantPermissions'].nil?
1379
-
1380
- payload['affinityGroup']['permissions'] = perms_payload
1377
+ perms_payload['resourcePermissions'] = perms['resourcePermissions'] if !perms['resourcePermissions'].nil? && !perms['resourcePermissions'].empty?
1378
+ perms_payload['tenantPermissions'] = perms['tenantPermissions'] if !perms['tenantPermissions'].nil? && !perms['tenantPermissions']['accounts'].empty?
1379
+
1380
+ payload['affinityGroup']['permissions'] = perms_payload if !perms_payload.empty?
1381
1381
  payload['affinityGroup']['visibility'] = perms['resourcePool']['visibility'] if !perms['resourcePool'].nil? && !perms['resourcePool']['visibility'].nil?
1382
1382
 
1383
1383
  # support -O OPTION switch on top of everything
1384
1384
  if options[:options]
1385
- payload.deep_merge!({'affinityGroup' => options[:options].reject {|k,v| k.is_a?(Symbol) }})
1385
+ payload.deep_merge!({'affinityGroup' => options[:options].reject {|k,v| k.is_a?(Symbol) || payload['affinityGroup'].key?(k) }})
1386
1386
  end
1387
1387
 
1388
1388
  if payload['affinityGroup'].nil? || payload['affinityGroup'].empty?
@@ -1599,7 +1599,14 @@ EOT
1599
1599
  {'fieldName' => 'affinityType', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Keep Separate', 'value' => 'KEEP_SEPARATE'}, {'name' => 'Keep Together', 'value' => 'KEEP_TOGETHER'}], 'description' => 'Choose affinity type.', 'required' => true, 'defaultValue' => 'KEEP_SEPARATE'},
1600
1600
  {'fieldName' => 'active', 'fieldLabel' => 'Active', 'type' => 'checkbox', 'defaultValue' => true},
1601
1601
  {'fieldName' => 'pool.id', 'fieldLabel' => 'Cluster', 'type' => 'select', 'optionSourceType' => 'vmware', 'optionSource' => 'vmwareZonePoolClusters', 'description' => 'Select cluster for the affinity group.', 'required' => true},
1602
- {'fieldName' => 'servers', 'fieldLabel' => 'Server', 'type' => 'multiSelect', 'optionSource' => 'searchServers', 'description' => 'Select servers to be in the affinity group.'},
1602
+ {'fieldName' => 'servers', 'fieldLabel' => 'Server', 'type' => 'multiTypeahead', 'optionSource' => 'searchServers', 'description' => 'Select servers to be in the affinity group.'},
1603
+ ]
1604
+ end
1605
+
1606
+ def update_cloud_affinity_group_option_types
1607
+ [
1608
+ {'fieldName' => 'active', 'fieldLabel' => 'Active', 'type' => 'checkbox'},
1609
+ {'fieldName' => 'servers', 'fieldLabel' => 'Server', 'type' => 'multiTypeahead', 'optionSource' => 'searchServers', 'description' => 'Select servers to be in the affinity group.'},
1603
1610
  ]
1604
1611
  end
1605
1612
 
@@ -0,0 +1,179 @@
1
+ require 'morpheus/cli/cli_command'
2
+
3
+ class Morpheus::Cli::ClusterTypes
4
+ include Morpheus::Cli::CliCommand
5
+
6
+ set_command_description "View cluster types."
7
+ set_command_name :'cluster-types'
8
+ register_subcommands :list, :get
9
+
10
+
11
+ # This is a hidden command, documenting clusters list-types and clusters get-type
12
+ set_command_hidden
13
+
14
+ def connect(opts)
15
+ @api_client = establish_remote_appliance_connection(opts)
16
+ @clusters_interface = @api_client.clusters
17
+ end
18
+
19
+ def handle(args)
20
+ handle_subcommand(args)
21
+ end
22
+
23
+ def list(args)
24
+ options = {}
25
+ params = {}
26
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
27
+ opts.banner = "Usage: #{prog_name} clusters list-types [search]"
28
+ #opts.banner = subcommand_usage("[search]")
29
+ # opts.on('--optionTypes [true|false]', String, "Include optionTypes in the response. Default is false.") do |val|
30
+ # params['optionTypes'] = (val.to_s == '' || val.to_s == 'on' || val.to_s == 'true')
31
+ # end
32
+ build_standard_list_options(opts, options)
33
+ opts.footer = "List cluster types."
34
+ end
35
+ optparse.parse!(args)
36
+ connect(options)
37
+ # verify_args!(args:args, optparse:optparse, count:0)
38
+ if args.count > 0
39
+ options[:phrase] = args.join(" ")
40
+ end
41
+ params.merge!(parse_list_options(options))
42
+ @clusters_interface.setopts(options)
43
+ if options[:dry_run]
44
+ print_dry_run @clusters_interface.dry.cluster_types(params)
45
+ return
46
+ end
47
+ json_response = @clusters_interface.cluster_types(params)
48
+ render_response(json_response, options, "clusterTypes") do
49
+ cluster_types = json_response["clusterTypes"]
50
+ print_h1 "Morpheus Cluster Types", parse_list_subtitles(options), options
51
+ if cluster_types.empty?
52
+ print cyan,"No cluster types found.",reset,"\n"
53
+ else
54
+ list_columns = {
55
+ "ID" => 'id',
56
+ "NAME" => 'name',
57
+ "CODE" => 'code',
58
+ "DESCRIPTION" => lambda {|it| truncate_string(it['description'], options[:wrap] ? nil : 100) },
59
+ }
60
+ print as_pretty_table(cluster_types, list_columns, options)
61
+ print_results_pagination(json_response)
62
+ end
63
+ print reset,"\n"
64
+ end
65
+ return 0, nil
66
+ end
67
+
68
+ def get(args)
69
+ params = {}
70
+ options = {}
71
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
72
+ opts.banner = "Usage: #{prog_name} clusters get-type [type] "
73
+ # opts.banner = subcommand_usage("[type]")
74
+ # opts.on('--optionTypes [true|false]', String, "Include optionTypes in the response. Default is true.") do |val|
75
+ # params['optionTypes'] = (val.to_s == '' || val.to_s == 'on' || val.to_s == 'true')
76
+ # end
77
+ build_standard_get_options(opts, options)
78
+ opts.footer = <<-EOT
79
+ Get details about a specific cluster type.
80
+ [type] is required. This is the name or id of a cluster type.
81
+ EOT
82
+ end
83
+ optparse.parse!(args)
84
+ verify_args!(args:args, optparse:optparse, min:1)
85
+ id = args.join(" ")
86
+ connect(options)
87
+ params.merge!(parse_query_options(options))
88
+ cluster_type = nil
89
+
90
+ # /api/cluster-types/$id does not exist, this loads them all.
91
+ # todo: fix api to support /api/cluster-types/$id
92
+ cluster_type = find_cluster_type_by_name_or_id(id)
93
+ if cluster_type.nil?
94
+ raise_command_error("cluster type not found for name or id '#{id}'") if cluster_type.nil?
95
+ end
96
+ id = cluster_type['id']
97
+ # /api/cluster-types does not return optionTypes by default, use ?optionTypes=true
98
+ @clusters_interface.setopts(options)
99
+ if options[:dry_run]
100
+ # print_dry_run @clusters_interface.dry.get_type(id, params)
101
+ print_dry_run @clusters_interface.dry.cluster_types(params)
102
+ return
103
+ end
104
+ # json_response = @clusters_interface.get(id, params)
105
+ # cluster_type = json_response[cluster_type_object_key]
106
+ json_response = cluster_type
107
+ render_response(json_response, options) do
108
+ print_h1 "Cluster Type Details", [], options
109
+ print cyan
110
+ show_columns = list_columns = {
111
+ "ID" => 'id',
112
+ "Name" => 'name',
113
+ "Code" => 'code',
114
+ "Description" => 'description',
115
+ }
116
+ print_description_list(show_columns, cluster_type)
117
+
118
+ if cluster_type['optionTypes'] && cluster_type['optionTypes'].size > 0
119
+ print_h2 "Configuration Options"
120
+ opt_columns = [
121
+ # {"ID" => lambda {|it| it['id'] } },
122
+ {"FIELD NAME" => lambda {|it| (it['fieldContext'] && it['fieldContext'] != 'domain') ? [it['fieldContext'], it['fieldName']].join('.') : it['fieldName'] } },
123
+ {"FIELD LABEL" => lambda {|it| it['fieldLabel'] } },
124
+ {"TYPE" => lambda {|it| it['type'] } },
125
+ {"DEFAULT" => lambda {|it| it['defaultValue'] } },
126
+ {"REQUIRED" => lambda {|it| format_boolean it['required'] } },
127
+ # {"DESCRIPTION" => lambda {|it| it['description'] }, # do it!
128
+ ]
129
+ print as_pretty_table(cluster_type['optionTypes'], opt_columns)
130
+ else
131
+ # print cyan,"No option types found for this cluster type.","\n",reset
132
+ end
133
+
134
+ controller_types = cluster_type['controllerTypes'] || []
135
+ if controller_types && controller_types.size > 0
136
+ print_h2 "Controller Types"
137
+ print as_pretty_table(controller_types, [:name, :code], options)
138
+ else
139
+ # print cyan,"No worker types found for this cluster type.","\n",reset
140
+ end
141
+
142
+ worker_types = cluster_type['workerTypes'] || []
143
+ if worker_types && worker_types.size > 0
144
+ print_h2 "Worker Types"
145
+ print as_pretty_table(worker_types, [:name, :code], options)
146
+ else
147
+ # print cyan,"No worker types found for this cluster type.","\n",reset
148
+ end
149
+
150
+ print reset,"\n"
151
+ end
152
+ return 0, nil
153
+ end
154
+
155
+ protected
156
+
157
+ def find_cluster_type_by_name_or_id(val)
158
+ (val.to_s =~ /\A\d{1,}\Z/) ? find_cluster_type_by_id(val) : find_cluster_type_by_name(val)
159
+ end
160
+
161
+ def find_cluster_type_by_id(id)
162
+ get_cluster_types.find { |it| it['id'] == id.to_i }
163
+ end
164
+
165
+ def find_cluster_type_by_name(name)
166
+ get_cluster_types.find { |it| it['name'].downcase == name.downcase || it['code'].downcase == name.downcase }
167
+ end
168
+
169
+ def cluster_types_for_dropdown
170
+ get_cluster_types.collect {|it| {'id' => it['id'], 'name' => it['name'], 'code' => it['code'], 'value' => it['code']} }
171
+ end
172
+
173
+ def get_cluster_types(refresh=false)
174
+ if !@cluster_types || refresh
175
+ @cluster_types = @clusters_interface.cluster_types()['clusterTypes']
176
+ end
177
+ @cluster_types
178
+ end
179
+ end
@@ -9,6 +9,7 @@ class Morpheus::Cli::Clusters
9
9
  include Morpheus::Cli::ExecutionRequestHelper
10
10
 
11
11
  register_subcommands :list, :count, :get, :view, :add, :update, :remove, :logs, :history, {:'history-details' => :history_details}, {:'history-event' => :history_event_details}
12
+ register_subcommands :list_types, :get_type
12
13
  register_subcommands :list_workers, :add_worker, :remove_worker, :update_worker_count
13
14
  register_subcommands :list_masters
14
15
  register_subcommands :upgrade_cluster
@@ -3409,12 +3410,7 @@ class Morpheus::Cli::Clusters
3409
3410
  optparse = Morpheus::Cli::OptionParser.new do |opts|
3410
3411
  opts.banner = subcommand_usage( "[cluster] [name] [options]")
3411
3412
  build_option_type_options(opts, options, add_affinity_group_option_types)
3412
- # opts.on('--refresh [SECONDS]', String, "Refresh until execution is complete. Default interval is #{default_refresh_interval} seconds.") do |val|
3413
- # options[:refresh_interval] = val.to_s.empty? ? default_refresh_interval : val.to_f
3414
- # end
3415
- # opts.on(nil, '--no-refresh', "Do not refresh" ) do
3416
- # options[:no_refresh] = true
3417
- # end
3413
+ add_perms_options(opts, options, ['plans'])
3418
3414
  build_standard_add_options(opts, options)
3419
3415
  opts.footer = "Add affinity group to a cluster.\n" +
3420
3416
  "[cluster] is required. This is the name or id of an existing cluster.\n" +
@@ -3453,10 +3449,10 @@ class Morpheus::Cli::Clusters
3453
3449
  # end
3454
3450
 
3455
3451
  # perms
3456
- perms = prompt_permissions(options.merge({:for_affinity_group => true}), ['groupDefaults'])
3452
+ perms = prompt_permissions(options, is_master_account ? ['plans'] : ['plans', 'visibility', 'tenants'])
3457
3453
 
3458
3454
  affinity_group['resourcePermissions'] = perms['resourcePermissions'] unless perms['resourcePermissions'].nil?
3459
- affinity_group['tenants'] = perms['tenantPermissions'] unless perms['tenantPermissions'].nil?
3455
+ affinity_group['tenants'] = perms['tenantPermissions'] unless perms['tenantPermissions'].nil? || perms['tenantPermissions']['accounts'].empty?
3460
3456
  affinity_group['visibility'] = perms['resourcePool']['visibility'] if !perms['resourcePool'].nil? && !perms['resourcePool']['visibility'].nil?
3461
3457
 
3462
3458
  payload = {'affinityGroup' => affinity_group}
@@ -3496,10 +3492,8 @@ class Morpheus::Cli::Clusters
3496
3492
  options = {}
3497
3493
  optparse = Morpheus::Cli::OptionParser.new do |opts|
3498
3494
  opts.banner = subcommand_usage( "[cluster] [affinity group] [options]")
3499
- opts.on('--active [on|off]', String, "Enable affinity group") do |val|
3500
- options[:active] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == ''
3501
- end
3502
- # add_perms_options(opts, options, ['groupDefaults'])
3495
+ build_option_type_options(opts, options, update_affinity_group_option_types)
3496
+ add_perms_options(opts, options, ['plans'])
3503
3497
  build_standard_update_options(opts, options)
3504
3498
  opts.footer = "Update a cluster affinity group.\n" +
3505
3499
  "[cluster] is required. This is the name or id of an existing cluster.\n" +
@@ -3529,19 +3523,25 @@ class Morpheus::Cli::Clusters
3529
3523
  end
3530
3524
  else
3531
3525
  payload = {'affinityGroup' => {}}
3532
- payload['affinityGroup']['active'] = options[:active].nil? ? (Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'active', 'fieldLabel' => 'Active', 'type' => 'checkbox', 'description' => 'Active', 'defaultValue' => true}], options[:options], @api_client))['active'] == 'on' : options[:active]
3533
-
3534
- perms = prompt_permissions(options.merge({:available_plans => namespace_service_plans}), affinity_group['owner']['id'] == current_user['accountId'] ? ['plans', 'groupDefaults'] : ['plans', 'groupDefaults', 'visibility', 'tenants'])
3526
+ options[:params] ||= {}
3527
+ options[:params].merge!({:serverGroupId => cluster['id']})
3528
+ option_types = update_affinity_group_option_types
3529
+ v_prompt = Morpheus::Cli::OptionTypes.no_prompt(option_types, options[:options], @api_client, options[:params])
3530
+ v_prompt.deep_compact!.booleanize!
3531
+ payload.deep_merge!({'affinityGroup' => v_prompt})
3532
+
3533
+ perms = prompt_permissions(options.merge({:no_prompt => true}), is_master_account ? ['plans'] : ['plans', 'visibility', 'tenants'])
3534
+
3535
3535
  perms_payload = {}
3536
- perms_payload['resourcePermissions'] = perms['resourcePermissions'] if !perms['resourcePermissions'].nil?
3537
- perms_payload['tenantPermissions'] = perms['tenantPermissions'] if !perms['tenantPermissions'].nil?
3538
-
3539
- payload['affinityGroup']['permissions'] = perms_payload
3536
+ perms_payload['resourcePermissions'] = perms['resourcePermissions'] if !perms['resourcePermissions'].nil? && !perms['resourcePermissions'].empty?
3537
+ perms_payload['tenantPermissions'] = perms['tenantPermissions'] if !perms['tenantPermissions'].nil? && !perms['tenantPermissions']['accounts'].empty?
3538
+
3539
+ payload['affinityGroup']['permissions'] = perms_payload if !perms_payload.empty?
3540
3540
  payload['affinityGroup']['visibility'] = perms['resourcePool']['visibility'] if !perms['resourcePool'].nil? && !perms['resourcePool']['visibility'].nil?
3541
3541
 
3542
3542
  # support -O OPTION switch on top of everything
3543
3543
  if options[:options]
3544
- payload.deep_merge!({'affinityGroup' => options[:options].reject {|k,v| k.is_a?(Symbol) }})
3544
+ payload.deep_merge!({'affinityGroup' => options[:options].reject {|k,v| k.is_a?(Symbol) || payload['affinityGroup'].key?(k) }})
3545
3545
  end
3546
3546
 
3547
3547
  if payload['affinityGroup'].nil? || payload['affinityGroup'].empty?
@@ -4413,6 +4413,14 @@ class Morpheus::Cli::Clusters
4413
4413
  end
4414
4414
  end
4415
4415
 
4416
+ def list_types(args)
4417
+ Morpheus::Cli::ClusterTypes.new.list(args)
4418
+ end
4419
+
4420
+ def get_type(args)
4421
+ Morpheus::Cli::ClusterTypes.new.get(args)
4422
+ end
4423
+
4416
4424
  private
4417
4425
 
4418
4426
  def print_clusters_table(clusters, opts={})
@@ -4621,7 +4629,7 @@ class Morpheus::Cli::Clusters
4621
4629
  end
4622
4630
 
4623
4631
  def find_cluster_type_by_id(id)
4624
- get_cluster_types.find { |it| it['id'] == id }
4632
+ get_cluster_types.find { |it| it['id'] == id.to_i }
4625
4633
  end
4626
4634
 
4627
4635
  def find_cluster_type_by_name(name)
@@ -5260,7 +5268,14 @@ class Morpheus::Cli::Clusters
5260
5268
  {'fieldName' => 'affinityType', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Keep Separate', 'value' => 'KEEP_SEPARATE'}, {'name' => 'Keep Together', 'value' => 'KEEP_TOGETHER'}], 'description' => 'Choose affinity type.', 'required' => true, 'defaultValue' => 'KEEP_SEPARATE'},
5261
5269
  {'fieldName' => 'active', 'fieldLabel' => 'Active', 'type' => 'checkbox', 'defaultValue' => true},
5262
5270
  # {'fieldName' => 'pool.id', 'fieldLabel' => 'Cluster', 'type' => 'select', 'optionSourceType' => 'vmware', 'optionSource' => 'vmwareZonePoolClusters', 'description' => 'Select cluster for the affinity group.', 'required' => true},
5263
- {'fieldName' => 'servers', 'fieldLabel' => 'Server', 'type' => 'multiSelect', 'optionSource' => 'searchServers', 'description' => 'Select servers to be in the affinity group.'},
5271
+ {'fieldName' => 'servers', 'fieldLabel' => 'Server', 'type' => 'multiTypeahead', 'optionSource' => 'searchServers', 'description' => 'Select servers to be in the affinity group.'},
5272
+ ]
5273
+ end
5274
+
5275
+ def update_affinity_group_option_types
5276
+ [
5277
+ {'fieldName' => 'active', 'fieldLabel' => 'Active', 'type' => 'checkbox'},
5278
+ {'fieldName' => 'servers', 'fieldLabel' => 'Server', 'type' => 'multiTypeahead', 'optionSource' => 'searchServers', 'description' => 'Select servers to be in the affinity group.'},
5264
5279
  ]
5265
5280
  end
5266
5281
 
@@ -75,6 +75,9 @@ class Morpheus::Cli::Hosts
75
75
  # params[:clusterId] = val
76
76
  options[:cluster] = val
77
77
  end
78
+ opts.on( '--parent HOST', "Parent Host / Hypervisor Name or ID" ) do |val|
79
+ options[:parent_server_id] = val
80
+ end
78
81
  opts.on( '--plan NAME', String, "Filter by Plan name(s)" ) do |val|
79
82
  # commas used in names a lot so use --plan one --plan two
80
83
  params['plan'] ||= []
@@ -188,6 +191,13 @@ class Morpheus::Cli::Hosts
188
191
  params['clusterId'] = cluster['id']
189
192
  end
190
193
  end
194
+ parent_hosts = nil
195
+ if options[:parent_server_id]
196
+ parent_hosts = parse_id_list(options[:parent_server_id]).collect do |parent_server_id|
197
+ find_host_by_name_or_id(parent_server_id)
198
+ end
199
+ params['parentServerId'] = parent_hosts.collect {|it| it['id'] }
200
+ end
191
201
  params['labels'] = options[:labels] if options[:labels]
192
202
  if options[:tags] && !options[:tags].empty?
193
203
  options[:tags].each do |k,v|
@@ -233,6 +243,9 @@ class Morpheus::Cli::Hosts
233
243
  elsif params['clusterId']
234
244
  subtitles << "Cluster: #{params['clusterId']}".strip
235
245
  end
246
+ if parent_hosts
247
+ subtitles << "Parent Host: #{parent_hosts.collect {|it| it['name'] }.join(", ")}".strip
248
+ end
236
249
  subtitles += parse_list_subtitles(options)
237
250
  print_h1 title, subtitles, options
238
251
  if servers.empty?
@@ -379,6 +392,13 @@ class Morpheus::Cli::Hosts
379
392
  opts.on( '-i', '--ip IPADDRESS', "Filter by IP Address" ) do |val|
380
393
  params[:ip] = val
381
394
  end
395
+ opts.on( '--cluster CLUSTER', '--cluster CLUSTER', "Filter by Cluster Name or ID" ) do |val|
396
+ # params[:clusterId] = val
397
+ options[:cluster] = val
398
+ end
399
+ opts.on( '--parent HOST', "Parent Host / Hypervisor Name or ID" ) do |val|
400
+ options[:parent_server_id] = val
401
+ end
382
402
  opts.on('--vm', "Show only virtual machines" ) do
383
403
  params[:vm] = true
384
404
  end
@@ -403,9 +423,6 @@ class Morpheus::Cli::Hosts
403
423
  opts.on( '--created-by USER', "Created By User Username or ID" ) do |val|
404
424
  options[:created_by] = val
405
425
  end
406
- opts.on('--details', "Display more details: memory and storage usage used / max values." ) do
407
- options[:details] = true
408
- end
409
426
  opts.on( '-s', '--search PHRASE', "Search Phrase" ) do |phrase|
410
427
  options[:phrase] = phrase
411
428
  end
@@ -443,6 +460,23 @@ class Morpheus::Cli::Hosts
443
460
  params['createdBy'] = created_by_ids
444
461
  # params['ownerId'] = created_by_ids # 4.2.1+
445
462
  end
463
+ cluster = nil
464
+ if options[:cluster]
465
+ if options[:cluster].to_s =~ /\A\d{1,}\Z/
466
+ params['clusterId'] = options[:cluster]
467
+ else
468
+ cluster = find_cluster_by_name_or_id(options[:cluster])
469
+ return 1 if cluster.nil?
470
+ params['clusterId'] = cluster['id']
471
+ end
472
+ end
473
+ parent_hosts = nil
474
+ if options[:parent_server_id]
475
+ parent_hosts = parse_id_list(options[:parent_server_id]).collect do |parent_server_id|
476
+ find_host_by_name_or_id(parent_server_id)
477
+ end
478
+ params['parentServerId'] = parent_hosts.collect {|it| it['id'] }
479
+ end
446
480
  @servers_interface.setopts(options)
447
481
  if options[:dry_run]
448
482
  print_dry_run @servers_interface.dry.list(params)
@@ -83,6 +83,9 @@ class Morpheus::Cli::Instances
83
83
  opts.on( '-H', '--host HOST', "Host Name or ID" ) do |val|
84
84
  options[:host] = val
85
85
  end
86
+ opts.on( '--parent HOST', "Parent Host / Hypervisor Name or ID" ) do |val|
87
+ options[:parent_server_id] = val
88
+ end
86
89
  opts.on( '--owner USER', "Owner Username or ID" ) do |val|
87
90
  options[:owner] = val
88
91
  end
@@ -175,6 +178,14 @@ class Morpheus::Cli::Instances
175
178
  params['serverId'] = host['id']
176
179
  end
177
180
 
181
+ parent_hosts = nil
182
+ if options[:parent_server_id]
183
+ parent_hosts = parse_id_list(options[:parent_server_id]).collect do |parent_server_id|
184
+ find_host_by_name_or_id(parent_server_id)
185
+ end
186
+ params['parentServerId'] = parent_hosts.collect {|it| it['id'] }
187
+ end
188
+
178
189
  account = nil
179
190
  #todo: user = find_available_user_option(owner_id)
180
191
 
@@ -224,6 +235,9 @@ class Morpheus::Cli::Instances
224
235
  if host
225
236
  subtitles << "Host: #{host['name']}".strip
226
237
  end
238
+ if parent_hosts
239
+ subtitles << "Parent Host: #{parent_hosts.collect {|it| it['name'] }.join(", ")}".strip
240
+ end
227
241
  if options[:owner]
228
242
  subtitles << "Created By: #{options[:owner]}"
229
243
  end
@@ -315,6 +329,9 @@ class Morpheus::Cli::Instances
315
329
  opts.on( '-H', '--host HOST', "Host Name or ID" ) do |val|
316
330
  options[:host] = val
317
331
  end
332
+ opts.on( '--parent HOST', "Parent Host (Hypervisor) Name or ID" ) do |val|
333
+ options[:parent_server_id] = val
334
+ end
318
335
  opts.on( '--owner USER', "Owner Username or ID" ) do |val|
319
336
  options[:owner] = val
320
337
  end
@@ -350,6 +367,14 @@ class Morpheus::Cli::Instances
350
367
  params['serverId'] = host['id']
351
368
  end
352
369
 
370
+ parent_hosts = nil
371
+ if options[:parent_server_id]
372
+ parent_hosts = parse_id_list(options[:parent_server_id]).collect do |parent_server_id|
373
+ find_host_by_name_or_id(parent_server_id)
374
+ end
375
+ params['parentServerId'] = parent_hosts.collect {|it| it['id'] }
376
+ end
377
+
353
378
  account = nil
354
379
  if options[:owner]
355
380
  created_by_ids = find_all_user_ids(account ? account['id'] : nil, options[:owner])