morpheus-cli 4.2.21 → 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 +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +30 -0
- data/lib/morpheus/api/billing_interface.rb +34 -0
- data/lib/morpheus/api/catalog_item_types_interface.rb +9 -0
- data/lib/morpheus/api/deploy_interface.rb +1 -1
- data/lib/morpheus/api/deployments_interface.rb +20 -1
- data/lib/morpheus/api/forgot_password_interface.rb +17 -0
- data/lib/morpheus/api/instances_interface.rb +16 -2
- data/lib/morpheus/api/rest_interface.rb +0 -6
- data/lib/morpheus/api/roles_interface.rb +14 -0
- data/lib/morpheus/api/search_interface.rb +13 -0
- data/lib/morpheus/api/servers_interface.rb +14 -0
- data/lib/morpheus/api/service_catalog_interface.rb +89 -0
- data/lib/morpheus/api/usage_interface.rb +18 -0
- data/lib/morpheus/cli.rb +7 -3
- data/lib/morpheus/cli/apps.rb +6 -27
- data/lib/morpheus/cli/backup_jobs_command.rb +3 -0
- data/lib/morpheus/cli/backups_command.rb +3 -0
- data/lib/morpheus/cli/catalog_item_types_command.rb +622 -0
- data/lib/morpheus/cli/cli_command.rb +70 -21
- data/lib/morpheus/cli/commands/standard/curl_command.rb +26 -12
- data/lib/morpheus/cli/commands/standard/history_command.rb +3 -1
- data/lib/morpheus/cli/commands/standard/man_command.rb +74 -40
- data/lib/morpheus/cli/commands/standard/source_command.rb +1 -1
- data/lib/morpheus/cli/commands/standard/update_command.rb +76 -0
- data/lib/morpheus/cli/containers_command.rb +14 -24
- data/lib/morpheus/cli/cypher_command.rb +6 -2
- data/lib/morpheus/cli/deploy.rb +199 -90
- data/lib/morpheus/cli/deployments.rb +341 -28
- data/lib/morpheus/cli/deploys.rb +206 -41
- data/lib/morpheus/cli/error_handler.rb +7 -0
- data/lib/morpheus/cli/forgot_password.rb +133 -0
- data/lib/morpheus/cli/groups.rb +1 -1
- data/lib/morpheus/cli/health_command.rb +59 -2
- data/lib/morpheus/cli/hosts.rb +265 -34
- data/lib/morpheus/cli/instances.rb +186 -100
- data/lib/morpheus/cli/invoices_command.rb +33 -16
- data/lib/morpheus/cli/jobs_command.rb +28 -6
- data/lib/morpheus/cli/library_option_lists_command.rb +15 -7
- data/lib/morpheus/cli/library_option_types_command.rb +5 -2
- data/lib/morpheus/cli/logs_command.rb +9 -6
- data/lib/morpheus/cli/mixins/accounts_helper.rb +12 -7
- data/lib/morpheus/cli/mixins/backups_helper.rb +2 -4
- data/lib/morpheus/cli/mixins/deployments_helper.rb +31 -3
- data/lib/morpheus/cli/mixins/option_source_helper.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +46 -21
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +100 -4
- data/lib/morpheus/cli/network_pools_command.rb +14 -6
- data/lib/morpheus/cli/option_types.rb +271 -22
- data/lib/morpheus/cli/ping.rb +0 -1
- data/lib/morpheus/cli/remote.rb +35 -12
- data/lib/morpheus/cli/reports_command.rb +99 -30
- data/lib/morpheus/cli/roles.rb +453 -113
- data/lib/morpheus/cli/search_command.rb +182 -0
- data/lib/morpheus/cli/service_catalog_command.rb +1474 -0
- data/lib/morpheus/cli/service_plans_command.rb +2 -2
- data/lib/morpheus/cli/setup.rb +1 -1
- data/lib/morpheus/cli/shell.rb +33 -11
- data/lib/morpheus/cli/storage_providers_command.rb +40 -56
- data/lib/morpheus/cli/tasks.rb +29 -32
- data/lib/morpheus/cli/usage_command.rb +203 -0
- data/lib/morpheus/cli/user_settings_command.rb +1 -0
- data/lib/morpheus/cli/users.rb +12 -1
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/virtual_images.rb +429 -254
- data/lib/morpheus/cli/whoami.rb +6 -6
- data/lib/morpheus/cli/workflows.rb +34 -41
- data/lib/morpheus/formatters.rb +75 -7
- data/lib/morpheus/terminal.rb +6 -2
- metadata +14 -2
@@ -94,6 +94,7 @@ EOT
|
|
94
94
|
"Linux Key Pair" => lambda {|it| it['linuxKeyPairId'] },
|
95
95
|
"Windows Username" => lambda {|it| it['windowsUsername'] },
|
96
96
|
"Windows Password" => lambda {|it| it['windowsPassword'] },
|
97
|
+
"Default Persona" => lambda {|it| it['defaultPersona'] ? it['defaultPersona']['name'] : '' },
|
97
98
|
}
|
98
99
|
print_description_list(description_cols, user_settings)
|
99
100
|
|
data/lib/morpheus/cli/users.rb
CHANGED
@@ -161,12 +161,22 @@ class Morpheus::Cli::Users
|
|
161
161
|
options[:include_app_templates_access] = true
|
162
162
|
params['includeAccess'] = true
|
163
163
|
end
|
164
|
+
opts.on(nil,'--catalog-item-type-access', "Display Catalog Item Type Access") do
|
165
|
+
options[:include_catalog_item_types_access] = true
|
166
|
+
params['includeAccess'] = true
|
167
|
+
end
|
168
|
+
opts.on(nil,'--personas', "Display Persona Access") do
|
169
|
+
options[:include_personas_access] = true
|
170
|
+
params['includeAccess'] = true
|
171
|
+
end
|
164
172
|
opts.on(nil,'--all', "Display All Access Lists") do
|
165
173
|
options[:include_features_access] = true
|
166
174
|
options[:include_sites_access] = true
|
167
175
|
options[:include_zones_access] = true
|
168
176
|
options[:include_instance_types_access] = true
|
169
177
|
options[:include_app_templates_access] = true
|
178
|
+
options[:include_catalog_item_types_access] = true
|
179
|
+
options[:include_personas_access] = true
|
170
180
|
params['includeAccess'] = true
|
171
181
|
end
|
172
182
|
opts.on('-i', '--include-none-access', "Include Items with 'None' Access in Access List") do
|
@@ -241,7 +251,8 @@ EOT
|
|
241
251
|
puts yellow,"No permissions found.",reset
|
242
252
|
end
|
243
253
|
else
|
244
|
-
available_field_options = {'features' => 'Feature', 'sites' => 'Group', 'zones' => 'Cloud', 'instance_types' => 'Instance Type',
|
254
|
+
available_field_options = {'features' => 'Feature', 'sites' => 'Group', 'zones' => 'Cloud', 'instance_types' => 'Instance Type',
|
255
|
+
'app_templates' => 'Blueprint', 'catalog_item_types' => 'Catalog Item Types', 'personas' => 'Personas'}
|
245
256
|
available_field_options.each do |field, label|
|
246
257
|
if !(field == 'sites' && is_tenant_account) && options["include_#{field}_access".to_sym]
|
247
258
|
access = user['access'][field.split('_').enum_for(:each_with_index).collect {|word, idx| idx == 0 ? word : word.capitalize}.join]
|
data/lib/morpheus/cli/version.rb
CHANGED
@@ -8,6 +8,7 @@ require 'morpheus/cli/cli_command'
|
|
8
8
|
|
9
9
|
class Morpheus::Cli::VirtualImages
|
10
10
|
include Morpheus::Cli::CliCommand
|
11
|
+
include Morpheus::Cli::ProvisioningHelper
|
11
12
|
|
12
13
|
register_subcommands :list, :get, :add, :add_file, :remove_file, :update, :remove, :types => :virtual_image_types
|
13
14
|
alias_subcommand :details, :get
|
@@ -27,6 +28,7 @@ class Morpheus::Cli::VirtualImages
|
|
27
28
|
end
|
28
29
|
|
29
30
|
def list(args)
|
31
|
+
params = {}
|
30
32
|
options = {}
|
31
33
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
32
34
|
opts.banner = subcommand_usage()
|
@@ -42,42 +44,48 @@ class Morpheus::Cli::VirtualImages
|
|
42
44
|
opts.on('--system', "System Images" ) do
|
43
45
|
options[:filterType] = 'System'
|
44
46
|
end
|
45
|
-
|
47
|
+
opts.on('--tags Name=Value',String, "Filter by tags (metadata name value pairs).") do |val|
|
48
|
+
val.split(",").each do |value_pair|
|
49
|
+
k,v = value_pair.strip.split("=")
|
50
|
+
options[:tags] ||= {}
|
51
|
+
options[:tags][k] ||= []
|
52
|
+
options[:tags][k] << (v || '')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
opts.on('-a', '--details', "Show more details." ) do
|
56
|
+
options[:details] = true
|
57
|
+
end
|
58
|
+
build_standard_list_options(opts, options)
|
46
59
|
opts.footer = "List virtual images."
|
47
60
|
end
|
48
61
|
optparse.parse!(args)
|
49
62
|
connect(options)
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
json_response = @virtual_images_interface.get(params)
|
65
|
-
|
66
|
-
if options[:json]
|
67
|
-
puts as_json(json_response, options, "virtualImages")
|
68
|
-
return 0
|
69
|
-
elsif options[:yaml]
|
70
|
-
puts as_yaml(json_response, options, "virtualImages")
|
71
|
-
return 0
|
72
|
-
elsif options[:csv]
|
73
|
-
puts records_as_csv(json_response["virtualImages"], options)
|
74
|
-
return 0
|
63
|
+
# verify_args!(args:args, optparse:optparse, count:0)
|
64
|
+
if args.count > 0
|
65
|
+
options[:phrase] = args.join(" ")
|
66
|
+
end
|
67
|
+
params.merge!(parse_list_options(options))
|
68
|
+
if options[:imageType]
|
69
|
+
params[:imageType] = options[:imageType]
|
70
|
+
end
|
71
|
+
if options[:filterType]
|
72
|
+
params[:filterType] = options[:filterType]
|
73
|
+
end
|
74
|
+
if options[:tags]
|
75
|
+
options[:tags].each do |k,v|
|
76
|
+
params['tags.' + k] = v
|
75
77
|
end
|
76
|
-
|
77
|
-
|
78
|
-
|
78
|
+
end
|
79
|
+
@virtual_images_interface.setopts(options)
|
80
|
+
if options[:dry_run]
|
81
|
+
print_dry_run @virtual_images_interface.dry.list(params)
|
82
|
+
return
|
83
|
+
end
|
84
|
+
json_response = @virtual_images_interface.list(params)
|
85
|
+
images = json_response['virtualImages']
|
86
|
+
render_response(json_response, options, 'virtualImages') do
|
79
87
|
title = "Morpheus Virtual Images"
|
80
|
-
subtitles =
|
88
|
+
subtitles = parse_list_subtitles(options)
|
81
89
|
if options[:imageType]
|
82
90
|
subtitles << "Image Type: #{options[:imageType]}".strip
|
83
91
|
end
|
@@ -91,129 +99,188 @@ class Morpheus::Cli::VirtualImages
|
|
91
99
|
if images.empty?
|
92
100
|
print cyan,"No virtual images found.",reset,"\n"
|
93
101
|
else
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
102
|
+
virtual_image_column_definitions = {
|
103
|
+
"ID" => 'id',
|
104
|
+
"Name" => 'name',
|
105
|
+
"Type" => lambda {|it|
|
106
|
+
# yick, api should return the type with every virtualImage
|
107
|
+
image_type = virtual_image_type_for_name_or_code(it['imageType'])
|
108
|
+
image_type ? "#{image_type['name']}" : it['imageType']
|
109
|
+
},
|
110
|
+
"Operating System" => lambda {|it| it['osType'] ? it['osType']['name'] : "" },
|
111
|
+
"Storage" => lambda {|it| !it['storageProvider'].nil? ? it['storageProvider']['name'] : 'Default' },
|
112
|
+
"Size" => lambda {|it| it['rawSize'].nil? ? 'Unknown' : "#{Filesize.from("#{it['rawSize']} B").pretty}" },
|
113
|
+
"Visibility" => lambda {|it| it['visibility'] },
|
114
|
+
# "Tenant" => lambda {|it| it['account'].instance_of?(Hash) ? it['account']['name'] : it['ownerId'] },
|
115
|
+
"Tenants" => lambda {|it| format_list(it['accounts'].collect {|a| a['name'] }, '', 3) rescue '' },
|
116
|
+
"Source" => lambda {|it| format_virtual_image_source(it) },
|
117
|
+
"Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
118
|
+
"Updated" => lambda {|it| format_local_dt(it['lastUpdated']) },
|
119
|
+
"Tags" => lambda {|it| it['tags'] ? it['tags'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
|
120
|
+
}
|
121
|
+
if json_response['multiTenant'] != true
|
122
|
+
virtual_image_column_definitions.delete("Visibility")
|
123
|
+
virtual_image_column_definitions.delete("Tenants")
|
124
|
+
end
|
125
|
+
if options[:details] != true
|
126
|
+
virtual_image_column_definitions.delete("Tags")
|
127
|
+
virtual_image_column_definitions.delete("Created")
|
128
|
+
virtual_image_column_definitions.delete("Updated")
|
98
129
|
end
|
99
|
-
|
100
|
-
columns = options[:include_fields] if options[:include_fields]
|
101
|
-
print cyan
|
102
|
-
print as_pretty_table(rows, columns, options)
|
130
|
+
print as_pretty_table(images, virtual_image_column_definitions.upcase_keys!, options)
|
103
131
|
print_results_pagination(json_response)
|
104
132
|
end
|
105
133
|
print reset,"\n"
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
134
|
+
end
|
135
|
+
if images.empty?
|
136
|
+
return -1, "no virtual images found"
|
137
|
+
else
|
138
|
+
return 0, nil
|
111
139
|
end
|
112
140
|
end
|
113
141
|
|
114
142
|
def get(args)
|
143
|
+
params = {}
|
115
144
|
options = {}
|
116
|
-
show_details = false
|
117
145
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
118
|
-
opts.banner = subcommand_usage("[
|
119
|
-
opts.on('--details', "Show more details." ) do
|
120
|
-
|
121
|
-
end
|
122
|
-
|
123
|
-
|
124
|
-
|
146
|
+
opts.banner = subcommand_usage("[image]")
|
147
|
+
opts.on('-a', '--details', "Show more details." ) do
|
148
|
+
options[:details] = true
|
149
|
+
end
|
150
|
+
opts.on('--tags LIST', String, "Metadata tags in the format 'name:value, name:value'") do |val|
|
151
|
+
options[:tags] = val
|
152
|
+
end
|
153
|
+
build_standard_get_options(opts, options)
|
154
|
+
opts.footer = <<-EOT
|
155
|
+
Get details about a virtual image.
|
156
|
+
[image] is required. This is the name or id of a virtual image.
|
157
|
+
EOT
|
125
158
|
end
|
126
159
|
optparse.parse!(args)
|
127
|
-
|
128
|
-
puts optparse
|
129
|
-
exit 1
|
130
|
-
end
|
131
|
-
image_name = args[0]
|
160
|
+
verify_args!(args:args, optparse:optparse, min:1)
|
132
161
|
connect(options)
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
162
|
+
id_list = parse_id_list(args)
|
163
|
+
# lookup IDs if names are given
|
164
|
+
id_list = id_list.collect do |id|
|
165
|
+
if id.to_s =~ /\A\d{1,}\Z/
|
166
|
+
id
|
167
|
+
else
|
168
|
+
image = find_virtual_image_by_name_or_id(id)
|
169
|
+
if image
|
170
|
+
image['id']
|
138
171
|
else
|
139
|
-
|
172
|
+
raise_command_error "virtual image not found for name '#{id}'"
|
140
173
|
end
|
141
|
-
return
|
142
|
-
end
|
143
|
-
image = find_virtual_image_by_name_or_id(image_name)
|
144
|
-
return 1 if image.nil?
|
145
|
-
# refetch
|
146
|
-
json_response = @virtual_images_interface.get(image['id'])
|
147
|
-
if options[:json]
|
148
|
-
puts as_json(json_response, options, "virtualImage")
|
149
|
-
return 0
|
150
|
-
elsif options[:yaml]
|
151
|
-
puts as_yaml(json_response, options, "virtualImage")
|
152
|
-
return 0
|
153
|
-
elsif options[:csv]
|
154
|
-
puts records_as_csv([json_response["virtualImage"]], options)
|
155
|
-
return 0
|
156
174
|
end
|
175
|
+
end
|
176
|
+
return run_command_for_each_arg(id_list) do |arg|
|
177
|
+
_get(arg, params, options)
|
178
|
+
end
|
179
|
+
end
|
157
180
|
|
181
|
+
def _get(id, params, options)
|
182
|
+
@virtual_images_interface.setopts(options)
|
183
|
+
if options[:dry_run]
|
184
|
+
print_dry_run @virtual_images_interface.dry.get(id.to_i)
|
185
|
+
return
|
186
|
+
end
|
187
|
+
json_response = @virtual_images_interface.get(id.to_i)
|
158
188
|
image = json_response['virtualImage']
|
189
|
+
image_config = image['config'] || {}
|
190
|
+
image_volumes = image['volumes'] || []
|
159
191
|
image_files = json_response['cloudFiles'] || json_response['files']
|
160
|
-
|
161
|
-
|
162
192
|
image_type = virtual_image_type_for_name_or_code(image['imageType'])
|
163
193
|
image_type_display = image_type ? "#{image_type['name']}" : image['imageType']
|
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
|
-
|
194
|
+
render_response(json_response, options, 'virtualImage') do
|
195
|
+
print_h1 "Virtual Image Details", [], options
|
196
|
+
description_cols = {
|
197
|
+
"ID" => 'id',
|
198
|
+
"Name" => 'name',
|
199
|
+
"Type" => lambda {|it| image_type_display },
|
200
|
+
"Operating System" => lambda {|it| it['osType'] ? it['osType']['name'] : "" },
|
201
|
+
"Storage" => lambda {|it| !image['storageProvider'].nil? ? image['storageProvider']['name'] : 'Default' },
|
202
|
+
"Size" => lambda {|it| image['rawSize'].nil? ? 'Unknown' : "#{Filesize.from("#{image['rawSize']} B").pretty}" },
|
203
|
+
"Azure Publisher" => lambda {|it| image_config['publisher'] },
|
204
|
+
"Azure Offer" => lambda {|it| image_config['offer'] },
|
205
|
+
"Azure Sku" => lambda {|it| image_config['sku'] },
|
206
|
+
"Azure Version" => lambda {|it| image_config['version'] },
|
207
|
+
"Source" => lambda {|it| format_virtual_image_source(it) },
|
208
|
+
"Tags" => lambda {|it| it['tags'] ? it['tags'].collect {|m| "#{m['name']}: #{m['value']}" }.join(', ') : '' },
|
209
|
+
"Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
210
|
+
"Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
|
211
|
+
}
|
212
|
+
description_cols.delete("Tags") if image['tags'].nil? || image['tags'].empty?
|
213
|
+
if image['imageType'] == "azure-reference" || image['imageType'] == "azure"
|
214
|
+
description_cols.delete("Size")
|
215
|
+
description_cols.delete("Storage")
|
216
|
+
description_cols["Source"] = lambda {|it| "#{bold}#{cyan}AZURE#{reset}#{cyan}" }
|
217
|
+
else
|
218
|
+
description_cols.delete("Azure Publisher")
|
219
|
+
description_cols.delete("Azure Sku")
|
220
|
+
description_cols.delete("Azure Offer")
|
221
|
+
description_cols.delete("Azure Version")
|
222
|
+
end
|
223
|
+
advanced_description_cols = {
|
224
|
+
#"OS Type" => lambda {|it| it['osType'] ? it['osType']['name'] : "" }, # displayed above as Operating System
|
225
|
+
"Min Memory" => lambda {|it| it['minRam'].to_i != 0 ? Filesize.from("#{it['minRam']} B").pretty : "" },
|
226
|
+
"Min Disk" => lambda {|it| it['minDisk'].to_i != 0 ? Filesize.from("#{it['minDisk']} B").pretty : "" },
|
227
|
+
"Cloud Init?" => lambda {|it| format_boolean it['osType'] },
|
228
|
+
"Install Agent?" => lambda {|it| format_boolean it['osType'] },
|
229
|
+
"SSH Username" => lambda {|it| it['sshUsername'] },
|
230
|
+
"SSH Password" => lambda {|it| it['sshPassword'] },
|
231
|
+
"User Data" => lambda {|it| it['userData'] },
|
232
|
+
"Owner" => lambda {|it| it['tenant'].instance_of?(Hash) ? it['tenant']['name'] : it['ownerId'] },
|
233
|
+
"Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
|
234
|
+
"Tenants" => lambda {|it| format_tenants(it['accounts']) },
|
235
|
+
"Auto Join Domain?" => lambda {|it| format_boolean it['isAutoJoinDomain'] },
|
236
|
+
"VirtIO Drivers Loaded?" => lambda {|it| format_boolean it['virtioSupported'] },
|
237
|
+
"VM Tools Installed?" => lambda {|it| format_boolean it['vmToolsInstalled'] },
|
238
|
+
"Force Guest Customization?" => lambda {|it| format_boolean it['isForceCustomization'] },
|
239
|
+
"Trial Version" => lambda {|it| format_boolean it['trialVersion'] },
|
240
|
+
"Sysprep Enabled?" => lambda {|it| format_boolean it['isSysprep'] },
|
241
|
+
}
|
242
|
+
if options[:details]
|
243
|
+
description_cols.merge!(advanced_description_cols)
|
244
|
+
end
|
245
|
+
print_description_list(description_cols, image)
|
246
|
+
|
247
|
+
if image_volumes && !image_volumes.empty?
|
248
|
+
print_h2 "Volumes", options
|
249
|
+
image_volume_rows = image_volumes.collect do |image_volume|
|
250
|
+
{name: image_volume['name'], size: Filesize.from("#{image_volume['rawSize']} B").pretty}
|
251
|
+
end
|
252
|
+
print cyan
|
253
|
+
print as_pretty_table(image_volume_rows, [:name, :size])
|
254
|
+
print cyan
|
255
|
+
# print "\n", reset
|
207
256
|
end
|
208
|
-
|
209
|
-
|
210
|
-
|
257
|
+
|
258
|
+
if image_files
|
259
|
+
print_h2 "Files (#{image_files.size})"
|
260
|
+
# image_files.each {|image_file|
|
261
|
+
# pretty_filesize = Filesize.from("#{image_file['size']} B").pretty
|
262
|
+
# print cyan," = #{image_file['name']} [#{pretty_filesize}]", "\n"
|
263
|
+
# }
|
264
|
+
# size property changed to GB to match volumes
|
265
|
+
# contentLength is bytes
|
266
|
+
image_file_rows = image_files.collect do |image_file|
|
267
|
+
{filename: image_file['name'], size: Filesize.from("#{image_file['contentLength'] || image_file['size']} B").pretty}
|
268
|
+
end
|
269
|
+
print cyan
|
270
|
+
print as_pretty_table(image_file_rows, [:filename, :size])
|
271
|
+
# print reset,"\n"
|
272
|
+
end
|
273
|
+
|
274
|
+
if options[:details] && image_config && !image_config.empty?
|
275
|
+
print_h2 "Config", options
|
276
|
+
print cyan
|
277
|
+
print as_description_list(image_config, image_config.keys, options)
|
278
|
+
# print "\n", reset
|
279
|
+
end
|
280
|
+
|
281
|
+
print reset,"\n"
|
211
282
|
end
|
212
|
-
|
213
|
-
rescue RestClient::Exception => e
|
214
|
-
print_rest_exception(e, options)
|
215
|
-
exit 1
|
216
|
-
end
|
283
|
+
return 0, nil
|
217
284
|
end
|
218
285
|
|
219
286
|
def update(args)
|
@@ -229,60 +296,68 @@ class Morpheus::Cli::VirtualImages
|
|
229
296
|
tenants_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
230
297
|
end
|
231
298
|
end
|
299
|
+
opts.on('--tags LIST', String, "Tags in the format 'name:value, name:value'. This will add and remove tags.") do |val|
|
300
|
+
options[:tags] = val
|
301
|
+
end
|
302
|
+
opts.on('--add-tags TAGS', String, "Add Tags in the format 'name:value, name:value'. This will only add/update project tags.") do |val|
|
303
|
+
options[:add_tags] = val
|
304
|
+
end
|
305
|
+
opts.on('--remove-tags TAGS', String, "Remove Tags in the format 'name, name:value'. This removes tags, the :value component is optional and must match if passed.") do |val|
|
306
|
+
options[:remove_tags] = val
|
307
|
+
end
|
232
308
|
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
233
309
|
opts.footer = "Update a virtual image." + "\n" +
|
234
310
|
"[name] is required. This is the name or id of a virtual image."
|
235
311
|
end
|
236
312
|
optparse.parse!(args)
|
237
|
-
|
238
|
-
puts optparse
|
239
|
-
exit 1
|
240
|
-
end
|
313
|
+
verify_args!(args:args, optparse:optparse, count:1)
|
241
314
|
|
242
315
|
connect(options)
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
316
|
+
|
317
|
+
virtual_image = find_virtual_image_by_name_or_id(image_name)
|
318
|
+
return 1 if virtual_image.nil?
|
319
|
+
|
320
|
+
passed_options = parse_passed_options(options)
|
321
|
+
payload = nil
|
322
|
+
if options[:payload]
|
323
|
+
payload = options[:payload]
|
324
|
+
payload.deep_merge!({virtual_image_object_key => passed_options}) unless passed_options.empty?
|
325
|
+
else
|
326
|
+
virtual_image_payload = passed_options
|
327
|
+
if tenants_list
|
328
|
+
virtual_image_payload['accounts'] = tenants_list
|
329
|
+
end
|
330
|
+
# metadata tags
|
331
|
+
if options[:tags]
|
332
|
+
virtual_image_payload['tags'] = parse_metadata(options[:tags])
|
255
333
|
else
|
256
|
-
|
257
|
-
|
258
|
-
puts optparse
|
259
|
-
option_lines = update_virtual_image_option_types().collect {|it| "\t-O #{it['fieldContext'] ? (it['fieldContext'] + '.') : ''}#{it['fieldName']}=\"value\"" }.join("\n")
|
260
|
-
puts "\nAvailable Options:\n#{option_lines}\n\n"
|
261
|
-
exit 1
|
262
|
-
end
|
263
|
-
if tenants_list
|
264
|
-
params['accounts'] = tenants_list
|
265
|
-
end
|
266
|
-
payload = {'virtualImage' => params}
|
334
|
+
# tags = prompt_metadata(options)
|
335
|
+
# payload[virtual_image_object_key]['tags'] = tags of tags
|
267
336
|
end
|
268
|
-
|
269
|
-
if options[:
|
270
|
-
|
271
|
-
return
|
337
|
+
# metadata tags
|
338
|
+
if options[:add_tags]
|
339
|
+
virtual_image_payload['addTags'] = parse_metadata(options[:add_tags])
|
272
340
|
end
|
273
|
-
|
274
|
-
|
275
|
-
print JSON.pretty_generate(json_response)
|
276
|
-
if !response['success']
|
277
|
-
exit 1
|
278
|
-
end
|
279
|
-
else
|
280
|
-
print "\n", cyan, "Virtual Image #{image['name']} updated", reset, "\n\n"
|
341
|
+
if options[:remove_tags]
|
342
|
+
virtual_image_payload['removeTags'] = parse_metadata(options[:remove_tags])
|
281
343
|
end
|
282
|
-
|
283
|
-
|
284
|
-
|
344
|
+
if virtual_image_payload.empty?
|
345
|
+
raise_command_error "Specify at least one option to update.\n#{optparse}"
|
346
|
+
end
|
347
|
+
payload = {'virtualImage' => virtual_image_payload}
|
348
|
+
end
|
349
|
+
@virtual_images_interface.setopts(options)
|
350
|
+
if options[:dry_run]
|
351
|
+
print_dry_run @virtual_images_interface.dry.update(virtual_image['id'], payload)
|
352
|
+
return
|
353
|
+
end
|
354
|
+
json_response = @virtual_images_interface.update(virtual_image['id'], payload)
|
355
|
+
render_response(json_response, options, 'virtualImage') do
|
356
|
+
print_green_success "Updated virtual image #{virtual_image['name']}"
|
357
|
+
_get(virtual_image["id"], {}, options)
|
285
358
|
end
|
359
|
+
return 0, nil
|
360
|
+
|
286
361
|
end
|
287
362
|
|
288
363
|
def virtual_image_types(args)
|
@@ -339,6 +414,19 @@ class Morpheus::Cli::VirtualImages
|
|
339
414
|
opts.on( '-U', '--url URL', "Image File URL. This can be used instead of uploading local files." ) do |val|
|
340
415
|
file_url = val
|
341
416
|
end
|
417
|
+
opts.on( '-c', '--cloud CLOUD', "Cloud to scope image to, certain types require a cloud to be selected, eg. Azure Reference" ) do |val|
|
418
|
+
# options[:cloud] = val
|
419
|
+
options[:options]['cloud'] = val
|
420
|
+
end
|
421
|
+
opts.on( '--azure-offer OFFER', String, "Azure Reference offer value, only applies to Azure Reference" ) do |val|
|
422
|
+
options[:options]['offer'] = val
|
423
|
+
end
|
424
|
+
opts.on( '--azure-sku SKU', String, "Azure SKU value, only applies to Azure Reference" ) do |val|
|
425
|
+
options[:options]['sku'] = val
|
426
|
+
end
|
427
|
+
opts.on( '--azure-version VERSION', String, "Azure Version value, only applies to Azure Reference" ) do |val|
|
428
|
+
options[:options]['version'] = val
|
429
|
+
end
|
342
430
|
opts.on('--tenants LIST', Array, "Tenant Access, comma separated list of account IDs") do |list|
|
343
431
|
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
344
432
|
tenants_list = []
|
@@ -346,7 +434,13 @@ class Morpheus::Cli::VirtualImages
|
|
346
434
|
tenants_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
347
435
|
end
|
348
436
|
end
|
349
|
-
|
437
|
+
opts.on('--tags LIST', String, "Metadata tags in the format 'name:value, name:value'") do |val|
|
438
|
+
options[:tags] = val
|
439
|
+
end
|
440
|
+
# build_option_type_options(opts, options, add_virtual_image_option_types)
|
441
|
+
# build_option_type_options(opts, options, add_virtual_image_advanced_option_types)
|
442
|
+
build_standard_add_options(opts, options)
|
443
|
+
|
350
444
|
opts.footer = "Create a virtual image."
|
351
445
|
end
|
352
446
|
optparse.parse!(args)
|
@@ -368,26 +462,43 @@ class Morpheus::Cli::VirtualImages
|
|
368
462
|
options[:options]['name'] ||= image_name
|
369
463
|
end
|
370
464
|
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
465
|
+
payload = {}
|
466
|
+
if options[:payload]
|
467
|
+
payload = options[:payload]
|
468
|
+
payload.deep_merge!({'virtualImage' => parse_passed_options(options)})
|
469
|
+
else
|
470
|
+
payload.deep_merge!({'virtualImage' => parse_passed_options(options)})
|
471
|
+
virtual_image_payload = {}
|
472
|
+
# v_prompt = Morpheus::Cli::OptionTypes.prompt(add_virtual_image_option_types, options[:options], @api_client, options[:params])
|
473
|
+
if image_type_name
|
474
|
+
image_type = virtual_image_type_for_name_or_code(image_type_name)
|
475
|
+
# fix issue with api returning imageType vmware instead of vmdk
|
476
|
+
if image_type.nil? && image_type_name == 'vmware'
|
477
|
+
image_type = virtual_image_type_for_name_or_code('vmdk')
|
478
|
+
elsif image_type.nil? && image_type_name == 'vmdk'
|
479
|
+
image_type = virtual_image_type_for_name_or_code('vmware')
|
480
|
+
end
|
481
|
+
if image_type.nil?
|
482
|
+
print_red_alert "Virtual Image Type not found by code '#{image_type_name}'"
|
483
|
+
return 1
|
484
|
+
end
|
485
|
+
# options[:options] ||= {}
|
486
|
+
# options[:options]['imageType'] ||= image_type['code']
|
487
|
+
else
|
488
|
+
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,{})
|
489
|
+
image_type = virtual_image_type_for_name_or_code(image_type_prompt['imageType'])
|
378
490
|
end
|
379
|
-
|
380
|
-
|
381
|
-
|
491
|
+
|
492
|
+
# azure requires us to search the marketplace to select publisher, cloud, offerm sku
|
493
|
+
if image_type['code'] == "azure-reference" || image_type['code'] == "azure"
|
494
|
+
cloud_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'cloud', 'fieldLabel' => 'Cloud', 'type' => 'select', 'optionSource' => 'clouds', 'required' => true, 'description' => 'Select Azure Cloud.', :fmt=>:natural}],options[:options],@api_client, {zoneTypeWhiteList: 'azure'})
|
495
|
+
cloud_id = cloud_prompt['cloud'].to_i
|
496
|
+
|
497
|
+
marketplace_config = prompt_azure_marketplace(cloud_id, options)
|
498
|
+
virtual_image_payload['config'] ||= {}
|
499
|
+
virtual_image_payload['config'].deep_merge!(marketplace_config)
|
382
500
|
end
|
383
|
-
# options[:options] ||= {}
|
384
|
-
# options[:options]['imageType'] ||= image_type['code']
|
385
|
-
else
|
386
|
-
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,{})
|
387
|
-
image_type = virtual_image_type_for_name_or_code(image_type_prompt['imageType'])
|
388
|
-
end
|
389
501
|
|
390
|
-
begin
|
391
502
|
my_option_types = add_virtual_image_option_types(image_type, !file_url)
|
392
503
|
# if options[:no_prompt]
|
393
504
|
# my_option_types.each do |it|
|
@@ -396,9 +507,9 @@ class Morpheus::Cli::VirtualImages
|
|
396
507
|
# end
|
397
508
|
# end
|
398
509
|
# end
|
399
|
-
|
400
|
-
|
401
|
-
virtual_image_payload
|
510
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt(my_option_types, options[:options], @api_client, options[:params])
|
511
|
+
v_prompt.deep_compact!
|
512
|
+
virtual_image_payload.deep_merge!(v_prompt)
|
402
513
|
virtual_image_files = virtual_image_payload.delete('virtualImageFiles')
|
403
514
|
virtual_image_payload['imageType'] = image_type['code']
|
404
515
|
storage_provider_id = virtual_image_payload.delete('storageProviderId')
|
@@ -408,65 +519,74 @@ class Morpheus::Cli::VirtualImages
|
|
408
519
|
if tenants_list
|
409
520
|
virtual_image_payload['accounts'] = tenants_list
|
410
521
|
end
|
522
|
+
# metadata tags
|
523
|
+
if options[:tags]
|
524
|
+
tags = parse_metadata(options[:tags])
|
525
|
+
virtual_image_payload['tags'] = tags if tags
|
526
|
+
else
|
527
|
+
# tags = prompt_metadata(options)
|
528
|
+
# virtual_image_payload['tags'] = tags of tags
|
529
|
+
end
|
411
530
|
# fix issue with api returning imageType vmware instead of vmdk
|
412
531
|
if virtual_image_payload && virtual_image_payload['imageType'] == 'vmware'
|
413
532
|
virtual_image_payload['imageType'] == 'vmdk'
|
414
533
|
end
|
415
|
-
payload = {virtualImage
|
416
|
-
|
417
|
-
|
418
|
-
print_dry_run @virtual_images_interface.dry.create(payload)
|
419
|
-
if file_url
|
420
|
-
print_dry_run @virtual_images_interface.dry.upload_by_url(":id", file_url, file_name)
|
421
|
-
elsif virtual_image_files && !virtual_image_files.empty?
|
422
|
-
virtual_image_files.each do |key, filepath|
|
423
|
-
print_dry_run @virtual_images_interface.dry.upload(":id", "(Contents of file #{filepath})")
|
424
|
-
end
|
425
|
-
end
|
426
|
-
return
|
427
|
-
end
|
428
|
-
|
429
|
-
json_response = @virtual_images_interface.create(payload)
|
430
|
-
virtual_image = json_response['virtualImage']
|
431
|
-
|
432
|
-
if options[:json]
|
433
|
-
print JSON.pretty_generate(json_response)
|
434
|
-
elsif !options[:quiet]
|
435
|
-
print "\n", cyan, "Virtual Image #{virtual_image['name']} created successfully", reset, "\n\n"
|
436
|
-
end
|
534
|
+
#payload = {'virtualImage' => virtual_image_payload}
|
535
|
+
payload.deep_merge!({'virtualImage' => virtual_image_payload})
|
536
|
+
end
|
437
537
|
|
438
|
-
|
538
|
+
@virtual_images_interface.setopts(options)
|
539
|
+
if options[:dry_run]
|
540
|
+
print_dry_run @virtual_images_interface.dry.create(payload)
|
439
541
|
if file_url
|
440
|
-
|
441
|
-
print cyan, "Uploading file by url #{file_url} ...", reset, "\n"
|
442
|
-
end
|
443
|
-
upload_json_response = @virtual_images_interface.upload_by_url(virtual_image['id'], file_url, file_name)
|
444
|
-
if options[:json]
|
445
|
-
print JSON.pretty_generate(upload_json_response)
|
446
|
-
end
|
542
|
+
print_dry_run @virtual_images_interface.dry.upload_by_url(":id", file_url, file_name)
|
447
543
|
elsif virtual_image_files && !virtual_image_files.empty?
|
448
544
|
virtual_image_files.each do |key, filepath|
|
449
|
-
|
450
|
-
print cyan, "Uploading file (#{key}) #{filepath} ...", reset, "\n"
|
451
|
-
end
|
452
|
-
image_file = File.new(filepath, 'rb')
|
453
|
-
upload_json_response = @virtual_images_interface.upload(virtual_image['id'], image_file, file_name)
|
454
|
-
if options[:json]
|
455
|
-
print JSON.pretty_generate(upload_json_response)
|
456
|
-
end
|
545
|
+
print_dry_run @virtual_images_interface.dry.upload(":id", "(Contents of file #{filepath})")
|
457
546
|
end
|
458
|
-
else
|
459
|
-
puts cyan, "No files uploaded.", reset
|
460
547
|
end
|
548
|
+
return
|
549
|
+
end
|
550
|
+
|
551
|
+
json_response = @virtual_images_interface.create(payload)
|
552
|
+
virtual_image = json_response['virtualImage']
|
553
|
+
|
554
|
+
# if options[:json]
|
555
|
+
# print JSON.pretty_generate(json_response)
|
556
|
+
# elsif !options[:quiet]
|
557
|
+
# print "\n", cyan, "Virtual Image #{virtual_image['name']} created successfully", reset, "\n\n"
|
558
|
+
# end
|
461
559
|
|
462
|
-
|
463
|
-
|
560
|
+
# now upload the file, do this in the background maybe?
|
561
|
+
if file_url
|
562
|
+
unless options[:quiet]
|
563
|
+
print cyan, "Uploading file by url #{file_url} ...", reset, "\n"
|
564
|
+
end
|
565
|
+
upload_json_response = @virtual_images_interface.upload_by_url(virtual_image['id'], file_url, file_name)
|
566
|
+
# if options[:json]
|
567
|
+
# print JSON.pretty_generate(upload_json_response)
|
568
|
+
# end
|
569
|
+
elsif virtual_image_files && !virtual_image_files.empty?
|
570
|
+
virtual_image_files.each do |key, filepath|
|
571
|
+
unless options[:quiet]
|
572
|
+
print cyan, "Uploading file (#{key}) #{filepath} ...", reset, "\n"
|
573
|
+
end
|
574
|
+
image_file = File.new(filepath, 'rb')
|
575
|
+
upload_json_response = @virtual_images_interface.upload(virtual_image['id'], image_file, file_name)
|
576
|
+
# if options[:json]
|
577
|
+
# print JSON.pretty_generate(upload_json_response)
|
578
|
+
# end
|
464
579
|
end
|
580
|
+
else
|
581
|
+
# puts cyan, "No files uploaded.", reset
|
582
|
+
end
|
465
583
|
|
466
|
-
|
467
|
-
|
468
|
-
|
584
|
+
render_response(json_response, options, 'virtualImage') do
|
585
|
+
print_green_success "Added virtual image #{virtual_image['name']}"
|
586
|
+
return _get(virtual_image["id"], {}, options)
|
469
587
|
end
|
588
|
+
return 0, nil
|
589
|
+
|
470
590
|
end
|
471
591
|
|
472
592
|
def add_file(args)
|
@@ -676,16 +796,17 @@ class Morpheus::Cli::VirtualImages
|
|
676
796
|
tmp_option_types = [
|
677
797
|
{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
|
678
798
|
#{'fieldName' => 'imageType', 'fieldLabel' => 'Image Type', 'type' => 'select', 'optionSource' => 'virtualImageTypes', 'required' => true, 'description' => 'Select Virtual Image Type.', 'displayOrder' => 2},
|
679
|
-
{'fieldName' => 'osType', 'fieldLabel' => '
|
680
|
-
{'fieldName' => '
|
681
|
-
{'fieldName' => '
|
682
|
-
{'fieldName' => '
|
683
|
-
{'fieldName' => '
|
684
|
-
{'fieldName' => '
|
685
|
-
{'fieldName' => '
|
799
|
+
{'fieldName' => 'osType', 'fieldLabel' => 'Operating System', 'type' => 'select', 'optionSource' => 'osTypes', 'required' => false, 'description' => 'Select Operating System.', 'displayOrder' => 3},
|
800
|
+
{'fieldName' => 'minRamGB', 'fieldLabel' => 'Minimum Memory (GB)', 'type' => 'number', 'required' => false, 'description' => 'Minimum Memory (GB)', 'displayOrder' => 4},
|
801
|
+
# {'fieldName' => 'minDiskGB', 'fieldLabel' => 'Minimum Disk (GB)', 'type' => 'number', 'required' => false, 'description' => 'Minimum Memory (GB)', 'displayOrder' => 4},
|
802
|
+
{'fieldName' => 'isCloudInit', 'fieldLabel' => 'Cloud Init Enabled?', 'type' => 'checkbox', 'defaultValue' => 'off', 'required' => false, 'description' => 'Cloud Init Enabled?', 'displayOrder' => 5},
|
803
|
+
{'fieldName' => 'installAgent', 'fieldLabel' => 'Install Agent?', 'type' => 'checkbox', 'defaultValue' => 'off', 'required' => false, 'description' => 'Install Agent?', 'displayOrder' => 6},
|
804
|
+
{'fieldName' => 'sshUsername', 'fieldLabel' => 'SSH Username', 'type' => 'text', 'required' => false, 'description' => 'Enter an SSH Username', 'displayOrder' => 7},
|
805
|
+
{'fieldName' => 'sshPassword', 'fieldLabel' => 'SSH Password', 'type' => 'password', 'required' => false, 'description' => 'Enter an SSH Password', 'displayOrder' => 8},
|
806
|
+
{'fieldName' => 'storageProviderId', 'type' => 'select', 'fieldLabel' => 'Storage Provider', 'optionSource' => 'storageProviders', 'required' => false, 'description' => 'Select Storage Provider.', 'displayOrder' => 9},
|
686
807
|
{'fieldName' => 'userData', 'fieldLabel' => 'Cloud-Init User Data', 'type' => 'textarea', 'required' => false, 'displayOrder' => 10},
|
687
808
|
{'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},
|
688
|
-
{'fieldName' => 'isAutoJoinDomain', 'fieldLabel' => 'Auto Join Domain?', 'type' => 'checkbox', 'required' => false, 'description' => 'Auto Join Domain?', 'category' => 'advanced', 'displayOrder' => 40},
|
809
|
+
{'fieldName' => 'isAutoJoinDomain', 'fieldLabel' => 'Auto Join Domain?', 'type' => 'checkbox', 'defaultValue' => 'off', 'required' => false, 'description' => 'Auto Join Domain?', 'category' => 'advanced', 'displayOrder' => 40},
|
689
810
|
{'fieldName' => 'virtioSupported', 'fieldLabel' => 'VirtIO Drivers Loaded?', 'type' => 'checkbox', 'defaultValue' => 'on', 'required' => false, 'description' => 'VirtIO Drivers Loaded?', 'category' => 'advanced', 'displayOrder' => 40},
|
690
811
|
{'fieldName' => 'vmToolsInstalled', 'fieldLabel' => 'VM Tools Installed?', 'type' => 'checkbox', 'defaultValue' => 'on', 'required' => false, 'description' => 'VM Tools Installed?', 'category' => 'advanced', 'displayOrder' => 40},
|
691
812
|
{'fieldName' => 'isForceCustomization', 'fieldLabel' => 'Force Guest Customization?', 'type' => 'checkbox', 'defaultValue' => 'off', 'required' => false, 'description' => 'Force Guest Customization?', 'category' => 'advanced', 'displayOrder' => 40},
|
@@ -696,22 +817,25 @@ class Morpheus::Cli::VirtualImages
|
|
696
817
|
image_type_code = image_type ? image_type['code'] : nil
|
697
818
|
if image_type_code
|
698
819
|
if image_type_code == 'ami'
|
699
|
-
tmp_option_types << {'fieldName' => 'externalId', 'fieldLabel' => 'AMI id', 'type' => 'text', 'required' => false, 'displayOrder' =>
|
820
|
+
tmp_option_types << {'fieldName' => 'externalId', 'fieldLabel' => 'AMI id', 'type' => 'text', 'required' => false, 'displayOrder' => 11}
|
700
821
|
if include_file_selection
|
701
|
-
tmp_option_types << {'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => false, 'displayOrder' =>
|
822
|
+
tmp_option_types << {'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => false, 'displayOrder' => 12}
|
702
823
|
end
|
703
824
|
elsif image_type_code == 'vmware' || image_type_code == 'vmdk'
|
704
825
|
if include_file_selection
|
705
|
-
tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageFile', 'fieldLabel' => 'OVF File', 'type' => 'file', 'required' => false, 'displayOrder' =>
|
706
|
-
tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageDescriptorFile', 'fieldLabel' => 'VMDK File', 'type' => 'file', 'required' => false, 'displayOrder' =>
|
826
|
+
tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageFile', 'fieldLabel' => 'OVF File', 'type' => 'file', 'required' => false, 'displayOrder' => 11}
|
827
|
+
tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageDescriptorFile', 'fieldLabel' => 'VMDK File', 'type' => 'file', 'required' => false, 'displayOrder' => 12}
|
707
828
|
end
|
708
829
|
elsif image_type_code == 'pxe'
|
709
|
-
tmp_option_types << {'fieldName' => 'config.menu', 'fieldLabel' => 'Menu', 'type' => 'text', 'required' => false, 'displayOrder' =>
|
710
|
-
tmp_option_types << {'fieldName' => 'imagePath', 'fieldLabel' => 'Image Path', 'type' => 'text', 'required' => true, 'displayOrder' =>
|
830
|
+
tmp_option_types << {'fieldName' => 'config.menu', 'fieldLabel' => 'Menu', 'type' => 'text', 'required' => false, 'displayOrder' => 11}
|
831
|
+
tmp_option_types << {'fieldName' => 'imagePath', 'fieldLabel' => 'Image Path', 'type' => 'text', 'required' => true, 'displayOrder' => 12}
|
711
832
|
tmp_option_types.reject! {|opt| ['isCloudInit', 'installAgent', 'sshUsername', 'sshPassword'].include?(opt['fieldName'])}
|
833
|
+
elsif image_type_code == 'azure' || image_type_code == 'azure-reference'
|
834
|
+
# Azure Marketplace Prompt happens elsewhere
|
835
|
+
tmp_option_types.reject! {|opt| ['storageProviderId', 'userData', 'sshUsername', 'sshPassword'].include?(opt['fieldName'])}
|
712
836
|
else
|
713
837
|
if include_file_selection
|
714
|
-
tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => false, 'description' => 'Choose an image file to upload', 'displayOrder' =>
|
838
|
+
tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => false, 'description' => 'Choose an image file to upload', 'displayOrder' => 11}
|
715
839
|
end
|
716
840
|
end
|
717
841
|
end
|
@@ -721,7 +845,10 @@ class Morpheus::Cli::VirtualImages
|
|
721
845
|
|
722
846
|
def update_virtual_image_option_types(image_type = nil)
|
723
847
|
list = add_virtual_image_option_types(image_type)
|
724
|
-
list.each {|it|
|
848
|
+
list.each {|it|
|
849
|
+
it.delete('required')
|
850
|
+
it.delete('defaultValue')
|
851
|
+
}
|
725
852
|
list
|
726
853
|
end
|
727
854
|
|
@@ -735,5 +862,53 @@ class Morpheus::Cli::VirtualImages
|
|
735
862
|
""
|
736
863
|
end
|
737
864
|
end
|
865
|
+
|
866
|
+
def prompt_azure_marketplace(cloud_id, options)
|
867
|
+
rtn = {}
|
868
|
+
publisher_value, offer_value, sku_value, version_value = nil, nil, nil, nil
|
869
|
+
|
870
|
+
# Marketplace Publisher & Offer
|
871
|
+
marketplace_api_params = {'zoneId' => cloud_id}
|
872
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'offer', 'fieldLabel' => 'Azure Marketplace Offer', 'type' => 'typeahead', 'optionSource' => 'searchAzureMarketplace', 'required' => true, 'description' => "Select Azure Marketplace Offer."}], options[:options],@api_client, marketplace_api_params)
|
873
|
+
# offer_value = v_prompt['marketplace']
|
874
|
+
# actually need both offer and publisher of these to query correctly..sigh
|
875
|
+
marketplace_option = Morpheus::Cli::OptionTypes.get_last_select()
|
876
|
+
offer_value = marketplace_option['offer']
|
877
|
+
publisher_value = marketplace_option['publisher']
|
878
|
+
|
879
|
+
# SKU & VERSION
|
880
|
+
if options[:options] && options[:options]['sku'] && options[:options]['version']
|
881
|
+
# the value to match on is actually sku|version
|
882
|
+
options[:options]['sku'] = options[:options]['sku'] + '|' + options[:options]['version']
|
883
|
+
end
|
884
|
+
sku_api_params = {'zoneId' => cloud_id, publisher: publisher_value, offer: offer_value}
|
885
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'sku', 'fieldLabel' => 'Azure Marketplace SKU', 'type' => 'select', 'optionSource' => 'searchAzureMarketplaceSkus', 'required' => true, 'description' => "Select Azure Marketplace SKU and Version, the format is SKU|Version"}], options[:options],@api_client, sku_api_params)
|
886
|
+
# marketplace_option = Morpheus::Cli::OptionTypes.get_last_select()
|
887
|
+
# sku_value = marketplace_option['sku']
|
888
|
+
# version_value = marketplace_option['version']
|
889
|
+
sku_value = v_prompt['sku']
|
890
|
+
if sku_value && sku_value.include?("|")
|
891
|
+
sku_value, version_value = sku_value.split("|")
|
892
|
+
end
|
893
|
+
|
894
|
+
rtn['publisher'] = publisher_value
|
895
|
+
rtn['offer'] = offer_value
|
896
|
+
rtn['sku'] = sku_value
|
897
|
+
rtn['version'] = version_value
|
898
|
+
return rtn
|
899
|
+
end
|
900
|
+
|
901
|
+
def format_virtual_image_source(virtual_image, return_color=cyan)
|
902
|
+
out = ""
|
903
|
+
if virtual_image['userUploaded']
|
904
|
+
# out << "#{green}UPLOADED#{return_color}"
|
905
|
+
out << "#{cyan}UPLOADED#{return_color}"
|
906
|
+
elsif virtual_image['systemImage']
|
907
|
+
out << "#{cyan}SYSTEM#{return_color}"
|
908
|
+
else
|
909
|
+
out << "#{cyan}SYNCED#{return_color}"
|
910
|
+
end
|
911
|
+
out
|
912
|
+
end
|
738
913
|
|
739
914
|
end
|