morpheus-cli 3.3.1.4 → 3.3.2

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.
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