morpheus-cli 2.10.0 → 2.10.1

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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/bin/morpheus +27 -32
  3. data/lib/morpheus/api/accounts_interface.rb +36 -47
  4. data/lib/morpheus/api/api_client.rb +141 -110
  5. data/lib/morpheus/api/app_templates_interface.rb +56 -72
  6. data/lib/morpheus/api/apps_interface.rb +111 -132
  7. data/lib/morpheus/api/auth_interface.rb +30 -0
  8. data/lib/morpheus/api/clouds_interface.rb +71 -76
  9. data/lib/morpheus/api/custom_instance_types_interface.rb +21 -46
  10. data/lib/morpheus/api/dashboard_interface.rb +10 -17
  11. data/lib/morpheus/api/deploy_interface.rb +60 -72
  12. data/lib/morpheus/api/deployments_interface.rb +53 -71
  13. data/lib/morpheus/api/groups_interface.rb +55 -45
  14. data/lib/morpheus/api/instance_types_interface.rb +19 -23
  15. data/lib/morpheus/api/instances_interface.rb +179 -177
  16. data/lib/morpheus/api/key_pairs_interface.rb +11 -17
  17. data/lib/morpheus/api/license_interface.rb +18 -23
  18. data/lib/morpheus/api/load_balancers_interface.rb +54 -69
  19. data/lib/morpheus/api/logs_interface.rb +25 -29
  20. data/lib/morpheus/api/options_interface.rb +13 -17
  21. data/lib/morpheus/api/provision_types_interface.rb +19 -22
  22. data/lib/morpheus/api/roles_interface.rb +75 -94
  23. data/lib/morpheus/api/security_group_rules_interface.rb +28 -37
  24. data/lib/morpheus/api/security_groups_interface.rb +39 -51
  25. data/lib/morpheus/api/servers_interface.rb +113 -115
  26. data/lib/morpheus/api/setup_interface.rb +31 -0
  27. data/lib/morpheus/api/task_sets_interface.rb +36 -38
  28. data/lib/morpheus/api/tasks_interface.rb +56 -69
  29. data/lib/morpheus/api/users_interface.rb +67 -76
  30. data/lib/morpheus/api/virtual_images_interface.rb +61 -61
  31. data/lib/morpheus/api/whoami_interface.rb +12 -15
  32. data/lib/morpheus/cli.rb +71 -60
  33. data/lib/morpheus/cli/accounts.rb +254 -315
  34. data/lib/morpheus/cli/alias_command.rb +219 -0
  35. data/lib/morpheus/cli/app_templates.rb +264 -272
  36. data/lib/morpheus/cli/apps.rb +608 -671
  37. data/lib/morpheus/cli/cli_command.rb +259 -21
  38. data/lib/morpheus/cli/cli_registry.rb +99 -14
  39. data/lib/morpheus/cli/clouds.rb +599 -372
  40. data/lib/morpheus/cli/config_file.rb +126 -0
  41. data/lib/morpheus/cli/credentials.rb +141 -117
  42. data/lib/morpheus/cli/dashboard_command.rb +48 -56
  43. data/lib/morpheus/cli/deployments.rb +254 -268
  44. data/lib/morpheus/cli/deploys.rb +150 -142
  45. data/lib/morpheus/cli/error_handler.rb +38 -0
  46. data/lib/morpheus/cli/groups.rb +551 -179
  47. data/lib/morpheus/cli/hosts.rb +862 -617
  48. data/lib/morpheus/cli/instance_types.rb +103 -95
  49. data/lib/morpheus/cli/instances.rb +1335 -1009
  50. data/lib/morpheus/cli/key_pairs.rb +82 -90
  51. data/lib/morpheus/cli/library.rb +498 -499
  52. data/lib/morpheus/cli/license.rb +83 -101
  53. data/lib/morpheus/cli/load_balancers.rb +314 -300
  54. data/lib/morpheus/cli/login.rb +66 -44
  55. data/lib/morpheus/cli/logout.rb +47 -46
  56. data/lib/morpheus/cli/mixins/accounts_helper.rb +69 -31
  57. data/lib/morpheus/cli/mixins/infrastructure_helper.rb +106 -0
  58. data/lib/morpheus/cli/mixins/print_helper.rb +181 -17
  59. data/lib/morpheus/cli/mixins/provisioning_helper.rb +535 -458
  60. data/lib/morpheus/cli/mixins/whoami_helper.rb +2 -2
  61. data/lib/morpheus/cli/option_parser.rb +35 -0
  62. data/lib/morpheus/cli/option_types.rb +232 -192
  63. data/lib/morpheus/cli/recent_activity_command.rb +61 -65
  64. data/lib/morpheus/cli/remote.rb +446 -199
  65. data/lib/morpheus/cli/roles.rb +884 -906
  66. data/lib/morpheus/cli/security_group_rules.rb +213 -203
  67. data/lib/morpheus/cli/security_groups.rb +237 -192
  68. data/lib/morpheus/cli/shell.rb +338 -231
  69. data/lib/morpheus/cli/tasks.rb +326 -308
  70. data/lib/morpheus/cli/users.rb +457 -462
  71. data/lib/morpheus/cli/version.rb +1 -1
  72. data/lib/morpheus/cli/version_command.rb +16 -18
  73. data/lib/morpheus/cli/virtual_images.rb +526 -345
  74. data/lib/morpheus/cli/whoami.rb +125 -111
  75. data/lib/morpheus/cli/workflows.rb +338 -185
  76. data/lib/morpheus/formatters.rb +8 -1
  77. data/lib/morpheus/logging.rb +1 -1
  78. data/lib/morpheus/rest_client.rb +17 -8
  79. metadata +9 -3
  80. data/lib/morpheus/api/custom_instance_types.rb +0 -55
@@ -9,55 +9,31 @@ require 'json'
9
9
  class Morpheus::Cli::KeyPairs
10
10
  include Morpheus::Cli::CliCommand
11
11
  include Morpheus::Cli::AccountsHelper
12
-
13
- def initialize()
14
- @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
12
+ register_subcommands :list, :get, :add, :update, :remove
13
+ alias_subcommand :details, :get
14
+
15
+ def initialize()
16
+ # @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
15
17
  end
16
18
 
17
19
  def connect(opts)
18
- @access_token = Morpheus::Cli::Credentials.new(@appliance_name,@appliance_url).request_credentials()
19
- if @access_token.empty?
20
- print_red_alert "Invalid Credentials. Unable to acquire access token. Please verify your credentials and try again."
21
- exit 1
22
- end
23
- @api_client = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url)
20
+ @api_client = establish_remote_appliance_connection(opts)
24
21
  @accounts_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).accounts
25
22
  @key_pairs_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).key_pairs
26
23
  end
27
24
 
28
25
  def handle(args)
29
- usage = "Usage: morpheus key-pairs [list,add,update,remove] [name]"
30
- if args.empty?
31
- puts "\n#{usage}\n\n"
32
- exit 1
33
- end
34
-
35
- case args[0]
36
- when 'list'
37
- list(args[1..-1])
38
- when 'details'
39
- details(args[1..-1])
40
- when 'add'
41
- add(args[1..-1])
42
- when 'update'
43
- update(args[1..-1])
44
- when 'remove'
45
- remove(args[1..-1])
46
- else
47
- puts "\n#{usage}\n\n"
48
- exit 127
49
- end
26
+ handle_subcommand(args)
50
27
  end
51
28
 
52
29
  def list(args)
53
- usage = "Usage: morpheus key-pairs list [options]"
54
30
  options = {}
55
31
  params = {}
56
32
  optparse = OptionParser.new do|opts|
57
- opts.banner = usage
33
+ opts.banner = subcommand_usage()
58
34
  build_common_options(opts, options, [:account, :list, :json])
59
35
  end
60
- optparse.parse(args)
36
+ optparse.parse!(args)
61
37
  connect(options)
62
38
  begin
63
39
 
@@ -74,13 +50,23 @@ class Morpheus::Cli::KeyPairs
74
50
  print JSON.pretty_generate(json_response)
