morpheus-cli 2.10.0 → 2.10.1

Sign up to get free protection for your applications and to get access to all the features.
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