morpheus-cli 5.3.2 → 5.3.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -6,11 +6,12 @@ class Morpheus::Cli::LogSettingsCommand
6
6
 
7
7
  set_command_name :'log-settings'
8
8
 
9
- register_subcommands :get, :update
10
- register_subcommands :enable_integration, :disable_integration, :remove_integration
9
+ register_subcommands :get, :update
11
10
  register_subcommands :add_syslog_rule, :remove_syslog_rule
12
11
 
13
- set_default_subcommand :get
12
+ # these command are deprecated in 5.3.3 and can be removed
13
+ register_subcommands :enable_integration, :disable_integration, :remove_integration
14
+ set_subcommands_hidden :enable_integration, :disable_integration, :remove_integration
14
15
 
15
16
  def connect(opts)
16
17
  @api_client = establish_remote_appliance_connection(opts)
@@ -186,6 +187,7 @@ class Morpheus::Cli::LogSettingsCommand
186
187
  end
187
188
 
188
189
  def enable_integration(args)
190
+ print_error yellow,"[DEPRECATED] The command `#{command_name} enable-integration` is deprecated.",reset,"\n"
189
191
  options = {}
190
192
 
191
193
  optparse = Morpheus::Cli::OptionParser.new do |opts|
@@ -240,6 +242,7 @@ class Morpheus::Cli::LogSettingsCommand
240
242
  end
241
243
 
242
244
  def disable_integration(args)
245
+ print_error yellow,"[DEPRECATED] The command `#{command_name} disable-integration` is deprecated.",reset,"\n"
243
246
  options = {}
244
247
 
245
248
  optparse = Morpheus::Cli::OptionParser.new do |opts|
@@ -285,6 +288,7 @@ class Morpheus::Cli::LogSettingsCommand
285
288
  end
286
289
 
287
290
  def remove_integration(args)
291
+ print_error yellow,"[DEPRECATED] The command `#{command_name } remove-integration` is deprecated.",reset,"\n"
288
292
  options = {}
289
293
 
290
294
  optparse = Morpheus::Cli::OptionParser.new do |opts|
