morpheus-cli 3.3.1.4 → 3.3.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/lib/morpheus/api/api_client.rb +28 -0
  3. data/lib/morpheus/api/instance_types_interface.rb +12 -10
  4. data/lib/morpheus/api/instances_interface.rb +4 -0
  5. data/lib/morpheus/api/library_container_scripts_interface.rb +49 -0
  6. data/lib/morpheus/api/library_container_templates_interface.rb +49 -0
  7. data/lib/morpheus/api/library_container_types_interface.rb +65 -0
  8. data/lib/morpheus/api/library_container_upgrades_interface.rb +66 -0
  9. data/lib/morpheus/api/library_instance_types_interface.rb +59 -0
  10. data/lib/morpheus/api/library_layouts_interface.rb +65 -0
  11. data/lib/morpheus/api/servers_interface.rb +4 -0
  12. data/lib/morpheus/api/user_sources_interface.rb +120 -0
  13. data/lib/morpheus/api/virtual_images_interface.rb +7 -0
  14. data/lib/morpheus/cli.rb +12 -1
  15. data/lib/morpheus/cli/accounts.rb +35 -9
  16. data/lib/morpheus/cli/cli_command.rb +82 -2
  17. data/lib/morpheus/cli/curl_command.rb +1 -1
  18. data/lib/morpheus/cli/echo_command.rb +1 -1
  19. data/lib/morpheus/cli/hosts.rb +40 -14
  20. data/lib/morpheus/cli/instance_types.rb +106 -64
  21. data/lib/morpheus/cli/instances.rb +39 -15
  22. data/lib/morpheus/cli/library.rb +1 -1184
  23. data/lib/morpheus/cli/library_container_scripts_command.rb +437 -0
  24. data/lib/morpheus/cli/library_container_templates_command.rb +397 -0
  25. data/lib/morpheus/cli/library_container_types_command.rb +653 -0
  26. data/lib/morpheus/cli/library_instance_types_command.rb +491 -0
  27. data/lib/morpheus/cli/library_layouts_command.rb +650 -0
  28. data/lib/morpheus/cli/library_option_lists_command.rb +476 -0
  29. data/lib/morpheus/cli/library_option_types_command.rb +549 -0
  30. data/lib/morpheus/cli/library_upgrades_command.rb +604 -0
  31. data/lib/morpheus/cli/mixins/library_helper.rb +123 -0
  32. data/lib/morpheus/cli/mixins/print_helper.rb +21 -22
  33. data/lib/morpheus/cli/mixins/provisioning_helper.rb +56 -11
  34. data/lib/morpheus/cli/network_services_command.rb +1 -1
  35. data/lib/morpheus/cli/option_types.rb +12 -2
  36. data/lib/morpheus/cli/power_scheduling_command.rb +1 -1
  37. data/lib/morpheus/cli/shell.rb +120 -22
  38. data/lib/morpheus/cli/sleep_command.rb +45 -0
  39. data/lib/morpheus/cli/user_sources_command.rb +963 -0
  40. data/lib/morpheus/cli/users.rb +33 -2
  41. data/lib/morpheus/cli/version.rb +1 -1
  42. data/lib/morpheus/cli/version_command.rb +1 -1
  43. data/lib/morpheus/cli/virtual_images.rb +93 -39
  44. data/lib/morpheus/formatters.rb +37 -27
  45. data/lib/morpheus/terminal.rb +1 -1
  46. metadata +20 -2
