morpheus-cli 3.3.1.4 → 3.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/morpheus/api/api_client.rb +28 -0
- data/lib/morpheus/api/instance_types_interface.rb +12 -10
- data/lib/morpheus/api/instances_interface.rb +4 -0
- data/lib/morpheus/api/library_container_scripts_interface.rb +49 -0
- data/lib/morpheus/api/library_container_templates_interface.rb +49 -0
- data/lib/morpheus/api/library_container_types_interface.rb +65 -0
- data/lib/morpheus/api/library_container_upgrades_interface.rb +66 -0
- data/lib/morpheus/api/library_instance_types_interface.rb +59 -0
- data/lib/morpheus/api/library_layouts_interface.rb +65 -0
- data/lib/morpheus/api/servers_interface.rb +4 -0
- data/lib/morpheus/api/user_sources_interface.rb +120 -0
- data/lib/morpheus/api/virtual_images_interface.rb +7 -0
- data/lib/morpheus/cli.rb +12 -1
- data/lib/morpheus/cli/accounts.rb +35 -9
- data/lib/morpheus/cli/cli_command.rb +82 -2
- data/lib/morpheus/cli/curl_command.rb +1 -1
- data/lib/morpheus/cli/echo_command.rb +1 -1
- data/lib/morpheus/cli/hosts.rb +40 -14
- data/lib/morpheus/cli/instance_types.rb +106 -64
- data/lib/morpheus/cli/instances.rb +39 -15
- data/lib/morpheus/cli/library.rb +1 -1184
- data/lib/morpheus/cli/library_container_scripts_command.rb +437 -0
- data/lib/morpheus/cli/library_container_templates_command.rb +397 -0
- data/lib/morpheus/cli/library_container_types_command.rb +653 -0
- data/lib/morpheus/cli/library_instance_types_command.rb +491 -0
- data/lib/morpheus/cli/library_layouts_command.rb +650 -0
- data/lib/morpheus/cli/library_option_lists_command.rb +476 -0
- data/lib/morpheus/cli/library_option_types_command.rb +549 -0
- data/lib/morpheus/cli/library_upgrades_command.rb +604 -0
- data/lib/morpheus/cli/mixins/library_helper.rb +123 -0
- data/lib/morpheus/cli/mixins/print_helper.rb +21 -22
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +56 -11
- data/lib/morpheus/cli/network_services_command.rb +1 -1
- data/lib/morpheus/cli/option_types.rb +12 -2
- data/lib/morpheus/cli/power_scheduling_command.rb +1 -1
- data/lib/morpheus/cli/shell.rb +120 -22
- data/lib/morpheus/cli/sleep_command.rb +45 -0
- data/lib/morpheus/cli/user_sources_command.rb +963 -0
- data/lib/morpheus/cli/users.rb +33 -2
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/version_command.rb +1 -1
- data/lib/morpheus/cli/virtual_images.rb +93 -39
- data/lib/morpheus/formatters.rb +37 -27
- data/lib/morpheus/terminal.rb +1 -1
- metadata +20 -2
@@ -0,0 +1,653 @@
|
|
1
|
+
require 'io/console'
|
2
|
+
require 'optparse'
|
3
|
+
require 'filesize'
|
4
|
+
require 'morpheus/cli/cli_command'
|
5
|
+
require 'morpheus/cli/mixins/library_helper'
|
6
|
+
|
7
|
+
class Morpheus::Cli::LibraryContainerTypesCommand
|
8
|
+
include Morpheus::Cli::CliCommand
|
9
|
+
include Morpheus::Cli::LibraryHelper
|
10
|
+
|
11
|
+
set_command_name :'library-node-types'
|
12
|
+
|
13
|
+
register_subcommands :list, :get, :add, :update, :remove
|
14
|
+
|
15
|
+
def initialize()
|
16
|
+
# @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
17
|
+
end
|
18
|
+
|
19
|
+
def connect(opts)
|
20
|
+
@api_client = establish_remote_appliance_connection(opts)
|
21
|
+
@library_container_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).library_container_types
|
22
|
+
@library_layouts_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).library_layouts
|
23
|
+
#@library_instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).library_instance_types
|
24
|
+
@provision_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).provision_types
|
25
|
+
@option_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).option_types
|
26
|
+
#@option_type_lists_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).option_type_lists
|
27
|
+
end
|
28
|
+
|
29
|
+
def handle(args)
|
30
|
+
handle_subcommand(args)
|
31
|
+
end
|
32
|
+
|
33
|
+
def list(args)
|
34
|
+
options = {}
|
35
|
+
params = {}
|
36
|
+
layout_id = nil
|
37
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
38
|
+
opts.banner = subcommand_usage()
|
39
|
+
opts.on('--layout ID', String, "Filter by Layout") do |val|
|
40
|
+
layout_id = val
|
41
|
+
end
|
42
|
+
opts.on('--technology VALUE', String, "Filter by technology") do |val|
|
43
|
+
params['provisionType'] = val
|
44
|
+
end
|
45
|
+
opts.on('--category VALUE', String, "Filter by category") do |val|
|
46
|
+
params['category'] = val
|
47
|
+
end
|
48
|
+
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
49
|
+
opts.footer = "List node types."
|
50
|
+
end
|
51
|
+
optparse.parse!(args)
|
52
|
+
if args.count > 0
|
53
|
+
print_error Morpheus::Terminal.angry_prompt
|
54
|
+
puts_error "wrong number of arguments, expected 0 and got (#{args.count}) #{args.inspect}\n#{optparse}"
|
55
|
+
return 1
|
56
|
+
end
|
57
|
+
connect(options)
|
58
|
+
begin
|
59
|
+
# construct payload
|
60
|
+
params.merge!(parse_list_options(options))
|
61
|
+
# dry run?
|
62
|
+
if options[:dry_run]
|
63
|
+
print_dry_run @library_container_types_interface.dry.list(layout_id, params)
|
64
|
+
return
|
65
|
+
end
|
66
|
+
# do it
|
67
|
+
json_response = @library_container_types_interface.list(layout_id, params)
|
68
|
+
if options[:include_fields]
|
69
|
+
json_response = {"containerTypes" => filter_data(json_response["containerTypes"], options[:include_fields]) }
|
70
|
+
end
|
71
|
+
# print and/or return result
|
72
|
+
# return 0 if options[:quiet]
|
73
|
+
if options[:json]
|
74
|
+
puts as_json(json_response, options)
|
75
|
+
return 0
|
76
|
+
elsif options[:csv]
|
77
|
+
puts records_as_csv(json_response['containerTypes'], options)
|
78
|
+
return 0
|
79
|
+
elsif options[:yaml]
|
80
|
+
puts as_yaml(json_response, options)
|
81
|
+
return 0
|
82
|
+
end
|
83
|
+
container_types = json_response['containerTypes']
|
84
|
+
title = "Morpheus Library - Node Types"
|
85
|
+
subtitles = []
|
86
|
+
if layout_id
|
87
|
+
subtitles << "Layout: #{layout_id}".strip
|
88
|
+
end
|
89
|
+
subtitles += parse_list_subtitles(options)
|
90
|
+
print_h1 title, subtitles
|
91
|
+
if container_types.empty?
|
92
|
+
print cyan,"No node types found.",reset,"\n"
|
93
|
+
else
|
94
|
+
print_container_types_table(container_types, options)
|
95
|
+
print_results_pagination(json_response, {:label => "node type", :n_label => "node types"})
|
96
|
+
end
|
97
|
+
print reset,"\n"
|
98
|
+
rescue RestClient::Exception => e
|
99
|
+
print_rest_exception(e, options)
|
100
|
+
return 1
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def get(args)
|
105
|
+
options = {}
|
106
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
107
|
+
opts.banner = subcommand_usage("[name]")
|
108
|
+
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
109
|
+
opts.footer = "Display node type details." + "\n" +
|
110
|
+
"[name] is required. This is the name or id of a node type."
|
111
|
+
end
|
112
|
+
optparse.parse!(args)
|
113
|
+
if args.count < 1
|
114
|
+
puts optparse
|
115
|
+
return 1
|
116
|
+
end
|
117
|
+
connect(options)
|
118
|
+
id_list = parse_id_list(args)
|
119
|
+
return run_command_for_each_arg(id_list) do |arg|
|
120
|
+
_get(arg, options)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def _get(id, options)
|
125
|
+
layout_id = nil
|
126
|
+
begin
|
127
|
+
if options[:dry_run]
|
128
|
+
if arg.to_s =~ /\A\d{1,}\Z/
|
129
|
+
print_dry_run @library_container_types_interface.dry.get(layout_id, arg.to_i)
|
130
|
+
else
|
131
|
+
print_dry_run @library_container_types_interface.dry.list(layout_id, {name:arg})
|
132
|
+
end
|
133
|
+
return
|
134
|
+
end
|
135
|
+
container_type = find_container_type_by_name_or_id(layout_id, id)
|
136
|
+
if container_type.nil?
|
137
|
+
return 1
|
138
|
+
end
|
139
|
+
# skip redundant request
|
140
|
+
#json_response = @library_container_types_interface.get(layout_id, container_type['id'])
|
141
|
+
json_response = {'containerType' => container_type}
|
142
|
+
#container_type = json_response['containerType']
|
143
|
+
if options[:include_fields]
|
144
|
+
json_response = {"containerType" => filter_data(json_response["containerType"], options[:include_fields]) }
|
145
|
+
end
|
146
|
+
if options[:json]
|
147
|
+
puts as_json(json_response, options)
|
148
|
+
return 0
|
149
|
+
elsif options[:yaml]
|
150
|
+
puts as_yaml(json_response, options)
|
151
|
+
return 0
|
152
|
+
elsif options[:csv]
|
153
|
+
puts records_as_csv([json_response['containerType']], options)
|
154
|
+
return 0
|
155
|
+
end
|
156
|
+
|
157
|
+
print_h1 "Node Type Details"
|
158
|
+
print cyan
|
159
|
+
description_cols = {
|
160
|
+
"ID" => lambda {|it| it['id'] },
|
161
|
+
"Name" => lambda {|it| it['name'] },
|
162
|
+
"Short Name" => lambda {|it| it['shortName'] },
|
163
|
+
"Version" => lambda {|it| it['containerVersion'] },
|
164
|
+
"Technology" => lambda {|it| format_container_type_technology(it) },
|
165
|
+
"Category" => lambda {|it| it['category'] },
|
166
|
+
"Virtual Image" => lambda {|it|
|
167
|
+
it['virtualImage'] ? it['virtualImage']['name'] : ''
|
168
|
+
},
|
169
|
+
# "Category" => lambda {|it| it['category'].to_s.capitalize },
|
170
|
+
# # "Logo" => lambda {|it| it['logo'].to_s },
|
171
|
+
# "Visiblity" => lambda {|it| it['visibility'].to_s.capitalize },
|
172
|
+
# "Environment Prefix" => lambda {|it| it['environmentPrefix'] },
|
173
|
+
# "Enable Settings" => lambda {|it| format_boolean it['hasSettings'] },
|
174
|
+
# "Enable Scaling" => lambda {|it| format_boolean it['hasAutoScale'] },
|
175
|
+
# "Supports Deployments" => lambda {|it| format_boolean it['hasDeployment'] },
|
176
|
+
# "Featured" => lambda {|it| format_boolean it['featured'] },
|
177
|
+
# "Owner" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
178
|
+
# "Active" => lambda {|it| format_boolean it['active'] },
|
179
|
+
# "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
180
|
+
# "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
|
181
|
+
}
|
182
|
+
print_description_list(description_cols, container_type)
|
183
|
+
|
184
|
+
|
185
|
+
evars = container_type['environmentVariables']
|
186
|
+
if evars && evars.size > 0
|
187
|
+
print_h2 "Environment Variables"
|
188
|
+
evar_columns = [
|
189
|
+
{"NAME" => lambda {|it| it['name'] } },
|
190
|
+
{"VALUE" => lambda {|it| it['defaultValue'] } },
|
191
|
+
{"TYPE" => lambda {|it| it['valueType'].to_s.capitalize } },
|
192
|
+
{"EXPORT" => lambda {|it| format_boolean it['export'] } },
|
193
|
+
{"MASKED" => lambda {|it| format_boolean it['mask'] } },
|
194
|
+
]
|
195
|
+
print as_pretty_table(evars, evar_columns)
|
196
|
+
else
|
197
|
+
# print yellow,"No environment variables found for this node type.","\n",reset
|
198
|
+
end
|
199
|
+
|
200
|
+
exposed_ports = container_type['containerPorts']
|
201
|
+
if exposed_ports && exposed_ports.size > 0
|
202
|
+
print_h2 "Exposed Ports"
|
203
|
+
columns = [
|
204
|
+
#{"ID" => lambda {|it| it['id'] } },
|
205
|
+
{"NAME" => lambda {|it| it['name'] } },
|
206
|
+
{"PORT" => lambda {|it| it['port'] } },
|
207
|
+
{"LB PROTOCOL" => lambda {|it| it['loadBalanceProtocol'] } },
|
208
|
+
]
|
209
|
+
print as_pretty_table(exposed_ports, columns)
|
210
|
+
else
|
211
|
+
# print yellow,"No exposed ports found for this node type.","\n",reset
|
212
|
+
end
|
213
|
+
|
214
|
+
container_scripts = container_type['containerScripts'] || container_type['scripts']
|
215
|
+
if container_scripts && container_scripts.size > 0
|
216
|
+
print_h2 "Scripts"
|
217
|
+
columns = [
|
218
|
+
{"ID" => lambda {|it| it['id'] } },
|
219
|
+
{"NAME" => lambda {|it| it['name'] } }
|
220
|
+
]
|
221
|
+
print as_pretty_table(container_scripts, columns)
|
222
|
+
else
|
223
|
+
# print yellow,"No scripts found for this node type.","\n",reset
|
224
|
+
end
|
225
|
+
|
226
|
+
container_file_templates = container_type['containerTemplates'] || container_type['templates']
|
227
|
+
if container_file_templates && container_file_templates.size > 0
|
228
|
+
print_h2 "File Templates"
|
229
|
+
columns = [
|
230
|
+
{"ID" => lambda {|it| it['id'] } },
|
231
|
+
{"NAME" => lambda {|it| it['name'] } }
|
232
|
+
]
|
233
|
+
print as_pretty_table(container_file_templates, columns)
|
234
|
+
else
|
235
|
+
# print yellow,"No scripts found for this node type.","\n",reset
|
236
|
+
end
|
237
|
+
|
238
|
+
print reset,"\n"
|
239
|
+
|
240
|
+
rescue RestClient::Exception => e
|
241
|
+
print_rest_exception(e, options)
|
242
|
+
return 1
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def add(args)
|
247
|
+
options = {}
|
248
|
+
params = {}
|
249
|
+
layout = nil
|
250
|
+
layout_id = nil
|
251
|
+
script_ids = nil
|
252
|
+
file_template_ids = nil
|
253
|
+
evars = nil
|
254
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
255
|
+
opts.banner = subcommand_usage()
|
256
|
+
opts.on('--name VALUE', String, "Name for this node type") do |val|
|
257
|
+
params['name'] = val
|
258
|
+
end
|
259
|
+
opts.on('--shortName VALUE', String, "Short Name") do |val|
|
260
|
+
params['shortName'] = val
|
261
|
+
end
|
262
|
+
opts.on('--version VALUE', String, "Version") do |val|
|
263
|
+
params['containerVersion'] = val
|
264
|
+
end
|
265
|
+
opts.on('--technology CODE', String, "Technology. This is the provision type code.") do |val|
|
266
|
+
params['provisionTypeCode'] = val
|
267
|
+
end
|
268
|
+
opts.on('--scripts x,y,z', Array, "List of Script IDs") do |val|
|
269
|
+
script_ids = val #.collect {|it| it.to_i }
|
270
|
+
end
|
271
|
+
opts.on('--file-templates x,y,z', Array, "List of File Template IDs") do |val|
|
272
|
+
file_template_ids = val #.collect {|it| it.to_i }
|
273
|
+
end
|
274
|
+
#build_option_type_options(opts, options, add_layout_option_types())
|
275
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
276
|
+
opts.footer = "Create a node type." + "\n" +
|
277
|
+
"[name] is required and can be passed as --name instead."
|
278
|
+
"Technology --technology is required. Additional options vary by type."
|
279
|
+
end
|
280
|
+
optparse.parse!(args)
|
281
|
+
connect(options)
|
282
|
+
if args.count > 1
|
283
|
+
print_error Morpheus::Terminal.angry_prompt
|
284
|
+
puts_error "wrong number of arguments, expected 0-1 and got (#{args.count}) #{args.inspect}\n#{optparse}"
|
285
|
+
return 1
|
286
|
+
end
|
287
|
+
if args[0]
|
288
|
+
params['name'] = args[0]
|
289
|
+
end
|
290
|
+
begin
|
291
|
+
# construct payload
|
292
|
+
if layout_id
|
293
|
+
layout = find_layout_by_name_or_id(instance_type_id)
|
294
|
+
return 1 if layout.nil?
|
295
|
+
layout_id = layout['id']
|
296
|
+
end
|
297
|
+
payload = nil
|
298
|
+
if options[:payload]
|
299
|
+
payload = options[:payload]
|
300
|
+
else
|
301
|
+
payload = {}
|
302
|
+
# support the old -O OPTION switch
|
303
|
+
payload.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
304
|
+
# prompt for options
|
305
|
+
prompt_params = params.merge(:no_prompt=>options[:no_prompt]) # usually of options[:options]
|
306
|
+
if !params['name']
|
307
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Name', 'required' => true}], prompt_params)
|
308
|
+
params['name'] = v_prompt['name']
|
309
|
+
end
|
310
|
+
if !params['shortName']
|
311
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'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.'}], prompt_params)
|
312
|
+
params['shortName'] = v_prompt['shortName']
|
313
|
+
end
|
314
|
+
if !params['containerVersion']
|
315
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'containerVersion', 'type' => 'text', 'fieldLabel' => 'Version', 'required' => true}], prompt_params)
|
316
|
+
params['containerVersion'] = v_prompt['containerVersion']
|
317
|
+
end
|
318
|
+
|
319
|
+
# prompt for all the ProvisionType.customOptionTypes
|
320
|
+
# err, these optionTypes have the fieldContext
|
321
|
+
# so merge them at the root level of the request.
|
322
|
+
|
323
|
+
provision_types = @provision_types_interface.get({customSupported: true})['provisionTypes']
|
324
|
+
if provision_types.empty?
|
325
|
+
print_red_alert "No available provision types found!"
|
326
|
+
return 1
|
327
|
+
end
|
328
|
+
provision_type_options = provision_types.collect {|it| { 'name' => it['name'], 'value' => it['code']} }
|
329
|
+
provision_type = nil
|
330
|
+
if !params['provisionTypeCode']
|
331
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'provisionTypeCode', 'type' => 'select', 'selectOptions' => provision_type_options, 'fieldLabel' => 'Technology', 'required' => true, 'description' => 'The type of container technology.'}], prompt_params)
|
332
|
+
params['provisionTypeCode'] = v_prompt['provisionTypeCode']
|
333
|
+
end
|
334
|
+
provision_type = provision_types.find {|it| it['code'] == params['provisionTypeCode'] }
|
335
|
+
if provision_type.nil?
|
336
|
+
print_red_alert "Provision Type not found by code '#{params['provisionTypeCode']}'!"
|
337
|
+
return 1
|
338
|
+
end
|
339
|
+
|
340
|
+
# prompt custom options for the selected provision type
|
341
|
+
provision_type_custom_option_types = provision_type['customOptionTypes']
|
342
|
+
if (!provision_type_custom_option_types || provision_type_custom_option_types.empty?)
|
343
|
+
print yellow,"Sorry, no options were found for provision type #{provision_type['name']}.","\n",reset
|
344
|
+
return 1
|
345
|
+
end
|
346
|
+
field_group_name = provision_type_custom_option_types.first['fieldGroup'] || "#{provision_type['name']} Options"
|
347
|
+
field_group_name = "#{provision_type['name']} Options"
|
348
|
+
# print "\n"
|
349
|
+
puts field_group_name
|
350
|
+
puts "==============="
|
351
|
+
provision_type_v_prompt = Morpheus::Cli::OptionTypes.prompt(provision_type_custom_option_types,options[:options],@api_client, {provisionTypCode: params['provisionTypeCode']})
|
352
|
+
|
353
|
+
# payload.deep_merge!(provision_type_v_prompt)
|
354
|
+
|
355
|
+
# ENVIRONMENT VARIABLES
|
356
|
+
if evars
|
357
|
+
params['environmentVariables'] = evars
|
358
|
+
else
|
359
|
+
# prompt
|
360
|
+
# parsed_evars = parse_environment_variables
|
361
|
+
end
|
362
|
+
|
363
|
+
# SCRIPTS
|
364
|
+
if script_ids
|
365
|
+
params['scripts'] = script_ids.collect {|it| it.to_i }.select { |it| it != 0 }
|
366
|
+
else
|
367
|
+
# prompt
|
368
|
+
end
|
369
|
+
|
370
|
+
# FILE TEMPLATES
|
371
|
+
if file_template_ids
|
372
|
+
params['scripts'] = file_template_ids.collect {|it| it.to_i }.select { |it| it != 0 }
|
373
|
+
else
|
374
|
+
# prompt
|
375
|
+
end
|
376
|
+
|
377
|
+
# payload = {'containerType' => params}
|
378
|
+
payload['containerType'] ||= {}
|
379
|
+
payload['containerType'].deep_merge!(params)
|
380
|
+
payload.deep_merge!(provision_type_v_prompt)
|
381
|
+
|
382
|
+
|
383
|
+
end
|
384
|
+
|
385
|
+
if options[:dry_run]
|
386
|
+
print_dry_run @library_container_types_interface.dry.create(layout_id, payload)
|
387
|
+
return
|
388
|
+
end
|
389
|
+
|
390
|
+
json_response = @library_container_types_interface.create(layout_id, payload)
|
391
|
+
|
392
|
+
if options[:json]
|
393
|
+
print JSON.pretty_generate(json_response), "\n"
|
394
|
+
return
|
395
|
+
end
|
396
|
+
container_type = json_response['containerType']
|
397
|
+
print_green_success "Added Node Type #{container_type['name']}"
|
398
|
+
get([json_response['containerType']['id']])
|
399
|
+
rescue RestClient::Exception => e
|
400
|
+
print_rest_exception(e, options)
|
401
|
+
exit 1
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
def update(args)
|
406
|
+
options = {}
|
407
|
+
params = {}
|
408
|
+
layout = nil
|
409
|
+
layout_id = nil
|
410
|
+
script_ids = nil
|
411
|
+
file_template_ids = nil
|
412
|
+
evars = nil
|
413
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
414
|
+
opts.banner = subcommand_usage("[name] [options]")
|
415
|
+
opts.on('--name VALUE', String, "Name for this layout") do |val|
|
416
|
+
params['name'] = val
|
417
|
+
end
|
418
|
+
opts.on('--shortName VALUE', String, "Short Name") do |val|
|
419
|
+
params['shortName'] = val
|
420
|
+
end
|
421
|
+
opts.on('--version VALUE', String, "Version") do |val|
|
422
|
+
params['containerVersion'] = val
|
423
|
+
end
|
424
|
+
# opts.on('--technology CODE', String, "Technology") do |val|
|
425
|
+
# params['provisionTypeCode'] = val
|
426
|
+
# end
|
427
|
+
opts.on('--scripts x,y,z', Array, "List of Script IDs") do |val|
|
428
|
+
script_ids = val #.collect {|it| it.to_i }
|
429
|
+
end
|
430
|
+
opts.on('--file-templates x,y,z', Array, "List of File Template IDs") do |val|
|
431
|
+
file_template_ids = val #.collect {|it| it.to_i }
|
432
|
+
end
|
433
|
+
#build_option_type_options(opts, options, update_layout_option_types())
|
434
|
+
build_common_options(opts, options, [:options, :json, :dry_run, :remote])
|
435
|
+
opts.footer = "Update a node type."
|
436
|
+
end
|
437
|
+
optparse.parse!(args)
|
438
|
+
if args.count < 1
|
439
|
+
puts optparse
|
440
|
+
exit 1
|
441
|
+
end
|
442
|
+
connect(options)
|
443
|
+
begin
|
444
|
+
container_type = find_container_type_by_name_or_id(layout_id, args[0])
|
445
|
+
if container_type.nil?
|
446
|
+
return 1
|
447
|
+
end
|
448
|
+
# construct payload
|
449
|
+
payload = nil
|
450
|
+
if options[:payload]
|
451
|
+
payload = options[:payload]
|
452
|
+
else
|
453
|
+
payload = {}
|
454
|
+
# option_types = update_layout_option_types(instance_type)
|
455
|
+
# params = Morpheus::Cli::OptionTypes.prompt(option_types, options[:options], @api_client, options[:params])
|
456
|
+
payload.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
457
|
+
|
458
|
+
# ENVIRONMENT VARIABLES
|
459
|
+
if evars
|
460
|
+
|
461
|
+
else
|
462
|
+
# prompt
|
463
|
+
end
|
464
|
+
|
465
|
+
# SCRIPTS
|
466
|
+
if script_ids
|
467
|
+
params['scripts'] = script_ids.collect {|it| it.to_i }.select { |it| it != 0 }
|
468
|
+
else
|
469
|
+
# prompt
|
470
|
+
end
|
471
|
+
|
472
|
+
# FILE TEMPLATES
|
473
|
+
if file_template_ids
|
474
|
+
params['templates'] = file_template_ids.collect {|it| it.to_i }.select { |it| it != 0 }
|
475
|
+
else
|
476
|
+
# prompt
|
477
|
+
end
|
478
|
+
|
479
|
+
if params.empty?
|
480
|
+
puts optparse
|
481
|
+
exit 1
|
482
|
+
end
|
483
|
+
|
484
|
+
# payload = {'containerType' => params}
|
485
|
+
payload['containerType'] ||= {}
|
486
|
+
payload['containerType'].deep_merge!(params)
|
487
|
+
|
488
|
+
end
|
489
|
+
|
490
|
+
if options[:dry_run]
|
491
|
+
print_dry_run @library_container_types_interface.dry.update(layout_id, container_type['id'], payload)
|
492
|
+
return
|
493
|
+
end
|
494
|
+
|
495
|
+
json_response = @library_container_types_interface.update(layout_id, container_type['id'], payload)
|
496
|
+
if options[:json]
|
497
|
+
print JSON.pretty_generate(json_response), "\n"
|
498
|
+
return
|
499
|
+
end
|
500
|
+
container_type = json_response['containerType']
|
501
|
+
print_green_success "Updated Node Type #{container_type['name']}"
|
502
|
+
get([container_type['id']])
|
503
|
+
rescue RestClient::Exception => e
|
504
|
+
print_rest_exception(e, options)
|
505
|
+
exit 1
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
def remove(args)
|
510
|
+
options = {}
|
511
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
512
|
+
opts.banner = subcommand_usage("[name]")
|
513
|
+
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
514
|
+
opts.footer = "Delete a node type."
|
515
|
+
end
|
516
|
+
optparse.parse!(args)
|
517
|
+
if args.count < 1
|
518
|
+
puts optparse
|
519
|
+
exit 1
|
520
|
+
end
|
521
|
+
connect(options)
|
522
|
+
|
523
|
+
begin
|
524
|
+
container_type = find_container_type_by_name_or_id(layout_id, id)
|
525
|
+
if container_type.nil?
|
526
|
+
return 1
|
527
|
+
end
|
528
|
+
|
529
|
+
unless Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the node type #{container_type['name']}?", options)
|
530
|
+
exit
|
531
|
+
end
|
532
|
+
if options[:dry_run]
|
533
|
+
print_dry_run @library_container_types_interface.dry.destroy(nil, container_type['id'])
|
534
|
+
return
|
535
|
+
end
|
536
|
+
json_response = @library_container_types_interface.destroy(nil, container_type['id'])
|
537
|
+
|
538
|
+
if options[:json]
|
539
|
+
print JSON.pretty_generate(json_response), "\n"
|
540
|
+
return
|
541
|
+
end
|
542
|
+
|
543
|
+
print_green_success "Removed Node Type #{container_type['name']}"
|
544
|
+
#list([])
|
545
|
+
rescue RestClient::Exception => e
|
546
|
+
print_rest_exception(e, options)
|
547
|
+
exit 1
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
private
|
552
|
+
|
553
|
+
def find_container_type_by_name_or_id(layout_id, val)
|
554
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
555
|
+
return find_container_type_by_id(layout_id, val)
|
556
|
+
else
|
557
|
+
return find_container_type_by_name(layout_id, val)
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
561
|
+
def find_container_type_by_id(layout_id, id)
|
562
|
+
begin
|
563
|
+
json_response = @library_container_types_interface.get(layout_id, id.to_i)
|
564
|
+
return json_response['containerType']
|
565
|
+
rescue RestClient::Exception => e
|
566
|
+
if e.response && e.response.code == 404
|
567
|
+
print_red_alert "Instance Type not found by id #{id}"
|
568
|
+
else
|
569
|
+
raise e
|
570
|
+
end
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
def find_container_type_by_name(layout_id, name)
|
575
|
+
container_types = @library_container_types_interface.list(layout_id, {name: name.to_s})['containerTypes']
|
576
|
+
if container_types.empty?
|
577
|
+
print_red_alert "Node Type not found by name #{name}"
|
578
|
+
return nil
|
579
|
+
elsif container_types.size > 1
|
580
|
+
print_red_alert "#{container_types.size} node types found by name #{name}"
|
581
|
+
print_container_types_table(container_types, {color: red})
|
582
|
+
print_red_alert "Try using ID instead"
|
583
|
+
print reset,"\n"
|
584
|
+
return nil
|
585
|
+
else
|
586
|
+
return container_types[0]
|
587
|
+
end
|
588
|
+
end
|
589
|
+
|
590
|
+
def print_container_types_table(container_types, opts={})
|
591
|
+
columns = [
|
592
|
+
{"ID" => lambda {|it| it['id'] } },
|
593
|
+
{"TECHNOLOGY" => lambda {|it| format_container_type_technology(it) } },
|
594
|
+
{"NAME" => lambda {|it| it['name'] } },
|
595
|
+
{"SHORT NAME" => lambda {|it| it['shortName'] } },
|
596
|
+
{"VERSION" => lambda {|it| it['containerVersion'] } },
|
597
|
+
{"CATEGORY" => lambda {|it| it['category'] } },
|
598
|
+
{"OWNER" => lambda {|it| it['account'] ? it['account']['name'] : '' } }
|
599
|
+
]
|
600
|
+
if opts[:include_fields]
|
601
|
+
columns = opts[:include_fields]
|
602
|
+
end
|
603
|
+
print as_pretty_table(container_types, columns, opts)
|
604
|
+
end
|
605
|
+
|
606
|
+
def format_container_type_technology(container_type)
|
607
|
+
if container_type
|
608
|
+
container_type['provisionType'] ? container_type['provisionType']['name'] : ''
|
609
|
+
else
|
610
|
+
""
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
|
615
|
+
def find_layout_by_name_or_id(instance_type_id, val)
|
616
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
617
|
+
return find_layout_by_id(instance_type_id, val)
|
618
|
+
else
|
619
|
+
return find_layout_by_name(instance_type_id, val)
|
620
|
+
end
|
621
|
+
end
|
622
|
+
|
623
|
+
def find_layout_by_id(instance_type_id, id)
|
624
|
+
begin
|
625
|
+
json_response = @library_layouts_interface.get(instance_type_id, id.to_i)
|
626
|
+
return json_response['instanceTypeLayout']
|
627
|
+
rescue RestClient::Exception => e
|
628
|
+
if e.response && e.response.code == 404
|
629
|
+
print_red_alert "Instance Type not found by id #{id}"
|
630
|
+
else
|
631
|
+
raise e
|
632
|
+
end
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
def find_layout_by_name(instance_type_id, name)
|
637
|
+
layouts = @library_layouts_interface.list(instance_type_id, {name: name.to_s})['instanceTypeLayouts']
|
638
|
+
if layouts.empty?
|
639
|
+
print_red_alert "Layout not found by name #{name}"
|
640
|
+
return nil
|
641
|
+
elsif layouts.size > 1
|
642
|
+
print_red_alert "#{layouts.size} layouts found by name #{name}"
|
643
|
+
print_layouts_table(layouts, {color: red})
|
644
|
+
print_red_alert "Try using ID instead"
|
645
|
+
print reset,"\n"
|
646
|
+
return nil
|
647
|
+
else
|
648
|
+
return layouts[0]
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
|
653
|
+
end
|