morpheus-cli 5.3.2.1 → 5.3.4
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 +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
|