morpheus-cli 2.10.0 → 2.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/morpheus +27 -32
- data/lib/morpheus/api/accounts_interface.rb +36 -47
- data/lib/morpheus/api/api_client.rb +141 -110
- data/lib/morpheus/api/app_templates_interface.rb +56 -72
- data/lib/morpheus/api/apps_interface.rb +111 -132
- data/lib/morpheus/api/auth_interface.rb +30 -0
- data/lib/morpheus/api/clouds_interface.rb +71 -76
- data/lib/morpheus/api/custom_instance_types_interface.rb +21 -46
- data/lib/morpheus/api/dashboard_interface.rb +10 -17
- data/lib/morpheus/api/deploy_interface.rb +60 -72
- data/lib/morpheus/api/deployments_interface.rb +53 -71
- data/lib/morpheus/api/groups_interface.rb +55 -45
- data/lib/morpheus/api/instance_types_interface.rb +19 -23
- data/lib/morpheus/api/instances_interface.rb +179 -177
- data/lib/morpheus/api/key_pairs_interface.rb +11 -17
- data/lib/morpheus/api/license_interface.rb +18 -23
- data/lib/morpheus/api/load_balancers_interface.rb +54 -69
- data/lib/morpheus/api/logs_interface.rb +25 -29
- data/lib/morpheus/api/options_interface.rb +13 -17
- data/lib/morpheus/api/provision_types_interface.rb +19 -22
- data/lib/morpheus/api/roles_interface.rb +75 -94
- data/lib/morpheus/api/security_group_rules_interface.rb +28 -37
- data/lib/morpheus/api/security_groups_interface.rb +39 -51
- data/lib/morpheus/api/servers_interface.rb +113 -115
- data/lib/morpheus/api/setup_interface.rb +31 -0
- data/lib/morpheus/api/task_sets_interface.rb +36 -38
- data/lib/morpheus/api/tasks_interface.rb +56 -69
- data/lib/morpheus/api/users_interface.rb +67 -76
- data/lib/morpheus/api/virtual_images_interface.rb +61 -61
- data/lib/morpheus/api/whoami_interface.rb +12 -15
- data/lib/morpheus/cli.rb +71 -60
- data/lib/morpheus/cli/accounts.rb +254 -315
- data/lib/morpheus/cli/alias_command.rb +219 -0
- data/lib/morpheus/cli/app_templates.rb +264 -272
- data/lib/morpheus/cli/apps.rb +608 -671
- data/lib/morpheus/cli/cli_command.rb +259 -21
- data/lib/morpheus/cli/cli_registry.rb +99 -14
- data/lib/morpheus/cli/clouds.rb +599 -372
- data/lib/morpheus/cli/config_file.rb +126 -0
- data/lib/morpheus/cli/credentials.rb +141 -117
- data/lib/morpheus/cli/dashboard_command.rb +48 -56
- data/lib/morpheus/cli/deployments.rb +254 -268
- data/lib/morpheus/cli/deploys.rb +150 -142
- data/lib/morpheus/cli/error_handler.rb +38 -0
- data/lib/morpheus/cli/groups.rb +551 -179
- data/lib/morpheus/cli/hosts.rb +862 -617
- data/lib/morpheus/cli/instance_types.rb +103 -95
- data/lib/morpheus/cli/instances.rb +1335 -1009
- data/lib/morpheus/cli/key_pairs.rb +82 -90
- data/lib/morpheus/cli/library.rb +498 -499
- data/lib/morpheus/cli/license.rb +83 -101
- data/lib/morpheus/cli/load_balancers.rb +314 -300
- data/lib/morpheus/cli/login.rb +66 -44
- data/lib/morpheus/cli/logout.rb +47 -46
- data/lib/morpheus/cli/mixins/accounts_helper.rb +69 -31
- data/lib/morpheus/cli/mixins/infrastructure_helper.rb +106 -0
- data/lib/morpheus/cli/mixins/print_helper.rb +181 -17
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +535 -458
- data/lib/morpheus/cli/mixins/whoami_helper.rb +2 -2
- data/lib/morpheus/cli/option_parser.rb +35 -0
- data/lib/morpheus/cli/option_types.rb +232 -192
- data/lib/morpheus/cli/recent_activity_command.rb +61 -65
- data/lib/morpheus/cli/remote.rb +446 -199
- data/lib/morpheus/cli/roles.rb +884 -906
- data/lib/morpheus/cli/security_group_rules.rb +213 -203
- data/lib/morpheus/cli/security_groups.rb +237 -192
- data/lib/morpheus/cli/shell.rb +338 -231
- data/lib/morpheus/cli/tasks.rb +326 -308
- data/lib/morpheus/cli/users.rb +457 -462
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/version_command.rb +16 -18
- data/lib/morpheus/cli/virtual_images.rb +526 -345
- data/lib/morpheus/cli/whoami.rb +125 -111
- data/lib/morpheus/cli/workflows.rb +338 -185
- data/lib/morpheus/formatters.rb +8 -1
- data/lib/morpheus/logging.rb +1 -1
- data/lib/morpheus/rest_client.rb +17 -8
- metadata +9 -3
- data/lib/morpheus/api/custom_instance_types.rb +0 -55
data/lib/morpheus/cli/version.rb
CHANGED
@@ -4,16 +4,15 @@ require 'morpheus/cli/cli_command'
|
|
4
4
|
class Morpheus::Cli::VersionCommand
|
5
5
|
include Morpheus::Cli::CliCommand
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
7
|
+
set_command_name :version
|
8
|
+
def initialize
|
9
|
+
end
|
11
10
|
|
12
11
|
def usage
|
13
12
|
"morpheus version"
|
14
13
|
end
|
15
14
|
|
16
|
-
|
15
|
+
def handle(args)
|
17
16
|
options = {}
|
18
17
|
optparse = OptionParser.new do|opts|
|
19
18
|
opts.banner = usage
|
@@ -22,24 +21,23 @@ class Morpheus::Cli::VersionCommand
|
|
22
21
|
end
|
23
22
|
build_common_options(opts, options)
|
24
23
|
end
|
25
|
-
optparse.parse(args)
|
24
|
+
optparse.parse!(args)
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
26
|
+
client_version = Morpheus::Cli::VERSION
|
27
|
+
if options[:short]
|
28
|
+
puts client_version
|
30
29
|
else
|
31
|
-
|
30
|
+
print cyan
|
32
31
|
banner = "" +
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
32
|
+
" __ ___ __ \n" +
|
33
|
+
" / |/ /__ _______ / / ___ __ _____\n" +
|
34
|
+
" / /|_/ / _ \\/ __/ _ \\/ _ \\/ -_) // (_-<\n" +
|
35
|
+
"/_/ /_/\\___/_/ / .__/_//_/\\__/\\_,_/___/\n" +
|
36
|
+
"****************************************"
|
38
37
|
puts(banner)
|
39
38
|
puts(" Client Version: #{client_version}")
|
40
39
|
puts("****************************************")
|
41
|
-
print reset
|
40
|
+
print reset,"\n"
|
42
41
|
end
|
43
|
-
|
44
|
-
|
42
|
+
end
|
45
43
|
end
|
@@ -5,351 +5,532 @@ require 'optparse'
|
|
5
5
|
require 'table_print'
|
6
6
|
require 'morpheus/cli/cli_command'
|
7
7
|
|
8
|
+
# JD: I don't think a lot of this has ever worked, fix it up.
|
9
|
+
|
8
10
|
class Morpheus::Cli::VirtualImages
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
11
|
+
include Morpheus::Cli::CliCommand
|
12
|
+
|
13
|
+
register_subcommands :list, :get, :add, :add_file, :remove_file, :update, :remove, :types => :virtual_image_types
|
14
|
+
alias_subcommand :details, :get
|
15
|
+
set_default_subcommand :list
|
16
|
+
|
17
|
+
# def initialize()
|
18
|
+
# # @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
19
|
+
# end
|
20
|
+
|
21
|
+
def connect(opts)
|
22
|
+
@api_client = establish_remote_appliance_connection(opts)
|
23
|
+
@virtual_images_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).virtual_images
|
24
|
+
end
|
25
|
+
|
26
|
+
def handle(args)
|
27
|
+
handle_subcommand(args)
|
28
|
+
end
|
29
|
+
|
30
|
+
def list(args)
|
31
|
+
options = {}
|
32
|
+
optparse = OptionParser.new do|opts|
|
33
|
+
opts.banner = subcommand_usage()
|
34
|
+
opts.on( '-t', '--type IMAGE_TYPE', "Image Type" ) do |val|
|
35
|
+
options[:imageType] = val.downcase
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on( '', '--all', "All Images" ) do |val|
|
39
|
+
options[:filterType] = 'All'
|
40
|
+
end
|
41
|
+
opts.on( '', '--user', "User Images" ) do |val|
|
42
|
+
options[:filterType] = 'User'
|
43
|
+
end
|
44
|
+
opts.on( '', '--system', "System Images" ) do |val|
|
45
|
+
options[:filterType] = 'System'
|
46
|
+
end
|
47
|
+
build_common_options(opts, options, [:list, :json, :dry_run, :remote])
|
48
|
+
end
|
49
|
+
optparse.parse!(args)
|
50
|
+
connect(options)
|
51
|
+
begin
|
52
|
+
params = {}
|
53
|
+
[:phrase, :offset, :max, :sort, :direction].each do |k|
|
54
|
+
params[k] = options[k] unless options[k].nil?
|
55
|
+
end
|
56
|
+
if options[:imageType]
|
57
|
+
params[:imageType] = options[:imageType]
|
58
|
+
end
|
59
|
+
if options[:filterType]
|
60
|
+
params[:filterType] = options[:filterType]
|
61
|
+
end
|
62
|
+
if options[:dry_run]
|
63
|
+
print_dry_run @virtual_images_interface.dry.get(params)
|
64
|
+
return
|
65
|
+
end
|
66
|
+
json_response = @virtual_images_interface.get(params)
|
67
|
+
if options[:json]
|
68
|
+
print JSON.pretty_generate(json_response)
|
69
|
+
else
|
70
|
+
images = json_response['virtualImages']
|
71
|
+
print "\n" ,cyan, bold, "Morpheus Virtual Images\n","=======================", reset, "\n\n"
|
72
|
+
if images.empty?
|
73
|
+
puts yellow,"No virtual images currently exist.",reset
|
74
|
+
else
|
75
|
+
print cyan
|
76
|
+
image_table_data = images.collect do |image|
|
77
|
+
image_type = virtual_image_type_for_name_or_code(image['imageType'])
|
78
|
+
image_type_display = image_type ? "#{image_type['name']}" : image['imageType']
|
79
|
+
{name: image['name'], id: image['id'], type: image_type_display, source: image['userUploaded'] ? "#{green}UPLOADED#{cyan}" : (image['systemImage'] ? 'SYSTEM' : "#{white}SYNCED#{cyan}"), storage: !image['storageProvider'].nil? ? image['storageProvider']['name'] : 'Default', size: image['rawSize'].nil? ? 'Unknown' : "#{Filesize.from("#{image['rawSize']} B").pretty}"}
|
80
|
+
end
|
81
|
+
tp image_table_data, :id, :name, :type, :storage, :size, :source
|
82
|
+
print_results_pagination(json_response)
|
83
|
+
end
|
84
|
+
print reset,"\n"
|
85
|
+
end
|
86
|
+
rescue RestClient::Exception => e
|
87
|
+
print_rest_exception(e, options)
|
88
|
+
exit 1
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def get(args)
|
93
|
+
options = {}
|
94
|
+
optparse = OptionParser.new do|opts|
|
95
|
+
opts.banner = subcommand_usage("[name]")
|
96
|
+
build_common_options(opts, options, [:json, :dry_run, :remote])
|
97
|
+
end
|
98
|
+
optparse.parse!(args)
|
99
|
+
if args.count < 1
|
100
|
+
puts optparse
|
101
|
+
exit 1
|
102
|
+
end
|
103
|
+
image_name = args[0]
|
104
|
+
connect(options)
|
105
|
+
begin
|
106
|
+
if options[:dry_run]
|
107
|
+
if args[0].to_s =~ /\A\d{1,}\Z/
|
108
|
+
print_dry_run @virtual_images_interface.dry.get(args[0].to_i)
|
109
|
+
else
|
110
|
+
print_dry_run @virtual_images_interface.dry.get({name:args[0]})
|
111
|
+
end
|
112
|
+
return
|
113
|
+
end
|
114
|
+
image = find_virtual_image_by_name_or_id(image_name)
|
115
|
+
exit 1 if image.nil?
|
116
|
+
# refetch
|
117
|
+
json_response = @virtual_images_interface.get(image['id'])
|
118
|
+
image = json_response['virtualImage']
|
119
|
+
image_files = json_response['cloudFiles'] || json_response['files']
|
120
|
+
|
121
|
+
if options[:json]
|
122
|
+
puts JSON.pretty_generate(json_response)
|
123
|
+
else
|
124
|
+
image_type = virtual_image_type_for_name_or_code(image['imageType'])
|
125
|
+
image_type_display = image_type ? "#{image_type['name']}" : image['imageType']
|
126
|
+
print "\n" ,cyan, bold, "Virtual Image Details\n","==================", reset, "\n\n"
|
127
|
+
print cyan
|
128
|
+
puts "ID: #{image['id']}"
|
129
|
+
puts "Name: #{image['name']}"
|
130
|
+
puts "Type: #{image_type_display}"
|
131
|
+
#puts "Date Created: #{format_local_dt(image['dateCreated'])}"
|
132
|
+
#puts "Last Updated: #{format_local_dt(image['lastUpdated'])}"
|
133
|
+
if image_files
|
134
|
+
puts "Files:"
|
135
|
+
image_files.each {|image_file|
|
136
|
+
pretty_filesize = Filesize.from("#{image_file['size']} B").pretty
|
137
|
+
print cyan," = #{image_file['name']} [#{pretty_filesize}]", "\n"
|
138
|
+
}
|
139
|
+
end
|
140
|
+
print reset,"\n"
|
141
|
+
end
|
142
|
+
rescue RestClient::Exception => e
|
143
|
+
print_rest_exception(e, options)
|
144
|
+
exit 1
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# JD: I don't think this has ever worked
|
149
|
+
def update(args)
|
150
|
+
image_name = args[0]
|
151
|
+
options = {}
|
152
|
+
account_name = nil
|
153
|
+
optparse = OptionParser.new do|opts|
|
154
|
+
opts.banner = subcommand_usage("[name] [options]")
|
155
|
+
build_common_options(opts, options, [:options, :json, :dry_run, :remote])
|
156
|
+
end
|
157
|
+
optparse.parse!(args)
|
158
|
+
if args.count < 1
|
159
|
+
puts optparse
|
160
|
+
exit 1
|
161
|
+
end
|
162
|
+
|
163
|
+
connect(options)
|
164
|
+
begin
|
165
|
+
|
166
|
+
image = find_virtual_image_by_name_or_id(image_name)
|
167
|
+
exit 1 if image.nil?
|
168
|
+
|
169
|
+
params = options[:options] || {}
|
170
|
+
|
171
|
+
if params.empty?
|
172
|
+
puts optparse
|
173
|
+
option_lines = update_virtual_image_option_types().collect {|it| "\t-O #{it['fieldContext'] ? (it['fieldContext'] + '.') : ''}#{it['fieldName']}=\"value\"" }.join("\n")
|
174
|
+
puts "\nAvailable Options:\n#{option_lines}\n\n"
|
175
|
+
exit 1
|
176
|
+
end
|
177
|
+
|
178
|
+
image_payload = {id: image['id']}
|
179
|
+
image_payload.merge(params)
|
180
|
+
# JD: what can be updated?
|
181
|
+
payload = {virtualImage: image_payload}
|
182
|
+
if options[:dry_run]
|
183
|
+
print_dry_run @virtual_images_interface.dry.update(image['id'], payload)
|
184
|
+
return
|
185
|
+
end
|
186
|
+
response = @virtual_images_interface.update(image['id'], payload)
|
187
|
+
if options[:json]
|
188
|
+
print JSON.pretty_generate(json_response)
|
189
|
+
if !response['success']
|
190
|
+
exit 1
|
191
|
+
end
|
192
|
+
else
|
193
|
+
print "\n", cyan, "Task #{response['task']['name']} updated", reset, "\n\n"
|
194
|
+
end
|
195
|
+
rescue RestClient::Exception => e
|
196
|
+
print_rest_exception(e, options)
|
197
|
+
exit 1
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def virtual_image_types(args)
|
202
|
+
options = {}
|
203
|
+
optparse = OptionParser.new do|opts|
|
204
|
+
opts.banner = subcommand_usage()
|
205
|
+
build_common_options(opts, options, [:json, :dry_run, :remote])
|
206
|
+
end
|
207
|
+
optparse.parse!(args)
|
208
|
+
connect(options)
|
209
|
+
begin
|
210
|
+
params = {}
|
211
|
+
if options[:dry_run]
|
212
|
+
print_dry_run @virtual_images_interface.dry.virtual_image_types(params)
|
213
|
+
return
|
214
|
+
end
|
215
|
+
json_response = @virtual_images_interface.virtual_image_types(params)
|
216
|
+
if options[:json]
|
217
|
+
print JSON.pretty_generate(json_response)
|
218
|
+
else
|
219
|
+
image_types = json_response['virtualImageTypes']
|
220
|
+
print "\n" ,cyan, bold, "Morpheus Virtual Image Types\n","============================", reset, "\n\n"
|
221
|
+
if image_types.nil? || image_types.empty?
|
222
|
+
puts yellow,"No image types currently exist on this appliance. This could be a seed issue.",reset
|
223
|
+
else
|
224
|
+
print cyan
|
225
|
+
lb_table_data = image_types.collect do |lb_type|
|
226
|
+
{name: lb_type['name'], code: lb_type['code']}
|
227
|
+
end
|
228
|
+
tp lb_table_data, :name, :code
|
229
|
+
end
|
230
|
+
|
231
|
+
print reset,"\n\n"
|
232
|
+
end
|
233
|
+
rescue RestClient::Exception => e
|
234
|
+
print_rest_exception(e, options)
|
235
|
+
exit 1
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def add(args)
|
240
|
+
image_type_name = nil
|
241
|
+
options = {}
|
242
|
+
optparse = OptionParser.new do|opts|
|
243
|
+
opts.banner = subcommand_usage("[name] -t TYPE")
|
244
|
+
opts.on( '-t', '--type TYPE', "Virtual Image Type" ) do |val|
|
245
|
+
image_type_name = val
|
246
|
+
end
|
247
|
+
build_common_options(opts, options, [:options, :json, :dry_run, :remote])
|
248
|
+
end
|
249
|
+
optparse.parse!(args)
|
250
|
+
# if args.count < 1
|
251
|
+
# puts optparse
|
252
|
+
# exit 1
|
253
|
+
# end
|
254
|
+
image_name = args[0]
|
255
|
+
connect(options)
|
256
|
+
|
257
|
+
# if image_type_name.nil?
|
258
|
+
# puts "Virtual Image Type must be specified"
|
259
|
+
# puts optparse
|
260
|
+
# exit 1
|
261
|
+
# end
|
262
|
+
|
263
|
+
#
|
264
|
+
if image_name
|
265
|
+
options[:options] ||= {}
|
266
|
+
options[:options]['name'] ||= image_name
|
267
|
+
end
|
268
|
+
|
269
|
+
if image_type_name
|
270
|
+
image_type = virtual_image_type_for_name_or_code(image_type_name)
|
271
|
+
exit 1 if image_type.nil?
|
272
|
+
# options[:options] ||= {}
|
273
|
+
# options[:options]['imageType'] ||= image_type['code']
|
274
|
+
else
|
275
|
+
image_type_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'imageType', 'fieldLabel' => 'Image Type', 'type' => 'select', 'optionSource' => 'virtualImageTypes', 'required' => true, 'description' => 'Select Virtual Image Type.', 'displayOrder' => 2}],options[:options],@api_client,{})
|
276
|
+
image_type = virtual_image_type_for_name_or_code(image_type_prompt['imageType'])
|
277
|
+
end
|
278
|
+
|
279
|
+
begin
|
280
|
+
my_option_types = add_virtual_image_option_types(image_type)
|
281
|
+
params = Morpheus::Cli::OptionTypes.prompt(add_virtual_image_option_types(image_type), options[:options], @api_client, options[:params])
|
282
|
+
virtual_image_payload = {}.merge(params)
|
283
|
+
virtual_image_files = virtual_image_payload.delete('virtualImageFiles')
|
284
|
+
virtual_image_payload['imageType'] = image_type['code']
|
285
|
+
storage_provider_id = virtual_image_payload.delete('storageProviderId')
|
286
|
+
if !storage_provider_id.empty?
|
287
|
+
virtual_image_payload['storageProvider'] = {id: storage_provider_id}
|
288
|
+
end
|
289
|
+
payload = {virtualImage: virtual_image_payload}
|
290
|
+
|
291
|
+
if options[:dry_run]
|
292
|
+
print_dry_run @virtual_images_interface.dry.create(payload)
|
293
|
+
if !virtual_image_files.empty?
|
294
|
+
virtual_image_files.each do |key, filename|
|
295
|
+
print_dry_run @virtual_images_interface.dry.upload(":id", "(Contents of file #{filename})")
|
296
|
+
end
|
297
|
+
end
|
298
|
+
return
|
299
|
+
end
|
300
|
+
|
301
|
+
json_response = @virtual_images_interface.create(payload)
|
302
|
+
virtual_image = json_response['virtualImage']
|
303
|
+
|
304
|
+
if options[:json]
|
305
|
+
print JSON.pretty_generate(json_response)
|
306
|
+
elsif !options[:quiet]
|
307
|
+
print "\n", cyan, "Virtual Image #{virtual_image['name']} created successfully", reset, "\n\n"
|
308
|
+
end
|
309
|
+
|
310
|
+
# now upload the file, do this in the background maybe?
|
311
|
+
if !virtual_image_files.empty?
|
312
|
+
virtual_image_files.each do |key, filename|
|
313
|
+
unless options[:quiet]
|
314
|
+
print cyan, "Uploading file (#{key}) #{filename} ...", reset, "\n"
|
315
|
+
end
|
316
|
+
image_file = File.new(filename, 'rb')
|
317
|
+
upload_json_response = @virtual_images_interface.upload(virtual_image['id'], image_file)
|
318
|
+
if options[:json]
|
319
|
+
print JSON.pretty_generate(upload_json_response)
|
320
|
+
end
|
321
|
+
end
|
322
|
+
else
|
323
|
+
puts cyan, "No files uploaded.", reset
|
324
|
+
end
|
325
|
+
|
326
|
+
if !options[:json]
|
327
|
+
get([virtual_image['id']])
|
328
|
+
end
|
329
|
+
|
330
|
+
rescue RestClient::Exception => e
|
331
|
+
print_rest_exception(e, options)
|
332
|
+
exit 1
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
def add_file(args)
|
337
|
+
image_type_name = nil
|
338
|
+
options = {}
|
339
|
+
optparse = OptionParser.new do|opts|
|
340
|
+
opts.banner = subcommand_usage("[name] [filepath]")
|
341
|
+
build_common_options(opts, options, [:json, :dry_run, :remote])
|
342
|
+
end
|
343
|
+
optparse.parse!(args)
|
344
|
+
if args.count < 2
|
345
|
+
puts optparse
|
346
|
+
exit 1
|
347
|
+
end
|
348
|
+
image_name = args[0]
|
349
|
+
filename = args[1]
|
350
|
+
|
351
|
+
connect(options)
|
352
|
+
|
353
|
+
begin
|
354
|
+
image = find_virtual_image_by_name_or_id(image_name)
|
355
|
+
image_file = File.new(filename, 'rb')
|
356
|
+
|
357
|
+
if options[:dry_run]
|
358
|
+
print_dry_run @virtual_images_interface.dry.upload(image['id'], image_file)
|
359
|
+
return
|
360
|
+
end
|
361
|
+
|
362
|
+
unless options[:quiet]
|
363
|
+
print cyan, "Uploading file #{filename} ...", reset, "\n"
|
364
|
+
end
|
365
|
+
|
366
|
+
json_response = @virtual_images_interface.upload(image['id'], image_file)
|
367
|
+
|
368
|
+
if options[:json]
|
369
|
+
print JSON.pretty_generate(json_response)
|
370
|
+
elsif !options[:quiet]
|
371
|
+
print "\n", cyan, "Virtual Image #{image['name']} successfully updated.", reset, "\n\n"
|
372
|
+
get([image['id']])
|
373
|
+
end
|
374
|
+
|
375
|
+
rescue RestClient::Exception => e
|
376
|
+
print_rest_exception(e, options)
|
377
|
+
exit 1
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
def remove_file(args)
|
382
|
+
options = {}
|
383
|
+
optparse = OptionParser.new do|opts|
|
384
|
+
opts.banner = subcommand_usage("[name] [filename]")
|
385
|
+
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
386
|
+
end
|
387
|
+
optparse.parse!(args)
|
388
|
+
if args.count < 2
|
389
|
+
puts optparse
|
390
|
+
exit 1
|
391
|
+
end
|
392
|
+
image_name = args[0]
|
393
|
+
filename = args[1]
|
394
|
+
connect(options)
|
395
|
+
begin
|
396
|
+
image = find_virtual_image_by_name_or_id(image_name)
|
397
|
+
exit 1 if image.nil?
|
398
|
+
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the virtual image filename #{filename}?")
|
399
|
+
exit
|
400
|
+
end
|
401
|
+
if options[:dry_run]
|
402
|
+
print_dry_run @virtual_images_interface.dry.destroy_file(image['id'], filename)
|
403
|
+
return
|
404
|
+
end
|
405
|
+
json_response = @virtual_images_interface.destroy_file(image['id'], filename)
|
406
|
+
if options[:json]
|
407
|
+
print JSON.pretty_generate(json_response)
|
408
|
+
else
|
409
|
+
print "\n", cyan, "Virtual Image #{image['name']} filename #{filename} removed", reset, "\n\n"
|
410
|
+
end
|
411
|
+
rescue RestClient::Exception => e
|
412
|
+
print_rest_exception(e, options)
|
413
|
+
exit 1
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
def remove(args)
|
418
|
+
options = {}
|
419
|
+
optparse = OptionParser.new do|opts|
|
420
|
+
opts.banner = subcommand_usage("[name]")
|
421
|
+
build_common_options(opts, options, [:auto_confirm, :json, :dry_run, :remote])
|
422
|
+
end
|
423
|
+
optparse.parse!(args)
|
424
|
+
if args.count < 1
|
425
|
+
puts optparse
|
426
|
+
exit 1
|
427
|
+
end
|
428
|
+
image_name = args[0]
|
429
|
+
connect(options)
|
430
|
+
begin
|
431
|
+
image = find_virtual_image_by_name_or_id(image_name)
|
432
|
+
exit 1 if image.nil?
|
433
|
+
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the virtual image #{image['name']}?")
|
434
|
+
exit
|
435
|
+
end
|
436
|
+
if options[:dry_run]
|
437
|
+
print_dry_run @virtual_images_interface.dry.destroy(image['id'])
|
438
|
+
return
|
439
|
+
end
|
440
|
+
json_response = @virtual_images_interface.destroy(image['id'])
|
441
|
+
if options[:json]
|
442
|
+
print JSON.pretty_generate(json_response)
|
443
|
+
else
|
444
|
+
print "\n", cyan, "Virtual Image #{image['name']} removed", reset, "\n\n"
|
445
|
+
end
|
446
|
+
rescue RestClient::Exception => e
|
447
|
+
print_rest_exception(e, options)
|
448
|
+
exit 1
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
|
453
|
+
private
|
454
|
+
def find_virtual_image_by_name_or_id(val)
|
455
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
456
|
+
return find_virtual_image_by_id(val)
|
457
|
+
else
|
458
|
+
return find_virtual_image_by_name(val)
|
459
|
+
end
|
460
|
+
end
|
461
|
+
|
462
|
+
def find_virtual_image_by_id(id)
|
463
|
+
begin
|
464
|
+
json_response = @virtual_images_interface.get(id.to_i)
|
465
|
+
return json_response['virtualImage']
|
466
|
+
rescue RestClient::Exception => e
|
467
|
+
if e.response && e.response.code == 404
|
468
|
+
print_red_alert "Virtual Image not found by id #{id}"
|
469
|
+
else
|
470
|
+
raise e
|
471
|
+
end
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
def find_virtual_image_by_name(name)
|
476
|
+
json_results = @virtual_images_interface.get({name: name.to_s})
|
477
|
+
if json_results['virtualImages'].empty?
|
478
|
+
print_red_alert "Virtual Image not found by name #{name}"
|
479
|
+
exit 1
|
480
|
+
end
|
481
|
+
virtual_image = json_results['virtualImages'][0]
|
482
|
+
return virtual_image
|
483
|
+
end
|
484
|
+
|
485
|
+
|
486
|
+
def get_available_virtual_image_types(refresh=false)
|
487
|
+
if !@available_virtual_image_types || refresh
|
488
|
+
@available_virtual_image_types = @virtual_images_interface.virtual_image_types['virtualImageTypes'] # || []
|
489
|
+
end
|
490
|
+
return @available_virtual_image_types
|
491
|
+
end
|
492
|
+
def virtual_image_type_for_name_or_code(name)
|
493
|
+
return get_available_virtual_image_types().find { |z| z['name'].downcase == name.downcase || z['code'].downcase == name.downcase}
|
494
|
+
end
|
495
|
+
|
496
|
+
def add_virtual_image_option_types(image_type)
|
497
|
+
image_type_code = image_type['code']
|
498
|
+
# todo: make api provide virtualImageType and its optionTypes.
|
499
|
+
tmp_option_types = [
|
500
|
+
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
|
501
|
+
#{'fieldName' => 'imageType', 'fieldLabel' => 'Image Type', 'type' => 'select', 'optionSource' => 'virtualImageTypes', 'required' => true, 'description' => 'Select Virtual Image Type.', 'displayOrder' => 2},
|
502
|
+
{'fieldName' => 'osType', 'fieldLabel' => 'OS Type', 'type' => 'select', 'optionSource' => 'osTypes', 'required' => false, 'description' => 'Select OS Type.', 'displayOrder' => 3},
|
503
|
+
{'fieldName' => 'isCloudInit', 'fieldLabel' => 'Cloud Init Enabled?', 'type' => 'checkbox', 'required' => false, 'description' => 'Cloud Init Enabled?', 'displayOrder' => 4},
|
504
|
+
{'fieldName' => 'installAgent', 'fieldLabel' => 'Install Agent?', 'type' => 'checkbox', 'required' => false, 'description' => 'Cloud Init Enabled?', 'displayOrder' => 4},
|
505
|
+
{'fieldName' => 'sshUsername', 'fieldLabel' => 'SSH Username', 'type' => 'text', 'required' => false, 'description' => 'Enter an SSH Username', 'displayOrder' => 5},
|
506
|
+
{'fieldName' => 'sshPassword', 'fieldLabel' => 'SSH Password', 'type' => 'password', 'required' => false, 'description' => 'Enter an SSH Password', 'displayOrder' => 6},
|
507
|
+
{'fieldName' => 'storageProviderId', 'type' => 'select', 'fieldLabel' => 'Storage Provider', 'optionSource' => 'storageProviders', 'required' => false, 'description' => 'Select Storage Provider.', 'displayOrder' => 7},
|
508
|
+
{'fieldName' => 'userData', 'fieldLabel' => 'Cloud-Init User Data', 'type' => 'textarea', 'required' => false, 'displayOrder' => 10},
|
509
|
+
{'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'},{'name' => 'Public', 'value' => 'public'}], 'required' => false, 'description' => 'Visibility', 'category' => 'permissions', 'defaultValue' => 'private', 'displayOrder' => 40},
|
510
|
+
{'fieldName' => 'isAutoJoinDomain', 'fieldLabel' => 'Auto Join Domain?', 'type' => 'checkbox', 'required' => false, 'description' => 'Cloud Init Enabled?', 'category' => 'advanced', 'displayOrder' => 40},
|
511
|
+
{'fieldName' => 'virtioSupported', 'fieldLabel' => 'VirtIO Drivers Loaded?', 'type' => 'checkbox', 'defaultValue' => 'on', 'required' => false, 'description' => 'VirtIO Drivers Loaded?', 'category' => 'advanced', 'displayOrder' => 40}
|
512
|
+
]
|
513
|
+
|
514
|
+
if image_type_code == 'ami'
|
515
|
+
tmp_option_types << {'fieldName' => 'externalId', 'fieldLabel' => 'AMI id', 'type' => 'text', 'required' => false, 'displayOrder' => 10}
|
516
|
+
tmp_option_types << {'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => true, 'displayOrder' => 10}
|
517
|
+
elsif image_type_code == 'vmware'
|
518
|
+
tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageFile', 'fieldLabel' => 'OVF File', 'type' => 'file', 'required' => true, 'displayOrder' => 10}
|
519
|
+
tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageDescriptorFile', 'fieldLabel' => 'VMDK File', 'type' => 'file', 'required' => false, 'displayOrder' => 10}
|
520
|
+
elsif image_type_code == 'pxe'
|
521
|
+
tmp_option_types << {'fieldName' => 'config.menu', 'fieldLabel' => 'Menu', 'type' => 'text', 'required' => false, 'displayOrder' => 10}
|
522
|
+
tmp_option_types << {'fieldName' => 'imagePath', 'fieldLabel' => 'Image Path', 'type' => 'text', 'required' => true, 'displayOrder' => 10}
|
523
|
+
tmp_option_types.reject! {|opt| ['isCloudInit', 'installAgent', 'sshUsername', 'sshPassword'].include?(opt['fieldName'])}
|
524
|
+
else
|
525
|
+
tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => true, 'description' => 'Choose an image file to upload', 'displayOrder' => 10}
|
526
|
+
end
|
527
|
+
|
528
|
+
return tmp_option_types
|
529
|
+
end
|
530
|
+
|
531
|
+
# JD: what can be updated?
|
532
|
+
def update_virtual_image_option_types
|
533
|
+
[]
|
534
|
+
end
|
354
535
|
|
355
536
|
end
|