75
51
  print "\n"
76
52
  else
77
- print "\n" ,cyan, bold, "Morpheus Key Pairs\n","==================", reset, "\n\n"
53
+ title = "Morpheus Hosts"
54
+ subtitles = []
55
+ if account
56
+ subtitles << "Account: #{account['name']}".strip
57
+ end
58
+ if params[:phrase]
59
+ subtitles << "Search: #{params[:phrase]}".strip
60
+ end
61
+ subtitle = subtitles.join(', ')
62
+ print "\n" ,cyan, bold, title, (subtitle.empty? ? "" : " - #{subtitle}"), "\n", "==================", reset, "\n\n"
78
63
  if key_pairs.empty?
79
64
  puts yellow,"No key pairs found.",reset
80
65
  else
81
66
  print_key_pairs_table(key_pairs)
67
+ print_results_pagination(json_response)
82
68
  end
83
- print reset,"\n\n"
69
+ print reset,"\n"
84
70
  end
85
71
  rescue RestClient::Exception => e
86
72
  print_rest_exception(e, options)
@@ -88,33 +74,26 @@ class Morpheus::Cli::KeyPairs
88
74
  end
89
75
  end
90
76
 
91
- def details(args)
92
- usage = "Usage: morpheus key-pairs details [name] [options]"
77
+ def get(args)
93
78
  options = {}
94
79
  params = {}
95
80
  optparse = OptionParser.new do|opts|
96
- opts.banner = usage
81
+ opts.banner = subcommand_usage("[name]")
97
82
  build_common_options(opts, options, [:account, :json])
98
83
  end
99
- optparse.parse(args)
84
+ optparse.parse!(args)
100
85
 
101
86
  if args.count < 1
102
- puts "\n#{usage}\n\n"
87
+ puts optparse
103
88
  exit 1
104
89
  end
105
- name = args[0]
106
90
 
107
91
  connect(options)
108
92
  begin
109
-
110
93
  account = find_account_from_options(options)
111
94
  account_id = account ? account['id'] : nil
112
95
 
113
- # todo: key_pairs_response = @key_pairs_interface.list(account_id, {name: name})
114
- # there may be response data outside of account that needs to be displayed
115
-
116
- # allow finding by ID since name is not unique!
117
- key_pair = ((name.to_s =~ /\A\d{1,}\Z/) ? find_key_pair_by_id(account_id, name) : find_key_pair_by_name(account_id, name) )
96
+ key_pair = find_key_pair_by_name_or_id(account_id, args[0])
118
97
  exit 1 if key_pair.nil?
119
98
 
120
99
  if options[:json]
@@ -128,7 +107,7 @@ class Morpheus::Cli::KeyPairs
128
107
  puts "MD5: #{key_pair['md5']}"
129
108
  puts "Date Created: #{format_local_dt(key_pair['dateCreated'])}"
130
109
  #puts "Last Updated: #{format_local_dt(key_pair['lastUpdated'])}"
131
- print reset,"\n\n"
110
+ print reset,"\n"
132
111
 
133
112
  # todo: show public key
134
113
 
@@ -142,8 +121,7 @@ class Morpheus::Cli::KeyPairs
142
121
  def add(args)
143
122
  options = {}
144
123
  optparse = OptionParser.new do|opts|
145
- opts.banner = "Usage: morpheus key-pairs add [name] [options]"
146
-
124
+ opts.banner = subcommand_usage("[name] [options]")
147
125
  opts.on('', '--public-key-file FILENAME', "Public Key File" ) do |filename|
148
126
  if File.exists?(File.expand_path(filename))
149
127
  options['publicKey'] = File.read(File.expand_path(filename))
@@ -178,19 +156,19 @@ class Morpheus::Cli::KeyPairs
178
156
  options[:options]['privateKey'] = options['privateKey']
179
157
  end
180
158
 
181
- build_common_options(opts, options, [:account, :options, :json])
159
+ build_common_options(opts, options, [:account, :options, :json, :dry_run])
182
160
  end
183
-
184
- if args.count < 1
185
- puts "\n#{optparse}\n\n"
186
- exit 1
161
+ optparse.parse!(args)
162
+ # if args.count < 1
163
+ # puts optparse
164
+ # exit 1
165
+ # end
166
+ if args[0]
167
+ options[:options] ||= {}
168
+ options[:options]['name'] ||= args[0]
187
169
  end
188
- optparse.parse(args)
189
-
190
170
  connect(options)
191
-
192
171
  begin
193
-
194
172
  account = find_account_from_options(options)
195
173
  account_id = account ? account['id'] : nil
196
174
 
@@ -203,12 +181,15 @@ class Morpheus::Cli::KeyPairs
203
181
  print_red_alert "privateKey is required"
204
182
  exit 1
205
183
  end
206
- params['name'] = args[0]
184
+ #params['name'] = args[0]
207
185
 
208
186
  key_pair_payload = params.select {|k,v| ['name','publicKey', 'privateKey'].include?(k) }
209
-
210
- request_payload = {keyPair: key_pair_payload}
211
- json_response = @key_pairs_interface.create(account_id, request_payload)
187
+ payload = {keyPair: key_pair_payload}
188
+ if options[:dry_run]
189
+ print_dry_run @key_pairs_interface.dry.create(account_id, payload)
190
+ return
191
+ end
192
+ json_response = @key_pairs_interface.create(account_id, payload)
212
193
  if options[:json]
213
194
  print JSON.pretty_generate(json_response)
214
195
  print "\n"
@@ -222,43 +203,44 @@ class Morpheus::Cli::KeyPairs
222
203
  end
223
204
 
224
205
  def update(args)
225
- usage = "Usage: morpheus key-pairs update [name] [options]"
226
206
  options = {}
227
207
  optparse = OptionParser.new do|opts|
228
- opts.banner = usage
229
- build_common_options(opts, options, [:account, :options, :json])
208
+ opts.banner = subcommand_usage("[name] [options]")
209
+ build_common_options(opts, options, [:account, :options, :json, :dry_run])
230
210
  end
231
- optparse.parse(args)
211
+ optparse.parse!(args)
232
212
 
233
213
  if args.count < 1
234
- puts "\n#{usage}\n\n"
214
+ puts optparse
235
215
  exit 1
236
216
  end
237
- name = args[0]
238
217
 
239
218
  connect(options)
240
-
241
219
  begin
242
220
 
243
221
  account = find_account_from_options(options)
244
222
  account_id = account ? account['id'] : nil
245
223
 
246
- key_pair = ((name.to_s =~ /\A\d{1,}\Z/) ? find_key_pair_by_id(account_id, name) : find_key_pair_by_name(account_id, name) )
224
+ key_pair = find_key_pair_by_name_or_id(account_id, args[0])
247
225
  exit 1 if key_pair.nil?
248
226
 
249
227
  #params = Morpheus::Cli::OptionTypes.prompt(update_key_pair_option_types, options[:options], @api_client, options[:params])
250
228
  params = options[:options] || {}
251
229
 
252
230
  if params.empty?
253
- puts "\n#{usage}\n\n"
231
+ puts optparse
254
232
  option_lines = update_key_pair_option_types.collect {|it| "\t-O #{it['fieldName']}=\"value\"" }.join("\n")
255
233
  puts "\nAvailable Options:\n#{option_lines}\n\n"
256
234
  exit 1
257
235
  end
258
236
 
259
237
  key_pair_payload = params.select {|k,v| ['name'].include?(k) }
260
- request_payload = {keyPair: key_pair_payload}
261
- json_response = @key_pairs_interface.update(account_id, key_pair['id'], request_payload)
238
+ payload = {keyPair: key_pair_payload}
239
+ if options[:dry_run]
240
+ print_dry_run @key_pairs_interface.dry.update(account_id, key_pair['id'], payload)
241
+ return
242
+ end
243
+ json_response = @key_pairs_interface.update(account_id, key_pair['id'], payload)
262
244
  if options[:json]