@@ -0,0 +1,156 @@
1
+ require 'morpheus/cli/mixins/print_helper'
2
+ require 'morpheus/cli/option_types'
3
+ require 'morpheus/rest_client'
4
+ # Mixin for Morpheus::Cli command classes
5
+ # Provides common methods for load balancer management
6
+ # including load balancers, load balancer types, virtual servers, etc.
7
+ module Morpheus::Cli::LoadBalancersHelper
8
+
9
+ def self.included(klass)
10
+ klass.send :include, Morpheus::Cli::PrintHelper
11
+ end
12
+
13
+ def load_balancers_interface
14
+ # @api_client.load_balancers
15
+ raise "#{self.class} has not defined @load_balancers_interface" if @load_balancers_interface.nil?
16
+ @load_balancers_interface
17
+ end
18
+
19
+ def load_balancer_types_interface
20
+ # @api_client.load_balancer_types
21
+ raise "#{self.class} has not defined @load_balancer_types_interface" if @load_balancer_types_interface.nil?
22
+ @load_balancer_types_interface
23
+ end
24
+
25
+ def load_balancer_object_key
26
+ 'loadBalancer'
27
+ end
28
+
29
+ def load_balancer_list_key
30
+ 'loadBalancers'
31
+ end
32
+
33
+ def load_balancer_label
34
+ 'Load Balancer'
35
+ end
36
+
37
+ def load_balancer_plural_label
38
+ 'Load Balancers'
39
+ end
40
+
41
+ def load_balancer_type_object_key
42
+ 'loadBalancerType'
43
+ end
44
+
45
+ def load_balancer_type_list_key
46
+ 'loadBalancerTypes'
47
+ end
48
+
49
+ def load_balancer_type_label
50
+ 'Load Balancer Type'
51
+ end
52
+
53
+ def load_balancer_type_plural_label
54
+ 'Load Balancer Types'
55
+ end
56
+
57
+ def find_load_balancer_by_name_or_id(val)
58
+ if val.to_s =~ /\A\d{1,}\Z/
59
+ return find_load_balancer_by_id(val)
60
+ else
61
+ return find_load_balancer_by_name(val)
62
+ end
63
+ end
64
+
65
+ def find_load_balancer_by_id(id)
66
+ begin
67
+ json_response = load_balancers_interface.get(id.to_i)
68
+ return json_response[load_balancer_object_key]
69
+ rescue RestClient::Exception => e
70
+ if e.response && e.response.code == 404
71
+ print_red_alert "Load Balancer not found by id #{id}"
72
+ else
73
+ raise e
74
+ end
75
+ end
76
+ end
77
+
78
+ def find_load_balancer_by_name(name)
79
+ lbs = load_balancers_interface.list({name: name.to_s})[load_balancer_list_key]
80
+ if lbs.empty?
81
+ print_red_alert "Load Balancer not found by name #{name}"
82
+ return nil
83
+ elsif lbs.size > 1
84
+ print_red_alert "#{lbs.size} load balancers found by name #{name}"
85
+ #print_lbs_table(lbs, {color: red})
86
+ print reset,"\n\n"
87
+ return nil
88
+ else
89
+ return lbs[0]
90
+ end
91
+ end
92
+
93
+ def get_available_load_balancer_types(refresh=false)
94
+ if !@available_load_balancer_types || refresh
95
+ @available_load_balancer_types = load_balancer_types_interface.list({max:1000})[load_balancer_type_list_key]
96
+ end
97
+ return @available_load_balancer_types
98
+ end
99
+
100
+ def load_balancer_type_for_name_or_id(val)
101
+ if val.to_s =~ /\A\d{1,}\Z/
102
+ return load_balancer_type_for_id(val)
103
+ else
104
+ return load_balancer_type_for_name(val)
105
+ end
106
+ end
107
+
108
+ def load_balancer_type_for_id(id)
109
+ return get_available_load_balancer_types().find { |z| z['id'].to_i == id.to_i}
110
+ end
111
+
112
+ def load_balancer_type_for_name(name)
113
+ return get_available_load_balancer_types().find { |z| z['name'].downcase == name.downcase || z['code'].downcase == name.downcase}
114
+ end
115
+
116
+ def find_load_balancer_type_by_name_or_id(val)
117
+ if val.to_s =~ /\A\d{1,}\Z/
118
+ return find_load_balancer_type_by_id(val)
119
+ else
120
+ return find_load_balancer_type_by_name(val)
121
+ end
122
+ end
123
+
124
+ def find_load_balancer_type_by_id(id)
125
+ begin
126
+ json_response = load_balancer_types_interface.get(id.to_i)
127
+ return json_response[load_balancer_type_object_key]
128
+ rescue RestClient::Exception => e
129
+ if e.response && e.response.code == 404
130
+ print_red_alert "Load Balancer Type not found by id #{id}"
131
+ return nil
132
+ else
133
+ raise e
134
+ end
135
+ end
136
+ end
137
+
138
+ def find_load_balancer_type_by_name(name)
139
+ json_response = load_balancer_types_interface.list({name: name.to_s})
140
+ load_balancer_types = json_response[load_balancer_type_list_key]
141
+ if load_balancer_types.empty?
142
+ print_red_alert "Load Balancer Type not found by name #{name}"
143
+ return load_balancer_types
144
+ elsif load_balancer_types.size > 1
145
+ print_red_alert "#{load_balancer_types.size} load balancer types found by name #{name}"
146
+ rows = load_balancer_types.collect do |it|
147
+ {id: it['id'], name: it['name']}
148
+ end
149
+ puts as_pretty_table(rows, [:id, :name], {color:red})
150
+ return nil
151
+ else
152
+ return load_balancer_types[0]
153
+ end
154
+ end
155
+
156
+ end
@@ -1335,4 +1335,15 @@ module Morpheus::Cli::PrintHelper
1335
1335
  parse_json_or_yaml(config, parsers)
1336
1336
  end
1337
1337
 
