morpheus-cli 5.0.2 → 5.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 25ca8fc7cabb51b4042eb212172b60191d6863cf9310ffce4e386d016692f7f1
4
- data.tar.gz: d1183424bef986bb22123d60b45e97ed077c8ea30c5bfd249f8bf503c0a22d13
3
+ metadata.gz: 4f4b5a29dcfa1a915ab2d3fed9ad07197d2a760758b2bc3b76e72cf6899c4372
4
+ data.tar.gz: 59c981a5aede057b69e08f5c717d27c884bdd64aed84fb81361b35291b3aaf72
5
5
  SHA512:
6
- metadata.gz: d006acc9447822675c3593de443679ac2eee514bf1ffe041ddfa5ddc44223e8edfbbeee9393056c59fb98c14d4beb240b0ce9725a3bcc56eb5e1095066d15d1c
7
- data.tar.gz: ca41986fc3561f562b799971514b92dfe08027e06ad5443b0e116713fee9132d62b84905c929209be03a7dc0f3855e97adf7fe053e64832067addca692ef4268
6
+ metadata.gz: 678ff7f73923c9883968ee8bba29b8d75d5464a4899ca812477ce943b25f758c74f187a481c781500928206c4d540d5153f858ee4e2242cfb24cc2604be1602d
7
+ data.tar.gz: c27881081abb71b05eceb4857280f51a4f838e9a568658baa34385afe7fc2b86be61eb31a070a4e3a9381000337ceb9b11f58fe8572fff8066882225133742ba
data/Dockerfile CHANGED
@@ -1,5 +1,5 @@
1
1
  FROM ruby:2.5.1
2
2
 
3
- RUN gem install morpheus-cli -v 5.0.2
3
+ RUN gem install morpheus-cli -v 5.2.0
4
4
 
5
5
  ENTRYPOINT ["morpheus"]
@@ -776,6 +776,10 @@ class Morpheus::APIClient
776
776
  Morpheus::CatalogItemTypesInterface.new(common_interface_options).setopts(@options)
777
777
  end
778
778
 
779
+ def catalog
780
+ Morpheus::ServiceCatalogInterface.new(common_interface_options).setopts(@options)
781
+ end
782
+
779
783
  def usage
780
784
  Morpheus::UsageInterface.new(common_interface_options).setopts(@options)
781
785
  end
@@ -169,10 +169,10 @@ class Morpheus::InstancesInterface < Morpheus::APIClient
169
169
  execute(opts)
170
170
  end
171
171
 
172
- def backup(id,server=true)
172
+ def backup(id, payload={})
173
173
  url = "#{@base_url}/api/instances/#{id}/backup"