263
245
  print JSON.pretty_generate(json_response)
264
246
  print "\n"
@@ -272,19 +254,17 @@ class Morpheus::Cli::KeyPairs
272
254
  end
273
255
 
274
256
  def remove(args)
275
- usage = "Usage: morpheus key-pairs remove [name]"
276
257
  options = {}
277
258
  optparse = OptionParser.new do|opts|
278
- opts.banner = usage
279
- build_common_options(opts, options, [:account, :auto_confirm, :json])
259
+ opts.banner = subcommand_usage("[name]")
260
+ build_common_options(opts, options, [:account, :auto_confirm, :json, :dry_run])
280
261
  end
281
- optparse.parse(args)
262
+ optparse.parse!(args)
282
263
 
283
264
  if args.count < 1
284
- puts "\n#{usage}\n\n"
265
+ puts optparse
285
266
  exit 1
286
267
  end
287
- name = args[0]
288
268
 
289
269
  connect(options)
290
270
  begin
@@ -292,11 +272,16 @@ class Morpheus::Cli::KeyPairs
292
272
  account = find_account_from_options(options)
293
273
  account_id = account ? account['id'] : nil
294
274
  # allow finding by ID since name is not unique!
295
- key_pair = ((name.to_s =~ /\A\d{1,}\Z/) ? find_key_pair_by_id(account_id, name) : find_key_pair_by_name(account_id, name) )
275
+ key_pair = find_key_pair_by_name_or_id(account_id, args[0])
296
276
  exit 1 if key_pair.nil?
277
+
297
278
  unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the key pair #{key_pair['name']}?")
298
279
  exit
299
280
  end
281
+ if options[:dry_run]
282
+ print_dry_run @key_pairs_interface.dry.destroy(account_id, key_pair['id'])
283
+ return
284
+ end
300
285
  json_response = @key_pairs_interface.destroy(account_id, key_pair['id'])
301
286
  if options[:json]
302
287
  print JSON.pretty_generate(json_response)
@@ -311,8 +296,15 @@ class Morpheus::Cli::KeyPairs
311
296
  end
312
297
  end
313
298
 
314
- private
315
-
299
+ private
300
+ def find_key_pair_by_name_or_id(account_id, val)
301
+ if val.to_s =~ /\A\d{1,}\Z/
302
+ return find_key_pair_by_id(account_id, val)
303
+ else
304
+ return find_key_pair_by_name(account_id, val)
305
+ end
306
+ end
307
+
316
308
  def find_key_pair_by_id(account_id, id)
317
309
  raise "#{self.class} has not defined @key_pairs_interface" if @key_pairs_interface.nil?
318
310
  begin
@@ -336,7 +328,7 @@ private
336
328
  elsif key_pairs.size > 1
337
329
  print_red_alert "#{key_pairs.size} key_pairs by name #{name}"
338
330
  print_key_pairs_table(key_pairs, {color: red})
339
- print reset,"\n\n"
331
+ print reset,"\n"
340
332
  return nil
341
333
  else
342
334
  return key_pairs[0]
@@ -347,17 +339,16 @@ private
347
339
  table_color = opts[:color] || cyan
348
340
  rows = key_pairs.collect do |key_pair|
349
341
  {
350
- id: key_pair['id'],
351
- name: key_pair['name'],
342
+ id: key_pair['id'],
343
+ name: key_pair['name'],
352
344
  md5: key_pair['md5'],
353
- dateCreated: format_local_dt(key_pair['dateCreated'])
345
+ dateCreated: format_local_dt(key_pair['dateCreated'])
354
346
  }
355
347
  end
356
-
357
348
  print table_color
358
349
  tp rows, [
359
- :id,
360
- :name,
350
+ :id,
351
+ :name,
361
352
  :md5,
362
353
  {:dateCreated => {:display_name => "Date Created"} }
363
354
  ]
@@ -367,6 +358,7 @@ private
367
358
 
368
359
  def add_key_pair_option_types
369
360
  [
361
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
370
362
  {'fieldName' => 'publicKey', 'fieldLabel' => 'Public Key', 'type' => 'text', 'required' => true, 'displayOrder' => 2},
371
363
  {'fieldName' => 'privateKey', 'fieldLabel' => 'Private Key', 'type' => 'text', 'required' => true, 'displayOrder' => 3},
372
364
  ]
@@ -6,496 +6,499 @@ require 'morpheus/cli/cli_command'
6
6
  class Morpheus::Cli::Library
7
7
  include Morpheus::Cli::CliCommand
8
8
 