1338
+ def format_option_types_table(option_types, options={}, domain_name=nil)
1339
+ columns = [
1340
+ {"FIELD LABEL" => lambda {|it| it['fieldLabel'] } },
1341
+ {"FIELD NAME" => lambda {|it| [it['fieldContext'] == domain_name ? nil : it['fieldContext'], it['fieldName']].select {|it| !it.to_s.empty? }.join('.') } },
1342
+ {"TYPE" => lambda {|it| it['type'] } },
1343
+ {"DEFAULT" => lambda {|it| it['defaultValue'] } },
1344
+ {"REQUIRED" => lambda {|it| format_boolean it['required'] } },
1345
+ ]
1346
+ as_pretty_table(option_types, columns, options)
1347
+ end
1348
+
1338
1349
  end
@@ -0,0 +1,657 @@
1
+ # RestCommand is a mixin for Morpheus::Cli command classes.
2
+ # Provides basic CRUD commands: list, get, add, update, remove
3
+ # Currently the command class must also include Morpheus::Cli::CliCommand
4
+ # The command class can define a few variables to dictate what the resource
5
+ # is called and the the api interface used to fetch the records. The command class
6
+ # or helper must also provide several methods to provide the default behavior.
7
+ # In the example below, the command (helper) defines the following methods:
8
+ # * load_balancer_object_key() - Key name of object returned by the "get" api endpoint.
9
+ # * load_balancer_list_key() - Key name of array of records returned by the "list" api endpoint.
10
+ # * load_balancer_column_definitions() - Column definitions for the "get" command display output.
11
+ # * load_balancer_list_column_definitions() - Column definitions for the "list" command display output.
12
+ #
13
+ # # An example of a RestCommand for `morpheus load-balancers`.
14
+ # class Morpheus::Cli::LoadBalancers
15
+ #
16
+ # include Morpheus::Cli::CliCommand
17
+ # include Morpheus::Cli::RestCommand
18
+ # include Morpheus::Cli::LoadBalancersHelper
19
+ #
20
+ # # All of the example settings below are redundant
21
+ # # and would be the default values if not set.
22
+ # set_rest_name :load_balancers
23
+ # set_rest_label "Load Balancer"
24
+ # set_rest_plural_label "Load Balancers"
25
+ # set_rest_object_key "load_balancer"
26
+ # set_rest_has_type true
27
+ # set_rest_type "load_balancer_types"
28
+ # register_interfaces :load_balancers, :load_balancer_types
29
+ #
30
+ # end
31
+ #
32
+ module Morpheus::Cli::RestCommand
33
+ def self.included(base)
34
+ #puts "including RestCommand for #{base}"
35
+ #base.send :include, Morpheus::Cli::CliCommand
36
+ base.extend ClassMethods
37
+ end
38
+
39
+ module ClassMethods
40
+
41
+ # rest_name is the plural name of the rest command resource eg. NeatThingsCommand would be "neat_things"
42
+ # It is used to derive all other default rest settings key, label, etc.
43
+ # The default name the command name with underscores `_` instead of dashes `-`.
44
+ def rest_name
45
+ @rest_name || default_rest_name
46
+ end
47
+
48
+ def default_rest_name
49
+ self.command_name.to_s.gsub("-", "_")
50
+ end
51
+
52
+ def rest_name=(v)
53
+ @rest_name = v
54
+ end
55
+
56
+ alias :set_rest_name :rest_name=
57
+
58
+ # rest_key is the singular name of the resource eg. "neat_thing"
59
+ def rest_key
60
+ @rest_key || default_rest_key
61
+ end
62
+
63
+ def default_rest_key
64
+ rest_name.chomp("s")
65
+ end
66
+
67
+ def rest_key=(v)
68
+ @rest_key = v
69
+ end
70
+
71
+ alias :set_rest_key :rest_key=
72
+
73
+ # rest_arg is a label for the arg in the command usage eg. "thing" gets displayed as [thing]
74
+ def rest_arg
75
+ @rest_arg || default_rest_arg
76
+ end
77
+
78
+ def default_rest_arg
79
+ rest_key.gsub("_", " ") # "[" + rest_key.gsub("_", " ") + "]"
80
+ end
81
+
82
+ def rest_arg=(v)
83
+ @rest_arg = v
84
+ end
85
+
86
+ alias :set_rest_arg :rest_arg=
87
+
88
+ # rest_label is the capitalized resource label eg. "Neat Thing"
89
+ def rest_label
90
+ @rest_label || default_rest_label
91
+ end
92
+
93
+ def default_rest_label
94
+ rest_key.to_s.split("_").collect {|it| it.to_s.capitalize }.join(" ")
95
+ end
96
+
97
+ def rest_label=(v)
98
+ @rest_label = v
99
+ end
100
+
101
+ alias :set_rest_label :rest_label=
102
+
103
+ # the plural version of the label eg. "Neat Things"
104
+ def rest_plural_label
105
+ @rest_plural_label || default_rest_plural_label
106
+ end
107
+
108
+ def default_rest_plural_label
109
+ #rest_name.to_s.split("_").collect {|it| it.to_s.capitalize }.join(" ")
110
+ rest_label.to_s.pluralize
111
+ end
112
+
113
+ def rest_plural_label=(v)
114
+ @rest_plural_label = v
115
+ end
116
+
117
+ alias :set_rest_plural_label :rest_plural_label=
118
+
119
+ # rest_interface_name is the interface name for the resource. eg. "neat_things"
120
+ def rest_interface_name
121
+ @rest_interface_name || default_rest_interface_name
122
+ end
123
+
124
+ def default_rest_interface_name
125
+ rest_name
126
+ end
127
+
128
+ def rest_interface_name=(v)
129
+ @rest_interface_name = v
130
+ end
131
+
132
+ alias :set_rest_interface_name :rest_interface_name=
133
+
134
+ # rest_has_type indicates a resource has a type. default is false
135
+ def rest_has_type
136
+ @rest_has_type == true
137
+ end
138
+
139
+ def default_rest_has_type
140
+ false
141
+ end
142
+
143
+ def rest_has_type=(v)
144
+ @rest_has_type = !!v
145
+ end
146
+
147
+ alias :set_rest_has_type :rest_has_type=
148
+
149
+ ## duplicated the rest_* settings with rest_type, for the types resource
150
+
151
+ # rest_type_name is the rest_name for the type, only applicable if rest_has_type
152
+ def rest_type_name
153
+ @rest_type_name || default_rest_type_name
154
+ end
155
+
156
+ def default_rest_type_name
157
+ rest_key + "_types"
158
+ end
159
+
160
+ def rest_type_name=(v)
161
+ @rest_type_name = v
162
+ end
163
+
164
+ alias :set_rest_type_name :rest_type_name=
165
+ alias :set_rest_type :rest_type_name=
166
+ #alias :rest_type= :rest_type_name=
167
+
168
+ # rest_type_key is the singular name of the resource eg. "neat_thing"
169
+ def rest_type_key
170
+ @rest_type_key || default_rest_type_key
171
+ end
172
+
173
+ def default_rest_type_key
174
+ rest_type_name.chomp("s")
175
+ end
176
+
177
+ def rest_type_key=(v)
178
+ @rest_type_key = v
179
+ end
180
+
181
+ alias :set_rest_type_key :rest_type_key=
182
+
183
+ def rest_type_arg
184
+ @rest_type_arg || default_rest_type_arg
185
+ end
186
+
187
+ def default_rest_type_arg
188
+ # rest_type_key.gsub("_", " ") # "[" + rest_key.gsub("_", " ") + "]"
189
+ "type" # [type]
190
+ end
191
+
192
+ def rest_type_arg=(v)
193
+ @rest_type_arg = v
194
+ end
195
+
196
+ alias :set_rest_type_arg :rest_type_arg=
197
+
198
+ # rest_type_label is the capitalized resource label eg. "Neat Thing"
199
+ def rest_type_label
200
+ @rest_type_label || default_rest_type_label
201
+ end
202
+
203
+ def default_rest_type_label
204
+ rest_type_key.to_s.split("_").collect {|it| it.to_s.capitalize }.join(" ")
205
+ end
206
+
207
+ def rest_type_label=(v)
208
+ @rest_type_label = v
209
+ end
210
+
211
+ alias :set_rest_type_label :rest_type_label=
212
+
213
+ # the plural version of the label eg. "Neat Things"
214
+ def rest_type_plural_label
215
+ @rest_type_plural_label || default_rest_type_plural_label
216
+ end
217
+
218
+ def default_rest_type_plural_label
219
+ #rest_type_name.to_s.split("_").collect {|it| it.to_s.capitalize }.join(" ")
220
+ rest_type_label.to_s.pluralize
221
+ end
222
+
223
+ def rest_type_plural_label=(v)
224
+ @rest_type_plural_label = v
225
+ end
226
+
227
+ alias :set_rest_type_plural_label :rest_type_plural_label=
228
+
229
+ # the name of the default interface, matches the rest name eg. "neat_things"
230
+ def rest_type_interface_name
231
+ @rest_type_interface_name || default_rest_type_interface_name
232
+ end
233
+
234
+ def default_rest_type_interface_name
235
+ rest_type_name
236
+ end
237
+
238
+ def rest_type_interface_name=(v)
239
+ @rest_type_interface_name = v
240
+ end
241
+
242
+ alias :set_rest_type_interface_name :rest_type_interface_name=
243
+
244
+ # set or append to the list of interface names to register for this command
245
+ # The registered interfaces will be pre-loaded into instance variables
246
+ # eg. [:neat_things, :neat_thing_types] will instantiate @neat_things_interface and @neat_thing_types_interface
247
+ def register_interfaces(*interfaces)
248
+ @registered_interfaces ||= []
249
+ interfaces.flatten.each do |it|
250
+ @registered_interfaces << it.to_sym
251
+ end
252
+ # put the default rest_interface first
253
+ if rest_interface_name && !@registered_interfaces.include?(rest_interface_name)
254
+ @registered_interfaces.unshift(rest_interface_name)
255
+ end
256
+ # and also the rest_type_interface
257
+ if rest_has_type && !@registered_interfaces.include?(rest_type_interface_name)
258
+ @registered_interfaces.unshift(rest_type_interface_name)
259
+ end
260
+ end
261
+
262
+ alias :register_interface :register_interfaces
263
+
264
+ # get list of interface names that are registered for this command
265
+ # automatically includes the interface for the rest_name and rest_type_name if has_type
266
+ def registered_interfaces
267
+ @registered_interfaces ||= []
268
+ # put the default rest_interface first
269
+ if @registered_interfaces.empty?
270
+ if rest_interface_name
271
+ @registered_interfaces.unshift(rest_interface_name)
272
+ end
273
+ if rest_has_type
274
+ @registered_interfaces.unshift(rest_type_interface_name)
275
+ end
276
+ end
277
+ @registered_interfaces
278
+ end
279
+
280
+ # clear the list of registered interfaces, perhaps useful in a command subclass
281
+ def clear_registered_interfaces()
282
+ @registered_interfaces = []
283
+ end
284
+
285
+ end
286
+
287
+ def rest_name
288
+ self.class.rest_name
289
+ end
290
+
291
+ def rest_key
292
+ self.class.rest_key
293
+ end
294
+
295
+ def rest_arg
296
+ self.class.rest_arg
297
+ end
298
+
299
+ def rest_label
300
+ self.class.rest_label
301
+ end
302
+
303
+ def rest_plural_label
304
+ self.class.rest_plural_label
305
+ end
306
+
307
+ def rest_interface_name
308
+ self.class.rest_interface_name
309
+ end
310
+
311
+ # returns the default rest interface, allows using rest_interface_name = "your"
312
+ # or override this method to return @your_interface if needed
313
+ def rest_interface
314
+ instance_variable_get("@#{rest_interface_name}_interface")
315
+ end
316
+
317
+ def rest_object_key
318
+ self.send("#{rest_key}_object_key")
319
+ end
320
+
321
+ def rest_list_key
322
+ self.send("#{rest_key}_list_key")
323
+ end
324
+
325
+ def rest_column_definitions
326
+ self.send("#{rest_key}_column_definitions")
327
+ end
328
+
329
+ def rest_list_column_definitions
330
+ self.send("#{rest_key}_list_column_definitions")
331
+ end
332
+
333
+ def rest_find_by_name_or_id(name)
334
+ return self.send("find_#{rest_key}_by_name_or_id", name)
335
+ end
336
+
337
+ def rest_has_type
338
+ self.class.rest_has_type
339
+ end
340
+
341
+ ## duplicated the rest_* settings with rest_type, for the types resource
342
+
343
+ def rest_type_name
344
+ self.class.rest_type_name
345
+ end
346
+
347
+ def rest_type_key
348
+ self.class.rest_type_key
349
+ end
350
+
351
+ def rest_type_arg
352
+ self.class.rest_type_arg
353
+ end
354
+
355
+ def rest_type_label
356
+ self.class.rest_type_label
357
+ end
358
+
359
+ def rest_type_plural_label
360
+ self.class.rest_type_plural_label
361
+ end
362
+
363
+ def rest_type_interface_name
364
+ self.class.rest_type_interface_name # || "@#{rest_type_name}_interface"
365
+ end
366
+
367
+ def rest_type_interface
368
+ instance_variable_get("@#{rest_type_interface_name}_interface")
369
+ end
370
+
371
+ def rest_type_object_key
372
+ self.send("#{rest_type_key}_object_key")
373
+ end
374
+
375
+ def rest_type_list_key
376
+ self.send("#{rest_type_key}_list_key")
377
+ end
378
+
379
+ def rest_type_column_definitions
380
+ self.send("#{rest_type_key}_column_definitions")
381
+ end
382
+
383
+ def rest_type_list_column_definitions
384
+ self.send("#{rest_type_key}_list_column_definitions")
385
+ end
386
+
387
+ def rest_type_find_by_name_or_id(name)
388
+ return self.send("find_#{rest_type_key}_by_name_or_id", name)
389
+ end
390
+
391
+ def registered_interfaces
392
+ self.class.registered_interfaces
393
+ end
394
+
395
+ # standard connect method to establish @api_client
396
+ # and @{name}_interface variables for each registered interface.
397
+ def connect(options)
398
+ @api_client = establish_remote_appliance_connection(options)
399
+ self.class.registered_interfaces.each do |interface_name|
400
+ if interface_name.is_a?(String) || interface_name.is_a?(Symbol)
401
+ instance_variable_set("@#{interface_name}_interface", @api_client.send(interface_name))
402
+ elsif interface_name.is_a?(Hash)
403
+ interface_name.each do |k,v|
404
+ instance_variable_set("#{k}_interface", @api_client.send(v))
405
+ end
406
+ end
407
+ end
408
+ end
409
+
410
+ def handle(args)
411
+ handle_subcommand(args)
412
+ end
413
+
414
+ def list(args)
415
+ params = {}
416
+ options = {}
417
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
418
+ opts.banner = subcommand_usage()
419
+ build_standard_list_options(opts, options)
420
+ opts.footer = "List #{rest_plural_label.downcase}."
421
+ end
422
+ optparse.parse!(args)
423
+ connect(options)
424
+ if args.count > 0
425
+ options[:phrase] = args.join(" ")
426
+ end
427
+ params.merge!(parse_list_options(options))
428
+ rest_interface.setopts(options)
429
+ if options[:dry_run]
430
+ print_dry_run rest_interface.dry.list(params)
431
+ return
432
+ end
433
+ json_response = rest_interface.list(params)
434
+ render_response(json_response, options, rest_list_key) do
435
+ records = json_response[rest_list_key]
436
+ print_h1 "Morpheus #{rest_plural_label}"
437
+ if records.nil? || records.empty?
438
+ print cyan,"No #{rest_plural_label.downcase} found.",reset,"\n"
439
+ else
440
+ print as_pretty_table(records, rest_list_column_definitions.upcase_keys!, options)
441
+ print_results_pagination(json_response) if json_response['meta']
442
+ end
443
+ print reset,"\n"
444
+ end
445
+ return 0, nil
446
+ end
447
+
448
+ def get(args)
449
+ params = {}
450
+ options = {}
451
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
452
+ opts.banner = subcommand_usage("[type]")
453
+ build_standard_get_options(opts, options)
454
+ opts.footer = <<-EOT
455
+ Get details about #{a_or_an(rest_label)} #{rest_label.downcase}.
456
+ [#{rest_arg}] is required. This is the name or id of #{a_or_an(rest_label)} #{rest_label.downcase}.
457
+ EOT
458
+ end
459
+ optparse.parse!(args)
460
+ verify_args!(args:args, optparse:optparse, min:1)
461
+ connect(options)
462
+ params.merge!(parse_query_options(options))
463
+ id_list = parse_id_list(args)
464
+ return run_command_for_each_arg(id_list) do |arg|
465
+ _get(arg, params, options)
466
+ end
467
+ end
468
+
469
+ def _get(id, params, options)
470
+ if id !~ /\A\d{1,}\Z/
471
+ record = rest_find_by_name_or_id(id)
472
+ if record.nil?
473
+ raise_command_error "#{rest_label} not found for name '#{id}'"
474
+ end
475
+ id = record['id']
476
+ end
477
+ rest_interface.setopts(options)
478
+ if options[:dry_run]
479
+ print_dry_run rest_interface.dry.get(id, params)
480
+ return
481
+ end
482
+ json_response = rest_interface.get(id, params)
483
+ render_response_for_get(json_response, options)
484
+ return 0, nil
485
+ end
486
+
487
+ def render_response_for_get(json_response, options)
488
+ render_response(json_response, options, rest_object_key) do
489
+ record = json_response[rest_object_key]
490
+ print_h1 rest_label, [], options
491
+ print cyan
492
+ print_description_list(rest_column_definitions, record, options)
493
+ # show config settings...
494
+ if record['optionTypes'] && record['optionTypes'].size > 0
495
+ print_h2 "Option Types", options
496
+ print format_option_types_table(record['optionTypes'], options, rest_object_key)
497
+ end
498
+ print reset,"\n"
499
+ end
500
+ end
501
+
502
+ def add(args)
503
+ record_type_id = nil
504
+ options = {}
505
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
506
+ if rest_has_type
507
+ opts.banner = subcommand_usage("[name] -t TYPE")
508
+ opts.on( '-t', "--#{rest_type_arg} TYPE", "#{rest_type_label}" ) do |val|
509
+ record_type_id = val
510
+ end
511
+ else
512
+ opts.banner = subcommand_usage("[name]")
513
+ end
514
+ # if defined?(add_#{rest_key}_option_types)
515
+ # build_option_type_options(opts, options, add_#{rest_key}_option_types)
516
+ # end
517
+ build_standard_add_options(opts, options)
518
+ end
519
+ optparse.parse!(args)
520
+ # todo: make supporting args[0] optional and more flexible
521
+ # for now args[0] is assumed to be the 'name'
522
+ record_name = nil
523
+ if args[0] # && rest_has_name
524
+ record_name = args[0]
525
+ end
526
+ verify_args!(args:args, optparse:optparse, min:0, max: 1)
527
+ # todo: maybe need a flag to make this required, it could be an option type too, so
528
+ if rest_has_type
529
+ if record_type_id.nil?
530
+ raise_command_error "#{rest_type_label} is required.\n#{optparse}"
531
+ end
532
+ end
533
+ connect(options)
534
+ if rest_has_type
535
+ record_type = rest_type_find_by_name_or_id(record_type_id)
536
+ if record_type.nil?
537
+ raise_command_error "#{rest_type_label} not found for '#{record_type_id}'.\n#{optparse}"
538
+ end
539
+ end
540
+ passed_options = parse_passed_options(options)
541
+ payload = {}
542
+ if options[:payload]
543
+ payload = options[:payload]
544
+ payload.deep_merge!({rest_object_key => passed_options})
545
+ else
546
+ record_payload = {}
547
+ if record_name
548
+ record_payload['name'] = record_name
549
+ options[:options]['name'] = record_name # injected for prompt
550
+ end
551
+ if rest_has_type && record_type
552
+ # record_payload['type'] = {'code' => record_type['code']}
553
+ record_payload['type'] = record_type['code']
554
+ options[:options]['type'] = record_type['code'] # injected for prompt
555
+ end
556
+ record_payload.deep_merge!(passed_options)
557
+ # options by type
558
+ my_option_types = record_type ? record_type['optionTypes'] : nil
559
+ if my_option_types && !my_option_types.empty?
560
+ # remove redundant fieldContext
561
+ my_option_types.each do |option_type|
562
+ if option_type['fieldContext'] == rest_object_key
563
+ option_type['fieldContext'] = nil
564
+ end
565
+ end
566
+ v_prompt = Morpheus::Cli::OptionTypes.prompt(my_option_types, options[:options], @api_client, options[:params])
567
+ v_prompt.deep_compact!
568
+ v_prompt.booleanize! # 'on' => true
569
+ record_payload.deep_merge!(v_prompt)
570
+ end
571
+ payload[rest_object_key] = record_payload
572
+ end
573
+ rest_interface.setopts(options)
574
+ if options[:dry_run]
575
+ print_dry_run rest_interface.dry.create(payload)
576
+ return
577
+ end
578
+ json_response = rest_interface.create(payload)
579
+ render_response(json_response, options, rest_object_key) do
580
+ record = json_response[rest_object_key]
581
+ print_green_success "Added #{rest_label.downcase} #{record['name'] || record['id']}"
582
+ return _get(record["id"], {}, options)
583
+ end
584
+ return 0, nil
585
+ end
586
+
587
+ def update(args)
588
+ id = args[0]
589
+ options = {}
590
+ params = {}
591
+ account_name = nil
592
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
593
+ opts.banner = subcommand_usage("[#{rest_arg}] [options]")
594
+ build_standard_update_options(opts, options)
595
+ end
596
+ optparse.parse!(args)
597
+ verify_args!(args:args, optparse:optparse, count:1)
598
+ connect(options)
599
+ record = rest_find_by_name_or_id(id)
600
+ passed_options = parse_passed_options(options)
601
+ payload = nil
602
+ if options[:payload]
603
+ payload = options[:payload]
604
+ payload.deep_merge!({rest_object_key => passed_options}) unless passed_options.empty?
605
+ else
606
+ record_payload = passed_options
607
+ if record_payload.empty?
608
+ raise_command_error "Specify at least one option to update.\n#{optparse}"
609
+ end
610
+ payload[rest_object_key] = record_payload
611
+ end
612
+ rest_interface.setopts(options)
613
+ if options[:dry_run]
614
+ print_dry_run rest_interface.dry.update(record['id'], payload)
615
+ return
616
+ end
617
+ json_response = rest_interface.update(record['id'], payload)
618
+ render_response(json_response, options, rest_object_key) do
619
+ print_green_success "Updated #{rest_label.downcase} #{record['name'] || record['id']}"
620
+ _get(record["id"], {}, options)
621
+ end
622
+ return 0, nil
623
+ end
624
+
625
+ def remove(args)
626
+ id = args[0]
627
+ params = {}
628
+ options = {}
629
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
630
+ opts.banner = subcommand_usage("[#{rest_arg}]")
631
+ build_standard_remove_options(opts, options)
632
+ end
633
+ optparse.parse!(args)
634
+ verify_args!(args:args, optparse:optparse, count:1)
635
+ connect(options)
636
+ params.merge!(parse_query_options(options))
637
+ record = rest_find_by_name_or_id(id)
638
+ if record.nil?
639
+ return 1, "#{rest_name} not found for '#{id}'"
640
+ end
641
+ unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the #{rest_label.downcase} #{record['name'] || record['id']}?")
642
+ return 9, "aborted"
643
+ end
644
+ rest_interface.setopts(options)
645
+ if options[:dry_run]
646
+ print_dry_run rest_interface.dry.destroy(record['id'])
647
+ return 0, nil
648
+ end
649
+ json_response = rest_interface.destroy(record['id'], params)
650
+ render_response(json_response, options) do
651
+ print_green_success "Removed #{rest_label.downcase} #{record['name'] || record['id']}"
652
+ end
653
+ return 0, nil
654
+ end
655
+
656
+ end
657
+