morpheus-cli 5.5.3.2 → 6.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +8 -0
- data/lib/morpheus/api/cloud_resource_pools_interface.rb +28 -3
- data/lib/morpheus/api/containers_interface.rb +10 -0
- data/lib/morpheus/api/doc_interface.rb +1 -10
- data/lib/morpheus/api/jobs_interface.rb +2 -2
- data/lib/morpheus/api/key_pairs_interface.rb +9 -0
- data/lib/morpheus/api/network_floating_ips_interface.rb +37 -0
- data/lib/morpheus/api/resource_pool_groups_interface.rb +51 -0
- data/lib/morpheus/cli/cli_command.rb +17 -11
- data/lib/morpheus/cli/commands/appliance_settings_command.rb +5 -0
- data/lib/morpheus/cli/commands/apps.rb +12 -6
- data/lib/morpheus/cli/commands/catalog_item_types_command.rb +44 -12
- data/lib/morpheus/cli/commands/clusters.rb +23 -2
- data/lib/morpheus/cli/commands/containers_command.rb +129 -4
- data/lib/morpheus/cli/commands/doc.rb +14 -13
- data/lib/morpheus/cli/commands/hosts.rb +2 -0
- data/lib/morpheus/cli/commands/instances.rb +9 -3
- data/lib/morpheus/cli/commands/jobs_command.rb +50 -3
- data/lib/morpheus/cli/commands/key_pairs.rb +94 -33
- data/lib/morpheus/cli/commands/network_floating_ips.rb +109 -0
- data/lib/morpheus/cli/commands/reports_command.rb +8 -1
- data/lib/morpheus/cli/commands/resource_pool_groups_command.rb +586 -0
- data/lib/morpheus/cli/commands/roles.rb +10 -10
- data/lib/morpheus/cli/commands/service_catalog_command.rb +40 -2
- data/lib/morpheus/cli/commands/service_plans_command.rb +51 -22
- data/lib/morpheus/cli/commands/shell.rb +1 -1
- data/lib/morpheus/cli/commands/tasks.rb +130 -35
- data/lib/morpheus/cli/commands/workflows.rb +109 -23
- data/lib/morpheus/cli/mixins/infrastructure_helper.rb +148 -0
- data/lib/morpheus/cli/mixins/jobs_helper.rb +30 -3
- data/lib/morpheus/cli/mixins/processes_helper.rb +2 -26
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +2 -1
- data/lib/morpheus/cli/option_types.rb +2 -2
- data/lib/morpheus/cli/version.rb +1 -1
- data/test/cli/doc_test.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4160be97bfb96acf0fe1091e9e8d6ecde617bd2aba547ef1cfab8a11d6134ecf
|
4
|
+
data.tar.gz: 5e0675e4e1061595e560e2395625e7a7546813e68e09a8237ccd33d92aeb948d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a2992a310163d78082f7d748ca4ae50c673c32e7ae782497bb89f721135ed66509549c124290e9b4bd644cad2e3838c878331427ddd1090325f8946c7d30e731
|
7
|
+
data.tar.gz: 48ec07412e0cdcad359ea2dc050cc5017a9a39e368fb662e50b880628213fc4681b85da9cd5d8503ea7426be0fbac77b5e61d2dd8bc397ab13f0ce21695d2758
|
data/Dockerfile
CHANGED
@@ -400,6 +400,10 @@ class Morpheus::APIClient
|
|
400
400
|
Morpheus::CloudResourcePoolsInterface.new(common_interface_options).setopts(@options)
|
401
401
|
end
|
402
402
|
|
403
|
+
def resource_pool_groups
|
404
|
+
Morpheus::ResourcePoolGroupsInterface.new(common_interface_options).setopts(@options)
|
405
|
+
end
|
406
|
+
|
403
407
|
def cloud_folders
|
404
408
|
Morpheus::CloudFoldersInterface.new(common_interface_options).setopts(@options)
|
405
409
|
end
|
@@ -950,6 +954,10 @@ class Morpheus::APIClient
|
|
950
954
|
Morpheus::SecurityScansInterface.new(common_interface_options).setopts(@options)
|
951
955
|
end
|
952
956
|
|
957
|
+
def network_floating_ips
|
958
|
+
Morpheus::NetworkFloatingIpsInterface.new(common_interface_options).setopts(@options)
|
959
|
+
end
|
960
|
+
|
953
961
|
def rest(endpoint)
|
954
962
|
Morpheus::RestInterface.new(common_interface_options).setopts(@options.merge({base_path: "#{@base_url}/api/#{endpoint}"}))
|
955
963
|
end
|
@@ -4,7 +4,15 @@ class Morpheus::CloudResourcePoolsInterface < Morpheus::APIClient
|
|
4
4
|
|
5
5
|
def get(cloud_id, id, params={})
|
6
6
|
raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
|
7
|
-
url = cloud_id.nil? ? "#{@base_url}/api/zones/resource-pools/#{id}" : "#{@base_url}/api/zones/#{cloud_id}/resource-pools/#{id}"
|
7
|
+
url = cloud_id.nil? ? "#{@base_url}/api/zones/resource-pools/#{update_resource_pool_id(id)}" : "#{@base_url}/api/zones/#{cloud_id}/resource-pools/#{update_resource_pool_id(id)}"
|
8
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
9
|
+
opts = {method: :get, url: url, headers: headers}
|
10
|
+
execute(opts)
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_without_cloud(id, params={})
|
14
|
+
raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
|
15
|
+
url = "#{@base_url}/api/resource-pools/#{update_resource_pool_id(id)}"
|
8
16
|
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
9
17
|
opts = {method: :get, url: url, headers: headers}
|
10
18
|
execute(opts)
|
@@ -17,6 +25,13 @@ class Morpheus::CloudResourcePoolsInterface < Morpheus::APIClient
|
|
17
25
|
execute(opts)
|
18
26
|
end
|
19
27
|
|
28
|
+
def list_without_cloud(params={})
|
29
|
+
url = "#{@base_url}/api/resource-pools"
|
30
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
31
|
+
opts = {method: :get, url: url, headers: headers}
|
32
|
+
execute(opts)
|
33
|
+
end
|
34
|
+
|
20
35
|
def create(cloud_id, payload)
|
21
36
|
url = "#{@base_url}/api/zones/#{cloud_id}/resource-pools"
|
22
37
|
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
@@ -25,17 +40,27 @@ class Morpheus::CloudResourcePoolsInterface < Morpheus::APIClient
|
|
25
40
|
end
|
26
41
|
|
27
42
|
def update(cloud_id, id, payload)
|
28
|
-
url = "#{@base_url}/api/zones/#{cloud_id}/resource-pools/#{id}"
|
43
|
+
url = "#{@base_url}/api/zones/#{cloud_id}/resource-pools/#{update_resource_pool_id(id)}"
|
29
44
|
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
30
45
|
opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
|
31
46
|
execute(opts)
|
32
47
|
end
|
33
48
|
|
34
49
|
def destroy(cloud_id, id, params={})
|
35
|
-
url = "#{@base_url}/api/zones/#{cloud_id}/resource-pools/#{id}"
|
50
|
+
url = "#{@base_url}/api/zones/#{cloud_id}/resource-pools/#{update_resource_pool_id(id)}"
|
36
51
|
headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
37
52
|
opts = {method: :delete, url: url, headers: headers}
|
38
53
|
execute(opts)
|
39
54
|
end
|
40
55
|
|
56
|
+
private
|
57
|
+
|
58
|
+
def update_resource_pool_id(id)
|
59
|
+
id_string = id.to_s
|
60
|
+
if id_string["pool-"]
|
61
|
+
return id_string[5..-1]
|
62
|
+
end
|
63
|
+
return id
|
64
|
+
end
|
65
|
+
|
41
66
|
end
|
@@ -132,4 +132,14 @@ class Morpheus::ContainersInterface < Morpheus::APIClient
|
|
132
132
|
execute(method: :put, url: "#{base_path}/#{container_id}/clone-image", payload: payload, headers: headers)
|
133
133
|
end
|
134
134
|
|
135
|
+
def attach_floating_ip(container_id, payload={}, headers={})
|
136
|
+
validate_id!(container_id)
|
137
|
+
execute(method: :put, url: "#{base_path}/#{container_id}/attach-floating-ip", payload: payload, headers: headers)
|
138
|
+
end
|
139
|
+
|
140
|
+
def detach_floating_ip(container_id, payload={}, headers={})
|
141
|
+
validate_id!(container_id)
|
142
|
+
execute(method: :put, url: "#{base_path}/#{container_id}/detach-floating-ip", payload: payload, headers: headers)
|
143
|
+
end
|
144
|
+
|
135
145
|
end
|
@@ -1,11 +1,6 @@
|
|
1
1
|
require 'morpheus/api/api_client'
|
2
2
|
|
3
3
|
class Morpheus::DocInterface < Morpheus::APIClient
|
4
|
-
|
5
|
-
# no Authorization header is required
|
6
|
-
def authorization_required?
|
7
|
-
false
|
8
|
-
end
|
9
4
|
|
10
5
|
def list(params={})
|
11
6
|
url = "/api/doc"
|
@@ -24,8 +19,6 @@ class Morpheus::DocInterface < Morpheus::APIClient
|
|
24
19
|
execute(method: :get, url: url, headers: headers, timeout: 172800, parse_json: !is_yaml)
|
25
20
|
end
|
26
21
|
|
27
|
-
alias :swagger :openapi
|
28
|
-
|
29
22
|
def download_openapi(outfile, params={})
|
30
23
|
# note that RestClient.execute still requires the full path with base_url
|
31
24
|
url = "#{@base_url}/api/doc/openapi"
|
@@ -33,7 +26,7 @@ class Morpheus::DocInterface < Morpheus::APIClient
|
|
33
26
|
if fmt
|
34
27
|
url = url + "." + fmt
|
35
28
|
end
|
36
|
-
headers = {params: params}
|
29
|
+
headers = {params: params, authorization: "Bearer #{@access_token}"}
|
37
30
|
opts = {method: :get, url: url, headers: headers, timeout: 172800, parse_json: false}
|
38
31
|
|
39
32
|
if @dry_run
|
@@ -54,6 +47,4 @@ class Morpheus::DocInterface < Morpheus::APIClient
|
|
54
47
|
http_response
|
55
48
|
end
|
56
49
|
|
57
|
-
alias :swagger :download_openapi
|
58
|
-
|
59
50
|
end
|
@@ -43,10 +43,10 @@ class Morpheus::JobsInterface < Morpheus::APIClient
|
|
43
43
|
execute(method: :delete, url: url, headers: headers)
|
44
44
|
end
|
45
45
|
|
46
|
-
def execute_job(id, params={})
|
46
|
+
def execute_job(id, payload={}, params={})
|
47
47
|
url = "#{base_path}/#{id}/execute"
|
48
48
|
headers = { params: params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
49
|
-
execute(method: :put, url: url, headers: headers)
|
49
|
+
execute(method: :put, url: url, headers: headers, payload: payload.to_json)
|
50
50
|
end
|
51
51
|
|
52
52
|
=begin
|
@@ -45,4 +45,13 @@ class Morpheus::KeyPairsInterface < Morpheus::APIClient
|
|
45
45
|
opts = {method: :delete, url: url, headers: headers}
|
46
46
|
execute(opts)
|
47
47
|
end
|
48
|
+
|
49
|
+
def generate(account_id, options)
|
50
|
+
url = "#{@base_url}/api/key-pairs/generate"
|
51
|
+
headers = { :params => {}, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
52
|
+
headers[:params]['accountId'] = account_id if account_id
|
53
|
+
payload = options
|
54
|
+
opts = {method: :post, url: url, headers: headers, payload: payload.to_json}
|
55
|
+
execute(opts)
|
56
|
+
end
|
48
57
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'morpheus/api/api_client'
|
2
|
+
|
3
|
+
class Morpheus::NetworkFloatingIpsInterface < Morpheus::APIClient
|
4
|
+
|
5
|
+
def base_path
|
6
|
+
"/api/networks/floating-ips"
|
7
|
+
end
|
8
|
+
|
9
|
+
def list(params={}, headers={})
|
10
|
+
execute(method: :get, url: "#{base_path}", params: params, headers: headers)
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(id, params={}, headers={})
|
14
|
+
validate_id!(id)
|
15
|
+
execute(method: :get, url: "#{base_path}/#{CGI::escape(id.to_s)}", params: params, headers: headers)
|
16
|
+
end
|
17
|
+
|
18
|
+
# def create(payload, params={}, headers={})
|
19
|
+
# execute(method: :post, url: "#{base_path}", params: params, payload: payload, headers: headers)
|
20
|
+
# end
|
21
|
+
|
22
|
+
# def update(id, payload, params={}, headers={})
|
23
|
+
# validate_id!(id)
|
24
|
+
# execute(method: :put, url: "#{base_path}/#{CGI::escape(id.to_s)}", params: params, payload: payload, headers: headers)
|
25
|
+
# end
|
26
|
+
|
27
|
+
def destroy(id, params = {}, headers={})
|
28
|
+
validate_id!(id)
|
29
|
+
execute(method: :delete, url: "#{base_path}/#{CGI::escape(id.to_s)}", params: params, headers: headers)
|
30
|
+
end
|
31
|
+
|
32
|
+
def release(id, payload={}, params={}, headers={})
|
33
|
+
validate_id!(id)
|
34
|
+
execute(method: :put, url: "#{base_path}/#{CGI::escape(id.to_s)}/release", params: params, payload: payload, headers: headers)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'morpheus/api/api_client'
|
2
|
+
|
3
|
+
class Morpheus::ResourcePoolGroupsInterface < Morpheus::APIClient
|
4
|
+
|
5
|
+
def get(id, params={})
|
6
|
+
raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
|
7
|
+
url = "#{@base_url}/api/resource-pools/groups/#{update_resource_pool_group_id(id)}"
|
8
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
9
|
+
opts = {method: :get, url: url, headers: headers}
|
10
|
+
execute(opts)
|
11
|
+
end
|
12
|
+
|
13
|
+
def list(params={})
|
14
|
+
url = "#{@base_url}/api/resource-pools/groups"
|
15
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
16
|
+
opts = {method: :get, url: url, headers: headers}
|
17
|
+
execute(opts)
|
18
|
+
end
|
19
|
+
|
20
|
+
def create(payload)
|
21
|
+
url = "#{@base_url}/api/resource-pools/groups"
|
22
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
23
|
+
opts = {method: :post, url: url, headers: headers, payload: payload.to_json}
|
24
|
+
execute(opts)
|
25
|
+
end
|
26
|
+
|
27
|
+
def update(id, payload)
|
28
|
+
url = "#{@base_url}/api/resource-pools/groups/#{update_resource_pool_group_id(id)}"
|
29
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
30
|
+
opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
|
31
|
+
execute(opts)
|
32
|
+
end
|
33
|
+
|
34
|
+
def destroy(id, params={})
|
35
|
+
url ="#{@base_url}/api/resource-pools/groups/#{update_resource_pool_group_id(id)}"
|
36
|
+
headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
37
|
+
opts = {method: :delete, url: url, headers: headers}
|
38
|
+
execute(opts)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def update_resource_pool_group_id(id)
|
44
|
+
id_string = id.to_s
|
45
|
+
if id_string["poolGroup-"]
|
46
|
+
return id_string[10..-1]
|
47
|
+
end
|
48
|
+
return id
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -149,6 +149,7 @@ module Morpheus
|
|
149
149
|
#opts.separator ""
|
150
150
|
#opts.separator "Options:"
|
151
151
|
options[:options] ||= {} # this is where these go..for now
|
152
|
+
options[:option_types] = (options[:option_types] || []) + option_types
|
152
153
|
custom_options = options[:options]
|
153
154
|
|
154
155
|
# add each one to the OptionParser
|
@@ -345,6 +346,7 @@ module Morpheus
|
|
345
346
|
custom_option_args = option.sub(/\s?\=\s?/, '__OPTION_DELIM__').split('__OPTION_DELIM__')
|
346
347
|
custom_options = options[:options]
|
347
348
|
option_name_args = custom_option_args[0].split('.')
|
349
|
+
option_type = (options[:option_types] || []).find {|it| it['fieldName'] == custom_option_args[0]} || {}
|
348
350
|
if option_name_args.count > 1
|
349
351
|
nested_options = custom_options
|
350
352
|
option_name_args.each_with_index do |name_element,index|
|
@@ -353,11 +355,13 @@ module Morpheus
|
|
353
355
|
nested_options = nested_options[name_element]
|
354
356
|
else
|
355
357
|
val = custom_option_args[1]
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
358
|
+
unless option_type['noParse']
|
359
|
+
if (val.to_s[0] == '{' && val.to_s[-1] == '}') || (val.to_s[0] == '[' && val.to_s[-1] == ']')
|
360
|
+
begin
|
361
|
+
val = JSON.parse(val)
|
362
|
+
rescue
|
363
|
+
Morpheus::Logging::DarkPrinter.puts "Failed to parse option value '#{val}' as JSON" if Morpheus::Logging.debug?
|
364
|
+
end
|
361
365
|
end
|
362
366
|
end
|
363
367
|
nested_options[name_element] = val
|
@@ -365,11 +369,13 @@ module Morpheus
|
|
365
369
|
end
|
366
370
|
else
|
367
371
|
val = custom_option_args[1]
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
372
|
+
unless option_type['noParse']
|
373
|
+
if (val.to_s[0] == '{' && val.to_s[-1] == '}') || (val.to_s[0] == '[' && val.to_s[-1] == ']')
|
374
|
+
begin
|
375
|
+
val = JSON.parse(val)
|
376
|
+
rescue
|
377
|
+
Morpheus::Logging::DarkPrinter.puts "Failed to parse option value '#{val}' as JSON" if Morpheus::Logging.debug?
|
378
|
+
end
|
373
379
|
end
|
374
380
|
end
|
375
381
|
custom_options[custom_option_args[0]] = val
|
@@ -1347,7 +1353,7 @@ module Morpheus
|
|
1347
1353
|
if record.nil?
|
1348
1354
|
# avoid double error render by exiting here, ew
|
1349
1355
|
exit 1
|
1350
|
-
raise_command_error "
|
1356
|
+
raise_command_error "#{type.titleize} not found for '#{val}'"
|
1351
1357
|
end
|
1352
1358
|
params[param_name] = record['id']
|
1353
1359
|
else
|
@@ -89,6 +89,8 @@ class Morpheus::Cli::ApplianceSettingsCommand
|
|
89
89
|
# Currency Settings
|
90
90
|
"Currency Provider" => lambda {|it| it['currencyProvider'] },
|
91
91
|
"Currency Provider API Key" => lambda {|it| it['currencyKey'] },
|
92
|
+
# Retention Settings
|
93
|
+
"Stats Retainment Period" => lambda {|it| it['statsRetainmentPeriod'] ? it['statsRetainmentPeriod'].to_s + ' days' : '' },
|
92
94
|
}
|
93
95
|
print_description_list(description_cols, appliance_settings)
|
94
96
|
|
@@ -215,6 +217,9 @@ class Morpheus::Cli::ApplianceSettingsCommand
|
|
215
217
|
opts.on("--disable-all-clouds", "Set all cloud types enabled status off, can be used in conjunction with --enable-clouds options") do
|
216
218
|
params['disableAllZoneTypes'] = true
|
217
219
|
end
|
220
|
+
opts.on("--stats-retainment-period DAYS", Integer, "Stats retainment period. The number of days stats should be available. Can be 30, 60, or 90.") do |val|
|
221
|
+
params['statsRetainmentPeriod'] = val.to_i
|
222
|
+
end
|
218
223
|
build_common_options(opts, options, [:json, :payload, :dry_run, :quiet, :remote])
|
219
224
|
end
|
220
225
|
|
@@ -781,11 +781,11 @@ class Morpheus::Cli::Apps
|
|
781
781
|
print_h2 "#{app_tier['tier']['name']}", options
|
782
782
|
print cyan
|
783
783
|
tier_instances = (app_tier['appInstances'] || []).collect {|it| it['instance']}
|
784
|
-
|
785
|
-
if
|
784
|
+
instance_list = tier_instances.collect { |tier_instance| instances.find { |i| i['id'] == tier_instance['id'] } }
|
785
|
+
if instance_list.empty?
|
786
786
|
puts yellow, "This tier is empty", reset
|
787
787
|
else
|
788
|
-
instances_rows =
|
788
|
+
instances_rows = instance_list.collect do |instance|
|
789
789
|
connection_string = ''
|
790
790
|
if !instance['connectionInfo'].nil? && instance['connectionInfo'].empty? == false
|
791
791
|
connection_string = "#{instance['connectionInfo'][0]['ip']}:#{instance['connectionInfo'][0]['port']}"
|
@@ -1020,7 +1020,7 @@ EOT
|
|
1020
1020
|
end
|
1021
1021
|
|
1022
1022
|
def apply(args)
|
1023
|
-
default_refresh_interval =
|
1023
|
+
default_refresh_interval = 5
|
1024
1024
|
params, payload, options = {}, {}, {}
|
1025
1025
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1026
1026
|
opts.banner = subcommand_usage("[app] [options]")
|
@@ -1381,9 +1381,15 @@ EOT
|
|
1381
1381
|
opts.on( '--keep-backups', '--keep-backups', "Preserve copy of backups" ) do
|
1382
1382
|
query_params[:keepBackups] = 'on'
|
1383
1383
|
end
|
1384
|
-
opts.on('--
|
1385
|
-
query_params[:
|
1384
|
+
opts.on('--release-ips [on|off]', ['on','off'], "Release Floating IPs. Default is on. Applies to certain types only. Only applies when used with --remove-instances") do |val|
|
1385
|
+
query_params[:releaseFloatingIps] = val.nil? ? 'on' : val
|
1386
|
+
query_params[:releaseEIPs] = query_params[:releaseFloatingIps] # old parameter before 6.0
|
1386
1387
|
end
|
1388
|
+
opts.on('--releaseEIPs [on|off]', ['on','off'], "Alias for Release Floating IPs") do |val|
|
1389
|
+
query_params[:releaseFloatingIps] = val.nil? ? 'on' : val
|
1390
|
+
query_params[:releaseEIPs] = query_params[:releaseFloatingIps] # old parameter before 6.0
|
1391
|
+
end
|
1392
|
+
opts.add_hidden_option('--releaseEIPs')
|
1387
1393
|
opts.on( '-f', '--force', "Force Delete" ) do
|
1388
1394
|
query_params[:force] = 'on'
|
1389
1395
|
end
|
@@ -43,6 +43,12 @@ class Morpheus::Cli::CatalogItemTypesCommand
|
|
43
43
|
opts.on('--all-labels LABEL', String, "Filter by labels, must match all of the values") do |val|
|
44
44
|
add_query_parameter(params, 'allLabels', parse_labels(val))
|
45
45
|
end
|
46
|
+
opts.on('--code CODE', String, "Filter by code" ) do |val|
|
47
|
+
params[:code] = val
|
48
|
+
end
|
49
|
+
opts.on('-c', '--category CATEGORY', String, "Filter by category") do |val|
|
50
|
+
add_query_parameter(params, 'category', val)
|
51
|
+
end
|
46
52
|
build_standard_list_options(opts, options)
|
47
53
|
opts.footer = "List catalog item types."
|
48
54
|
end
|
@@ -212,6 +218,23 @@ EOT
|
|
212
218
|
print reset,"(blank)","\n",reset
|
213
219
|
end
|
214
220
|
elsif item_type_code == 'workflow' || item_type_code == 'operationalworkflow' || item_type_code == 'taskset'
|
221
|
+
print_h2 "Workflow Config"
|
222
|
+
if catalog_item_type['workflowConfig']
|
223
|
+
#print reset,(JSON.pretty_generate(config) rescue config),"\n",reset
|
224
|
+
#print reset,(as_yaml(config, options) rescue config),"\n",reset
|
225
|
+
config_string = catalog_item_type['workflowConfig'] || ""
|
226
|
+
config_lines = config_string.split("\n")
|
227
|
+
config_line_count = config_lines.size
|
228
|
+
max_lines = 10
|
229
|
+
if config_lines.size > max_lines
|
230
|
+
config_string = config_lines.first(max_lines).join("\n")
|
231
|
+
config_string << "\n\n"
|
232
|
+
config_string << "#{dark}(#{(config_line_count - max_lines)} more lines were not shown, use -c to show the config)#{reset}"
|
233
|
+
end
|
234
|
+
print reset,config_string.chomp("\n"),"\n",reset
|
235
|
+
else
|
236
|
+
print reset,"(blank)","\n",reset
|
237
|
+
end
|
215
238
|
end
|
216
239
|
end
|
217
240
|
|
@@ -227,7 +250,7 @@ EOT
|
|
227
250
|
end
|
228
251
|
|
229
252
|
def add(args)
|
230
|
-
options = {}
|
253
|
+
options = {:option_types => add_catalog_item_type_option_types}
|
231
254
|
params = {}
|
232
255
|
logo_file = nil
|
233
256
|
dark_logo_file = nil
|
@@ -657,6 +680,8 @@ EOT
|
|
657
680
|
{
|
658
681
|
"ID" => 'id',
|
659
682
|
"Name" => 'name',
|
683
|
+
"Code" => 'code',
|
684
|
+
"Category" => 'category',
|
660
685
|
"Labels" => lambda {|it| format_list(it['labels'], '', 3) },
|
661
686
|
"Description" => 'description',
|
662
687
|
"Type" => lambda {|it| format_catalog_type(it) },
|
@@ -680,6 +705,8 @@ EOT
|
|
680
705
|
"Name" => 'name',
|
681
706
|
"Labels" => lambda {|it| format_list(it['labels']) },
|
682
707
|
"Description" => 'description',
|
708
|
+
"Code" => 'code',
|
709
|
+
"Category" => 'category',
|
683
710
|
"Type" => lambda {|it| format_catalog_type(it) },
|
684
711
|
"Visibility" => 'visibility',
|
685
712
|
"Layout Code" => 'layoutCode',
|
@@ -689,6 +716,7 @@ EOT
|
|
689
716
|
# "Content" => lambda {|it| it['content'] },
|
690
717
|
"Enabled" => lambda {|it| format_boolean(it['enabled']) },
|
691
718
|
"Featured" => lambda {|it| format_boolean(it['featured']) },
|
719
|
+
"Allow Quantity" => lambda {|it| format_boolean(it['allowQuantity']) },
|
692
720
|
#"Config" => lambda {|it| it['config'] },
|
693
721
|
"Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
694
722
|
"Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
|
@@ -725,21 +753,25 @@ EOT
|
|
725
753
|
[
|
726
754
|
{'code' => 'catalogItemType.type', 'shorthand' => '-t', 'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Instance', 'value' => 'instance'}, {'name' => 'Blueprint', 'value' => 'blueprint'}, {'name' => 'Workflow', 'value' => 'workflow'}], 'defaultValue' => 'instance', 'required' => true, 'displayOrder' => 1},
|
727
755
|
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 2},
|
728
|
-
{'fieldName' => '
|
729
|
-
{'fieldName' => '
|
730
|
-
{'fieldName' => '
|
731
|
-
{'fieldName' => '
|
732
|
-
{'fieldName' => '
|
733
|
-
{'fieldName' => '
|
756
|
+
{'fieldName' => 'code', 'fieldLabel' => 'Code', 'type' => 'text', 'displayOrder' => 3},
|
757
|
+
{'fieldName' => 'category', 'fieldLabel' => 'Category', 'type' => 'text', 'displayOrder' => 3.5},
|
758
|
+
{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'displayOrder' => 4},
|
759
|
+
{'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'defaultValue' => true, 'displayOrder' => 5},
|
760
|
+
{'fieldName' => 'featured', 'fieldLabel' => 'Featured', 'type' => 'checkbox', 'defaultValue' => false, 'displayOrder' => 6},
|
761
|
+
{'fieldName' => 'allowQuantity', 'fieldLabel' => 'Allow Quantity', 'type' => 'checkbox', 'defaultValue' => false, 'displayOrder' => 7},
|
762
|
+
{'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'required' => true, 'displayOrder' => 8},
|
763
|
+
{'fieldName' => 'layoutCode', 'fieldLabel' => 'Layout Code', 'type' => 'text', 'required' => false, 'displayOrder' => 9},
|
764
|
+
{'fieldName' => 'iconPath', 'fieldLabel' => 'Logo', 'type' => 'select', 'optionSource' => 'iconList', 'displayOrder' => 10},
|
734
765
|
#{'fieldName' => 'optionTypes', 'fieldLabel' => 'Option Types', 'type' => 'text', 'description' => 'Option Types to include, comma separated list of names or IDs.', 'displayOrder' => 8},
|
735
|
-
{'dependsOnCode' => 'catalogItemType.type:instance', 'fieldName' => 'config', 'fieldLabel' => 'Config', 'type' => 'code-editor', 'description' => 'JSON or YAML', 'required' => true, 'displayOrder' =>
|
736
|
-
{'dependsOnCode' => 'catalogItemType.type:
|
737
|
-
{'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => '
|
738
|
-
{'dependsOnCode' => 'catalogItemType.type:
|
766
|
+
{'dependsOnCode' => 'catalogItemType.type:instance', 'fieldName' => 'config', 'fieldLabel' => 'Config', 'type' => 'code-editor', 'description' => 'JSON or YAML', 'required' => true, 'displayOrder' => 11},
|
767
|
+
{'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'workflowConfig', 'fieldLabel' => 'Config', 'type' => 'textarea', 'description' => 'Enter configuration for the Workflow', 'required' => false, 'noParse' => true, 'displayOrder' => 11},
|
768
|
+
{'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => 'blueprint', 'fieldLabel' => 'Blueprint', 'type' => 'select', 'optionSource' => 'blueprints', 'description' => 'Choose a blueprint to apply to the catalog item.', 'required' => true, 'noParams' => true, 'displayOrder' => 12},
|
769
|
+
{'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => 'appSpec', 'fieldLabel' => 'App Spec', 'type' => 'code-editor', 'description' => 'Enter a spec in the for the App, the Scribe YAML format', 'required' => true, 'displayOrder' => 13},
|
770
|
+
{'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'workflow', 'fieldLabel' => 'Workflow', 'type' => 'select', 'optionSource' => 'operationWorkflows', 'description' => 'Enter a spec in the for the App, the Scribe YAML format', 'required' => true, 'noParams' => true, 'displayOrder' => 14},
|
739
771
|
{'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'context', 'fieldLabel' => 'Context Type', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
|
740
772
|
[{'name' => "Select", 'value' => ""}, {'name' => "None", 'value' => "appliance"}, {'name' => "Instance", 'value' => "instance"}, {'name' => "Server", 'value' => "server"}]
|
741
773
|
}, 'description' => 'Context for operational workflow, determines target type', 'defaultValue' => 'Select', 'required' => false},
|
742
|
-
{'fieldName' => 'content', 'fieldLabel' => 'Content', 'type' => 'code-editor', 'description' => 'Wiki Page Content describing the catalog item', 'displayOrder' =>
|
774
|
+
{'fieldName' => 'content', 'fieldLabel' => 'Content', 'type' => 'code-editor', 'description' => 'Wiki Page Content describing the catalog item', 'displayOrder' => 15}
|
743
775
|
]
|
744
776
|
end
|
745
777
|
|
@@ -33,6 +33,7 @@ class Morpheus::Cli::Clusters
|
|
33
33
|
@security_groups_interface = @api_client.security_groups
|
34
34
|
#@security_group_rules_interface = @api_client.security_group_rules
|
35
35
|
@cloud_resource_pools_interface = @api_client.cloud_resource_pools
|
36
|
+
@resource_pool_groups_interface = @api_client.resource_pool_groups
|
36
37
|
@clouds_interface = @api_client.clouds
|
37
38
|
@servers_interface = @api_client.servers
|
38
39
|
@server_types_interface = @api_client.server_types
|
@@ -644,6 +645,7 @@ class Morpheus::Cli::Clusters
|
|
644
645
|
!type['enabled'] || !type['creatable'] || type['fieldComponent']
|
645
646
|
} rescue []))
|
646
647
|
|
648
|
+
|
647
649
|
# remove metadata option_type , prompt manually for that field 'tags' instead of 'metadata'
|
648
650
|
metadata_option_type = option_type_list.find {|type| type['fieldName'] == 'metadata' }
|
649
651
|
option_type_list = option_type_list.reject {|type| type['fieldName'] == 'metadata' }
|
@@ -665,6 +667,14 @@ class Morpheus::Cli::Clusters
|
|
665
667
|
# Security Groups
|
666
668
|
server_payload['securityGroups'] = prompt_security_groups_by_cloud(cloud, provision_type, resource_pool, options)
|
667
669
|
|
670
|
+
# KLUDGE part 2: need to ask for hauwei floating ip option
|
671
|
+
if option_type = option_type_list.find {|type| type['code'] == 'computeServerType.openstackLinux.selectFloatingIp'}
|
672
|
+
floating_ip = load_floating_options(cluster_payload, options)
|
673
|
+
if floating_ip != nil
|
674
|
+
server_payload['config']['osExternalNetworkId'] = floating_ip
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
668
678
|
# Visibility
|
669
679
|
server_payload['visibility'] = options[:visibility] || (Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'defaultValue' => 'private', 'required' => true, 'selectOptions' => [{'name' => 'Private', 'value' => 'private'},{'name' => 'Public', 'value' => 'public'}]}], options[:options], @api_client, {})['visibility'])
|
670
680
|
|
@@ -3785,7 +3795,7 @@ class Morpheus::Cli::Clusters
|
|
3785
3795
|
name: cluster['name'],
|
3786
3796
|
type: (cluster['type']['name'] rescue ''),
|
3787
3797
|
layout: (cluster['layout']['name'] rescue ''),
|
3788
|
-
workers: cluster['
|
3798
|
+
workers: cluster['servers'].size,
|
3789
3799
|
cloud: (cluster['zone']['name'] rescue ''),
|
3790
3800
|
status: format_cluster_status(cluster)
|
3791
3801
|
}
|
@@ -4273,7 +4283,11 @@ class Morpheus::Cli::Clusters
|
|
4273
4283
|
else
|
4274
4284
|
resource_pool_id = resource_pool_options.first['id']
|
4275
4285
|
end
|
4276
|
-
|
4286
|
+
if resource_pool_id.to_s["poolGroup-"]
|
4287
|
+
resource_pool = @resource_pool_groups_interface.get(resource_pool_id)['resourcePoolGroup']
|
4288
|
+
else
|
4289
|
+
resource_pool = @cloud_resource_pools_interface.get(cloud['id'], resource_pool_id)['resourcePool']
|
4290
|
+
end
|
4277
4291
|
end
|
4278
4292
|
end
|
4279
4293
|
end
|
@@ -4357,6 +4371,13 @@ class Morpheus::Cli::Clusters
|
|
4357
4371
|
end
|
4358
4372
|
end
|
4359
4373
|
|
4374
|
+
def load_floating_options(cluster, options)
|
4375
|
+
floating_ip_opts = @api_client.options.options_for_source('openstackFloatingIpOptions', {optionsSourceType: 'openStack', zoneId: cluster['cloud']['id']})['data']
|
4376
|
+
floating_ip_opts = floating_ip_opts.reject {|it| it['value'] == '' }
|
4377
|
+
floating_ip = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'osExternalNetworkId', 'fieldLabel' => 'Floating IP', 'type' => 'select', 'selectOptions' => floating_ip_opts, 'required' => false, 'description' => "Select Floating IP"}], options[:options])['osExternalNetworkId']
|
4378
|
+
return floating_ip
|
4379
|
+
end
|
4380
|
+
|
4360
4381
|
def available_kube_templates
|
4361
4382
|
option_results = options_interface.options_for_source('availableKubeTemplates')
|
4362
4383
|
available_templates = option_results['data'].collect {|it|
|