9
- def initialize()
10
- @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
11
- end
12
-
13
- def connect(opts)
14
- @access_token = Morpheus::Cli::Credentials.new(@appliance_name,@appliance_url).request_credentials()
15
- if @access_token.empty?
16
- print_red_alert "Invalid Credentials. Unable to acquire access token. Please verify your credentials and try again."
17
- exit 1
18
- end
19
- @api_client = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url)
20
- @custom_instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).custom_instance_types
21
- @provision_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).provision_types
22
- end
23
-
24
- def handle(args)
25
- usage = "Usage: morpheus library [list,details,add,update,remove,add-version] [name]"
26
- case args[0]
27
- when 'list'
28
- list(args[1..-1])
29
- when 'details'
30
- details(args[1..-1])
31
- when 'add'
32
- add(args[1..-1])
33
- when 'update'
34
- update(args[1..-1])
35
- when 'remove'
36
- remove(args[1..-1])
37
- when 'add-version'
38
- add_version(args[1..-1])
39
- else
40
- puts "\n#{usage}\n\n"
41
- exit 127
42
- end
43
- end
44
-
45
- def list(args)
46
- options = {}
47
- optparse = OptionParser.new do|opts|
48
- opts.banner = "Usage: morpheus library list"
49
- build_common_options(opts, options, [:list, :json])
50
- end
51
- optparse.parse(args)
52
- connect(options)
53
- begin
54
- params = {}
55
- [:phrase, :offset, :max, :sort, :direction].each do |k|
56
- params[k] = options[k] unless options[k].nil?
57
- end
58
-
59
- json_response = @custom_instance_types_interface.list(params)
60
-
61
- if options[:json]
62
- print JSON.pretty_generate(json_response), "\n"
63
- return
64
- end
65
-
66
- instance_types = json_response['instanceTypes']
67
- print "\n" ,cyan, bold, "Morpheus Custom Instance Types\n","==================", reset, "\n\n"
68
- if instance_types.empty?
69
- puts yellow,"No instance types currently configured.",reset
70
- else
71
- instance_types.each do |instance_type|
72
- versions = instance_type['versions'].join(', ')
73
- print cyan, "= #{instance_type['name']} (#{instance_type['code']}) - #{versions}\n"
74
- instance_type['instanceTypeLayouts'].each do |layout|
75
- print green, " - #{layout['name']}\n",reset
76
- end
77
- end
78
- end
79
- print reset,"\n\n"
80
-
81
- rescue RestClient::Exception => e
82
- print_rest_exception(e, options)
83
- exit 1
84
- end
85
- end
86
-
87
- def details(args)
88
- options = {}
89
- optparse = OptionParser.new do|opts|
90
- opts.banner = "Usage: morpheus library details [name]"
91
- build_common_options(opts, options, [:json])
92
- end
93
- optparse.parse(args)
94
- if args.count < 1
95
- puts "\n#{optparse.banner}\n\n"
96
- exit 1
97
- end
98
-
99
- connect(options)
100
- begin
101
- instance_type = find_custom_instance_type_by_name_or_code(args[0])
102
- exit 1 if instance_type.nil?
103
-
104
- if options[:json]
105
- print JSON.pretty_generate({instanceType: instance_type}), "\n"
106
- return
107
- end
108
-
109
- if instance_type.nil?
110
- puts yellow,"No custom instance type found by name #{name}.",reset
111
- else
112
- print "\n" ,cyan, bold, "Custom Instance Type Details\n","==================", reset, "\n\n"
113
- versions = instance_type['versions'].join(', ')
114
- print cyan, "= #{instance_type['name']} (#{instance_type['code']}) - #{versions}\n"
115
- instance_type['instanceTypeLayouts'].each do |layout|
116
- print green, " - #{layout['name']}\n",reset
117
- end
118
- print reset,"\n\n"
119
- end
120
-
121
- rescue RestClient::Exception => e
122
- print_rest_exception(e, options)
123
- exit 1
124
- end
125
- end
126
-
127
- def add(args)
128
- options = {}
129
- optparse = OptionParser.new do|opts|
130
- opts.banner = "Usage: morpheus library add"
131
- build_common_options(opts, options, [:options, :json])
132
- end
133
- optparse.parse(args)
134
- connect(options)
135
- begin
136
- params = Morpheus::Cli::OptionTypes.prompt(add_instance_type_option_types, options[:options], @api_client, options[:params])
137
- instance_type_keys = ['name', 'description', 'category', 'visibility', 'environmentPrefix']
138
- instance_type_payload = params.select {|k,v| instance_type_keys.include?(k) }
139
- logo_file = nil
140
- if params['logo']
141
- filename = File.expand_path(params['logo'])
142
- if !File.exists?(filename)
143
- print_red_alert "File not found: #{filename}"
9
+ register_subcommands :list, :get, :add, :update, :remove, :'add-version'
10
+ alias_subcommand :details, :get
11
+
12
+ def initialize()
13
+ # @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
14
+ end
15
+
16
+ def connect(opts)
17
+ @api_client = establish_remote_appliance_connection(opts)
18
+ @custom_instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).custom_instance_types
19
+ @provision_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).provision_types
20
+ end
21
+
22
+ def handle(args)
23
+ handle_subcommand(args)
24
+ end
25
+
26
+
27
+ def list(args)
28
+ options = {}
29
+ optparse = OptionParser.new do|opts|
30
+ opts.banner = subcommand_usage()
31
+ build_common_options(opts, options, [:list, :dry_run, :json])
32
+ end
33
+ optparse.parse!(args)
34
+ connect(options)
35
+ begin
36
+ params = {}
37
+ [:phrase, :offset, :max, :sort, :direction].each do |k|
38
+ params[k] = options[k] unless options[k].nil?
39
+ end
40
+
41
+ if options[:dry_run]
42
+ print_dry_run @custom_instance_types_interface.dry.list(params)
43
+ return
44
+ end
45
+
46
+ json_response = @custom_instance_types_interface.list(params)
47
+
48
+ if options[:json]
49
+ print JSON.pretty_generate(json_response), "\n"
50
+ return
51
+ end
52
+
53
+ instance_types = json_response['instanceTypes']
54
+ print "\n" ,cyan, bold, "Morpheus Custom Instance Types\n","==================", reset, "\n\n"
55
+ if instance_types.empty?
56
+ puts yellow,"No instance types currently configured.",reset
57
+ else
58
+ instance_types.each do |instance_type|
59
+ versions = instance_type['versions'].join(', ')
60
+ print cyan, "= #{instance_type['name']} (#{instance_type['code']}) - #{versions}\n"
61
+ instance_type['instanceTypeLayouts'].each do |layout|
62
+ print green, " - #{layout['name']}\n",reset
63
+ end
64
+ end
65
+ end
66
+ print reset,"\n"
67
+ rescue RestClient::Exception => e
68
+ print_rest_exception(e, options)
69
+ exit 1
70
+ end
71
+ end
72
+
73
+ def get(args)
74
+ options = {}
75
+ optparse = OptionParser.new do|opts|
76
+ opts.banner = subcommand_usage("[name]")
77
+ build_common_options(opts, options, [:json, :dry_run])
78
+ end
79
+ optparse.parse!(args)
80
+ if args.count < 1
81
+ puts optparse
82
+ exit 1
83
+ end
84
+
85
+ connect(options)
86
+ begin
87
+ if options[:dry_run]
88
+ if args[0] =~ /code:/
89
+ print_dry_run @custom_instance_types_interface.dry.list({code: args[0]})
90
+ else
91
+ print_dry_run @custom_instance_types_interface.dry.list({name: args[0]})
92
+ end
93
+ return
94
+ end
95
+ instance_type = find_custom_instance_type_by_name_or_code(args[0])
96
+ exit 1 if instance_type.nil?
97
+
98
+ if options[:json]
99
+ print JSON.pretty_generate({instanceType: instance_type}), "\n"
100
+ return
101
+ end
102
+
103
+ if instance_type.nil?
104
+ puts yellow,"No custom instance type found by name #{name}.",reset
105
+ else
106
+ print "\n" ,cyan, bold, "Custom Instance Type Details\n","==================", reset, "\n\n"
107
+ versions = instance_type['versions'].join(', ')
108
+ print cyan, "= #{instance_type['name']} (#{instance_type['code']}) - #{versions}\n"
109
+ instance_type['instanceTypeLayouts'].each do |layout|
110
+ print green, " - #{layout['name']}\n",reset
111
+ end
112
+ print reset,"\n"
113
+ end
114
+
115
+ rescue RestClient::Exception => e
116
+ print_rest_exception(e, options)
117
+ exit 1
118
+ end
119
+ end
120
+
121
+ def add(args)
122
+ options = {}
123
+ optparse = OptionParser.new do|opts|
124
+ opts.banner = subcommand_usage()
125
+ build_common_options(opts, options, [:options, :json, :dry_run])
126
+ end
127
+ optparse.parse!(args)
128
+ connect(options)
129
+ begin
130
+ params = Morpheus::Cli::OptionTypes.prompt(add_instance_type_option_types, options[:options], @api_client, options[:params])
131
+ instance_type_keys = ['name', 'description', 'category', 'visibility', 'environmentPrefix']
132
+ instance_type_payload = params.select {|k,v| instance_type_keys.include?(k) }
133
+ logo_file = nil
134
+ if params['logo']
135
+ filename = File.expand_path(params['logo'])
136
+ if !File.exists?(filename)
137
+ print_red_alert "File not found: #{filename}"
144
138
  exit 1
