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,437 @@
1
+ require 'morpheus/cli/cli_command'
2
+
3
+ class Morpheus::Cli::LibraryContainerScriptsCommand
4
+ include Morpheus::Cli::CliCommand
5
+
6
+ set_command_name :'library-scripts'
7
+
8
+ register_subcommands :list, :get, :add, :update, :remove
9
+
10
+ def connect(opts)
11
+ @api_client = establish_remote_appliance_connection(opts)
12
+ @container_scripts_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).library_container_scripts
13
+ end
14
+
15
+ def handle(args)
16
+ handle_subcommand(args)
17
+ end
18
+
19
+ def list(args)
20
+ options = {}
21
+ params = {}
22
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
23
+ opts.banner = subcommand_usage()
24
+ build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
25
+ opts.footer = "List container scripts."
26
+ end
27
+ optparse.parse!(args)
28
+ connect(options)
29
+ if args.count > 0
30
+ print_error Morpheus::Terminal.angry_prompt
31
+ puts_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args.inspect}\n#{optparse}"
32
+ return 1
33
+ end
34
+ begin
35
+ # construct payload
36
+ params.merge!(parse_list_options(options))
37
+ # dry run?
38
+ if options[:dry_run]
39
+ print_dry_run @container_scripts_interface.dry.list(params)
40
+ return
41
+ end
42
+ # do it
43
+ json_response = @container_scripts_interface.list(params)
44
+ container_scripts = json_response['containerScripts']
45
+ if options[:include_fields]
46
+ json_response = {"containerScripts" => filter_data(json_response["containerScripts"], options[:include_fields]) }
47
+ end
48
+ # print result and return output
49
+ if options[:json]
50
+ puts as_json(json_response, options)
51
+ return 0
52
+ elsif options[:csv]
53
+ puts records_as_csv(json_response['containerScripts'], options)
54
+ return 0
55
+ elsif options[:yaml]
56
+ puts as_yaml(json_response, options)
57
+ return 0
58
+ end
59
+ container_scripts = json_response['containerScripts']
60
+ title = "Morpheus Library - Scripts"
61
+ subtitles = []
62
+ subtitles += parse_list_subtitles(options)
63
+ print_h1 title, subtitles
64
+ if container_scripts.empty?
65
+ print cyan,"No container scripts found.",reset,"\n"
66
+ else
67
+ print_container_scripts_table(container_scripts, options)
68
+ print_results_pagination(json_response, {:label => "container script", :n_label => "container scripts"})
69
+ end
70
+ print reset,"\n"
71
+ rescue RestClient::Exception => e
72
+ print_rest_exception(e, options)
73
+ return 1
74
+ end
75
+ end
76
+
77
+ def get(args)
78
+ options = {}
79
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
80
+ opts.banner = subcommand_usage("[name]")
81
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
82
+ end
83
+ optparse.parse!(args)
84
+ if args.count < 1
85
+ puts optparse
86
+ return 1
87
+ end
88
+ connect(options)
89
+ id_list = parse_id_list(args)
90
+ return run_command_for_each_arg(id_list) do |arg|
91
+ _get(arg, options)
92
+ end
93
+ end
94
+
95
+ def _get(id, options)
96
+
97
+ begin
98
+ container_script = find_container_script_by_name_or_id(id)
99
+ if container_script.nil?
100
+ return 1
101
+ end
102
+ if options[:dry_run]
103
+ print_dry_run @container_scripts_interface.dry.get(container_script['id'])
104
+ return
105
+ end
106
+ json_response = @container_scripts_interface.get(container_script['id'])
107
+ container_script = json_response['containerScript']
108
+ instances = json_response['instances'] || []
109
+ servers = json_response['servers'] || []
110
+ if options[:include_fields]
111
+ json_response = {"containerScript" => filter_data(json_response["containerScript"], options[:include_fields]) }
112
+ end
113
+ if options[:json]
114
+ puts as_json(json_response, options)
115
+ return 0
116
+ elsif options[:yaml]
117
+ puts as_yaml(json_response, options)
118
+ return 0
119
+ elsif options[:csv]
120
+ puts records_as_csv([json_response['containerScript']], options)
121
+ return 0
122
+ end
123
+
124
+ print_h1 "Container Script Details"
125
+ print cyan
126
+ description_cols = {
127
+ "ID" => lambda {|it| it['id'] },
128
+ "Name" => lambda {|it| it['name'] },
129
+ "Type" => lambda {|it| format_container_script_type(it['scriptType']) },
130
+ "Phase" => lambda {|it| format_container_script_phase(it['scriptPhase']) },
131
+ "Owner" => lambda {|it| it['account'] ? it['account']['name'] : '' },
132
+ # "Enabled" => lambda {|it| format_boolean it['enabled'] },
133
+ # "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
134
+ # "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
135
+ }
136
+ print_description_list(description_cols, container_script)
137
+
138
+ print_h2 "Script"
139
+
140
+ puts container_script['script']
141
+
142
+
143
+
144
+ print reset,"\n"
145
+
146
+ rescue RestClient::Exception => e
147
+ print_rest_exception(e, options)
148
+ return 1
149
+ end
150
+ end
151
+
152
+ def add(args)
153
+ options = {}
154
+ params = {'scriptType' => 'bash', 'scriptPhase' => 'postProvision'}
155
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
156
+ opts.banner = subcommand_usage("[name]")
157
+ opts.on('--name VALUE', String, "Name") do |val|
158
+ params['name'] = val
159
+ end
160
+ opts.on('--type [bash|powershell]', String, "Script Type. Default is 'bash'") do |val|
161
+ params['scriptType'] = val
162
+ end
163
+ opts.on('--phase [start|stop|postProvision]', String, "Script Phase. Default is 'postProvision'") do |val|
164
+ params['scriptPhase'] = val
165
+ end
166
+ opts.on('--category VALUE', String, "Category") do |val|
167
+ params['category'] = val
168
+ end
169
+ opts.on('--script TEXT', String, "Contents of the script.") do |val|
170
+ params['script'] = val
171
+ end
172
+ opts.on('--file FILE', "File containing the script. This can be used instead --script" ) do |filename|
173
+ full_filename = File.expand_path(filename)
174
+ if File.exists?(full_filename)
175
+ params['script'] = File.read(full_filename)
176
+ else
177
+ print_red_alert "File not found: #{full_filename}"
178
+ exit 1
179
+ end
180
+ # use the filename as the name by default.
181
+ if !params['name']
182
+ params['name'] = File.basename(full_filename)
183
+ end
184
+ end
185
+ # opts.on('--enabled [on|off]', String, "Can be used to disable it") do |val|
186
+ # options['enabled'] = !(val.to_s == 'off' || val.to_s == 'false')
187
+ # end
188
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote, :quiet])
189
+ opts.footer = "Create a new container script." + "\n" +
190
+ "[name] is required and can be passed as --name instead."
191
+ end
192
+ optparse.parse!(args)
193
+ # support [name] as first argument
194
+ if args[0]
195
+ params['name'] = args[0]
196
+ end
197
+ if !params['name']
198
+ print_error Morpheus::Terminal.angry_prompt
199
+ puts_error "wrong number of arguments, expected 0-1 and got (#{args.count}) #{args.inspect}\n#{optparse}"
200
+ return 1
201
+ end
202
+ connect(options)
203
+ begin
204
+ # construct payload
205
+ payload = nil
206
+ if options[:payload]
207
+ payload = options[:payload]
208
+ else
209
+ # merge -O options into normally parsed options
210
+ params.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
211
+ # todo: prompt?
212
+ payload = {'containerScript' => params}
213
+ end
214
+ if options[:dry_run]
215
+ print_dry_run @container_scripts_interface.dry.create(payload)
216
+ return
217
+ end
218
+ json_response = @container_scripts_interface.create(payload)
219
+ if options[:json]
220
+ puts as_json(json_response, options)
221
+ elsif !options[:quiet]
222
+ container_script = json_response['containerScript']
223
+ print_green_success "Added container script #{container_script['name']}"
224
+ _get(container_script['id'], {})
225
+ end
226
+ return 0
227
+ rescue RestClient::Exception => e
228
+ print_rest_exception(e, options)
229
+ return 1
230
+ end
231
+ end
232
+
233
+
234
+ def update(args)
235
+ options = {}
236
+ params = {}
237
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
238
+ opts.banner = subcommand_usage("[name]")
239
+ opts.on('--name VALUE', String, "Name") do |val|
240
+ params['name'] = val
241
+ end
242
+ # opts.on('--code VALUE', String, "Code") do |val|
243
+ # params['code'] = val
244
+ # end
245
+ # opts.on('--description VALUE', String, "Description") do |val|
246
+ # params['description'] = val
247
+ # end
248
+ opts.on('--type [bash|powershell]', String, "Script Type") do |val|
249
+ params['scriptType'] = val
250
+ end
251
+ opts.on('--phase [start|stop]', String, "Script Phase") do |val|
252
+ params['scriptPhase'] = val
253
+ end
254
+ opts.on('--category VALUE', String, "Category") do |val|
255
+ params['category'] = val
256
+ end
257
+ opts.on('--script TEXT', String, "Contents of the script.") do |val|
258
+ params['script'] = val
259
+ end
260
+ opts.on('--file FILE', "File containing the script. This can be used instead --script" ) do |filename|
261
+ full_filename = File.expand_path(filename)
262
+ if File.exists?(full_filename)
263
+ params['script'] = File.read(full_filename)
264
+ else
265
+ print_red_alert "File not found: #{full_filename}"
266
+ exit 1
267
+ end
268
+ # use the filename as the name by default.
269
+ if !params['name']
270
+ params['name'] = File.basename(full_filename)
271
+ end
272
+ end
273
+ opts.on('--file FILE', "File containing the script. This can be used instead --script" ) do |filename|
274
+ if File.exists?(File.expand_path(filename))
275
+ params['script'] = File.read(File.expand_path(filename))
276
+ else
277
+ print_red_alert "File not found: #{filename}"
278
+ exit 1
279
+ end
280
+ end
281
+ # opts.on('--enabled [on|off]', String, "Can be used to disable it") do |val|
282
+ # options['enabled'] = !(val.to_s == 'off' || val.to_s == 'false')
283
+ # end
284
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote, :quiet])
285
+ opts.footer = "Update a container script." + "\n" +
286
+ "[name] is required. This is the name or id of a container script."
287
+ end
288
+ optparse.parse!(args)
289
+ if args.count != 1
290
+ print_error Morpheus::Terminal.angry_prompt
291
+ puts_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.inspect}\n#{optparse}"
292
+ return 1
293
+ end
294
+ connect(options)
295
+ begin
296
+ container_script = find_container_script_by_name_or_id(args[0])
297
+ if container_script.nil?
298
+ return 1
299
+ end
300
+ # construct payload
301
+ payload = nil
302
+ if options[:payload]
303
+ payload = options[:payload]
304
+ else
305
+ # merge -O options into normally parsed options
306
+ params.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
307
+ payload = {'containerScript' => params}
308
+ end
309
+ if options[:dry_run]
310
+ print_dry_run @container_scripts_interface.dry.update(container_script["id"], payload)
311
+ return
312
+ end
313
+ json_response = @container_scripts_interface.update(container_script["id"], payload)
314
+ if options[:json]
315
+ puts as_json(json_response, options)
316
+ elsif !options[:quiet]
317
+ print_green_success "Updated container script #{container_script['name']}"
318
+ _get(container_script['id'], {})
319
+ end
320
+ return 0
321
+ rescue RestClient::Exception => e
322
+ print_rest_exception(e, options)
323
+ return 1
324
+ end
325
+ end
326
+
327
+ def remove(args)
328
+ options = {}
329
+ params = {}
330
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
331
+ opts.banner = subcommand_usage("[name]")
332
+ build_common_options(opts, options, [:json, :dry_run, :quiet, :auto_confirm])
333
+ end
334
+ optparse.parse!(args)
335
+ if args.count < 1
336
+ puts optparse
337
+ return 127
338
+ end
339
+ connect(options)
340
+
341
+ begin
342
+ container_script = find_container_script_by_name_or_id(args[0])
343
+ if container_script.nil?
344
+ return 1
345
+ end
346
+
347
+ unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to delete container script '#{container_script['name']}'?", options)
348
+ return false
349
+ end
350
+
351
+ # payload = {
352
+ # 'containerScript' => {id: container_script["id"]}
353
+ # }
354
+ # payload['containerScript'].merge!(container_script)
355
+ payload = params
356
+
357
+ if options[:dry_run]
358
+ print_dry_run @container_scripts_interface.dry.destroy(container_script["id"])
359
+ return
360
+ end
361
+
362
+ json_response = @container_scripts_interface.destroy(container_script["id"])
363
+ if options[:json]
364
+ puts as_json(json_response, options)
365
+ elsif !options[:quiet]
366
+ print_green_success "Deleted container script #{container_script['name']}"
367
+ end
368
+ return 0, nil
369
+ rescue RestClient::Exception => e
370
+ print_rest_exception(e, options)
371
+ return 1
372
+ end
373
+ end
374
+
375
+
376
+ private
377
+
378
+ def find_container_script_by_name_or_id(val)
379
+ if val.to_s =~ /\A\d{1,}\Z/
380
+ return find_container_script_by_id(val)
381
+ else
382
+ return find_container_script_by_name(val)
383
+ end
384
+ end
385
+
386
+ def find_container_script_by_id(id)
387
+ begin
388
+ json_response = @container_scripts_interface.get(id.to_i)
389
+ return json_response['containerScript']
390
+ rescue RestClient::Exception => e
391
+ if e.response && e.response.code == 404
392
+ print_red_alert "Container Script not found by id #{id}"
393
+ else
394
+ raise e
395
+ end
396
+ end
397
+ end
398
+
399
+ def find_container_script_by_name(name)
400
+ container_scripts = @container_scripts_interface.list({name: name.to_s})['containerScripts']
401
+ if container_scripts.empty?
402
+ print_red_alert "Container Script not found by name #{name}"
403
+ return nil
404
+ elsif container_scripts.size > 1
405
+ print_red_alert "#{container_scripts.size} container scripts found by name #{name}"
406
+ print_container_scripts_table(container_scripts, {color: red})
407
+ print_red_alert "Try using ID instead"
408
+ print reset,"\n"
409
+ return nil
410
+ else
411
+ return container_scripts[0]
412
+ end
413
+ end
414
+
415
+ def print_container_scripts_table(container_scripts, opts={})
416
+ columns = [
417
+ {"ID" => lambda {|container_script| container_script['id'] } },
418
+ {"NAME" => lambda {|container_script| container_script['name'] } },
419
+ {"TYPE" => lambda {|container_script| format_container_script_type(container_script['scriptType']) } },
420
+ {"PHASE" => lambda {|container_script| format_container_script_phase(container_script['scriptPhase']) } },
421
+ {"OWNER" => lambda {|container_script| container_script['account'] ? container_script['account']['name'] : '' } },
422
+ ]
423
+ if opts[:include_fields]
424
+ columns = opts[:include_fields]
425
+ end
426
+ print as_pretty_table(container_scripts, columns, opts)
427
+ end
428
+
429
+ def format_container_script_type(val)
430
+ val.to_s # .capitalize
431
+ end
432
+
433
+ def format_container_script_phase(val)
434
+ val.to_s # .capitalize
435
+ end
436
+
437
+ end
@@ -0,0 +1,397 @@
1
+ require 'morpheus/cli/cli_command'
2
+ require 'morpheus/cli/mixins/library_helper'
3
+
4
+ class Morpheus::Cli::LibraryContainerTemplatesCommand
5
+ include Morpheus::Cli::CliCommand
6
+ include Morpheus::Cli::LibraryHelper
7
+
8
+ set_command_name :'library-file-templates'
9
+
10
+ register_subcommands :list, :get, :add, :update, :remove
11
+
12
+ def connect(opts)
13
+ @api_client = establish_remote_appliance_connection(opts)
14
+ @container_templates_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).library_container_templates
15
+ end
16
+
17
+ def handle(args)
18
+ handle_subcommand(args)
19
+ end
20
+
21
+ def list(args)
22
+ options = {}
23
+ params = {}
24
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
25
+ opts.banner = subcommand_usage()
26
+ build_common_options(opts, options, [:list, :json, :yaml, :csv, :fields, :dry_run, :remote])
27
+ end
28
+ optparse.parse!(args)
29
+ connect(options)
30
+ begin
31
+ [:phrase, :offset, :max, :sort, :direction, :lastUpdated].each do |k|
32
+ params[k] = options[k] unless options[k].nil?
33
+ end
34
+
35
+ if options[:dry_run]
36
+ print_dry_run @container_templates_interface.dry.list(params)
37
+ return
38
+ end
39
+
40
+ json_response = @container_templates_interface.list(params)
41
+ if options[:include_fields]
42
+ json_response = {"containerTemplates" => filter_data(json_response["containerTemplates"], options[:include_fields]) }
43
+ end
44
+ if options[:json]
45
+ puts as_json(json_response, options)
46
+ return 0
47
+ elsif options[:csv]
48
+ puts records_as_csv(json_response['containerTemplates'], options)
49
+ return 0
50
+ elsif options[:yaml]
51
+ puts as_yaml(json_response, options)
52
+ return 0
53
+ end
54
+ container_templates = json_response['containerTemplates']
55
+ title = "Morpheus Library - File Templates"
56
+ subtitles = []
57
+ # if group
58
+ # subtitles << "Group: #{group['name']}".strip
59
+ # end
60
+ # if cloud
61
+ # subtitles << "Cloud: #{cloud['name']}".strip
62
+ # end
63
+ if params[:phrase]
64
+ subtitles << "Search: #{params[:phrase]}".strip
65
+ end
66
+ print_h1 title, subtitles
67
+ if container_templates.empty?
68
+ print cyan,"No container file templates found.",reset,"\n"
69
+ else
70
+ print_container_templates_table(container_templates, options)
71
+ print_results_pagination(json_response, {:label => "container file template", :n_label => "container file templates"})
72
+ # print_results_pagination(json_response)
73
+ end
74
+ print reset,"\n"
75
+ rescue RestClient::Exception => e
76
+ print_rest_exception(e, options)
77
+ return 1
78
+ end
79
+ end
80
+
81
+ def get(args)
82
+ options = {}
83
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
84
+ opts.banner = subcommand_usage("[name]")
85
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
86
+ end
87
+ optparse.parse!(args)
88
+ if args.count < 1
89
+ puts optparse
90
+ return 1
91
+ end
92
+ connect(options)
93
+ id_list = parse_id_list(args)
94
+ return run_command_for_each_arg(id_list) do |arg|
95
+ _get(arg, options)
96
+ end
97
+ end
98
+
99
+ def _get(id, options)
100
+
101
+ begin
102
+ container_template = find_container_template_by_name_or_id(id)
103
+ if container_template.nil?
104
+ return 1
105
+ end
106
+ if options[:dry_run]
107
+ print_dry_run @container_templates_interface.dry.get(container_template['id'])
108
+ return
109
+ end
110
+ json_response = @container_templates_interface.get(container_template['id'])
111
+ container_template = json_response['containerTemplate']
112
+ instances = json_response['instances'] || []
113
+ servers = json_response['servers'] || []
114
+ if options[:include_fields]
115
+ json_response = {"containerTemplate" => filter_data(json_response["containerTemplate"], options[:include_fields]) }
116
+ end
117
+ if options[:json]
118
+ puts as_json(json_response, options)
119
+ return 0
120
+ elsif options[:yaml]
121
+ puts as_yaml(json_response, options)
122
+ return 0
123
+ elsif options[:csv]
124
+ puts records_as_csv([json_response['containerTemplate']], options)
125
+ return 0
126
+ end
127
+
128
+ print_h1 "File Template Details"
129
+ print cyan
130
+ description_cols = {
131
+ "ID" => lambda {|it| it['id'] },
132
+ "Name" => lambda {|it| it['name'] },
133
+ "File Name" => lambda {|it| it['fileName'] },
134
+ "File Path" => lambda {|it| it['filePath'] },
135
+ "Setting Category" => lambda {|it| it['settingCategory'] },
136
+ "Setting Name" => lambda {|it| it['settingName'] },
137
+ "Phase" => lambda {|it| it['templatePhase'] },
138
+ "Owner" => lambda {|it| it['account'] ? it['account']['name'] : '' },
139
+ # "Enabled" => lambda {|it| format_boolean it['enabled'] },
140
+ "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
141
+ "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
142
+ }
143
+ print_description_list(description_cols, container_template)
144
+
145
+ print_h2 "Template"
146
+
147
+ puts container_template['template']
148
+
149
+
150
+
151
+ print reset,"\n"
152
+
153
+ rescue RestClient::Exception => e
154
+ print_rest_exception(e, options)
155
+ return 1
156
+ end
157
+ end
158
+
159
+ def add(args)
160
+ options = {}
161
+ params = {'templatePhase' => 'provision'}
162
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
163
+ opts.banner = subcommand_usage("[name]")
164
+ opts.on('--name VALUE', String, "Name") do |val|
165
+ params['name'] = val
166
+ end
167
+ # opts.on('--code VALUE', String, "Code") do |val|
168
+ # params['code'] = val
169
+ # end
170
+ # opts.on('--description VALUE', String, "Description") do |val|
171
+ # params['description'] = val
172
+ # end
173
+ opts.on('--phase [start|stop|postProvision]', String, "Template Phase. Default is 'provision'") do |val|
174
+ params['scriptPhase'] = val
175
+ end
176
+ opts.on('--category VALUE', String, "Category") do |val|
177
+ params['category'] = val
178
+ end
179
+ # opts.on('--enabled [on|off]', String, "Can be used to disable it") do |val|
180
+ # options['enabled'] = !(val.to_s == 'off' || val.to_s == 'false')
181
+ # end
182
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote, :quiet])
183
+ opts.footer = "Create a new file template." + "\n" +
184
+ "[name] is required and can be passed as --name instead."
185
+ end
186
+ optparse.parse!(args)
187
+ if args.count > 1
188
+ print_error Morpheus::Terminal.angry_prompt
189
+ puts_error "wrong number of arguments, expected 0-1 and got (#{args.count}) #{args.inspect}\n#{optparse}"
190
+ return 1
191
+ end
192
+ # support [name] as first argument
193
+ if args[0]
194
+ params['name'] = args[0]
195
+ end
196
+ connect(options)
197
+ begin
198
+ # construct payload
199
+ payload = nil
200
+ if options[:payload]
201
+ payload = options[:payload]
202
+ else
203
+ # merge -O options into normally parsed options
204
+ params.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
205
+ # todo: prompt?
206
+ payload = {'containerTemplate' => params}
207
+ end
208
+ if options[:dry_run]
209
+ print_dry_run @container_templates_interface.dry.create(payload)
210
+ return
211
+ end
212
+ json_response = @container_templates_interface.create(payload)
213
+ if options[:json]
214
+ puts as_json(json_response, options)
215
+ elsif !options[:quiet]
216
+ container_template = json_response['containerTemplate']
217
+ print_green_success "Added file template #{container_template['name']}"
218
+ _get(container_template['id'], {})
219
+ end
220
+ return 0
221
+ rescue RestClient::Exception => e
222
+ print_rest_exception(e, options)
223
+ return 1
224
+ end
225
+ end
226
+
227
+
228
+ def update(args)
229
+ options = {}
230
+ params = {}
231
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
232
+ opts.banner = subcommand_usage("[name]")
233
+ opts.on('--name VALUE', String, "Name") do |val|
234
+ params['name'] = val
235
+ end
236
+ # opts.on('--code VALUE', String, "Code") do |val|
237
+ # params['code'] = val
238
+ # end
239
+ # opts.on('--description VALUE', String, "Description") do |val|
240
+ # params['description'] = val
241
+ # end
242
+ opts.on('--phase [start|stop]', String, "Template Phase") do |val|
243
+ params['scriptPhase'] = val
244
+ end
245
+
246
+ # opts.on('--enabled [on|off]', String, "Can be used to disable it") do |val|
247
+ # options['enabled'] = !(val.to_s == 'off' || val.to_s == 'false')
248
+ # end
249
+ build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote, :quiet])
250
+ opts.footer = "Update a file template." + "\n" +
251
+ "[name] is required. This is the name or id of a file template."
252
+ end
253
+ optparse.parse!(args)
254
+ if args.count != 1
255
+ print_error Morpheus::Terminal.angry_prompt
256
+ puts_error "wrong number of arguments, expected 1 and got (#{args.count}) #{args.inspect}\n#{optparse}"
257
+ return 1
258
+ end
259
+ connect(options)
260
+ begin
261
+ container_template = find_container_template_by_name_or_id(args[0])
262
+ if container_template.nil?
263
+ return 1
264
+ end
265
+ # construct payload
266
+ payload = nil
267
+ if options[:payload]
268
+ payload = options[:payload]
269
+ else
270
+ # merge -O options into normally parsed options
271
+ params.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
272
+ payload = {'containerTemplate' => params}
273
+ end
274
+ if options[:dry_run]
275
+ print_dry_run @container_templates_interface.dry.update(container_template["id"], payload)
276
+ return
277
+ end
278
+ json_response = @container_templates_interface.update(container_template["id"], payload)
279
+ if options[:json]
280
+ puts as_json(json_response, options)
281
+ elsif !options[:quiet]
282
+ print_green_success "Updated file template #{container_template['name']}"
283
+ _get(container_template['id'], {})
284
+ end
285
+ return 0
286
+ rescue RestClient::Exception => e
287
+ print_rest_exception(e, options)
288
+ return 1
289
+ end
290
+ end
291
+
292
+ def remove(args)
293
+ options = {}
294
+ params = {}
295
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
296
+ opts.banner = subcommand_usage("[name]")
297
+ build_common_options(opts, options, [:json, :dry_run, :quiet, :auto_confirm])
298
+ end
299
+ optparse.parse!(args)
300
+ if args.count < 1
301
+ puts optparse
302
+ return 127
303
+ end
304
+ connect(options)
305
+
306
+ begin
307
+ container_template = find_container_template_by_name_or_id(args[0])
308
+ if container_template.nil?
309
+ return 1
310
+ end
311
+
312
+ unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to delete file template '#{container_template['name']}'?", options)
313
+ return false
314
+ end
315
+
316
+ # payload = {
317
+ # 'containerTemplate' => {id: container_template["id"]}
318
+ # }
319
+ # payload['containerTemplate'].merge!(container_template)
320
+ payload = params
321
+
322
+ if options[:dry_run]
323
+ print_dry_run @container_templates_interface.dry.destroy(container_template["id"])
324
+ return
325
+ end
326
+
327
+ json_response = @container_templates_interface.destroy(container_template["id"])
328
+ if options[:json]
329
+ puts as_json(json_response, options)
330
+ elsif !options[:quiet]
331
+ print_green_success "Deleted file template #{container_template['name']}"
332
+ end
333
+ return 0, nil
334
+ rescue RestClient::Exception => e
335
+ print_rest_exception(e, options)
336
+ return 1
337
+ end
338
+ end
339
+
340
+
341
+ private
342
+
343
+ def find_container_template_by_name_or_id(val)
344
+ if val.to_s =~ /\A\d{1,}\Z/
345
+ return find_container_template_by_id(val)
346
+ else
347
+ return find_container_template_by_name(val)
348
+ end
349
+ end
350
+
351
+ def find_container_template_by_id(id)
352
+ begin
353
+ json_response = @container_templates_interface.get(id.to_i)
354
+ return json_response['containerTemplate']
355
+ rescue RestClient::Exception => e
356
+ if e.response && e.response.code == 404
357
+ print_red_alert "File Template not found by id #{id}"
358
+ else
359
+ raise e
360
+ end
361
+ end
362
+ end
363
+
364
+ def find_container_template_by_name(name)
365
+ container_templates = @container_templates_interface.list({name: name.to_s})['containerTemplates']
366
+ if container_templates.empty?
367
+ print_red_alert "File Template not found by name #{name}"
368
+ return nil
369
+ elsif container_templates.size > 1
370
+ print_red_alert "#{container_templates.size} file templates found by name #{name}"
371
+ print_container_templates_table(container_templates, {color: red})
372
+ print_red_alert "Try using ID instead"
373
+ print reset,"\n"
374
+ return nil
375
+ else
376
+ return container_templates[0]
377
+ end
378
+ end
379
+
380
+ def print_container_templates_table(container_templates, opts={})
381
+ columns = [
382
+ {"ID" => lambda {|container_template| container_template['id'] } },
383
+ {"NAME" => lambda {|container_template| container_template['name'] } },
384
+ {"FILE NAME" => lambda {|container_template| container_template['fileName'] } },
385
+ {"FILE PATH" => lambda {|container_template| container_template['filePath'] } },
386
+ {"SETTING CATEGORY" => lambda {|container_template| container_template['settingCategory'] } },
387
+ {"SETTING NAME" => lambda {|container_template| container_template['settingName'] } },
388
+ {"OWNER" => lambda {|container_template| container_template['account'] ? container_template['account']['name'] : '' } },
389
+ ]
390
+ if opts[:include_fields]
391
+ columns = opts[:include_fields]
392
+ end
393
+ print as_pretty_table(container_templates, columns, opts)
394
+ end
395
+
396
+
397
+ end