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