145
- end
146
- #instance_type_payload['logo'] = File.new(filename, 'rb')
147
- logo_file = File.new(filename, 'rb')
148
- end
149
- if params['hasAutoScale'] == 'on'
150
- instance_type_payload['hasAutoScale'] = true
151
- end
152
- if params['hasDeployment'] == 'on'
153
- instance_type_payload['hasDeployment'] = true
154
- end
155
- request_payload = {instanceType: instance_type_payload}
156
- json_response = @custom_instance_types_interface.create(request_payload)
157
-
158
- if json_response['success']
159
- if logo_file
160
- begin
161
- @custom_instance_types_interface.update_logo(json_response['instanceType']['id'], logo_file)
162
- rescue RestClient::Exception => e
163
- print_red_alert "Failed to save logo!"
164
- print_rest_exception(e, options)
165
- end
166
- end
167
- end
168
-
169
- if options[:json]
170
- print JSON.pretty_generate(json_response), "\n"
171
- return
172
- end
173
-
174
- print_green_success "Added Instance Type #{instance_type_payload['name']}"
175
-
176
- unless options[:no_prompt]
177
- if ::Morpheus::Cli::OptionTypes::confirm("Add first version?", options)
178
- puts "\n"
179
- add_version(["code:#{json_response['code']}"])
180
- end
181
- end
182
-
183
- #list([])
184
-
185
- rescue RestClient::Exception => e
186
- print_rest_exception(e, options)
187
- exit 1
188
- end
189
- end
190
-
191
- def update(args)
192
- options = {}
193
- optparse = OptionParser.new do|opts|
194
- opts.banner = "Usage: morpheus library update [name] [options]"
195
- build_common_options(opts, options, [:options, :json])
196
- end
197
- optparse.parse(args)
198
- if args.count < 1
199
- puts "\n#{optparse.banner}\n\n"
200
- exit 1
201
- end
202
- connect(options)
203
- begin
204
- instance_type = find_custom_instance_type_by_name_or_code(args[0])
205
- exit 1 if instance_type.nil?
206
- # option_types = update_instance_type_option_types(instance_type)
207
- # params = Morpheus::Cli::OptionTypes.prompt(option_types, options[:options], @api_client, options[:params])
208
- params = options[:options] || {}
209
-
210
- instance_type_keys = ['name', 'description', 'category', 'visibility', 'environmentPrefix']
211
- instance_type_payload = params.select {|k,v| instance_type_keys.include?(k) }
212
- logo_file = nil
213
- if params['logo']
214
- filename = File.expand_path(params['logo'])
215
- if !File.exists?(filename)
216
- print_red_alert "File not found: #{filename}"
139
+ end
140
+ #instance_type_payload['logo'] = File.new(filename, 'rb')
141
+ logo_file = File.new(filename, 'rb')
142
+ end
143
+ if params['hasAutoScale'] == 'on'
144
+ instance_type_payload['hasAutoScale'] = true
145
+ end
146
+ if params['hasDeployment'] == 'on'
147
+ instance_type_payload['hasDeployment'] = true
148
+ end
149
+ payload = {instanceType: instance_type_payload}
150
+ if options[:dry_run]
151
+ print_dry_run @custom_instance_types_interface.dry.create(payload)
152
+ if logo_file
153
+ print_dry_run @custom_instance_types_interface.dry.update_logo(":id", logo_file)
154
+ end
155
+ return
156
+ end
157
+ json_response = @custom_instance_types_interface.create(payload)
158
+
159
+ if json_response['success']
160
+ if logo_file
161
+ begin
162
+ @custom_instance_types_interface.update_logo(json_response['instanceType']['id'], logo_file)
163
+ rescue RestClient::Exception => e
164
+ print_red_alert "Failed to save logo!"
165
+ print_rest_exception(e, options)
166
+ end
167
+ end
168
+ end
169
+
170
+ if options[:json]
171
+ print JSON.pretty_generate(json_response), "\n"
172
+ return
173
+ end
174
+
175
+ print_green_success "Added Instance Type #{instance_type_payload['name']}"
176
+ unless options[:no_prompt]
177
+ if ::Morpheus::Cli::OptionTypes::confirm("Add first version?", options)
178
+ puts "\n"
179
+ add_version(["code:#{json_response['code']}"])
180
+ end
181
+ end
182
+
183
+ #list([])
184
+
185
+ rescue RestClient::Exception => e
186
+ print_rest_exception(e, options)
187
+ exit 1
188
+ end
189
+ end
190
+
191
+ def update(args)
192
+ options = {}
193
+ optparse = OptionParser.new do|opts|
194
+ opts.banner = subcommand_usage("[name] [options]")
195
+ build_common_options(opts, options, [:options, :json, :dry_run])
196
+ end
197
+ optparse.parse!(args)
198
+ if args.count < 1
199
+ puts optparse
200
+ exit 1
201
+ end
202
+ connect(options)
203
+ begin
204
+ instance_type = find_custom_instance_type_by_name_or_code(args[0])
205
+ exit 1 if instance_type.nil?
206
+ # option_types = update_instance_type_option_types(instance_type)
207
+ # params = Morpheus::Cli::OptionTypes.prompt(option_types, options[:options], @api_client, options[:params])
208
+ params = options[:options] || {}
209
+ instance_type_keys = ['name', 'description', 'category', 'visibility', 'environmentPrefix']
210
+ instance_type_payload = params.select {|k,v| instance_type_keys.include?(k) }
211
+ logo_file = nil
212
+ if params['logo']
213
+ filename = File.expand_path(params['logo'])
214
+ if !File.exists?(filename)
215
+ print_red_alert "File not found: #{filename}"
217
216
  exit 1
