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,650 @@
|
|
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::LibraryLayoutsCommand
|
8
|
+
include Morpheus::Cli::CliCommand
|
9
|
+
include Morpheus::Cli::LibraryHelper
|
10
|
+
|
11
|
+
set_command_name :'library-layouts'
|
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_layouts_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).library_layouts
|
22
|
+
@library_instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).library_instance_types
|
23
|
+
@provision_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).provision_types
|
24
|
+
@option_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).option_types
|
25
|
+
@option_type_lists_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).option_type_lists
|
26
|
+
end
|
27
|
+
|
28
|
+
def handle(args)
|
29
|
+
handle_subcommand(args)
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
def list(args)
|
34
|
+
options = {}
|
35
|
+
params = {}
|
36
|
+
instance_type = nil
|
37
|
+
instance_type_id = nil
|
38
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
39
|
+
opts.banner = subcommand_usage()
|
40
|
+
opts.on('--instance-type ID', String, "Filter by Instance Type") do |val|
|
41
|
+
instance_type_id = val
|
42
|
+
end
|
43
|
+
opts.on('--category VALUE', String, "Filter by category") do |val|
|
44
|
+
params['category'] = val
|
45
|
+
end
|
46
|
+
opts.on('--code VALUE', String, "Filter by code") do |val|
|
47
|
+
params['code'] = val
|
48
|
+
end
|
49
|
+
opts.on('--technology VALUE', String, "Filter by technology") do |val|
|
50
|
+
params['provisionType'] = val
|
51
|
+
end
|
52
|
+
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
53
|
+
opts.footer = "List layouts."
|
54
|
+
end
|
55
|
+
optparse.parse!(args)
|
56
|
+
connect(options)
|
57
|
+
begin
|
58
|
+
# construct payload
|
59
|
+
if instance_type_id
|
60
|
+
instance_type = find_instance_type_by_name_or_id(instance_type_id)
|
61
|
+
return 1 if instance_type.nil?
|
62
|
+
instance_type_id = instance_type['id']
|
63
|
+
end
|
64
|
+
|
65
|
+
params.merge!(parse_list_options(options))
|
66
|
+
|
67
|
+
if options[:dry_run]
|
68
|
+
print_dry_run @library_layouts_interface.dry.list(instance_type_id, params)
|
69
|
+
return
|
70
|
+
end
|
71
|
+
|
72
|
+
json_response = @library_layouts_interface.list(instance_type_id, params)
|
73
|
+
if options[:include_fields]
|
74
|
+
json_response = {"instanceTypeLayouts" => filter_data(json_response["instanceTypeLayouts"], options[:include_fields]) }
|
75
|
+
end
|
76
|
+
if options[:json]
|
77
|
+
puts as_json(json_response, options)
|
78
|
+
return 0
|
79
|
+
elsif options[:csv]
|
80
|
+
puts records_as_csv(json_response['instanceTypeLayouts'], options)
|
81
|
+
return 0
|
82
|
+
elsif options[:yaml]
|
83
|
+
puts as_yaml(json_response, options)
|
84
|
+
return 0
|
85
|
+
end
|
86
|
+
layouts = json_response['instanceTypeLayouts']
|
87
|
+
title = "Morpheus Library - Layouts"
|
88
|
+
subtitles = []
|
89
|
+
if instance_type
|
90
|
+
subtitles << "Instance Type: #{instance_type['name']}".strip
|
91
|
+
end
|
92
|
+
subtitles += parse_list_subtitles(options)
|
93
|
+
print_h1 title, subtitles
|
94
|
+
if layouts.empty?
|
95
|
+
print cyan,"No layouts found.",reset,"\n"
|
96
|
+
else
|
97
|
+
print_layouts_table(layouts, options)
|
98
|
+
print_results_pagination(json_response, {:label => "layout", :n_label => "layouts"})
|
99
|
+
# print_results_pagination(json_response)
|
100
|
+
end
|
101
|
+
print reset,"\n"
|
102
|
+
rescue RestClient::Exception => e
|
103
|
+
print_rest_exception(e, options)
|
104
|
+
return 1
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def get(args)
|
109
|
+
options = {}
|
110
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
111
|
+
opts.banner = subcommand_usage("[name]")
|
112
|
+
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
113
|
+
end
|
114
|
+
optparse.parse!(args)
|
115
|
+
if args.count < 1
|
116
|
+
puts optparse
|
117
|
+
return 1
|
118
|
+
end
|
119
|
+
connect(options)
|
120
|
+
id_list = parse_id_list(args)
|
121
|
+
return run_command_for_each_arg(id_list) do |arg|
|
122
|
+
_get(arg, options)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def _get(id, options)
|
127
|
+
instance_type_id = nil
|
128
|
+
begin
|
129
|
+
if options[:dry_run]
|
130
|
+
if id.to_s =~ /\A\d{1,}\Z/
|
131
|
+
print_dry_run @library_layouts_interface.dry.get(instance_type_id, id.to_i)
|
132
|
+
else
|
133
|
+
print_dry_run @library_layouts_interface.dry.list(instance_type_id, {name:id})
|
134
|
+
end
|
135
|
+
return
|
136
|
+
end
|
137
|
+
layout = find_layout_by_name_or_id(instance_type_id, id)
|
138
|
+
if layout.nil?
|
139
|
+
return 1
|
140
|
+
end
|
141
|
+
# skip redundant request
|
142
|
+
#json_response = @library_layouts_interface.get(instance_type_id, layout['id'])
|
143
|
+
json_response = {'instanceTypeLayout' => layout}
|
144
|
+
#layout = json_response['instanceTypeLayout']
|
145
|
+
if options[:include_fields]
|
146
|
+
json_response = {"instanceTypeLayout" => filter_data(json_response["instanceTypeLayout"], options[:include_fields]) }
|
147
|
+
end
|
148
|
+
if options[:json]
|
149
|
+
puts as_json(json_response, options)
|
150
|
+
return 0
|
151
|
+
elsif options[:yaml]
|
152
|
+
puts as_yaml(json_response, options)
|
153
|
+
return 0
|
154
|
+
elsif options[:csv]
|
155
|
+
puts records_as_csv([json_response['instanceTypeLayout']], options)
|
156
|
+
return 0
|
157
|
+
end
|
158
|
+
|
159
|
+
print_h1 "Layout Details"
|
160
|
+
print cyan
|
161
|
+
description_cols = {
|
162
|
+
"ID" => lambda {|it| it['id'] },
|
163
|
+
"Name" => lambda {|it| it['name'] },
|
164
|
+
#"Code" => lambda {|it| it['code'] },
|
165
|
+
"Version" => lambda {|it| it['instanceVersion'] },
|
166
|
+
"Description" => lambda {|it| it['description'] },
|
167
|
+
"Technology" => lambda {|it| format_layout_technology(it) },
|
168
|
+
"Min Memory" => lambda {|it|
|
169
|
+
if it['memoryRequirement'].to_i != 0
|
170
|
+
(it['memoryRequirement'].to_i / (1024*1024)).to_s + " MB"
|
171
|
+
else
|
172
|
+
""
|
173
|
+
end
|
174
|
+
},
|
175
|
+
"Workflow" => lambda {|it|
|
176
|
+
if it['taskSets']
|
177
|
+
it['taskSets'][0]['name'] rescue ""
|
178
|
+
else
|
179
|
+
""
|
180
|
+
end
|
181
|
+
},
|
182
|
+
# "Category" => lambda {|it| it['category'].to_s.capitalize },
|
183
|
+
# # "Logo" => lambda {|it| it['logo'].to_s },
|
184
|
+
# "Visiblity" => lambda {|it| it['visibility'].to_s.capitalize },
|
185
|
+
# "Environment Prefix" => lambda {|it| it['environmentPrefix'] },
|
186
|
+
# "Enable Settings" => lambda {|it| format_boolean it['hasSettings'] },
|
187
|
+
# "Enable Scaling" => lambda {|it| format_boolean it['hasAutoScale'] },
|
188
|
+
# "Supports Deployments" => lambda {|it| format_boolean it['hasDeployment'] },
|
189
|
+
# "Featured" => lambda {|it| format_boolean it['featured'] },
|
190
|
+
# "Owner" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
191
|
+
# "Active" => lambda {|it| format_boolean it['active'] },
|
192
|
+
# "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
193
|
+
# "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
|
194
|
+
}
|
195
|
+
print_description_list(description_cols, layout)
|
196
|
+
|
197
|
+
|
198
|
+
|
199
|
+
layout_evars = layout['environmentVariables']
|
200
|
+
if layout_evars && layout_evars.size > 0
|
201
|
+
print_h2 "Environment Variables"
|
202
|
+
evar_columns = [
|
203
|
+
{"NAME" => lambda {|it| it['name'] } },
|
204
|
+
{"VALUE" => lambda {|it| it['defaultValue'] } },
|
205
|
+
{"TYPE" => lambda {|it| it['valueType'].to_s.capitalize } },
|
206
|
+
{"EXPORT" => lambda {|it| format_boolean it['export'] } },
|
207
|
+
{"MASKED" => lambda {|it| format_boolean it['mask'] } },
|
208
|
+
]
|
209
|
+
print as_pretty_table(layout_evars, evar_columns)
|
210
|
+
else
|
211
|
+
# print yellow,"No environment variables found for this instance type.","\n",reset
|
212
|
+
end
|
213
|
+
|
214
|
+
layout_option_types = layout['optionTypes']
|
215
|
+
if layout_option_types && layout_option_types.size > 0
|
216
|
+
print_h2 "Option Types"
|
217
|
+
columns = [
|
218
|
+
{"ID" => lambda {|it| it['id'] } },
|
219
|
+
{"NAME" => lambda {|it| it['name'] } },
|
220
|
+
{"TYPE" => lambda {|it| it['type'] } },
|
221
|
+
{"FIELD NAME" => lambda {|it| it['fieldName'] } },
|
222
|
+
{"FIELD LABEL" => lambda {|it| it['fieldLabel'] } },
|
223
|
+
{"DEFAULT" => lambda {|it| it['defaultValue'] } },
|
224
|
+
{"REQUIRED" => lambda {|it| format_boolean it['required'] } },
|
225
|
+
]
|
226
|
+
print as_pretty_table(layout_option_types, columns)
|
227
|
+
else
|
228
|
+
# print yellow,"No option types found for this layout.","\n",reset
|
229
|
+
end
|
230
|
+
|
231
|
+
print_h2 "Node Types"
|
232
|
+
layout_node_types = layout['containerTypes']
|
233
|
+
if layout_node_types && layout_node_types.size > 0
|
234
|
+
# match UI sorting [version desc, name asc]
|
235
|
+
# or use something simpler like one of these
|
236
|
+
layout_node_types = layout_node_types.sort { |a,b| a['name'] <=> b['name'] }
|
237
|
+
# layout_node_types = layout_node_types.sort { |a,b| a['sortOrder'] <=> b['sortOrder'] }
|
238
|
+
node_type_columns = [
|
239
|
+
{"ID" => lambda {|it| it['id'] } },
|
240
|
+
{"NAME" => lambda {|it| it['name'] } },
|
241
|
+
{"SHORT NAME" => lambda {|it| it['shortName'] } },
|
242
|
+
{"VERSION" => lambda {|it| it['containerVersion'] } },
|
243
|
+
{"TECHNOLOGY" => lambda {|it| it['provisionType'] ? it['provisionType']['name'] : '' } },
|
244
|
+
{"CATEGORY" => lambda {|it| it['category'] } },
|
245
|
+
]
|
246
|
+
print as_pretty_table(layout_node_types, node_type_columns)
|
247
|
+
else
|
248
|
+
print yellow,"No node types for this layout.","\n",reset
|
249
|
+
end
|
250
|
+
|
251
|
+
print reset,"\n"
|
252
|
+
|
253
|
+
rescue RestClient::Exception => e
|
254
|
+
print_rest_exception(e, options)
|
255
|
+
return 1
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def add(args)
|
260
|
+
options = {}
|
261
|
+
params = {}
|
262
|
+
instance_type_id = nil
|
263
|
+
option_type_ids = nil
|
264
|
+
node_type_ids = nil
|
265
|
+
evars = nil
|
266
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
267
|
+
opts.banner = subcommand_usage("[instance-type]")
|
268
|
+
opts.on('--instance-type ID', String, "Instance Type") do |val|
|
269
|
+
instance_type_id = val
|
270
|
+
end
|
271
|
+
opts.on('--name VALUE', String, "Name for this layout") do |val|
|
272
|
+
params['name'] = val
|
273
|
+
end
|
274
|
+
opts.on('--version VALUE', String, "Version") do |val|
|
275
|
+
params['instanceVersion'] = val
|
276
|
+
end
|
277
|
+
opts.on('--description VALUE', String, "Description") do |val|
|
278
|
+
params['description'] = val
|
279
|
+
end
|
280
|
+
opts.on('--technology CODE', String, "Technology") do |val|
|
281
|
+
params['provisionTypeCode'] = val
|
282
|
+
end
|
283
|
+
opts.on('--min-memory VALUE', String, "Minimum Memory (MB)") do |val|
|
284
|
+
params['memoryRequirement'] = val
|
285
|
+
end
|
286
|
+
opts.on('--workflow ID', String, "Workflow") do |val|
|
287
|
+
params['taskSetId'] = val.to_i
|
288
|
+
end
|
289
|
+
opts.on('--option-types x,y,z', Array, "List of Option Type IDs") do |val|
|
290
|
+
option_type_ids = val #.collect {|it| it.to_i }
|
291
|
+
end
|
292
|
+
opts.on('--node-types x,y,z', Array, "List of Node Type IDs") do |val|
|
293
|
+
node_type_ids = val #.collect {|it| it.to_i }
|
294
|
+
end
|
295
|
+
#build_option_type_options(opts, options, add_layout_option_types())
|
296
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
297
|
+
opts.footer = "Create a new layout." + "\n" +
|
298
|
+
"[instance-type] is required and can be passed as --instance-type instead."
|
299
|
+
end
|
300
|
+
optparse.parse!(args)
|
301
|
+
connect(options)
|
302
|
+
|
303
|
+
if instance_type_id.nil?
|
304
|
+
instance_type_id = args[0]
|
305
|
+
end
|
306
|
+
|
307
|
+
if !instance_type_id
|
308
|
+
puts optparse
|
309
|
+
exit 1
|
310
|
+
end
|
311
|
+
|
312
|
+
begin
|
313
|
+
instance_type = find_instance_type_by_name_or_id(instance_type_id)
|
314
|
+
exit 1 if instance_type.nil?
|
315
|
+
instance_type_id = instance_type['id']
|
316
|
+
|
317
|
+
# construct payload
|
318
|
+
payload = nil
|
319
|
+
if options[:payload]
|
320
|
+
payload = options[:payload]
|
321
|
+
else
|
322
|
+
# v_prompt = Morpheus::Cli::OptionTypes.prompt(add_layout_option_types, options[:options], @api_client, options[:params])
|
323
|
+
# params.deep_merge!(v_prompt)
|
324
|
+
params.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
325
|
+
|
326
|
+
if !params['name']
|
327
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => 'Name', 'required' => true}], options[:options])
|
328
|
+
params['name'] = v_prompt['name']
|
329
|
+
end
|
330
|
+
if !params['instanceVersion']
|
331
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'instanceVersion', 'type' => 'text', 'fieldLabel' => 'Version', 'required' => true}], options[:options])
|
332
|
+
params['instanceVersion'] = v_prompt['instanceVersion']
|
333
|
+
end
|
334
|
+
if !params['description']
|
335
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'description', 'type' => 'text', 'fieldLabel' => 'Description', 'required' => false}], options[:options])
|
336
|
+
params['description'] = v_prompt['description'] if v_prompt['description']
|
337
|
+
end
|
338
|
+
|
339
|
+
provision_types = @provision_types_interface.get({customSupported: true})['provisionTypes']
|
340
|
+
if provision_types.empty?
|
341
|
+
print_red_alert "No available provision types found!"
|
342
|
+
exit 1
|
343
|
+
end
|
344
|
+
provision_type_options = provision_types.collect {|it| { 'name' => it['name'], 'value' => it['code']} }
|
345
|
+
|
346
|
+
if !params['provisionTypeCode']
|
347
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'provisionTypeCode', 'type' => 'select', 'selectOptions' => provision_type_options, 'fieldLabel' => 'Technology', 'required' => true, 'description' => 'The type of container technology.'}], options[:options])
|
348
|
+
params['provisionTypeCode'] = v_prompt['provisionTypeCode']
|
349
|
+
else
|
350
|
+
|
351
|
+
end
|
352
|
+
provision_type = provision_types.find {|it| it['code'] == params['provisionTypeCode'] }
|
353
|
+
|
354
|
+
if !params['memoryRequirement']
|
355
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'memoryRequirement', 'type' => 'text', 'fieldLabel' => 'Min Memory (MB)', 'required' => false, 'description' => 'This will override any memory requirement set on the virtual image'}], options[:options])
|
356
|
+
params['memoryRequirement'] = v_prompt['memoryRequirement'] if v_prompt['memoryRequirement']
|
357
|
+
end
|
358
|
+
|
359
|
+
if !params['taskSetId']
|
360
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'taskSetId', 'type' => 'text', 'fieldLabel' => 'Workflow ID', 'required' => false, 'description' => 'Worflow ID'}], options[:options])
|
361
|
+
params['taskSetId'] = v_prompt['taskSetId'].to_i if v_prompt['taskSetId']
|
362
|
+
end
|
363
|
+
|
364
|
+
# ENVIRONMENT VARIABLES
|
365
|
+
if evars
|
366
|
+
|
367
|
+
else
|
368
|
+
# prompt
|
369
|
+
end
|
370
|
+
|
371
|
+
# OPTION TYPES
|
372
|
+
if option_type_ids
|
373
|
+
params['optionTypes'] = option_type_ids.collect {|it| it.to_i }.select { |it| it != 0 }
|
374
|
+
else
|
375
|
+
# prompt
|
376
|
+
end
|
377
|
+
|
378
|
+
# NODE TYPES
|
379
|
+
if node_type_ids
|
380
|
+
params['containerTypes'] = node_type_ids.collect {|it| it.to_i }.select { |it| it != 0 }
|
381
|
+
else
|
382
|
+
# prompt
|
383
|
+
end
|
384
|
+
|
385
|
+
|
386
|
+
payload = {'instanceTypeLayout' => params}
|
387
|
+
|
388
|
+
end
|
389
|
+
|
390
|
+
if options[:dry_run]
|
391
|
+
print_dry_run @library_layouts_interface.dry.create(instance_type_id, payload)
|
392
|
+
return
|
393
|
+
end
|
394
|
+
|
395
|
+
json_response = @library_layouts_interface.create(instance_type_id, payload)
|
396
|
+
|
397
|
+
if options[:json]
|
398
|
+
print JSON.pretty_generate(json_response), "\n"
|
399
|
+
return
|
400
|
+
end
|
401
|
+
|
402
|
+
print_green_success "Added Layout #{params['name']}"
|
403
|
+
|
404
|
+
#get([json_response['instanceTypeLayout']['id']])
|
405
|
+
|
406
|
+
rescue RestClient::Exception => e
|
407
|
+
print_rest_exception(e, options)
|
408
|
+
exit 1
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
def update(args)
|
413
|
+
options = {}
|
414
|
+
params = {}
|
415
|
+
instance_type_id = nil
|
416
|
+
option_type_ids = nil
|
417
|
+
node_type_ids = nil
|
418
|
+
evars = nil
|
419
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
420
|
+
opts.banner = subcommand_usage("[name] [options]")
|
421
|
+
opts.on('--name VALUE', String, "Name for this layout") do |val|
|
422
|
+
params['name'] = val
|
423
|
+
end
|
424
|
+
opts.on('--version VALUE', String, "Version") do |val|
|
425
|
+
params['instanceVersion'] = val
|
426
|
+
end
|
427
|
+
opts.on('--description VALUE', String, "Description") do |val|
|
428
|
+
params['description'] = val
|
429
|
+
end
|
430
|
+
# opts.on('--technology CODE', String, "Technology") do |val|
|
431
|
+
# params['provisionTypeCode'] = val
|
432
|
+
# end
|
433
|
+
opts.on('--min-memory VALUE', String, "Minimum Memory (MB)") do |val|
|
434
|
+
params['memoryRequirement'] = val
|
435
|
+
end
|
436
|
+
opts.on('--workflow ID', String, "Workflow") do |val|
|
437
|
+
params['taskSetId'] = val.to_i
|
438
|
+
end
|
439
|
+
opts.on('--option-types x,y,z', Array, "List of Option Type IDs") do |val|
|
440
|
+
option_type_ids = val #.collect {|it| it.to_i }
|
441
|
+
end
|
442
|
+
opts.on('--node-types x,y,z', Array, "List of Node Type IDs") do |val|
|
443
|
+
node_type_ids = val #.collect {|it| it.to_i }
|
444
|
+
end
|
445
|
+
#build_option_type_options(opts, options, update_layout_option_types())
|
446
|
+
build_common_options(opts, options, [:options, :json, :dry_run, :remote])
|
447
|
+
opts.footer = "Update a layout."
|
448
|
+
end
|
449
|
+
optparse.parse!(args)
|
450
|
+
if args.count < 1
|
451
|
+
puts optparse
|
452
|
+
exit 1
|
453
|
+
end
|
454
|
+
connect(options)
|
455
|
+
begin
|
456
|
+
layout = find_layout_by_name_or_id(nil, args[0])
|
457
|
+
exit 1 if layout.nil?
|
458
|
+
payload = nil
|
459
|
+
if options[:payload]
|
460
|
+
payload = options[:payload]
|
461
|
+
else
|
462
|
+
# option_types = update_layout_option_types(instance_type)
|
463
|
+
# params = Morpheus::Cli::OptionTypes.prompt(option_types, options[:options], @api_client, options[:params])
|
464
|
+
params.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
465
|
+
|
466
|
+
# ENVIRONMENT VARIABLES
|
467
|
+
if evars
|
468
|
+
|
469
|
+
else
|
470
|
+
# prompt
|
471
|
+
end
|
472
|
+
|
473
|
+
# OPTION TYPES
|
474
|
+
if option_type_ids
|
475
|
+
params['optionTypes'] = option_type_ids.collect {|it| it.to_i }.select { |it| it != 0 }
|
476
|
+
else
|
477
|
+
# prompt
|
478
|
+
end
|
479
|
+
|
480
|
+
# NODE TYPES
|
481
|
+
if node_type_ids
|
482
|
+
params['containerTypes'] = node_type_ids.collect {|it| it.to_i }.select { |it| it != 0 }
|
483
|
+
else
|
484
|
+
# prompt
|
485
|
+
end
|
486
|
+
|
487
|
+
if params.empty?
|
488
|
+
puts optparse
|
489
|
+
exit 1
|
490
|
+
end
|
491
|
+
|
492
|
+
payload = {'instanceTypeLayout' => params}
|
493
|
+
|
494
|
+
end
|
495
|
+
|
496
|
+
if options[:dry_run]
|
497
|
+
print_dry_run @library_layouts_interface.dry.update(nil, layout['id'], payload)
|
498
|
+
return
|
499
|
+
end
|
500
|
+
|
501
|
+
json_response = @library_layouts_interface.update(nil, layout['id'], payload)
|
502
|
+
|
503
|
+
if options[:json]
|
504
|
+
print JSON.pretty_generate(json_response), "\n"
|
505
|
+
return
|
506
|
+
end
|
507
|
+
|
508
|
+
print_green_success "Updated Layout #{params['name'] || layout['name']}"
|
509
|
+
#list([])
|
510
|
+
rescue RestClient::Exception => e
|
511
|
+
print_rest_exception(e, options)
|
512
|
+
exit 1
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
def remove(args)
|
517
|
+
options = {}
|
518
|
+
optparse = Morpheus::Cli::OptionParser.new do|opts|
|
519
|
+
opts.banner = subcommand_usage("[name]")
|
520
|
+
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
521
|
+
opts.footer = "Delete a layout."
|
522
|
+
end
|
523
|
+
optparse.parse!(args)
|
524
|
+
if args.count < 1
|
525
|
+
puts optparse
|
526
|
+
exit 1
|
527
|
+
end
|
528
|
+
connect(options)
|
529
|
+
|
530
|
+
begin
|
531
|
+
layout = find_layout_by_name_or_id(nil, args[0])
|
532
|
+
exit 1 if layout.nil?
|
533
|
+
|
534
|
+
unless Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the instance type #{layout['name']}?", options)
|
535
|
+
exit
|
536
|
+
end
|
537
|
+
if options[:dry_run]
|
538
|
+
print_dry_run @library_layouts_interface.dry.destroy(nil, layout['id'])
|
539
|
+
return
|
540
|
+
end
|
541
|
+
json_response = @library_layouts_interface.destroy(nil, layout['id'])
|
542
|
+
|
543
|
+
if options[:json]
|
544
|
+
print JSON.pretty_generate(json_response), "\n"
|
545
|
+
return
|
546
|
+
end
|
547
|
+
|
548
|
+
print_green_success "Removed Layout #{layout['name']}"
|
549
|
+
#list([])
|
550
|
+
rescue RestClient::Exception => e
|
551
|
+
print_rest_exception(e, options)
|
552
|
+
exit 1
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
private
|
557
|
+
|
558
|
+
def find_layout_by_name_or_id(instance_type_id, val)
|
559
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
560
|
+
return find_layout_by_id(instance_type_id, val)
|
561
|
+
else
|
562
|
+
return find_layout_by_name(instance_type_id, val)
|
563
|
+
end
|
564
|
+
end
|
565
|
+
|
566
|
+
def find_layout_by_id(instance_type_id, id)
|
567
|
+
begin
|
568
|
+
json_response = @library_layouts_interface.get(instance_type_id, id.to_i)
|
569
|
+
return json_response['instanceTypeLayout']
|
570
|
+
rescue RestClient::Exception => e
|
571
|
+
if e.response && e.response.code == 404
|
572
|
+
print_red_alert "Instance Type not found by id #{id}"
|
573
|
+
else
|
574
|
+
raise e
|
575
|
+
end
|
576
|
+
end
|
577
|
+
end
|
578
|
+
|
579
|
+
def find_layout_by_name(instance_type_id, name)
|
580
|
+
layouts = @library_layouts_interface.list(instance_type_id, {name: name.to_s})['instanceTypeLayouts']
|
581
|
+
if layouts.empty?
|
582
|
+
print_red_alert "Layout not found by name #{name}"
|
583
|
+
return nil
|
584
|
+
elsif layouts.size > 1
|
585
|
+
print_red_alert "#{layouts.size} layouts found by name #{name}"
|
586
|
+
print_layouts_table(layouts, {color: red})
|
587
|
+
print_red_alert "Try using ID instead"
|
588
|
+
print reset,"\n"
|
589
|
+
return nil
|
590
|
+
else
|
591
|
+
return layouts[0]
|
592
|
+
end
|
593
|
+
end
|
594
|
+
|
595
|
+
def print_layouts_table(layouts, opts={})
|
596
|
+
columns = [
|
597
|
+
{"ID" => lambda {|layout| layout['id'] } },
|
598
|
+
{"INSTANCE TYPE" => lambda {|layout| layout['instanceType'] ? layout['instanceType']['name'] : '' } },
|
599
|
+
{"NAME" => lambda {|layout| layout['name'] } },
|
600
|
+
{"VERSION" => lambda {|layout| layout['instanceVersion'] } },
|
601
|
+
{"TECHNOLOGY" => lambda {|layout| format_layout_technology(layout) } },
|
602
|
+
{"DESCRIPTION" => lambda {|layout| layout['description'] } },
|
603
|
+
{"OWNER" => lambda {|layout| layout['account'] ? layout['account']['name'] : '' } }
|
604
|
+
]
|
605
|
+
if opts[:include_fields]
|
606
|
+
columns = opts[:include_fields]
|
607
|
+
end
|
608
|
+
print as_pretty_table(layouts, columns, opts)
|
609
|
+
end
|
610
|
+
|
611
|
+
def format_layout_technology(layout)
|
612
|
+
if layout
|
613
|
+
layout['provisionType'] ? layout['provisionType']['name'] : ''
|
614
|
+
else
|
615
|
+
""
|
616
|
+
end
|
617
|
+
end
|
618
|
+
|
619
|
+
def format_instance_type_phase(val)
|
620
|
+
val.to_s # .capitalize
|
621
|
+
end
|
622
|
+
|
623
|
+
def add_layout_option_types
|
624
|
+
[
|
625
|
+
# {'fieldName' => 'instanceTypeId', 'fieldLabel' => 'Instance Type ID', 'type' => 'text', 'required' => true, 'displayOrder' => 2, 'description' => 'The instance type this layout belongs to'},
|
626
|
+
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
|
627
|
+
{'fieldName' => 'code', 'fieldLabel' => 'Code', 'type' => 'text', 'required' => true, 'displayOrder' => 2, 'description' => 'Useful shortcode for provisioning naming schemes and export reference.'},
|
628
|
+
{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'displayOrder' => 3},
|
629
|
+
{'fieldName' => 'category', 'fieldLabel' => 'Category', 'type' => 'select', 'optionSource' => 'categories', 'required' => true, 'displayOrder' => 4},
|
630
|
+
{'fieldName' => 'logo', 'fieldLabel' => 'Icon File', 'type' => 'text', 'displayOrder' => 5},
|
631
|
+
{'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'}, {'name' => 'Public', 'value' => 'public'}], 'defaultValue' => 'private', 'displayOrder' => 6},
|
632
|
+
{'fieldName' => 'environmentPrefix', 'fieldLabel' => 'Environment Prefix', 'type' => 'text', 'displayOrder' => 7, 'description' => 'Used for exportable environment variables when tying instance types together in app contexts. If not specified a name will be generated.'},
|
633
|
+
{'fieldName' => 'hasSettings', 'fieldLabel' => 'Enable Settings', 'type' => 'checkbox', 'displayOrder' => 8},
|
634
|
+
{'fieldName' => 'hasAutoScale', 'fieldLabel' => 'Enable Scaling (Horizontal)', 'type' => 'checkbox', 'displayOrder' => 9},
|
635
|
+
{'fieldName' => 'hasDeployment', 'fieldLabel' => 'Supports Deployments', 'type' => 'checkbox', 'displayOrder' => 10, 'description' => 'Requires a data volume be configured on each version. Files will be copied into this location.'}
|
636
|
+
]
|
637
|
+
end
|
638
|
+
|
639
|
+
def update_layout_option_types(instance_type=nil)
|
640
|
+
if instance_type
|
641
|
+
opts = add_layout_option_types
|
642
|
+
opts.find {|opt| opt['fieldName'] == 'name'}['defaultValue'] = instance_type['name']
|
643
|
+
opts
|
644
|
+
else
|
645
|
+
add_layout_option_types
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
|
650
|
+
end
|