174
174
  headers = {:authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
175
- opts = {method: :put, url: url, headers: headers}
175
+ opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
176
176
  execute(opts)
177
177
  end
178
178
 
@@ -218,6 +218,13 @@ class Morpheus::InstancesInterface < Morpheus::APIClient
218
218
  execute(opts)
219
219
  end
220
220
 
221
+ def snapshot(id, payload={})
222
+ url = "#{@base_url}/api/instances/#{id}/snapshot"
223
+ headers = {:authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
224
+ opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
225
+ execute(opts)
226
+ end
227
+
221
228
  def snapshots(instance_id, params={})
222
229
  url = "#{@base_url}/api/instances/#{instance_id}/snapshots"
223
230
  headers = { params: params, authorization: "Bearer #{@access_token}" }
@@ -176,4 +176,11 @@ class Morpheus::ServersInterface < Morpheus::APIClient
176
176
  execute(opts)
177
177
  end
178
178
 
179
+ def software(id, params={})
180
+ url = "#{@base_url}/api/servers/#{id}/software"
181
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
182
+ opts = {method: :get, url: url, headers: headers}
183
+ execute(opts)
184
+ end
185
+
179
186
  end
@@ -0,0 +1,89 @@
1
+ require 'morpheus/api/api_client'
2
+ # Service Catalog Persona interface
3
+ class Morpheus::ServiceCatalogInterface < Morpheus::APIClient
4
+
5
+ def base_path
6
+ # "/api/service-catalog"
7
+ "/api/catalog"
8
+ end
9
+
10
+ # dashboard
11
+ def dashboard(params={})
12
+ execute(method: :get, url: "#{base_path}/dashboard", params: params)
13
+ end
14
+
15
+ # list catalog types available for ordering
16
+ def list_types(params={})
17
+ execute(method: :get, url: "#{base_path}/types", params: params)
18
+ end
19
+
20
+ # get specific catalog type
21
+ def get_type(id, params={})
22
+ validate_id!(id)
23
+ execute(method: :get, url: "#{base_path}/types/#{id}", params: params)
24
+ end
25
+
26
+ # list catalog inventory (items)
27
+ def list_inventory(params={})
28
+ execute(method: :get, url: "#{base_path}/items", params: params)
29
+ end
30
+
31
+ # get catalog inventory item
32
+ def get_inventory(id, params={})
33
+ validate_id!(id)
34
+ execute(method: :get, url: "#{base_path}/items/#{id}", params: params)
35
+ end
36
+
37
+ # delete a catalog inventory item
38
+ def destroy_inventory(id, params = {})
39
+ validate_id!(id)
40
+ execute(method: :delete, url: "#{base_path}/items/#{id}", params: params)
41
+ end
42
+
43
+ # get cart (one per user)
44
+ def get_cart(params={})
45
+ execute(method: :get, url: "#{base_path}/cart", params: params)
46
+ end
47
+
48
+ # update cart (set cart name)
49
+ def update_cart(payload, params={})
50
+ execute(method: :put, url: "#{base_path}/cart", params: params, payload: payload.to_json)
51
+ end
52
+
53
+ # validate a new item, can be used before before adding it
54
+ def validate_cart_item(payload, params={})
55
+ execute(method: :post, url: "#{base_path}/cart/items/validate", params: params, payload: payload.to_json)
56
+ end
57
+
58
+ # add item to cart
59
+ def create_cart_item(payload, params={})
60
+ execute(method: :post, url: "#{base_path}/cart/items", params: params, payload: payload.to_json)
61
+ end
62
+
63
+ # update item in the cart
64
+ def update_cart_item(id, payload, params={})
65
+ validate_id!(id)
66
+ execute(method: :put, url: "#{base_path}/cart/items/#{id}", params: params, payload: payload.to_json)
67
+ end
68
+
69
+ # remove item from the cart
70
+ def destroy_cart_item(id, params={})
71
+ validate_id!(id)
72
+ execute(method: :delete, url: "#{base_path}/cart/items/#{id}", params: params)
73
+ end
74
+
75
+ # place order with cart
76
+ def checkout(payload, params={})
77
+ execute(method: :post, url: "#{base_path}/checkout", params: params, payload: payload.to_json)
78
+ end
79
+
80
+ # remove all items from cart and reset name
81
+ def clear_cart(params={})
82
+ execute(method: :delete, url: "#{base_path}/cart", params: params)
83
+ end
84
+
85
+ # create an order from scratch, without using a cart
86
+ def create_order(payload, params={})
87
+ execute(method: :post, url: "#{base_path}/orders", params: params, payload: payload.to_json)
88
+ end
89
+ end
@@ -175,7 +175,8 @@ module Morpheus
175
175
  load 'morpheus/cli/projects_command.rb'
176
176
  load 'morpheus/cli/backups_command.rb'
177
177
  load 'morpheus/cli/backup_jobs_command.rb'
178
- load 'morpheus/cli/catalog_command.rb'
178
+ load 'morpheus/cli/catalog_item_types_command.rb' # catalog-types
179
+ load 'morpheus/cli/service_catalog_command.rb' # catalog
179
180
  load 'morpheus/cli/usage_command.rb'
180
181
  # add new commands here...
181
182
 
@@ -72,9 +72,6 @@ class Morpheus::Cli::Apps
72
72
  options[:owner] = val
73
73
  end
74
74
  opts.add_hidden_option('--created-by')
75
- opts.on('--details', "Display more details: memory and storage usage used / max values." ) do
76
- options[:details] = true
77
- end
78
75
  opts.on('--pending-removal', "Include apps pending removal.") do
79
76
  options[:showDeleted] = true
80
77
  end
@@ -88,6 +85,9 @@ class Morpheus::Cli::Apps
88
85
  opts.on('--status STATUS', "Filter by status.") do |val|
89
86
  params['status'] = (params['status'] || []) + val.to_s.split(',').collect {|s| s.strip }.select {|s| s != "" }
90
87
  end
88
+ opts.on('-a', '--details', "Display all details: memory and storage usage used / max values." ) do
89
+ options[:details] = true
90
+ end
91
91
  build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
92
92
  opts.footer = "List apps."
93
93
  end
@@ -2185,26 +2185,6 @@ EOT
2185
2185
  print reset
2186
2186
  end
2187
2187
 
2188
- def format_app_status(app, return_color=cyan)
2189
- out = ""
2190
- status_string = app['status'] || app['appStatus'] || ''
2191
- if status_string == 'running'
2192
- out = "#{green}#{status_string.upcase}#{return_color}"
2193
- elsif status_string == 'provisioning'
2194
- out = "#{cyan}#{status_string.upcase}#{cyan}"
2195
- elsif status_string == 'stopped' or status_string == 'failed'
2196
- out = "#{red}#{status_string.upcase}#{return_color}"
2197
- elsif status_string == 'unknown'
2198
- out = "#{yellow}#{status_string.upcase}#{return_color}"
2199
- elsif status_string == 'warning' && app['instanceCount'].to_i == 0
2200
- # show this instead of WARNING
2201
- out = "#{cyan}EMPTY#{return_color}"
2202
- else
2203
- out = "#{yellow}#{status_string.upcase}#{return_color}"
2204
- end
2205
- out
2206
- end
2207
-
2208
2188
  def format_app_tiers(app)
2209
2189
  out = ""
2210
2190
  begin
@@ -1,17 +1,16 @@
1
1
  require 'morpheus/cli/cli_command'
2
2
 
3
3
  # CLI command self service
4
- # UI is Tools: Self Service - Catalog Items
4
+ # UI is Tools: Self Service - Catalog
5
5
  # API is /catalog-item-types and returns catalogItemTypes
6
- class Morpheus::Cli::CatalogCommand
6
+ class Morpheus::Cli::CatalogItemTypesCommand
7
7
  include Morpheus::Cli::CliCommand
8
- include Morpheus::Cli::CatalogHelper
9
8
  include Morpheus::Cli::LibraryHelper
10
9
  include Morpheus::Cli::OptionSourceHelper
11
10
 
12
- # hide until 5.1 when update api is fixed and service-catalog endpoints are available
13
- set_command_hidden
14
- set_command_name :'catalog'
11
+ # set_command_name :'catalog-types'
12
+ set_command_name :'self-service'
13
+ set_command_description "Self Service: View and manage catalog item types"
15
14
 
16
15
  register_subcommands :list, :get, :add, :update, :remove
17
16
 
@@ -38,7 +37,7 @@ class Morpheus::Cli::CatalogCommand
38
37
  params['featured'] = (val.to_s != 'false' && val.to_s != 'off')
39
38
  end
40
39
  build_standard_list_options(opts, options)
41
- opts.footer = "List catalog items."
40
+ opts.footer = "List catalog item types."
42
41
  end
43
42
  optparse.parse!(args)
44
43
  connect(options)
@@ -55,11 +54,14 @@ class Morpheus::Cli::CatalogCommand
55
54
  json_response = @catalog_item_types_interface.list(params)
56
55
  catalog_item_types = json_response[catalog_item_type_list_key]
57
56
  render_response(json_response, options, catalog_item_type_list_key) do
58
- print_h1 "Morpheus Catalog Items", parse_list_subtitles(options), options
57
+ print_h1 "Morpheus Catalog Item Types", parse_list_subtitles(options), options
59
58
  if catalog_item_types.empty?
60
- print cyan,"No catalog items found.",reset,"\n"
59
+ print cyan,"No catalog item types found.",reset,"\n"
61
60
  else
62
61
  list_columns = catalog_item_type_column_definitions.upcase_keys!
62
+ list_columns.delete("Blueprint")
63
+ list_columns.delete("Workflow")
64
+ list_columns.delete("Context")
63
65
  #list_columns["Config"] = lambda {|it| truncate_string(it['config'], 100) }
64
66
  print as_pretty_table(catalog_item_types, list_columns.upcase_keys!, options)
65
67
  print_results_pagination(json_response)
@@ -67,7 +69,7 @@ class Morpheus::Cli::CatalogCommand
67
69
  print reset,"\n"
68
70
  end
69
71
  if catalog_item_types.empty?
70
- return 1, "no catalog items found"
72
+ return 1, "no catalog item types found"
71
73
  else
72
74
  return 0, nil
73
75
  end
@@ -77,17 +79,20 @@ class Morpheus::Cli::CatalogCommand
77
79
  params = {}
78
80
  options = {}
79
81
  optparse = Morpheus::Cli::OptionParser.new do |opts|
80
- opts.banner = subcommand_usage("[catalog item type]")
82
+ opts.banner = subcommand_usage("[type]")
81
83
  opts.on( '-c', '--config', "Display raw config only. Default is YAML. Combine with -j for JSON instead." ) do
82
84
  options[:show_config] = true
83
85
  end
84
- # opts.on('--no-config', "Do not display config content." ) do
86
+ # opts.on('--no-config', "Do not display Config YAML." ) do
85
87
  # options[:no_config] = true
86
88
  # end
89
+ opts.on('--no-content', "Do not display Content." ) do
90
+ options[:no_content] = true
91
+ end
87
92
  build_standard_get_options(opts, options)
88
93
  opts.footer = <<-EOT
89
94
  Get details about a specific catalog item type.
90
- [catalog item type] is required. This is the name or id of a catalog item type.
95
+ [type] is required. This is the name or id of a catalog item type.
91
96
  EOT
92
97
  end
93
98
  optparse.parse!(args)
@@ -131,6 +136,8 @@ EOT
131
136
  print cyan
132
137
  show_columns = catalog_item_type_column_definitions
133
138
  show_columns.delete("Blueprint") unless catalog_item_type['blueprint']
139
+ show_columns.delete("Workflow") unless catalog_item_type['workflow']
140
+ show_columns.delete("Context") unless catalog_item_type['context'] # workflow context
134
141
  print_description_list(show_columns, catalog_item_type)
135
142
 
136
143
  if catalog_item_type['optionTypes'] && catalog_item_type['optionTypes'].size > 0
@@ -149,25 +156,62 @@ EOT
149
156
  # print cyan,"No option types found for this catalog item.","\n",reset
150
157
  end
151
158
 
152
- if config && options[:no_config] != true
153
- print_h2 "Config YAML"
154
- #print reset,(JSON.pretty_generate(config) rescue config),"\n",reset
155
- #print reset,(as_yaml(config, options) rescue config),"\n",reset
156
- config_string = as_yaml(config, options) rescue config
157
- config_lines = config_string.split("\n")
158
- config_line_count = config_lines.size
159
- max_lines = 10
160
- if config_lines.size > max_lines
161
- config_string = config_lines.first(max_lines).join("\n")
162
- config_string << "\n\n"
163
- config_string << "(#{(config_line_count - max_lines)} more lines were not shown, use -c to show the config)"
164
- #config_string << "\n"
165
- end
166
- # strip --- yaml header
167
- if config_string[0..3] == "---\n"
168
- config_string = config_string[4..-1]
159
+ item_type_code = catalog_item_type['type'].to_s.downcase
160
+ if options[:no_config] != true
161
+ if item_type_code == 'instance'
162
+ print_h2 "Config YAML"
163
+ if config
164
+ #print reset,(JSON.pretty_generate(config) rescue config),"\n",reset
165
+ #print reset,(as_yaml(config, options) rescue config),"\n",reset
166
+ config_string = as_yaml(config, options) rescue config
167
+ config_lines = config_string.split("\n")
168
+ config_line_count = config_lines.size
169
+ max_lines = 10
170
+ if config_lines.size > max_lines
171
+ config_string = config_lines.first(max_lines).join("\n")
172
+ config_string << "\n\n"
173
+ config_string << "#{dark}(#{(config_line_count - max_lines)} more lines were not shown, use -c to show the config)#{reset}"
174
+ #config_string << "\n"
175
+ end
176
+ # strip --- yaml header
177
+ if config_string[0..3] == "---\n"
178
+ config_string = config_string[4..-1]
179
+ end
180
+ print reset,config_string.chomp("\n"),"\n",reset
181
+ else
182
+ print reset,"(blank)","\n",reset
183
+ end
184
+ elsif item_type_code == 'blueprint' || item_type_code == 'apptemplate' || item_type_code == 'app'
185
+ print_h2 "App Spec"
186
+ if catalog_item_type['appSpec']
187
+ #print reset,(JSON.pretty_generate(config) rescue config),"\n",reset
188
+ #print reset,(as_yaml(config, options) rescue config),"\n",reset
189
+ config_string = catalog_item_type['appSpec'] || ""
190
+ config_lines = config_string.split("\n")
191
+ config_line_count = config_lines.size
192
+ max_lines = 10
193
+ if config_lines.size > max_lines
194
+ config_string = config_lines.first(max_lines).join("\n")
195
+ config_string << "\n\n"
196
+ config_string << "#{dark}(#{(config_line_count - max_lines)} more lines were not shown, use -c to show the config)#{reset}"
197
+ #config_string << "\n"
198
+ end
199
+ # strip --- yaml header
200
+ if config_string[0..3] == "---\n"
201
+ config_string = config_string[4..-1]
202
+ end
203
+ print reset,config_string.chomp("\n"),"\n",reset
204
+ else
205
+ print reset,"(blank)","\n",reset
206
+ end
207
+ elsif item_type_code == 'workflow' || item_type_code == 'operationalworkflow' || item_type_code == 'taskset'
169
208
  end
170
- print reset,config_string.chomp("\n"),"\n",reset
209
+ end
210
+
211
+ # Content (Wiki Page)
212
+ if !catalog_item_type["content"].to_s.empty? && options[:no_content] != true
213
+ print_h2 "Content"
214
+ print reset,catalog_item_type["content"].chomp("\n"),"\n",reset
171
215
  end
172
216
 
173
217
  print reset,"\n"
@@ -180,6 +224,10 @@ EOT
180
224
  params = {}
181
225
  optparse = Morpheus::Cli::OptionParser.new do |opts|
182
226
  opts.banner = subcommand_usage("[name] [options]")
227
+ # opts.on('-t', '--type [instance|blueprint|workflow]', "Item Type, default is instance.") do |val|
228
+ # # params['type'] = val.to_s.downcase
229
+ # options[:options]['type'] = val.to_s.downcase
230
+ # end
183
231
  build_option_type_options(opts, options, add_catalog_item_type_option_types)
184
232
  opts.on('--config-file FILE', String, "Config from a local JSON or YAML file") do |val|
185
233
  options[:config_file] = val.to_s
@@ -233,6 +281,8 @@ EOT
233
281
  payload.deep_merge!({catalog_item_type_object_key => parse_passed_options(options)})
234
282
  else
235
283
  payload.deep_merge!({catalog_item_type_object_key => parse_passed_options(options)})
284
+ # Type prompt first
285
+ #params['type'] = Morpheus::Cli::OptionTypes.no_prompt([{'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Instance', 'value' => 'instance'}, {'name' => 'Blueprint', 'value' => 'blueprint'}, {'name' => 'Workflow', 'value' => 'workflow'}], 'defaultValue' => 'instance', 'required' => true}], options[:options], @api_client, options[:params])['type']
236
286
  v_prompt = Morpheus::Cli::OptionTypes.prompt(add_catalog_item_type_option_types(), options[:options], @api_client, options[:params])
237
287
  params.deep_merge!(v_prompt)
238
288
  advanced_config = Morpheus::Cli::OptionTypes.no_prompt(add_catalog_item_type_advanced_option_types, options[:options], @api_client, options[:params])
@@ -241,13 +291,15 @@ EOT
241
291
  # convert checkbox "on" and "off" to true and false
242
292
  params.booleanize!
243
293
  # convert type to refType until api accepts type
244
- if params['type'] && !params['refType']
245
- if params['type'].to_s.downcase == 'blueprint'
246
- params['refType'] = 'AppTemplate'
247
- else
248
- params['refType'] = 'InstanceType'
249
- end
250
- end
294
+ # if params['type'] && !params['refType']
295
+ # if params['type'].to_s.downcase == 'instance'
296
+ # params['refType'] = 'InstanceType'
297
+ # elsif params['type'].to_s.downcase == 'blueprint'
298
+ # params['refType'] = 'AppTemplate'
299
+ # elsif params['type'].to_s.downcase == 'workflow'
300
+ # params['refType'] = 'OperationalWorkflow'
301
+ # end
302
+ # end
251
303
  # convert config string to a map
252
304
  config = params['config']
253
305
  if config && config.is_a?(String)
@@ -261,14 +313,14 @@ EOT
261
313
  params['config'] = config_map
262
314
  end
263
315
  end
264
- if params['optionTypes']
265
- # todo: move to optionSource, so it will be /api/options/optionTypes lol
266
- prompt_results = prompt_for_option_types(params, options, @api_client)
267
- if prompt_results[:success]
268
- params['optionTypes'] = prompt_results[:data] unless prompt_results[:data].nil?
269
- else
270
- return 1
271
- end
316
+ # massage association params a bit
317
+ params['workflow'] = {'id' => params['workflow']} if params['workflow'] && !params['workflow'].is_a?(Hash)
318
+ params['blueprint'] = {'id' => params['blueprint']} if params['blueprint'] && !params['blueprint'].is_a?(Hash)
319
+ prompt_results = prompt_for_option_types(params, options, @api_client)
320
+ if prompt_results[:success]
321
+ params['optionTypes'] = prompt_results[:data] unless prompt_results[:data].nil?
322
+ else
323
+ return 1, "failed to parse optionTypes"
272
324
  end
273
325
  payload[catalog_item_type_object_key].deep_merge!(params)
274
326
  end
@@ -280,7 +332,7 @@ EOT
280
332
  json_response = @catalog_item_types_interface.create(payload)
281
333
  catalog_item_type = json_response[catalog_item_type_object_key]
282
334
  render_response(json_response, options, catalog_item_type_object_key) do
283
- print_green_success "Added catalog item #{catalog_item_type['name']}"
335
+ print_green_success "Added catalog item type #{catalog_item_type['name']}"
284
336
  return _get(catalog_item_type["id"], {}, options)
285
337
  end
286
338
  return 0, nil
@@ -291,7 +343,7 @@ EOT
291
343
  params = {}
292
344
  payload = {}
293
345
  optparse = Morpheus::Cli::OptionParser.new do |opts|
294
- opts.banner = subcommand_usage("[catalog item type] [options]")
346
+ opts.banner = subcommand_usage("[type] [options]")
295
347
  build_option_type_options(opts, options, update_catalog_item_type_option_types)
296
348
  opts.on('--config-file FILE', String, "Config from a local JSON or YAML file") do |val|
297
349
  options[:config_file] = val.to_s
@@ -333,7 +385,7 @@ EOT
333
385
  build_standard_update_options(opts, options)
334
386
  opts.footer = <<-EOT
335
387
  Update a catalog item type.
336
- [catalog item type] is required. This is the name or id of a catalog item type.
388
+ [type] is required. This is the name or id of a catalog item type.
337
389
  EOT
338
390
  end
339
391
  optparse.parse!(args)
@@ -356,14 +408,7 @@ EOT
356
408
  params.deep_merge!(advanced_config)
357
409
  # convert checkbox "on" and "off" to true and false
358
410
  params.booleanize!
359
- # convert type to refType until api accepts type
360
- if params['type'] && !params['refType']
361
- if params['type'].to_s.downcase == 'blueprint'
362
- params['refType'] = 'AppTemplate'
363
- else
364
- params['refType'] = 'InstanceType'
365
- end
366
- end
411
+
367
412
  # convert config string to a map
368
413
  config = params['config']
369
414
  if config && config.is_a?(String)
@@ -377,6 +422,18 @@ EOT
377
422
  params['config'] = config_map
378
423
  end
379
424
  end
425
+ if params['optionTypes']
426
+ # todo: move to optionSource, so it will be /api/options/optionTypes lol
427
+ prompt_results = prompt_for_option_types(params, options, @api_client)
428
+ if prompt_results[:success]
429
+ params['optionTypes'] = prompt_results[:data] unless prompt_results[:data].nil?
430
+ else
431
+ return 1, "failed to parse optionTypes"
432
+ end
433
+ end
434
+ # massage association params a bit
435
+ params['workflow'] = {'id' => params['workflow']} if params['workflow'] && !params['workflow'].is_a?(Hash)
436
+ params['blueprint'] = {'id' => params['blueprint']} if params['blueprint'] && !params['blueprint'].is_a?(Hash)
380
437
  payload.deep_merge!({catalog_item_type_object_key => params})
381
438
  if payload[catalog_item_type_object_key].empty? # || options[:no_prompt]
382
439
  raise_command_error "Specify at least one option to update.\n#{optparse}"
@@ -390,7 +447,7 @@ EOT
390
447
  json_response = @catalog_item_types_interface.update(catalog_item_type['id'], payload)
391
448
  catalog_item_type = json_response[catalog_item_type_object_key]
392
449
  render_response(json_response, options, catalog_item_type_object_key) do
393
- print_green_success "Updated catalog item #{catalog_item_type['name']}"
450
+ print_green_success "Updated catalog item type #{catalog_item_type['name']}"
394
451
  return _get(catalog_item_type["id"], {}, options)
395
452
  end
396
453
  return 0, nil
@@ -400,11 +457,11 @@ EOT
400
457
  options = {}
401
458
  params = {}
402
459
  optparse = Morpheus::Cli::OptionParser.new do |opts|
403
- opts.banner = subcommand_usage("[catalog item type] [options]")
460
+ opts.banner = subcommand_usage("[type] [options]")
404
461
  build_standard_remove_options(opts, options)
405
462
  opts.footer = <<-EOT
406
- Delete a catalog_item_type.
407
- [catalog item type] is required. This is the name or id of a catalog item type.
463
+ Delete a catalog item type.
464
+ [type] is required. This is the name or id of a catalog item type.
408
465
  EOT
409
466
  end
410
467
  optparse.parse!(args)
@@ -417,12 +474,12 @@ EOT
417
474
  print_dry_run @catalog_item_types_interface.dry.destroy(catalog_item_type['id'], params)
418
475
  return
419
476
  end
420
- unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the catalog item #{catalog_item_type['name']}?")
477
+ unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the catalog item type #{catalog_item_type['name']}?")
421
478
  return 9, "aborted command"
422
479
  end
423
480
  json_response = @catalog_item_types_interface.destroy(catalog_item_type['id'], params)
424
481
  render_response(json_response, options) do
425
- print_green_success "Removed catalog item #{catalog_item_type['name']}"
482
+ print_green_success "Removed catalog item type #{catalog_item_type['name']}"
426
483
  end
427
484
  return 0, nil
428
485
  end
@@ -436,6 +493,9 @@ EOT
436
493
  "Description" => 'description',
437
494
  "Type" => lambda {|it| format_catalog_type(it) },
438
495
  "Blueprint" => lambda {|it| it['blueprint'] ? it['blueprint']['name'] : nil },
496
+ "Workflow" => lambda {|it| it['workflow'] ? it['workflow']['name'] : nil },
497
+ "Context" => lambda {|it| it['context'] },
498
+ # "Content" => lambda {|it| it['content'] },
439
499
  "Enabled" => lambda {|it| format_boolean(it['enabled']) },
440
500
  "Featured" => lambda {|it| format_boolean(it['featured']) },
441
501
  #"Config" => lambda {|it| it['config'] },
@@ -455,6 +515,7 @@ EOT
455
515
  out << (catalog_item_type['type']['name'] || catalog_item_type['type']['code']) rescue catalog_item_type['type'].to_s
456
516
  end
457
517
  else
518
+ # refType is not returned
458
519
  ref_type = catalog_item_type['refType']
459
520
  if ref_type == 'InstanceType'
460
521
  out << "Instance"
@@ -469,18 +530,24 @@ EOT
469
530
  out
470
531
  end
471
532
 
472
- # this is not so simple, need to first choose select instance, host or provider
473
533
  def add_catalog_item_type_option_types
474
534
  [
535
+ {'code' => 'catalogItemType.type', 'shorthand' => '-t', 'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Instance', 'value' => 'instance'}, {'name' => 'Blueprint', 'value' => 'blueprint'}, {'name' => 'Workflow', 'value' => 'workflow'}], 'defaultValue' => 'instance', 'required' => true},
475
536
  {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true},
476
537
  {'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text'},
477
- {'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => [{'name' => 'Instance', 'value' => 'instance'}, {'name' => 'Blueprint', 'value' => 'blueprint'}], 'defaultValue' => 'instance'},
478
538
  {'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'defaultValue' => true},
479
539
  {'fieldName' => 'featured', 'fieldLabel' => 'Featured', 'type' => 'checkbox', 'defaultValue' => false},
480
540
  {'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'required' => true},
481
541
  {'fieldName' => 'iconPath', 'fieldLabel' => 'Logo', 'type' => 'select', 'optionSource' => 'iconList'},
482
542
  #{'fieldName' => 'optionTypes', 'fieldLabel' => 'Option Types', 'type' => 'text', 'description' => 'Option Types to include, comma separated list of names or IDs.'},
483
- {'fieldName' => 'config', 'fieldLabel' => 'Config', 'type' => 'code-editor', 'required' => true, 'description' => 'JSON or YAML'}
543
+ {'dependsOnCode' => 'catalogItemType.type:instance', 'fieldName' => 'config', 'fieldLabel' => 'Config', 'type' => 'code-editor', 'description' => 'JSON or YAML', 'required' => true},
544
+ {'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => 'blueprint', 'fieldLabel' => 'Blueprint', 'type' => 'select', 'optionSource' => 'blueprints', 'description' => 'Choose a blueprint to apply to the catalog item.', 'required' => true, 'noParams' => true},
545
+ {'dependsOnCode' => 'catalogItemType.type:blueprint', 'fieldName' => 'appSpec', 'fieldLabel' => 'App Spec', 'type' => 'code-editor', 'description' => 'Enter a spec in the for the App, the Scribe YAML format', 'required' => true},
546
+ {'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'workflow', 'fieldLabel' => 'Workflow', 'type' => 'select', 'optionSource' => 'operationWorkflows', 'description' => 'Enter a spec in the for the App, the Scribe YAML format', 'noParams' => true},
547
+ {'dependsOnCode' => 'catalogItemType.type:workflow', 'fieldName' => 'context', 'fieldLabel' => 'Context Type', 'type' => 'select', 'optionSource' => lambda { |api_client, api_params|
548
+ [{'name' => "Select", 'value' => ""}, {'name' => "None", 'value' => "appliance"}, {'name' => "Instance", 'value' => "instance"}, {'name' => "Server", 'value' => "server"}]
549
+ }, 'description' => 'Context for operational workflow, determines target type', 'defaultValue' => 'Select', 'required' => false},
550
+ {'fieldName' => 'content', 'fieldLabel' => 'Content', 'type' => 'code-editor', 'description' => 'Wiki Page Content describing the catalog item'}
484
551
  ]
485
552
  end
486
553
 
@@ -489,11 +556,13 @@ EOT
489
556
  end
490
557
 
491
558
  def update_catalog_item_type_option_types
492
- add_catalog_item_type_option_types.collect {|it|
559
+ list = add_catalog_item_type_option_types.collect {|it|
493
560
  it.delete('required')
494
561
  it.delete('defaultValue')
495
562
  it
496
563
  }
564
+ list = list.reject {|it| ["type"].include? it['fieldName'] }
565
+ list
497
566
  end
498
567
 
499
568
  def update_catalog_item_type_advanced_option_types
@@ -504,4 +573,50 @@ EOT
504
573
  }
505
574
  end
506
575
 
576
+ def catalog_item_type_object_key
577
+ 'catalogItemType'
578
+ end
579
+
580
+ def catalog_item_type_list_key
581
+ 'catalogItemTypes'
582
+ end
583
+
584
+ def find_catalog_item_type_by_name_or_id(val)
585
+ if val.to_s =~ /\A\d{1,}\Z/
586
+ return find_catalog_item_type_by_id(val)
587
+ else
588
+ return find_catalog_item_type_by_name(val)
589
+ end
590
+ end
591
+
592
+ def find_catalog_item_type_by_id(id)
593
+ begin
594
+ json_response = @catalog_item_types_interface.get(id.to_i)
595
+ return json_response[catalog_item_type_object_key]
596
+ rescue RestClient::Exception => e
597
+ if e.response && e.response.code == 404
598
+ print_red_alert "catalog item type not found by id '#{id}'"
599
+ else
600
+ raise e
601
+ end
602
+ end
603
+ end
604
+
605
+ def find_catalog_item_type_by_name(name)
606
+ json_response = @catalog_item_types_interface.list({name: name.to_s})
607
+ catalog_item_types = json_response[catalog_item_type_list_key]
608
+ if catalog_item_types.empty?
609
+ print_red_alert "catalog item type not found by name '#{name}'"
610
+ return nil
611
+ elsif catalog_item_types.size > 1
612
+ print_red_alert "#{catalog_item_types.size} catalog item types found by name '#{name}'"
613
+ puts_error as_pretty_table(catalog_item_types, [:id, :name], {color:red})
614
+ print_red_alert "Try using ID instead"
615
+ print reset,"\n"
616
+ return nil
617
+ else
618
+ return catalog_item_types[0]
619
+ end
620
+ end
621
+
507
622
  end