218
- end
219
- #instance_type_payload['logo'] = File.new(filename, 'rb')
220
- logo_file = File.new(filename, 'rb')
221
- end
222
- if params['hasAutoScale'] == 'on'
223
- instance_type_payload['hasAutoScale'] = true
224
- elsif params['hasAutoScale'] == 'off'
225
- instance_type_payload['hasAutoScale'] = false
226
- end
227
- if params['hasDeployment'] == 'on'
228
- instance_type_payload['hasDeployment'] = true
229
- elsif params['hasDeployment'] == 'off'
230
- instance_type_payload['hasDeployment'] = false
231
- end
232
- if instance_type_payload.empty? && logo_file.nil?
233
- puts "\n#{optparse.banner}\n\n"
234
- option_lines = update_instance_type_option_types.collect {|it| "\t-O #{it['fieldName']}=\"value\"" }.join("\n")
235
- puts "\nAvailable Options:\n#{option_lines}\n\n"
236
- exit 1
237
- end
238
- if instance_type_payload.empty?
239
- # just updating logo (separate request)
240
- instance_type_payload['name'] = instance_type['name']
241
- end
242
- request_payload = {instanceType: instance_type_payload}
243
- json_response = @custom_instance_types_interface.update(instance_type['id'], request_payload)
244
-
245
- if json_response['success']
246
- if logo_file
247
- begin
248
- @custom_instance_types_interface.update_logo(json_response['instanceType']['id'], logo_file)
249
- rescue RestClient::Exception => e
250
- print_red_alert "Failed to save logo!"
251
- print_rest_exception(e, options)
252
- end
253
- end
254
- end
255
-
256
- if options[:json]
257
- print JSON.pretty_generate(json_response), "\n"
258
- return
259
- end
260
-
261
- print_green_success "Updated Instance Type #{instance_type_payload['name']}"
262
- #list([])
263
- rescue RestClient::Exception => e
264
- print_rest_exception(e, options)
265
- exit 1
266
- end
267
- end
268
-
269
- def remove(args)
270
- options = {}
271
- optparse = OptionParser.new do|opts|
272
- opts.banner = "Usage: morpheus library remove [name]"
273
- build_common_options(opts, options, [:json, :auto_confirm])
274
- end
275
- optparse.parse(args)
276
- if args.count < 1
277
- puts "\n#{optparse.banner}\n\n"
278
- exit 1
279
- end
280
- code = args[0]
281
- connect(options)
282
-
283
- begin
284
-
285
- instance_type = find_custom_instance_type_by_name_or_code(args[0])
286
- exit 1 if instance_type.nil?
287
-
288
- unless Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the instance type #{instance_type['name']}?", options)
289
- exit
290
- end
291
-
292
- json_response = @custom_instance_types_interface.destroy(instance_type['id'])
293
-
294
- if options[:json]
295
- print JSON.pretty_generate(json_response), "\n"
296
- return
297
- end
298
-
299
- print_green_success "Removed Instance Type #{instance_type['name']}"
300
- #list([])
301
- rescue RestClient::Exception => e
302
- print_rest_exception(e, options)
303
- exit 1
304
- end
305
- end
306
-
307
- def add_version(args)
308
- options = {}
309
- optparse = OptionParser.new do|opts|
310
- opts.banner = "Usage: morpheus library add-version [name]"
311
- build_common_options(opts, options, [:options, :json])
312
- end
313
- optparse.parse(args)
314
- if args.count < 1
315
- puts "\n#{optparse.banner}\n\n"
316
- exit 1
317
- end
318
- connect(options)
319
- begin
320
- instance_type = find_custom_instance_type_by_name_or_code(args[0])
321
- exit 1 if instance_type.nil?
322
-
323
- #params = Morpheus::Cli::OptionTypes.prompt(add_version_option_types, options[:options], @api_client, options[:params])
324
-
325
- provision_types = @provision_types_interface.get({customSupported: true})['provisionTypes']
326
- if provision_types.empty?
327
- print_red_alert "No available provision types found!"
328
- exit 1
329
- end
330
- provision_type_options = provision_types.collect {|it| { 'name' => it['name'], 'value' => it['code']} }
331
-
332
- payload = {'containerType' => {}, 'instanceTypeLayout' => {}, 'instanceType' => {}}
333
-
334
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => 'instanceTypeLayout', 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Name', 'required' => true, 'description' => 'A name for this layout.'}], options[:options])
335
- payload['instanceTypeLayout']['name'] = v_prompt['instanceTypeLayout']['name']
336
-
337
- # shortName is only available for the first new version
338
- if !instance_type['versions'] || instance_type['versions'].size == 0
339
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => 'containerType', 'fieldName' => 'shortName', 'type' => 'text', 'fieldLabel' => 'Short Name', 'required' => true, 'description' => 'The short name is a lowercase name with no spaces used for display in your container list.'}], options[:options])
340
- payload['containerType']['shortName'] = v_prompt['containerType']['shortName']
341
- end
342
-
343
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => 'containerType', 'fieldName' => 'provisionTypeCode', 'type' => 'select', 'selectOptions' => provision_type_options, 'fieldLabel' => 'Technology', 'required' => true, 'description' => 'The type of container technology.'}], options[:options])
344
- payload['containerType']['provisionTypeCode'] = v_prompt['containerType']['provisionTypeCode']
345
- provision_type = provision_types.find {|it| it['code'] == payload['containerType']['provisionTypeCode'] }
346
-
347
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => 'instanceTypeLayout', 'fieldName' => 'instanceVersion', 'type' => 'text', 'fieldLabel' => 'Version', 'required' => true, 'description' => 'A Version Number eg. 0.0.1'}], options[:options])
348
- payload['instanceTypeLayout']['instanceVersion'] = v_prompt['instanceTypeLayout']['instanceVersion']
349
-
350
- custom_option_types = provision_type['customOptionTypes']
351
-
352
- if (!custom_option_types || custom_option_types.empty?)
353
- puts yellow,"Sorry, no options were found for #{provision_type['name']}.",reset
354
- exit 1
355
- end
356
-
357
- # prompt custom options for the selected provision type
358
- field_group_name = custom_option_types.first['fieldGroup'] || "#{provision_type['name']} Options"
359
- puts field_group_name
360
- puts "==============="
361
- v_prompt = Morpheus::Cli::OptionTypes.prompt(custom_option_types,options[:options],@api_client, {provisionTypCode: payload['provisionTypeCode']})
362
-
363
- if v_prompt['containerType']
364
- payload['containerType'].merge!(v_prompt['containerType'])
365
- end
366
- if v_prompt['containerType.config']
367
- payload['containerType']['config'] = v_prompt['containerType.config']
368
- end
369
- if v_prompt['instanceTypeLayout']
370
- payload['instanceTypeLayout'].merge!(v_prompt['instanceTypeLayout'])
371
- end
372
- # instanceType.backupType, which is not even persisted on the server?
373
- if v_prompt['instanceType']
374
- payload['instanceType'].merge!(v_prompt['instanceType'])
375
- end
376
-
377
- # puts "PAYLOAD:"
378
- # puts JSON.pretty_generate(payload)
379
-
380
- # puts "\nexiting early"
381
- # exit 0
382
-
383
- payload['exposedPorts'] = prompt_exposed_ports(options, @api_client)
384
-
385
- request_payload = payload
386
- json_response = @custom_instance_types_interface.create_version(instance_type['id'], request_payload)
387
-
388
- if options[:json]
389
- print JSON.pretty_generate(json_response), "\n"
390
- return
391
- end
392
-
393
- print_green_success "Added Instance Type Version #{instance_type['name']} - #{payload['instanceTypeLayout']['instanceVersion']}"
394
- #list([])
395
- rescue RestClient::Exception => e
396
- print_rest_exception(e, options)
397
- exit 1
398
- end
399
- end
400
-
401
-
402
- private
403
-
404
- def find_custom_instance_type_by_code(code)
405
- instance_type_results = @custom_instance_types_interface.list({code: code})
406
- if instance_type_results['instanceTypes'].empty?
407
- print_red_alert "Custom Instance Type not found by code #{code}"
408
- return nil
409
- end
410
- return instance_type_results['instanceTypes'][0]
411
- end
412
-
413
- def find_custom_instance_type_by_name(name)
414
- instance_type_results = @custom_instance_types_interface.list({name: name})
415
- instance_types = instance_type_results['instanceTypes']
416
- if instance_types.empty?
417
- print_red_alert "Custom Instance Type not found by name #{name}"
418
- return nil
419
- elsif instance_types.size > 1
217
+ end
218
+ #instance_type_payload['logo'] = File.new(filename, 'rb')
219
+ logo_file = File.new(filename, 'rb')
220
+ end
221
+ if params['hasAutoScale'] == 'on'
222
+ instance_type_payload['hasAutoScale'] = true
223
+ elsif params['hasAutoScale'] == 'off'
224
+ instance_type_payload['hasAutoScale'] = false
225
+ end
226
+ if params['hasDeployment'] == 'on'
227
+ instance_type_payload['hasDeployment'] = true
228
+ elsif params['hasDeployment'] == 'off'
229
+ instance_type_payload['hasDeployment'] = false
230
+ end
231
+ if instance_type_payload.empty? && logo_file.nil?
232
+ puts optparse
233
+ option_lines = update_instance_type_option_types.collect {|it| "\t-O #{it['fieldName']}=\"value\"" }.join("\n")
234
+ puts "\nAvailable Options:\n#{option_lines}\n\n"
235
+ exit 1
236
+ end
237
+ if instance_type_payload.empty?
238
+ # just updating logo (separate request)
239
+ instance_type_payload['name'] = instance_type['name']
240
+ end
241
+ payload = {instanceType: instance_type_payload}
242
+ if options[:dry_run]
243
+ print_dry_run @custom_instance_types_interface.dry.update(instance_type['id'], payload)
244
+ if logo_file
245
+ print_dry_run @custom_instance_types_interface.dry.update_logo(":id", logo_file)
246
+ end
247
+ return
248
+ end
249
+ json_response = @custom_instance_types_interface.update(instance_type['id'], payload)
250
+
251
+ if json_response['success']
252
+ if logo_file
253
+ begin
254
+ @custom_instance_types_interface.update_logo(json_response['instanceType']['id'], logo_file)
255
+ rescue RestClient::Exception => e
256
+ print_red_alert "Failed to save logo!"
257
+ print_rest_exception(e, options)
258
+ end
259
+ end
260
+ end
261
+
262
+ if options[:json]
263
+ print JSON.pretty_generate(json_response), "\n"
264
+ return
265
+ end
266
+
267
+ print_green_success "Updated Instance Type #{instance_type_payload['name']}"
268
+ #list([])
269
+ rescue RestClient::Exception => e
270
+ print_rest_exception(e, options)
271
+ exit 1
272
+ end
273
+ end
274
+
275
+ def remove(args)
276
+ options = {}
277
+ optparse = OptionParser.new do|opts|
278
+ opts.banner = subcommand_usage("[name]")
279
+ build_common_options(opts, options, [:auto_confirm, :json, :dry_run])
280
+ end
281
+ optparse.parse!(args)
282
+ if args.count < 1
283
+ puts optparse
284
+ exit 1
285
+ end
286
+ connect(options)
287
+
288
+ begin
289
+ instance_type = find_custom_instance_type_by_name_or_code(args[0])
290
+ exit 1 if instance_type.nil?
291
+
292
+ unless Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the instance type #{instance_type['name']}?", options)
293
+ exit
294
+ end
295
+ if options[:dry_run]
296
+ print_dry_run @custom_instance_types_interface.dry.destroy(instance_type['id'])
297
+ return
298
+ end
299
+ json_response = @custom_instance_types_interface.destroy(instance_type['id'])
300
+
301
+ if options[:json]
302
+ print JSON.pretty_generate(json_response), "\n"
303
+ return
304
+ end
305
+
306
+ print_green_success "Removed Instance Type #{instance_type['name']}"
307
+ #list([])
308
+ rescue RestClient::Exception => e
309
+ print_rest_exception(e, options)
310
+ exit 1
311
+ end
312
+ end
313
+
314
+ def add_version(args)
315
+ options = {}
316
+ optparse = OptionParser.new do|opts|
317
+ opts.banner = subcommand_usage("[name]")
318
+ build_common_options(opts, options, [:options, :json])
319
+ end
320
+ optparse.parse!(args)
321
+ if args.count < 1
322
+ puts optparse
323
+ exit 1
324
+ end
325
+ connect(options)
326
+ begin
327
+ instance_type = find_custom_instance_type_by_name_or_code(args[0])
328
+ exit 1 if instance_type.nil?
329
+
330
+ #params = Morpheus::Cli::OptionTypes.prompt(add_version_option_types, options[:options], @api_client, options[:params])
331
+ provision_types = @provision_types_interface.get({customSupported: true})['provisionTypes']
332
+ if provision_types.empty?
333
+ print_red_alert "No available provision types found!"
334
+ exit 1
335
+ end
336
+ provision_type_options = provision_types.collect {|it| { 'name' => it['name'], 'value' => it['code']} }
337
+ payload = {'containerType' => {}, 'instanceTypeLayout' => {}, 'instanceType' => {}}
338
+
339
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => 'instanceTypeLayout', 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Name', 'required' => true, 'description' => 'A name for this layout.'}], options[:options])
340
+ payload['instanceTypeLayout']['name'] = v_prompt['instanceTypeLayout']['name']
341
+
342
+ # shortName is only available for the first new version
343
+ if !instance_type['versions'] || instance_type['versions'].size == 0
344
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => 'containerType', 'fieldName' => 'shortName', 'type' => 'text', 'fieldLabel' => 'Short Name', 'required' => true, 'description' => 'The short name is a lowercase name with no spaces used for display in your container list.'}], options[:options])
345
+ payload['containerType']['shortName'] = v_prompt['containerType']['shortName']
346
+ end
347
+
348
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => 'containerType', 'fieldName' => 'provisionTypeCode', 'type' => 'select', 'selectOptions' => provision_type_options, 'fieldLabel' => 'Technology', 'required' => true, 'description' => 'The type of container technology.'}], options[:options])
349
+ payload['containerType']['provisionTypeCode'] = v_prompt['containerType']['provisionTypeCode']
350
+ provision_type = provision_types.find {|it| it['code'] == payload['containerType']['provisionTypeCode'] }
351
+
352
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => 'instanceTypeLayout', 'fieldName' => 'instanceVersion', 'type' => 'text', 'fieldLabel' => 'Version', 'required' => true, 'description' => 'A Version Number eg. 0.0.1'}], options[:options])
353
+ payload['instanceTypeLayout']['instanceVersion'] = v_prompt['instanceTypeLayout']['instanceVersion']
354
+
355
+ custom_option_types = provision_type['customOptionTypes']
356
+
357
+ if (!custom_option_types || custom_option_types.empty?)
358
+ puts yellow,"Sorry, no options were found for #{provision_type['name']}.",reset
359
+ exit 1
360
+ end
361
+ # prompt custom options for the selected provision type
362
+ field_group_name = custom_option_types.first['fieldGroup'] || "#{provision_type['name']} Options"
363
+ puts field_group_name
364
+ puts "==============="
365
+ v_prompt = Morpheus::Cli::OptionTypes.prompt(custom_option_types,options[:options],@api_client, {provisionTypCode: payload['provisionTypeCode']})
366
+
367
+ if v_prompt['containerType']
368
+ payload['containerType'].merge!(v_prompt['containerType'])
369
+ end
370
+ if v_prompt['containerType.config']
371
+ payload['containerType']['config'] = v_prompt['containerType.config']
372
+ end
373
+ if v_prompt['instanceTypeLayout']
374
+ payload['instanceTypeLayout'].merge!(v_prompt['instanceTypeLayout'])
375
+ end
376
+ # instanceType.backupType, which is not even persisted on the server?
377
+ if v_prompt['instanceType']
378
+ payload['instanceType'].merge!(v_prompt['instanceType'])
379
+ end
380
+
381
+ # puts "PAYLOAD:"
382
+ # puts JSON.pretty_generate(payload)
383
+ # puts "\nexiting early"
384
+ # exit 0
385
+
386
+ payload['exposedPorts'] = prompt_exposed_ports(options, @api_client)
387
+
388
+ request_payload = payload
389
+ json_response = @custom_instance_types_interface.create_version(instance_type['id'], request_payload)
390
+
391
+ if options[:json]
392
+ print JSON.pretty_generate(json_response), "\n"
393
+ return
394
+ end
395
+
396
+ print_green_success "Added Instance Type Version #{instance_type['name']} - #{payload['instanceTypeLayout']['instanceVersion']}"
397
+ #list([])
398
+ rescue RestClient::Exception => e
399
+ print_rest_exception(e, options)
400
+ exit 1
401
+ end
402
+ end
403
+
404
+
405
+ private
406
+
407
+ def find_custom_instance_type_by_code(code)
408
+ instance_type_results = @custom_instance_types_interface.list({code: code})
409
+ if instance_type_results['instanceTypes'].empty?
410
+ print_red_alert "Custom Instance Type not found by code #{code}"
411
+ return nil
412
+ end
413
+ return instance_type_results['instanceTypes'][0]
414
+ end
415
+
416
+ def find_custom_instance_type_by_name(name)
417
+ instance_type_results = @custom_instance_types_interface.list({name: name})
418
+ instance_types = instance_type_results['instanceTypes']
419
+ if instance_types.empty?
420
+ print_red_alert "Custom Instance Type not found by name #{name}"
421
+ return nil
422
+ elsif instance_types.size > 1
420
423
  print_red_alert "Found #{instance_types.size} instance types by name #{name}"