@@ -0,0 +1,650 @@
1
+ require 'io/console'
2
+ require 'optparse'
3
+ require 'filesize'
4
+ require 'morpheus/cli/cli_command'
5
+ require 'morpheus/cli/mixins/library_helper'
6
+
7
+ class Morpheus::Cli::LibraryLayoutsCommand
8
+ include Morpheus::Cli::CliCommand
9
+ include Morpheus::Cli::LibraryHelper
10
+
11
+ set_command_name :'library-layouts'
12
+
13
+ register_subcommands :list, :get, :add, :update, :remove
14
+
15
+ def initialize()
16
+ # @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
17
+ end
18
+
19
+ def connect(opts)
20
+ @api_client = establish_remote_appliance_connection(opts)
21
+ @library_layouts_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).library_layouts
22
+ @library_instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).library_instance_types
23
+ @provision_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).provision_types
24
+ @option_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).option_types
25
+ @option_type_lists_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).option_type_lists
26
+ end
27
+
28
+ def handle(args)
29
+ handle_subcommand(args)
30
+ end
31
+
32
+
33
+ def list(args)
34
+ options = {}
35
+ params = {}
36
+ instance_type = nil
37
+ instance_type_id = nil
38
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
39
+ opts.banner = subcommand_usage()
40
+ opts.on('--instance-type ID', String, "Filter by Instance Type") do |val|
41
+ instance_type_id = val
42
+ end
43
+ opts.on('--category VALUE', String, "Filter by category") do |val|
44
+ params['category'] = val
45
+ end
46
+ opts.on('--code VALUE', String, "Filter by code") do |val|
47
+ params['code'] = val
48
+ end
49
+ opts.on('--technology VALUE', String, "Filter by technology") do |val|
50
+ params['provisionType'] = val
51
+ end
52
+ build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
53
+ opts.footer = "List layouts."
54
+ end
55
+ optparse.parse!(args)
56
+ connect(options)
57
+ begin
58
+ # construct payload
59
+ if instance_type_id
60
+ instance_type = find_instance_type_by_name_or_id(instance_type_id)
61
+ return 1 if instance_type.nil?
62
+ instance_type_id = instance_type['id']
63
+ end
64
+
65
+ params.merge!(parse_list_options(options))
66
+
67
+ if options[:dry_run]
68
+ print_dry_run @library_layouts_interface.dry.list(instance_type_id, params)
69
+ return
70
+ end
71
+
72
+ json_response = @library_layouts_interface.list(instance_type_id, params)
73
+ if options[:include_fields]
74
+ json_response = {"instanceTypeLayouts" => filter_data(json_response["instanceTypeLayouts"], options[:include_fields]) }
75
+ end
76
+ if options[:json]
77
+ puts as_json(json_response, options)
78
+ return 0
79
+ elsif options[:csv]
80
+ puts records_as_csv(json_response['instanceTypeLayouts'], options)
81
+ return 0
82
+ elsif options[:yaml]
83
+ puts as_yaml(json_response, options)
84
+ return 0
85
+ end
86
+ layouts = json_response['instanceTypeLayouts']
87
+ title = "Morpheus Library - Layouts"
88
+ subtitles = []
89
+ if instance_type
90
+ subtitles << "Instance Type: #{instance_type['name']}".strip
91
+ end
92
+ subtitles += parse_list_subtitles(options)
93
+ print_h1 title, subtitles
94
+ if layouts.empty?
95
+ print cyan,"No layouts found.",reset,"\n"
96
+ else
97
+ print_layouts_table(layouts, options)
98
+ print_results_pagination(json_response, {:label => "layout", :n_label => "layouts"})
99
+ # print_results_pagination(json_response)
100
+ end
101
+ print reset,"\n"
102
+ rescue RestClient::Exception => e
103
+ print_rest_exception(e, options)
104
+ return 1
105
+ end
106
+ end
107
+
108
+ def get(args)
109
+ options = {}
110
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
111
+ opts.banner = subcommand_usage("[name]")
112
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
113
+ end
114
+ optparse.parse!(args)
115
+ if args.count < 1
116
+ puts optparse
117
+ return 1
118
+ end
119
+ connect(options)
120
+ id_list = parse_id_list(args)
121
+ return run_command_for_each_arg(id_list) do |arg|
122
+ _get(arg, options)
123
+ end
124
+ end
125
+
126
+ def _get(id, options)
127
+ instance_type_id = nil
128
+ begin
129
+ if options[:dry_run]
130
+ if id.to_s =~ /\A\d{1,}\Z/
131
+ print_dry_run @library_layouts_interface.dry.get(instance_type_id, id.to_i)
132
+ else
133
+ print_dry_run @library_layouts_interface.dry.list(instance_type_id, {name:id})
134
+ end
135
+ return
136
+ end
137
+ layout = find_layout_by_name_or_id(instance_type_id, id)
138
+ if layout.nil?
139
+ return 1
140
+ end
141
+ # skip redundant request
142
+ #json_response = @library_layouts_interface.get(instance_type_id, layout['id'])
143
+ json_response = {'instanceTypeLayout' => layout}
144
+ #layout = json_response['instanceTypeLayout']
145
+ if options[:include_fields]
146
+ json_response = {"instanceTypeLayout" => filter_data(json_response["instanceTypeLayout"], options[:include_fields]) }
147
+ end
148
+ if options[:json]
149
+ puts as_json(json_response, options)
150
+ return 0
151
+ elsif options[:yaml]
152
+ puts as_yaml(json_response, options)
153
+ return 0
154
+ elsif options[:csv]
155
+ puts records_as_csv([json_response['instanceTypeLayout']], options)
156
+ return 0
157
+ end
158
+
159
+ print_h1 "Layout Details"
160
+ print cyan
161
+ description_cols = {
162
+ "ID" => lambda {|it| it['id'] },
163
+ "Name" => lambda {|it| it['name'] },
164
+ #"Code" => lambda {|it| it['code'] },
165
+ "Version" => lambda {|it| it['instanceVersion'] },
166
+ "Description" => lambda {|it| it['description'] },
167
+ "Technology" => lambda {|it| format_layout_technology(it) },
168
+ "Min Memory" => lambda {|it|
169
+ if it['memoryRequirement'].to_i != 0
170
+ (it['memoryRequirement'].to_i / (1024*1024)).to_s + " MB"
171
+ else
172
+ ""
173
+ end
174
+ },
175
+ "Workflow" => lambda {|it|
176
+ if it['taskSets']
177
+ it['taskSets'][0]['name'] rescue ""
178
+ else
179
+ ""
180
+ end
181
+ },
182
+ # "Category" => lambda {|it| it['category'].to_s.capitalize },
183
+ # # "Logo" => lambda {|it| it['logo'].to_s },
184
+ # "Visiblity" => lambda {|it| it['visibility'].to_s.capitalize },
185
+ # "Environment Prefix" => lambda {|it| it['environmentPrefix'] },
186
+ # "Enable Settings" => lambda {|it| format_boolean it['hasSettings'] },
187
+ # "Enable Scaling" => lambda {|it| format_boolean it['hasAutoScale'] },
188
+ # "Supports Deployments" => lambda {|it| format_boolean it['hasDeployment'] },
189
+ # "Featured" => lambda {|it| format_boolean it['featured'] },
190
+ # "Owner" => lambda {|it| it['account'] ? it['account']['name'] : '' },
191
+ # "Active" => lambda {|it| format_boolean it['active'] },
192
+ # "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
193
+ # "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
194
+ }
195
+ print_description_list(description_cols, layout)
196
+
197
+
198
+
199
+ layout_evars = layout['environmentVariables']
200
+ if layout_evars && layout_evars.size > 0
201
+ print_h2 "Environment Variables"
202
+ evar_columns = [
203
+ {"NAME" => lambda {|it| it['name'] } },
204
+ {"VALUE" => lambda {|it| it['defaultValue'] } },
205
+ {"TYPE" => lambda {|it| it['valueType'].to_s.capitalize } },
206
+ {"EXPORT" => lambda {|it| format_boolean it['export'] } },
207
+ {"MASKED" => lambda {|it| format_boolean it['mask'] } },
208
+ ]
209
+ print as_pretty_table(layout_evars, evar_columns)
210
+ else
211
+ # print yellow,"No environment variables found for this instance type.","\n",reset
212
+ end
213
+
214
+ layout_option_types = layout['optionTypes']
215
+ if layout_option_types && layout_option_types.size > 0
216
+ print_h2 "Option Types"
217
+ columns = [
218
+ {"ID" => lambda {|it| it['id'] } },
219
+ {"NAME" => lambda {|it| it['name'] } },
220
+ {"TYPE" => lambda {|it| it['type'] } },
221
+ {"FIELD NAME" => lambda {|it| it['fieldName'] } },
222
+ {"FIELD LABEL" => lambda {|it| it['fieldLabel'] } },
223
+ {"DEFAULT" => lambda {|it| it['defaultValue'] } },
224
+ {"REQUIRED" => lambda {|it| format_boolean it['required'] } },
225
+ ]
226
+ print as_pretty_table(layout_option_types, columns)
227
+ else
228
+ # print yellow,"No option types found for this layout.","\n",reset
229
+ end
230
+
231
+ print_h2 "Node Types"
232
+ layout_node_types = layout['containerTypes']
233
+ if layout_node_types && layout_node_types.size > 0
234
+ # match UI sorting [version desc, name asc]
235
+ # or use something simpler like one of these
236
+ layout_node_types = layout_node_types.sort { |a,b| a['name'] <=> b['name'] }
237
+ # layout_node_types = layout_node_types.sort { |a,b| a['sortOrder'] <=> b['sortOrder'] }
238
+ node_type_columns = [
239
+ {"ID" => lambda {|it| it['id'] } },
240
+ {"NAME" => lambda {|it| it['name'] } },
241
+ {"SHORT NAME" => lambda {|it| it['shortName'] } },
242
+ {"VERSION" => lambda {|it| it['containerVersion'] } },
243
+ {"TECHNOLOGY" => lambda {|it| it['provisionType'] ? it['provisionType']['name'] : '' } },
244
+ {"CATEGORY" => lambda {|it| it['category'] } },
245
+ ]
246
+ print as_pretty_table(layout_node_types, node_type_columns)
247
+ else
248
+ print yellow,"No node types for this layout.","\n",reset
249
+ end
250
+
251
+ print reset,"\n"
252
+
253
+ rescue RestClient::Exception => e
254
+ print_rest_exception(e, options)
255
+ return 1
256
+ end
257
+ end
258
+
259
+ def add(args)
260
+ options = {}
261
+ params = {}
262
+ instance_type_id = nil
263
+ option_type_ids = nil
264
+ node_type_ids = nil
265
+ evars = nil
266
+ optparse = Morpheus::Cli::OptionParser.new do|opts|
267
+ opts.banner = subcommand_usage("[instance-type]")
268
+ opts.on('--instance-type ID', String, "Instance Type") do |val|
269
+ instance_type_id = val
270
+ end
271
+ opts.on('--name VALUE', String, "Name for this layout") do |val|
272
+ params['name'] = val
273
+ end
274
+ opts.on('--version VALUE', String, "Version") do |val|
275
+ params['instanceVersion'] = val
276
+ end
277
+ opts.on('--description VALUE', String, "Description") do |val|
278
+ params['description'] = val
279
+ end
280
+ opts.on('--technology CODE', String, "Technology") do |val|
281
+ params['provisionTypeCode'] = val
282
+ end
283
+ opts.on('--min-memory VALUE', String, "Minimum Memory (MB)") do |val|
284
+ params['memoryRequirement'] = val
285
+ end
286
+ opts.on('--workflow ID', String, "Workflow") do |val|
287
+ params['taskSetId'] = val.to_i
288
+ end
289
+ opts.on('--option-types x,y,z', Array, "List of Option Type IDs") do |val|
290
+ option_type_ids = val #.collect {|it| it.to_i }
291
+ end
292
+ opts.on('--node-types x,y,z', Array, "List of Node Type IDs") do |val|
293
+ node_type_ids = val #.collect {|it| it.to_i }
294
+ end
295
+ #build_option_type_options(opts, options, add_layout_option_types())
296
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
297
+ opts.footer = "Create a new layout." + "\n" +
298
+ "[instance-type] is required and can be passed as --instance-type instead."
299
+ end
300
+ optparse.parse!(args)
301
+ connect(options)
302
+
303
+ if instance_type_id.nil?
304
+ instance_type_id = args[0]
305
+ end
306
+
307
+ if !instance_type_id
308
+ puts optparse
309
+ exit 1
310
+ end
311
+
312
+ begin
313
+ instance_type = find_instance_type_by_name_or_id(instance_type_id)
314
+ exit 1 if instance_type.nil?
315
+ instance_type_id = instance_type['id']
316
+
317
+ # construct payload
318
+ payload = nil
319
+ if options[:payload]
320
+ payload = options[:payload]
321
+ else
322
+ # v_prompt = Morpheus::Cli::OptionTypes.prompt(add_layout_option_types, options[:options], @api_client, options[:params])
323
+ # params.deep_merge!(v_prompt)
324
+ params.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
325
+
326
+ if !params['name']
327
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Name', 'required' => true}], options[:options])
328
+ params['name'] = v_prompt['name']
329
+ end
330
+ if !params['instanceVersion']
331
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'instanceVersion', 'type' => 'text', 'fieldLabel' => 'Version', 'required' => true}], options[:options])
332
+ params['instanceVersion'] = v_prompt['instanceVersion']
333
+ end
334
+ if !params['description']
335
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'description', 'type' => 'text', 'fieldLabel' => 'Description', 'required' => false}], options[:options])
336
+ params['description'] = v_prompt['description'] if v_prompt['description']
337
+ end
338
+
339
+ provision_types = @provision_types_interface.get({customSupported: true})['provisionTypes']
340
+ if provision_types.empty?
341
+ print_red_alert "No available provision types found!"
342
+ exit 1
343
+ end
344
+ provision_type_options = provision_types.collect {|it| { 'name' => it['name'], 'value' => it['code']} }
345
+
346
+ if !params['provisionTypeCode']
347
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'provisionTypeCode', 'type' => 'select', 'selectOptions' => provision_type_options, 'fieldLabel' => 'Technology', 'required' => true, 'description' => 'The type of container technology.'}], options[:options])
348
+ params['provisionTypeCode'] = v_prompt['provisionTypeCode']
349
+ else
350
+
351
+ end
352
+ provision_type = provision_types.find {|it| it['code'] == params['provisionTypeCode'] }
353
+
354
+ if !params['memoryRequirement']
355
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'memoryRequirement', 'type' => 'text', 'fieldLabel' => 'Min Memory (MB)', 'required' => false, 'description' => 'This will override any memory requirement set on the virtual image'}], options[:options])
356
+ params['memoryRequirement'] = v_prompt['memoryRequirement'] if v_prompt['memoryRequirement']
357
+ end
358
+
359
+ if !params['taskSetId']
360
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'taskSetId', 'type' => 'text', 'fieldLabel' => 'Workflow ID', 'required' => false, 'description' => 'Worflow ID'}], options[:options])
361
+ params['taskSetId'] = v_prompt['taskSetId'].to_i if v_prompt['taskSetId']
362
+ end
363
+
364
+ # ENVIRONMENT VARIABLES
365
+ if evars
366
+
367
+ else
368
+ # prompt
369
+ end
370
+
371
+ # OPTION TYPES
372
+ if option_type_ids
373
+ params['optionTypes'] = option_type_ids.collect {|it| it.to_i }.select { |it| it != 0 }
374
+ else
375
+ # prompt
376
+ end
377
+
378
+ # NODE TYPES
379
+ if node_type_ids
380
+ params['containerTypes'] = node_type_ids.collect {|it| it.to_i }.select { |it| it != 0 }
381
+ else
382
+ # prompt
383
+ end
384
+
385
+
386
+ payload = {'instanceTypeLayout' => params}
387
+
388
+ end
389
+
390
+ if options[:dry_run]
391
+ print_dry_run @library_layouts_interface.dry.create(instance_type_id, payload)
392
+ return
393
+ end
394
+
395
+ json_response = @library_layouts_interface.create(instance_type_id, payload)
396
+
397
+ if options[:json]
398
+ print JSON.pretty_generate(json_response), "\n"
399
+ return
400
+ end
401
+
402
+ print_green_success "Added Layout #{params['name']}"
403
+
404
+ #get([json_response['instanceTypeLayout']['id']])
405
+
406
+ rescue RestClient::Exception => e
407
+ print_rest_exception(e, options)
408
+ exit 1
409
+ end
410
+ end
411
+
412
+ def update(args)
413
+ options = {}
414
+ params = {}
415
+ instance_type_id = nil
416
+ option_type_ids = nil
417
+ node_type_ids = nil
418
+ evars = nil
419
+ optparse = Morpheus::Cli::OptionParser.new do|opts|
420
+ opts.banner = subcommand_usage("[name] [options]")
421
+ opts.on('--name VALUE', String, "Name for this layout") do |val|
422
+ params['name'] = val
423
+ end
424
+ opts.on('--version VALUE', String, "Version") do |val|
425
+ params['instanceVersion'] = val
426
+ end
427
+ opts.on('--description VALUE', String, "Description") do |val|
428
+ params['description'] = val
429
+ end
430
+ # opts.on('--technology CODE', String, "Technology") do |val|
431
+ # params['provisionTypeCode'] = val
432
+ # end
433
+ opts.on('--min-memory VALUE', String, "Minimum Memory (MB)") do |val|
434
+ params['memoryRequirement'] = val
435
+ end
436
+ opts.on('--workflow ID', String, "Workflow") do |val|
437
+ params['taskSetId'] = val.to_i
438
+ end
439
+ opts.on('--option-types x,y,z', Array, "List of Option Type IDs") do |val|
440
+ option_type_ids = val #.collect {|it| it.to_i }
441
+ end
442
+ opts.on('--node-types x,y,z', Array, "List of Node Type IDs") do |val|
443
+ node_type_ids = val #.collect {|it| it.to_i }
444
+ end
445
+ #build_option_type_options(opts, options, update_layout_option_types())
446
+ build_common_options(opts, options, [:options, :json, :dry_run, :remote])
447
+ opts.footer = "Update a layout."
448
+ end
449
+ optparse.parse!(args)
450
+ if args.count < 1
451
+ puts optparse
452
+ exit 1
453
+ end
454
+ connect(options)
455
+ begin
456
+ layout = find_layout_by_name_or_id(nil, args[0])
457
+ exit 1 if layout.nil?
458
+ payload = nil
459
+ if options[:payload]
460
+ payload = options[:payload]
461
+ else
462
+ # option_types = update_layout_option_types(instance_type)
463
+ # params = Morpheus::Cli::OptionTypes.prompt(option_types, options[:options], @api_client, options[:params])
464
+ params.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
465
+
466
+ # ENVIRONMENT VARIABLES
467
+ if evars
468
+
469
+ else
470
+ # prompt
471
+ end
472
+
473
+ # OPTION TYPES
474
+ if option_type_ids
475
+ params['optionTypes'] = option_type_ids.collect {|it| it.to_i }.select { |it| it != 0 }
476
+ else
477
+ # prompt
478
+ end
479
+
480
+ # NODE TYPES
481
+ if node_type_ids
482
+ params['containerTypes'] = node_type_ids.collect {|it| it.to_i }.select { |it| it != 0 }
483
+ else
484
+ # prompt
485
+ end
486
+
487
+ if params.empty?
488
+ puts optparse
489
+ exit 1
490
+ end
491
+
492
+ payload = {'instanceTypeLayout' => params}
493
+
494
+ end
495
+
496
+ if options[:dry_run]
497
+ print_dry_run @library_layouts_interface.dry.update(nil, layout['id'], payload)
498
+ return
499
+ end
500
+
501
+ json_response = @library_layouts_interface.update(nil, layout['id'], payload)
502
+
503
+ if options[:json]
504
+ print JSON.pretty_generate(json_response), "\n"
505
+ return
506
+ end
507
+
508
+ print_green_success "Updated Layout #{params['name'] || layout['name']}"
509
+ #list([])
510
+ rescue RestClient::Exception => e
511
+ print_rest_exception(e, options)
512
+ exit 1
513
+ end
514
+ end
515
+
516
+ def remove(args)
517
+ options = {}
518
+ optparse = Morpheus::Cli::OptionParser.new do|opts|
519
+ opts.banner = subcommand_usage("[name]")
520
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
521
+ opts.footer = "Delete a layout."
522
+ end
523
+ optparse.parse!(args)
524
+ if args.count < 1
525
+ puts optparse
526
+ exit 1
527
+ end
528
+ connect(options)
529
+
530
+ begin
531
+ layout = find_layout_by_name_or_id(nil, args[0])
532
+ exit 1 if layout.nil?
533
+
534
+ unless Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the instance type #{layout['name']}?", options)
535
+ exit
536
+ end
537
+ if options[:dry_run]
538
+ print_dry_run @library_layouts_interface.dry.destroy(nil, layout['id'])
539
+ return
540
+ end
541
+ json_response = @library_layouts_interface.destroy(nil, layout['id'])
542
+
543
+ if options[:json]
544
+ print JSON.pretty_generate(json_response), "\n"
545
+ return
546
+ end
547
+
548
+ print_green_success "Removed Layout #{layout['name']}"
549
+ #list([])
550
+ rescue RestClient::Exception => e
551
+ print_rest_exception(e, options)
552
+ exit 1
553
+ end
554
+ end
555
+
556
+ private
557
+
558
+ def find_layout_by_name_or_id(instance_type_id, val)
559
+ if val.to_s =~ /\A\d{1,}\Z/
560
+ return find_layout_by_id(instance_type_id, val)
561
+ else
562
+ return find_layout_by_name(instance_type_id, val)
563
+ end
564
+ end
565
+
566
+ def find_layout_by_id(instance_type_id, id)
567
+ begin
568
+ json_response = @library_layouts_interface.get(instance_type_id, id.to_i)
569
+ return json_response['instanceTypeLayout']
570
+ rescue RestClient::Exception => e
571
+ if e.response && e.response.code == 404
572
+ print_red_alert "Instance Type not found by id #{id}"
573
+ else
574
+ raise e
575
+ end
576
+ end
577
+ end
578
+
579
+ def find_layout_by_name(instance_type_id, name)
580
+ layouts = @library_layouts_interface.list(instance_type_id, {name: name.to_s})['instanceTypeLayouts']
581
+ if layouts.empty?
582
+ print_red_alert "Layout not found by name #{name}"
583
+ return nil
584
+ elsif layouts.size > 1
585
+ print_red_alert "#{layouts.size} layouts found by name #{name}"
586
+ print_layouts_table(layouts, {color: red})
587
+ print_red_alert "Try using ID instead"
588
+ print reset,"\n"
589
+ return nil
590
+ else
591
+ return layouts[0]
592
+ end
593
+ end
594
+
595
+ def print_layouts_table(layouts, opts={})
596
+ columns = [
597
+ {"ID" => lambda {|layout| layout['id'] } },
598
+ {"INSTANCE TYPE" => lambda {|layout| layout['instanceType'] ? layout['instanceType']['name'] : '' } },
599
+ {"NAME" => lambda {|layout| layout['name'] } },
600
+ {"VERSION" => lambda {|layout| layout['instanceVersion'] } },
601
+ {"TECHNOLOGY" => lambda {|layout| format_layout_technology(layout) } },
602
+ {"DESCRIPTION" => lambda {|layout| layout['description'] } },
603
+ {"OWNER" => lambda {|layout| layout['account'] ? layout['account']['name'] : '' } }
604
+ ]
605
+ if opts[:include_fields]
606
+ columns = opts[:include_fields]
607
+ end
608
+ print as_pretty_table(layouts, columns, opts)
609
+ end
610
+
611
+ def format_layout_technology(layout)
612
+ if layout
613
+ layout['provisionType'] ? layout['provisionType']['name'] : ''
614
+ else
615
+ ""
616
+ end
617
+ end
618
+
619
+ def format_instance_type_phase(val)
620
+ val.to_s # .capitalize
621
+ end
622
+
623
+ def add_layout_option_types
624
+ [
625
+ # {'fieldName' => 'instanceTypeId', 'fieldLabel' => 'Instance Type ID', 'type' => 'text', 'required' => true, 'displayOrder' => 2, 'description' => 'The instance type this layout belongs to'},
626
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
627
+ {'fieldName' => 'code', 'fieldLabel' => 'Code', 'type' => 'text', 'required' => true, 'displayOrder' => 2, 'description' => 'Useful shortcode for provisioning naming schemes and export reference.'},
628
+ {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'displayOrder' => 3},
629
+ {'fieldName' => 'category', 'fieldLabel' => 'Category', 'type' => 'select', 'optionSource' => 'categories', 'required' => true, 'displayOrder' => 4},
630
+ {'fieldName' => 'logo', 'fieldLabel' => 'Icon File', 'type' => 'text', 'displayOrder' => 5},
631
+ {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'displayOrder' => 6},
632
+ {'fieldName' => 'environmentPrefix', 'fieldLabel' => 'Environment Prefix', 'type' => 'text', 'displayOrder' => 7, 'description' => 'Used for exportable environment variables when tying instance types together in app contexts. If not specified a name will be generated.'},
633
+ {'fieldName' => 'hasSettings', 'fieldLabel' => 'Enable Settings', 'type' => 'checkbox', 'displayOrder' => 8},
634
+ {'fieldName' => 'hasAutoScale', 'fieldLabel' => 'Enable Scaling (Horizontal)', 'type' => 'checkbox', 'displayOrder' => 9},
635
+ {'fieldName' => 'hasDeployment', 'fieldLabel' => 'Supports Deployments', 'type' => 'checkbox', 'displayOrder' => 10, 'description' => 'Requires a data volume be configured on each version. Files will be copied into this location.'}
636
+ ]
637
+ end
638
+
639
+ def update_layout_option_types(instance_type=nil)
640
+ if instance_type
641
+ opts = add_layout_option_types
642
+ opts.find {|opt| opt['fieldName'] == 'name'}['defaultValue'] = instance_type['name']
643
+ opts
644
+ else
645
+ add_layout_option_types
646
+ end
647
+ end
648
+
649
+
650
+ end