morpheus-cli 5.3.2.1 → 5.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +12 -0
- data/lib/morpheus/api/clouds_interface.rb +4 -11
- data/lib/morpheus/api/instances_interface.rb +18 -5
- data/lib/morpheus/api/load_balancer_pools_interface.rb +4 -4
- data/lib/morpheus/api/load_balancer_profiles_interface.rb +10 -0
- data/lib/morpheus/api/load_balancer_virtual_servers_interface.rb +4 -4
- data/lib/morpheus/api/network_routers_interface.rb +21 -0
- data/lib/morpheus/api/network_servers_interface.rb +42 -0
- data/lib/morpheus/api/rest_interface.rb +2 -1
- data/lib/morpheus/api/virtual_images_interface.rb +23 -2
- data/lib/morpheus/api/virtual_servers_interface.rb +9 -0
- data/lib/morpheus/cli/apps.rb +3 -2
- data/lib/morpheus/cli/cli_command.rb +14 -6
- data/lib/morpheus/cli/cli_registry.rb +55 -2
- data/lib/morpheus/cli/cloud_resource_pools_command.rb +170 -134
- data/lib/morpheus/cli/clouds.rb +22 -40
- data/lib/morpheus/cli/clusters.rb +51 -33
- data/lib/morpheus/cli/hosts.rb +0 -1
- data/lib/morpheus/cli/instances.rb +372 -150
- data/lib/morpheus/cli/invoices_command.rb +117 -133
- data/lib/morpheus/cli/library_cluster_layouts_command.rb +20 -0
- data/lib/morpheus/cli/library_option_lists_command.rb +3 -3
- data/lib/morpheus/cli/load_balancer_pools.rb +111 -0
- data/lib/morpheus/cli/load_balancer_virtual_servers.rb +136 -0
- data/lib/morpheus/cli/load_balancers.rb +0 -155
- data/lib/morpheus/cli/mixins/load_balancers_helper.rb +2 -2
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +155 -112
- data/lib/morpheus/cli/mixins/rest_command.rb +53 -37
- data/lib/morpheus/cli/mixins/secondary_rest_command.rb +488 -0
- data/lib/morpheus/cli/monitoring_checks_command.rb +2 -0
- data/lib/morpheus/cli/network_routers_command.rb +291 -7
- data/lib/morpheus/cli/network_scopes_command.rb +442 -0
- data/lib/morpheus/cli/networks_command.rb +3 -3
- data/lib/morpheus/cli/option_parser.rb +25 -17
- data/lib/morpheus/cli/option_types.rb +42 -15
- data/lib/morpheus/cli/subnets_command.rb +7 -2
- data/lib/morpheus/cli/tasks.rb +25 -2
- data/lib/morpheus/cli/vdi_pools_command.rb +4 -1
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/virtual_images.rb +251 -29
- data/lib/morpheus/cli.rb +9 -1
- data/morpheus-cli.gemspec +1 -1
- metadata +11 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e1172b58bb99b6348f15121c97f5c3d8db818c25fa977cd33835f7a3645da44
|
4
|
+
data.tar.gz: bd216d539aadf61f968cee0dabb6d36361bd79dbdd4ac86527a80872f64620ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24e82961eae144b2b9a00f555313ae653b6c1f844a9be549553481c7e91789011858075acfc76efabfeb3a503f211f4ddc76c79a8a33cff1d4bf07a355179753
|
7
|
+
data.tar.gz: 0cf97e82534466142e81d7a20ff7672578de00179cfab36a1e94e6900a24193090e1dd1c91d6c6d409000ac92623ed06ae9e6f5f346937c2912b42b5fedac561
|
data/Dockerfile
CHANGED
@@ -486,6 +486,10 @@ class Morpheus::APIClient
|
|
486
486
|
Morpheus::LoadBalancerPoolsInterface.new(common_interface_options).setopts(@options)
|
487
487
|
end
|
488
488
|
|
489
|
+
def virtual_servers
|
490
|
+
Morpheus::VirtualServersInterface.new(common_interface_options).setopts(@options)
|
491
|
+
end
|
492
|
+
|
489
493
|
def tasks
|
490
494
|
Morpheus::TasksInterface.new(common_interface_options).setopts(@options)
|
491
495
|
end
|
@@ -836,6 +840,14 @@ class Morpheus::APIClient
|
|
836
840
|
Morpheus::VdiGatewaysInterface.new(common_interface_options).setopts(@options)
|
837
841
|
end
|
838
842
|
|
843
|
+
def network_servers
|
844
|
+
Morpheus::NetworkServersInterface.new(common_interface_options).setopts(@options)
|
845
|
+
end
|
846
|
+
|
847
|
+
def rest(endpoint)
|
848
|
+
Morpheus::RestInterface.new(common_interface_options).setopts(@options.merge({base_path: "#{@base_url}/api/#{endpoint}"}))
|
849
|
+
end
|
850
|
+
|
839
851
|
# add new interfaces here
|
840
852
|
|
841
853
|
protected
|
@@ -24,17 +24,10 @@ class Morpheus::CloudsInterface < Morpheus::APIClient
|
|
24
24
|
execute(opts)
|
25
25
|
end
|
26
26
|
|
27
|
-
def get(params=
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
if params.is_a?(Hash)
|
32
|
-
headers[:params].merge!(params)
|
33
|
-
elsif params.is_a?(Numeric)
|
34
|
-
url = "#{@base_url}/api/zones/#{params}"
|
35
|
-
elsif params.is_a?(String)
|
36
|
-
headers[:params]['name'] = params
|
37
|
-
end
|
27
|
+
def get(id, params={})
|
28
|
+
validate_id!(id)
|
29
|
+
url = "#{@base_url}/api/zones/#{id}"
|
30
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
38
31
|
opts = {method: :get, url: url, headers: headers}
|
39
32
|
execute(opts)
|
40
33
|
end
|
@@ -57,11 +57,24 @@ class Morpheus::InstancesInterface < Morpheus::APIClient
|
|
57
57
|
execute(opts)
|
58
58
|
end
|
59
59
|
|
60
|
-
def
|
61
|
-
url
|
62
|
-
|
63
|
-
|
64
|
-
|
60
|
+
def extend_shutdown(id, params={}, payload={}, headers={})
|
61
|
+
execute(method: :put, url: "#{base_path}/#{id}/extend-shutdown", params: params, payload: payload, headers: headers)
|
62
|
+
end
|
63
|
+
|
64
|
+
def extend_expiration(id, params={}, payload={}, headers={})
|
65
|
+
execute(method: :put, url: "#{base_path}/#{id}/extend-expiration", params: params, payload: payload, headers: headers)
|
66
|
+
end
|
67
|
+
|
68
|
+
def cancel_shutdown(id, params={}, payload={}, headers={})
|
69
|
+
execute(method: :put, url: "#{base_path}/#{id}/cancel-shutdown", params: params, payload: payload, headers: headers)
|
70
|
+
end
|
71
|
+
|
72
|
+
def cancel_expiration(id, params={}, payload={}, headers={})
|
73
|
+
execute(method: :put, url: "#{base_path}/#{id}/cancel-expiration", params: params, payload: payload, headers: headers)
|
74
|
+
end
|
75
|
+
|
76
|
+
def cancel_removal(id, params={}, payload={}, headers={})
|
77
|
+
execute(method: :put, url: "#{base_path}/#{id}/cancel-removal", params: params, payload: payload, headers: headers)
|
65
78
|
end
|
66
79
|
|
67
80
|
def stop(id, params={})
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require 'morpheus/api/
|
1
|
+
require 'morpheus/api/rest_interface'
|
2
2
|
|
3
|
-
class Morpheus::LoadBalancerPoolsInterface < Morpheus::
|
3
|
+
class Morpheus::LoadBalancerPoolsInterface < Morpheus::RestInterface
|
4
4
|
|
5
|
-
def base_path
|
6
|
-
"/api/load-
|
5
|
+
def base_path
|
6
|
+
"/api/load-balancer-pools"
|
7
7
|
end
|
8
8
|
|
9
9
|
end
|
@@ -1,9 +1,9 @@
|
|
1
|
-
require 'morpheus/api/
|
1
|
+
require 'morpheus/api/rest_interface'
|
2
2
|
|
3
|
-
class Morpheus::LoadBalancerVirtualServersInterface < Morpheus::
|
3
|
+
class Morpheus::LoadBalancerVirtualServersInterface < Morpheus::RestInterface
|
4
4
|
|
5
|
-
def base_path
|
6
|
-
"/api/load-
|
5
|
+
def base_path
|
6
|
+
"/api/load-balancer-virtual-servers"
|
7
7
|
end
|
8
8
|
|
9
9
|
end
|
@@ -143,6 +143,27 @@ class Morpheus::NetworkRoutersInterface < Morpheus::APIClient
|
|
143
143
|
execute(opts)
|
144
144
|
end
|
145
145
|
|
146
|
+
def create_bgp_neighbor(router_id, payload={})
|
147
|
+
url = "#{@base_url}/api/networks/routers/#{router_id}/bgp-neighbors"
|
148
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
149
|
+
opts = {method: :post, url: url, headers: headers, payload: payload.to_json}
|
150
|
+
execute(opts)
|
151
|
+
end
|
152
|
+
|
153
|
+
def update_bgp_neighbor(router_id, nat_id, payload={})
|
154
|
+
url = "#{@base_url}/api/networks/routers/#{router_id}/bgp-neighbors/#{nat_id}"
|
155
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
156
|
+
opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
|
157
|
+
execute(opts)
|
158
|
+
end
|
159
|
+
|
160
|
+
def destroy_bgp_neighbor(router_id, nat_id, payload={})
|
161
|
+
url = "#{@base_url}/api/networks/routers/#{router_id}/bgp-neighbors/#{nat_id}"
|
162
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
163
|
+
opts = {method: :delete, url: url, headers: headers, payload: payload.to_json}
|
164
|
+
execute(opts)
|
165
|
+
end
|
166
|
+
|
146
167
|
def update_permissions(router_id, payload)
|
147
168
|
url = "#{@base_url}/api/networks/routers/#{router_id}/permissions"
|
148
169
|
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'morpheus/api/api_client'
|
2
|
+
|
3
|
+
class Morpheus::NetworkServersInterface < Morpheus::RestInterface
|
4
|
+
|
5
|
+
def base_path
|
6
|
+
"/api/networks/servers"
|
7
|
+
end
|
8
|
+
|
9
|
+
def list_scopes(server_id, params={}, headers={})
|
10
|
+
validate_id!(server_id)
|
11
|
+
execute(method: :get, url: "#{base_path}/#{server_id}/scopes", params: params, headers: headers)
|
12
|
+
end
|
13
|
+
|
14
|
+
def get_scope(server_id, scope_id, params={}, headers={})
|
15
|
+
validate_id!(server_id)
|
16
|
+
validate_id!(scope_id)
|
17
|
+
execute(method: :get, url: "#{base_path}/#{server_id}/scopes/#{scope_id}", params: params, headers: headers)
|
18
|
+
end
|
19
|
+
|
20
|
+
def create_scope(server_id, payload, params={}, headers={})
|
21
|
+
validate_id!(server_id)
|
22
|
+
execute(method: :post, url: "#{base_path}/#{server_id}/scopes", params: params, payload: payload, headers: headers)
|
23
|
+
end
|
24
|
+
|
25
|
+
def update_scope(server_id, scope_id, payload, params={}, headers={})
|
26
|
+
validate_id!(server_id)
|
27
|
+
validate_id!(scope_id)
|
28
|
+
execute(method: :put, url: "#{base_path}/#{server_id}/scopes/#{scope_id}", params: params, payload: payload, headers: headers)
|
29
|
+
end
|
30
|
+
|
31
|
+
def destroy_scope(server_id, scope_id, params={}, headers={})
|
32
|
+
validate_id!(server_id)
|
33
|
+
validate_id!(scope_id)
|
34
|
+
execute(method: :delete, url: "#{base_path}/#{server_id}/scopes/#{scope_id}", params: params, headers: headers)
|
35
|
+
end
|
36
|
+
|
37
|
+
def update_scope_permissions(server_id, scope_id, payload, params={}, headers={})
|
38
|
+
validate_id!(server_id)
|
39
|
+
validate_id!(scope_id)
|
40
|
+
execute(method: :put, url: "#{base_path}/#{server_id}/scopes/#{scope_id}", payload: payload.to_json, params: params, headers: headers)
|
41
|
+
end
|
42
|
+
end
|
@@ -7,7 +7,8 @@ class Morpheus::RestInterface < Morpheus::APIClient
|
|
7
7
|
# subclasses should override in your interface
|
8
8
|
# Example: "/api/things"
|
9
9
|
def base_path
|
10
|
-
raise "#{self.class} has not defined base_path!"
|
10
|
+
raise "#{self.class} has not defined base_path!" if @options[:base_path].nil?
|
11
|
+
@options[:base_path]
|
11
12
|
end
|
12
13
|
|
13
14
|
def list(params={}, headers={})
|
@@ -45,10 +45,10 @@ class Morpheus::VirtualImagesInterface < Morpheus::APIClient
|
|
45
45
|
execute(method: :put, url: url, headers: headers, payload: payload.to_json)
|
46
46
|
end
|
47
47
|
|
48
|
-
def destroy(id)
|
48
|
+
def destroy(id, params={})
|
49
49
|
url = "#{@base_url}/api/virtual-images/#{id}"
|
50
50
|
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
51
|
-
execute(method: :delete, url: url, headers: headers)
|
51
|
+
execute(method: :delete, url: url, params: params, headers: headers)
|
52
52
|
end
|
53
53
|
|
54
54
|
# multipart file upload
|
@@ -165,4 +165,25 @@ class Morpheus::VirtualImagesInterface < Morpheus::APIClient
|
|
165
165
|
execute(method: :delete, url: url, headers: headers)
|
166
166
|
end
|
167
167
|
|
168
|
+
def location_base_path(resource_id)
|
169
|
+
"/api/virtual-images/#{resource_id}/locations"
|
170
|
+
end
|
171
|
+
|
172
|
+
def list_locations(resource_id, params={}, headers={})
|
173
|
+
validate_id!(resource_id)
|
174
|
+
execute(method: :get, url: "#{location_base_path(resource_id)}", params: params, headers: headers)
|
175
|
+
end
|
176
|
+
|
177
|
+
def get_location(resource_id, id, params={}, headers={})
|
178
|
+
validate_id!(resource_id)
|
179
|
+
validate_id!(id)
|
180
|
+
execute(method: :get, url: "#{location_base_path(resource_id)}/#{id}", params: params, headers: headers)
|
181
|
+
end
|
182
|
+
|
183
|
+
def destroy_location(resource_id, id, params = {}, headers={})
|
184
|
+
validate_id!(resource_id)
|
185
|
+
validate_id!(id)
|
186
|
+
execute(method: :delete, url: "#{location_base_path(resource_id)}/#{id}", params: params, headers: headers)
|
187
|
+
end
|
188
|
+
|
168
189
|
end
|
data/lib/morpheus/cli/apps.rb
CHANGED
@@ -438,7 +438,7 @@ class Morpheus::Cli::Apps
|
|
438
438
|
instance_prompt_options[:default_cloud] = cloud ? cloud['name'] : nil
|
439
439
|
instance_prompt_options[:environment] = selected_environment ? selected_environment['code'] : nil
|
440
440
|
instance_prompt_options[:default_security_groups] = scoped_instance_config['securityGroups'] ? scoped_instance_config['securityGroups'] : nil
|
441
|
-
|
441
|
+
|
442
442
|
instance_prompt_options[:no_prompt] = options[:no_prompt]
|
443
443
|
#instance_prompt_options[:always_prompt] = options[:no_prompt] != true # options[:always_prompt]
|
444
444
|
instance_prompt_options[:options] = scoped_instance_config # meh, actually need to make these default values instead..
|
@@ -460,8 +460,9 @@ class Morpheus::Cli::Apps
|
|
460
460
|
instance_prompt_options[:locked_fields] = scoped_instance_config['lockedFields']
|
461
461
|
instance_prompt_options[:for_app] = true
|
462
462
|
# this provisioning helper method handles all (most) of the parsing and prompting
|
463
|
+
scoped_instance_config = Marshal.load( Marshal.dump(scoped_instance_config) )
|
463
464
|
instance_config_payload = prompt_new_instance(instance_prompt_options)
|
464
|
-
|
465
|
+
|
465
466
|
# strip all empty string and nil
|
466
467
|
instance_config_payload.deep_compact!
|
467
468
|
# use the blueprint config as the base
|
@@ -215,7 +215,8 @@ module Morpheus
|
|
215
215
|
opts.on(arg1, arg2, description) do |val|
|
216
216
|
if option_type['type'] == 'checkbox'
|
217
217
|
val = (val.to_s != 'false' && val.to_s != 'off')
|
218
|
-
|
218
|
+
elsif option_type['dataType'] != 'string'
|
219
|
+
# 'dataType': 'string' added to cli to avoid auto conversion to JSON
|
219
220
|
# attempt to parse JSON, this allows blank arrays for multiSelect like --tenants []
|
220
221
|
if (val.to_s[0] == '{' && val.to_s[-1] == '}') || (val.to_s[0] == '[' && val.to_s[-1] == ']')
|
221
222
|
begin
|
@@ -1202,11 +1203,18 @@ module Morpheus
|
|
1202
1203
|
# this could go be done in optparse.parse instead perhaps
|
1203
1204
|
def verify_args!(opts={})
|
1204
1205
|
args = opts[:args] || []
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1206
|
+
count = opts[:count]
|
1207
|
+
# simplify output for verify_args!(min:2, max:2) or verify_args!(max:0)
|
1208
|
+
if opts[:min] && opts[:max] && opts[:min] == opts[:max]
|
1209
|
+
count = opts[:min]
|
1210
|
+
elsif opts[:max] == 0
|
1211
|
+
count = 0
|
1212
|
+
end
|
1213
|
+
if count
|
1214
|
+
if args.count < count
|
1215
|
+
raise_args_error("not enough arguments, expected #{count} and got #{args.count == 0 ? '0' : args.count.to_s + ': '}#{args.join(', ')}", args, opts[:optparse])
|
1216
|
+
elsif args.count > count
|
1217
|
+
raise_args_error("too many arguments, expected #{count} and got #{args.count == 0 ? '0' : args.count.to_s + ': '}#{args.join(', ')}", args, opts[:optparse])
|
1210
1218
|
end
|
1211
1219
|
else
|
1212
1220
|
if opts[:min]
|
@@ -77,14 +77,26 @@ module Morpheus
|
|
77
77
|
|
78
78
|
def exec_command(command_name, args)
|
79
79
|
#puts "exec_command(#{command_name}, #{args})"
|
80
|
-
found_alias_command = instance.get_alias(command_name)
|
81
80
|
if has_alias?(command_name)
|
82
81
|
exec_alias(command_name, args)
|
83
82
|
elsif has_command?(command_name)
|
84
83
|
instance.get(command_name).new.handle(args)
|
85
84
|
else
|
86
85
|
# todo: need to just return error instead of raise
|
87
|
-
|
86
|
+
msg = "'#{command_name}' is not a morpheus command."
|
87
|
+
suggestions = find_command_suggestions(command_name)
|
88
|
+
if suggestions && suggestions.size == 1
|
89
|
+
msg += "\nThe most similar command is:\n"
|
90
|
+
suggestions.first(5).each do |suggestion|
|
91
|
+
msg += "\t" + suggestion + "\n"
|
92
|
+
end
|
93
|
+
elsif suggestions && suggestions.size > 1
|
94
|
+
msg += "\nThe most similar commands are:\n"
|
95
|
+
suggestions.first(5).each do |suggestion|
|
96
|
+
msg += "\t" + suggestion + "\n"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
raise CommandNotFoundError.new(msg)
|
88
100
|
end
|
89
101
|
end
|
90
102
|
|
@@ -269,6 +281,47 @@ module Morpheus
|
|
269
281
|
return exit_code, err
|
270
282
|
end
|
271
283
|
|
284
|
+
def cached_command_list
|
285
|
+
@cached_command_list ||= (all.keys + all_aliases.keys).collect { |it| it.to_s }.sort
|
286
|
+
end
|
287
|
+
|
288
|
+
def clear_cached_command_list
|
289
|
+
@cached_command_list = nil
|
290
|
+
end
|
291
|
+
|
292
|
+
# find suggested commands (or aliases) for a name that was not found
|
293
|
+
# First this looks for the plural of the original guess
|
294
|
+
# Then pop characters off the end looking for partial matches
|
295
|
+
# as long as the guess is at least 3 characters
|
296
|
+
def find_command_suggestions(command_name)
|
297
|
+
every_command = cached_command_list
|
298
|
+
guess = command_name
|
299
|
+
suggestions = []
|
300
|
+
while guess.size >= 3
|
301
|
+
plural_guess = guess.pluralize
|
302
|
+
if every_command.include?(guess)
|
303
|
+
suggestions << guess
|
304
|
+
end
|
305
|
+
if every_command.include?(plural_guess)
|
306
|
+
suggestions << plural_guess
|
307
|
+
end
|
308
|
+
# if every_command.include?(guess)
|
309
|
+
# suggestions << plural_guess
|
310
|
+
# else
|
311
|
+
guess_regexp = /^#{Regexp.escape(guess)}/i
|
312
|
+
every_command.each do |it|
|
313
|
+
if it =~ guess_regexp
|
314
|
+
suggestions << it
|
315
|
+
end
|
316
|
+
end
|
317
|
+
# end
|
318
|
+
guess = guess[0..-2]
|
319
|
+
end
|
320
|
+
suggestions.uniq!
|
321
|
+
suggestions.sort! { |x,y| [x.split('-').size, x] <=> [y.split('-').size, y] }
|
322
|
+
return suggestions
|
323
|
+
end
|
324
|
+
|
272
325
|
end
|
273
326
|
|
274
327
|
end
|