421
424
  print red, "\n"
422
425
  instance_types.each do |instance_type|
423
426
  print "= #{instance_type['name']} (#{instance_type['code']})\n"
424
427
  end
425
428
  print "\n", "Find by code:<code> instead"
426
- print reset,"\n\n"
429
+ print reset,"\n"
427
430
  return nil
428
431
  else
429
432
  return instance_types[0]
430
433
  end
431
- end
432
-
433
- def find_custom_instance_type_by_name_or_code(val)
434
- if val =~ /code:/
435
- find_custom_instance_type_by_code(val.sub('code:', ''))
436
- else
437
- find_custom_instance_type_by_name(val)
438
- end
439
- end
440
-
441
- def instance_type_categories
442
- [
443
- {'name' => 'Web', 'value' => 'web'},
444
- {'name' => 'SQL', 'value' => 'sql'},
445
- {'name' => 'NoSQL', 'value' => 'nosql'},
446
- {'name' => 'Apps', 'value' => 'apps'},
447
- {'name' => 'Network', 'value' => 'network'},
448
- {'name' => 'Messaging', 'value' => 'messaging'},
449
- {'name' => 'Cache', 'value' => 'cache'},
450
- {'name' => 'OS', 'value' => 'os'},
451
- {'name' => 'Cloud', 'value' => 'cloud'},
452
- {'name' => 'Utility', 'value' => 'utility'}
453
- ]
454
- end
455
-
456
- def add_instance_type_option_types
457
- [
458
- {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
459
- {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'displayOrder' => 2},
460
- {'fieldName' => 'category', 'fieldLabel' => 'Category', 'type' => 'select', 'selectOptions' => instance_type_categories, 'required' => true, 'displayOrder' => 3},
461
- {'fieldName' => 'logo', 'fieldLabel' => 'Icon File', 'type' => 'text', 'displayOrder' => 4},
462
- {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'displayOrder' => 5},
463
- {'fieldName' => 'environmentPrefix', 'fieldLabel' => 'Environment Prefix', 'type' => 'text', 'displayOrder' => 6, 'description' => 'Used for exportable environment variables when tying instance types together in app contexts. If not specified a name will be generated.'},
464
- {'fieldName' => 'hasAutoScale', 'fieldLabel' => 'Enable Scaling (Horizontal)', 'type' => 'checkbox', 'displayOrder' => 7},
465
- {'fieldName' => 'hasDeployment', 'fieldLabel' => 'Supports Deployments', 'type' => 'checkbox', 'displayOrder' => 8, 'description' => 'Requires a data volume be configured on each version. Files will be copied into this location.'}
466
- ]
467
- end
468
-
469
- def update_instance_type_option_types(instance_type=nil)
470
- if instance_type
471
- opts = add_instance_type_option_types
472
- opts.find {|opt| opt['fieldName'] == 'name'}['defaultValue'] = instance_type['name']
473
- opts
474
- else
475
- add_instance_type_option_types
476
- end
477
- end
478
-
479
- def add_version_option_types
480
- [
481
- {'fieldName' => 'versionNumber', 'fieldLabel' => 'Version Number', 'type' => 'text', 'required' => true, 'displayOrder' => 1}
482
- ]
483
- end
484
-
485
- def update_version_option_types
486
- add_version_option_types
487
- end
488
-
489
- def load_balance_protocols
490
- [
491
- {'name' => 'None', 'value' => ''},
492
- {'name' => 'HTTP', 'value' => 'HTTP'},
493
- {'name' => 'HTTPS', 'value' => 'HTTPS'},
494
- {'name' => 'TCP', 'value' => 'TCP'}
495
- ]
496
- end
497
-
498
- # Prompts user for exposed ports array
434
+ end
435
+
436
+ def find_custom_instance_type_by_name_or_code(val)
437
+ if val =~ /code:/
438
+ find_custom_instance_type_by_code(val.sub('code:', ''))
439
+ else
440
+ find_custom_instance_type_by_name(val)
441
+ end
442
+ end
443
+
444
+ def instance_type_categories
445
+ [
446
+ {'name' => 'Web', 'value' => 'web'},
447
+ {'name' => 'SQL', 'value' => 'sql'},
448
+ {'name' => 'NoSQL', 'value' => 'nosql'},
449
+ {'name' => 'Apps', 'value' => 'apps'},
450
+ {'name' => 'Network', 'value' => 'network'},
451
+ {'name' => 'Messaging', 'value' => 'messaging'},
452
+ {'name' => 'Cache', 'value' => 'cache'},
453
+ {'name' => 'OS', 'value' => 'os'},
454
+ {'name' => 'Cloud', 'value' => 'cloud'},
455
+ {'name' => 'Utility', 'value' => 'utility'}
456
+ ]
457
+ end
458
+
459
+ def add_instance_type_option_types
460
+ [
461
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
462
+ {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'displayOrder' => 2},
463
+ {'fieldName' => 'category', 'fieldLabel' => 'Category', 'type' => 'select', 'selectOptions' => instance_type_categories, 'required' => true, 'displayOrder' => 3},
464
+ {'fieldName' => 'logo', 'fieldLabel' => 'Icon File', 'type' => 'text', 'displayOrder' => 4},
465
+ {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'displayOrder' => 5},
466
+ {'fieldName' => 'environmentPrefix', 'fieldLabel' => 'Environment Prefix', 'type' => 'text', 'displayOrder' => 6, 'description' => 'Used for exportable environment variables when tying instance types together in app contexts. If not specified a name will be generated.'},
467
+ {'fieldName' => 'hasAutoScale', 'fieldLabel' => 'Enable Scaling (Horizontal)', 'type' => 'checkbox', 'displayOrder' => 7},
468
+ {'fieldName' => 'hasDeployment', 'fieldLabel' => 'Supports Deployments', 'type' => 'checkbox', 'displayOrder' => 8, 'description' => 'Requires a data volume be configured on each version. Files will be copied into this location.'}
469
+ ]
470
+ end
471
+
472
+ def update_instance_type_option_types(instance_type=nil)
473
+ if instance_type
474
+ opts = add_instance_type_option_types
475
+ opts.find {|opt| opt['fieldName'] == 'name'}['defaultValue'] = instance_type['name']
476
+ opts
477
+ else
478
+ add_instance_type_option_types
479
+ end
480
+ end
481
+
482
+ def add_version_option_types
483
+ [
484
+ {'fieldName' => 'versionNumber', 'fieldLabel' => 'Version Number', 'type' => 'text', 'required' => true, 'displayOrder' => 1}
485
+ ]
486
+ end
487
+
488
+ def update_version_option_types
489
+ add_version_option_types
490
+ end
491
+
492
+ def load_balance_protocols
493
+ [
494
+ {'name' => 'None', 'value' => ''},
495
+ {'name' => 'HTTP', 'value' => 'HTTP'},
496
+ {'name' => 'HTTPS', 'value' => 'HTTPS'},
497
+ {'name' => 'TCP', 'value' => 'TCP'}
498
+ ]
499
+ end
500
+
501
+ # Prompts user for exposed ports array
499
502
  # returns array of port objects
500
503
  def prompt_exposed_ports(options={}, api_client=nil, api_params={})
501
504
  #puts "Configure ports:"
@@ -503,37 +506,33 @@ private
503
506
 
504
507
  ports = []
505
508
  port_index = 0
506
-
507
509
  has_another_port = options[:options] && options[:options]["exposedPort#{port_index}"]
508
510
  add_another_port = has_another_port || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add an exposed port?"))
509
-
510
511
  while add_another_port do
511
-
512
- field_context = "exposedPort#{port_index}"
512
+ field_context = "exposedPort#{port_index}"
513
513
 
514
- port = {}
515
- #port['name'] ||= "Port #{port_index}"
514
+ port = {}
515
+ #port['name'] ||= "Port #{port_index}"
516
+ port_label = port_index == 0 ? "Port" : "Port [#{port_index+1}]"
517
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "#{port_label} Name", 'required' => false, 'description' => 'Choose a name for this port.', 'defaultValue' => port['name']}], options[:options])
518
+ port['name'] = v_prompt[field_context]['name']
516
519
 
517
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "Port #{port_index} Name", 'required' => false, 'description' => 'Choose a name for this port.', 'defaultValue' => port['name']}], options[:options])
518
- port['name'] = v_prompt[field_context]['name']
520
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'port', 'type' => 'number', 'fieldLabel' => "#{port_label} Number", 'required' => true, 'description' => 'A port number. eg. 8001', 'defaultValue' => (port['port'] ? port['port'].to_i : nil)}], options[:options])
521
+ port['port'] = v_prompt[field_context]['port']
519
522
 
520
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'port', 'type' => 'number', 'fieldLabel' => "Port #{port_index} Number", 'required' => true, 'description' => 'Choose port number.', 'defaultValue' => (port['port'] ? port['port'].to_i : nil)}], options[:options])
521
- port['port'] = v_prompt[field_context]['port']
523
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'loadBalanceProtocol', 'type' => 'select', 'fieldLabel' => "#{port_label} LB", 'selectOptions' => load_balance_protocols, 'required' => false, 'skipSingleOption' => true, 'description' => 'Choose a load balance protocol.', 'defaultValue' => port['loadBalanceProtocol']}], options[:options])
524
+ port['loadBalanceProtocol'] = v_prompt[field_context]['loadBalanceProtocol']
522
525
 
523
- v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'loadBalanceProtocol', 'type' => 'select', 'fieldLabel' => "Port #{port_index} LB", 'selectOptions' => load_balance_protocols, 'required' => false, 'skipSingleOption' => true, 'description' => 'Choose a load balance protocol.', 'defaultValue' => port['loadBalanceProtocol']}], options[:options])
524
- port['loadBalanceProtocol'] = v_prompt[field_context]['loadBalanceProtocol']
526
+ ports << port
527
+ port_index += 1
528
+ has_another_port = options[:options] && options[:options]["exposedPort#{port_index}"]
529
+ add_another_port = has_another_port || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another exposed port?"))
530
+
531
+ end
525
532
 
526
- ports << port
527
-
528
- port_index += 1
529
- has_another_port = options[:options] && options[:options]["exposedPort#{port_index}"]
530
- add_another_port = has_another_port || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another exposed port?"))
531
533
 
534
+ return ports
532
535
  end
533
536
 
534
537
 
535
- return ports
536
538
  end
537
-
538
-
539
- end