morpheus-cli 5.0.0 → 5.0.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/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +12 -0
- data/lib/morpheus/api/billing_interface.rb +1 -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 +7 -0
- data/lib/morpheus/api/search_interface.rb +13 -0
- data/lib/morpheus/api/servers_interface.rb +7 -0
- data/lib/morpheus/api/usage_interface.rb +18 -0
- data/lib/morpheus/cli.rb +4 -1
- data/lib/morpheus/cli/cli_command.rb +26 -9
- data/lib/morpheus/cli/commands/standard/curl_command.rb +3 -5
- 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/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/health_command.rb +2 -2
- data/lib/morpheus/cli/hosts.rb +169 -32
- data/lib/morpheus/cli/instances.rb +83 -32
- data/lib/morpheus/cli/invoices_command.rb +33 -16
- data/lib/morpheus/cli/logs_command.rb +9 -6
- data/lib/morpheus/cli/mixins/deployments_helper.rb +31 -2
- data/lib/morpheus/cli/mixins/print_helper.rb +0 -21
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +24 -4
- data/lib/morpheus/cli/option_types.rb +266 -17
- data/lib/morpheus/cli/remote.rb +35 -10
- data/lib/morpheus/cli/reports_command.rb +99 -30
- data/lib/morpheus/cli/search_command.rb +182 -0
- data/lib/morpheus/cli/setup.rb +1 -1
- data/lib/morpheus/cli/shell.rb +33 -11
- data/lib/morpheus/cli/tasks.rb +20 -21
- data/lib/morpheus/cli/usage_command.rb +64 -11
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/virtual_images.rb +280 -199
- data/lib/morpheus/cli/whoami.rb +6 -6
- data/lib/morpheus/cli/workflows.rb +33 -40
- data/lib/morpheus/formatters.rb +22 -0
- data/lib/morpheus/terminal.rb +6 -2
- metadata +7 -2
data/lib/morpheus/cli/setup.rb
CHANGED
data/lib/morpheus/cli/shell.rb
CHANGED
@@ -92,6 +92,13 @@ class Morpheus::Cli::Shell
|
|
92
92
|
def recalculate_auto_complete_commands
|
93
93
|
@morpheus_commands = Morpheus::Cli::CliRegistry.all.keys.reject {|k| [:shell].include?(k) }
|
94
94
|
@shell_commands = [:clear, :history, :reload, :help, :exit]
|
95
|
+
@shell_command_descriptions = {
|
96
|
+
:clear => "Clear terminal output and move cursor to the top",
|
97
|
+
:history => "View morpheus shell command history",
|
98
|
+
:reload => "Reload the shell, can be useful when developing",
|
99
|
+
:help => "Print this help",
|
100
|
+
:exit => "Exit the morpheus shell"
|
101
|
+
}
|
95
102
|
@alias_commands = Morpheus::Cli::CliRegistry.all_aliases.keys
|
96
103
|
@exploded_commands = []
|
97
104
|
Morpheus::Cli::CliRegistry.all.each do |cmd, klass|
|
@@ -336,6 +343,11 @@ class Morpheus::Cli::Shell
|
|
336
343
|
#Morpheus::Logging::DarkPrinter.puts "Shell command: #{input}"
|
337
344
|
input = input.to_s.strip
|
338
345
|
|
346
|
+
# allow pasting in commands that have 'morpheus ' prefix
|
347
|
+
if input[0..(prog_name.size)] == "#{prog_name} "
|
348
|
+
input = input[(prog_name.size + 1)..-1] || ""
|
349
|
+
end
|
350
|
+
|
339
351
|
if !input.empty?
|
340
352
|
|
341
353
|
if input == 'exit'
|
@@ -345,26 +357,36 @@ class Morpheus::Cli::Shell
|
|
345
357
|
return 0
|
346
358
|
#exit 0
|
347
359
|
elsif input == 'help'
|
360
|
+
out = ""
|
348
361
|
if @temporary_shell_mode
|
349
|
-
|
362
|
+
out << "You are in a (temporary) morpheus shell\n"
|
350
363
|
else
|
351
|
-
|
364
|
+
out << "You are in a morpheus shell.\n"
|
352
365
|
end
|
353
|
-
|
366
|
+
out << "See the available commands below.\n"
|
354
367
|
|
355
|
-
|
368
|
+
out << "\nCommands:"
|
356
369
|
# commands = @morpheus_commands + @shell_commands
|
357
|
-
@morpheus_commands.sort.each {|cmd|
|
358
|
-
|
370
|
+
# @morpheus_commands.sort.each {|cmd|
|
371
|
+
# out << "\t#{cmd.to_s}\n"
|
372
|
+
# }
|
373
|
+
sorted_commands = Morpheus::Cli::CliRegistry.all.values.sort { |x,y| x.command_name.to_s <=> y.command_name.to_s }
|
374
|
+
sorted_commands.each {|cmd|
|
375
|
+
# JD: not ready to show description yet, gotta finish filling in every command first
|
376
|
+
# maybe change 'View and manage' to something more concise like 'Manage'
|
377
|
+
# out << "\t#{cmd.command_name.to_s.ljust(28, ' ')} #{cmd.command_description}\n"
|
378
|
+
out << "\t#{cmd.command_name.to_s}\n"
|
359
379
|
}
|
360
380
|
#puts "\n"
|
361
|
-
|
381
|
+
out << "\nShell Commands:\n"
|
362
382
|
@shell_commands.each {|cmd|
|
363
|
-
|
383
|
+
# out << "\t#{cmd.to_s.ljust(28, ' ')} #{@shell_command_descriptions ? @shell_command_descriptions[cmd] : ''}\n"
|
384
|
+
out << "\t#{cmd.to_s}\n"
|
364
385
|
}
|
365
|
-
|
366
|
-
|
367
|
-
|
386
|
+
out << "\n"
|
387
|
+
out << "For more information, see https://github.com/gomorpheus/morpheus-cli/wiki"
|
388
|
+
out << "\n"
|
389
|
+
print out
|
368
390
|
return 0
|
369
391
|
elsif input =~ /^\s*#/
|
370
392
|
Morpheus::Logging::DarkPrinter.puts "ignored comment: #{input}" if Morpheus::Logging.debug?
|
data/lib/morpheus/cli/tasks.rb
CHANGED
@@ -27,34 +27,31 @@ class Morpheus::Cli::Tasks
|
|
27
27
|
params = {}
|
28
28
|
options = {}
|
29
29
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
30
|
-
opts.banner = subcommand_usage()
|
30
|
+
opts.banner = subcommand_usage("[search]")
|
31
31
|
opts.on('-t', '--type x,y,z', Array, "Filter by task type code(s)") do |val|
|
32
32
|
params['taskTypeCodes'] = val
|
33
33
|
end
|
34
|
-
|
34
|
+
build_standard_list_options(opts, options)
|
35
|
+
opts.footer = "List tasks."
|
35
36
|
end
|
36
37
|
optparse.parse!(args)
|
38
|
+
connect(options)
|
37
39
|
if args.count > 0
|
38
|
-
|
40
|
+
options[:phrase] = args.join(" ")
|
39
41
|
end
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
@tasks_interface.
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
render_result = render_with_format(json_response, options, 'tasks')
|
51
|
-
return 0 if render_result
|
52
|
-
|
42
|
+
params.merge!(parse_list_options(options))
|
43
|
+
@tasks_interface.setopts(options)
|
44
|
+
if options[:dry_run]
|
45
|
+
print_dry_run @tasks_interface.dry.list(params)
|
46
|
+
return
|
47
|
+
end
|
48
|
+
json_response = @tasks_interface.list(params)
|
49
|
+
tasks = json_response['tasks']
|
50
|
+
render_response(json_response, options, 'tasks') do
|
53
51
|
title = "Morpheus Tasks"
|
54
52
|
subtitles = []
|
55
53
|
subtitles += parse_list_subtitles(options)
|
56
54
|
print_h1 title, subtitles
|
57
|
-
tasks = json_response['tasks']
|
58
55
|
if tasks.empty?
|
59
56
|
print cyan,"No tasks found.",reset,"\n"
|
60
57
|
else
|
@@ -63,11 +60,13 @@ class Morpheus::Cli::Tasks
|
|
63
60
|
print_results_pagination(json_response)
|
64
61
|
end
|
65
62
|
print reset,"\n"
|
66
|
-
return 0
|
67
|
-
rescue RestClient::Exception => e
|
68
|
-
print_rest_exception(e, options)
|
69
|
-
exit 1
|
70
63
|
end
|
64
|
+
if tasks.empty?
|
65
|
+
return 1, "no tasks found"
|
66
|
+
else
|
67
|
+
return 0, nil
|
68
|
+
end
|
69
|
+
|
71
70
|
end
|
72
71
|
|
73
72
|
def get(args)
|
@@ -2,18 +2,18 @@ require 'morpheus/cli/cli_command'
|
|
2
2
|
|
3
3
|
# CLI command usages
|
4
4
|
# UI is Costing - Usage
|
5
|
-
# API is /
|
5
|
+
# API is /usage and returns usages
|
6
6
|
class Morpheus::Cli::UsageCommand
|
7
7
|
include Morpheus::Cli::CliCommand
|
8
8
|
include Morpheus::Cli::OptionSourceHelper
|
9
9
|
|
10
10
|
set_command_name :'usage'
|
11
11
|
|
12
|
-
register_subcommands :list
|
12
|
+
register_subcommands :list, :get
|
13
13
|
|
14
14
|
def connect(opts)
|
15
15
|
@api_client = establish_remote_appliance_connection(opts)
|
16
|
-
@
|
16
|
+
@usage_interface = @api_client.usage
|
17
17
|
end
|
18
18
|
|
19
19
|
def handle(args)
|
@@ -33,10 +33,10 @@ class Morpheus::Cli::UsageCommand
|
|
33
33
|
options[:cloud] = val
|
34
34
|
end
|
35
35
|
opts.on('--start DATE', String, "Start date in the format YYYY-MM-DD.") do |val|
|
36
|
-
params['startDate'] = val #parse_time(val).utc.iso8601
|
36
|
+
params['startDate'] = val # parse_time(val).utc.iso8601
|
37
37
|
end
|
38
|
-
opts.on('--end DATE', String, "End date in the format YYYY-MM-DD. Default is
|
39
|
-
params['endDate'] = val #parse_time(val).utc.iso8601
|
38
|
+
opts.on('--end DATE', String, "End date in the format YYYY-MM-DD. Default is the current date.") do |val|
|
39
|
+
params['endDate'] = val # parse_time(val).utc.iso8601
|
40
40
|
end
|
41
41
|
opts.on('--sigdig DIGITS', "Significant digits when rounding cost values for display as currency. Default is 5.") do |val|
|
42
42
|
options[:sigdig] = val.to_i
|
@@ -64,12 +64,12 @@ class Morpheus::Cli::UsageCommand
|
|
64
64
|
}
|
65
65
|
end
|
66
66
|
|
67
|
-
@
|
67
|
+
@usage_interface.setopts(options)
|
68
68
|
if options[:dry_run]
|
69
|
-
print_dry_run @
|
69
|
+
print_dry_run @usage_interface.dry.list(params)
|
70
70
|
return
|
71
71
|
end
|
72
|
-
json_response = @
|
72
|
+
json_response = @usage_interface.list(params)
|
73
73
|
usages = json_response[usage_list_key]
|
74
74
|
render_response(json_response, options, usage_list_key) do
|
75
75
|
print_h1 "Morpheus Usages", parse_list_subtitles(options), options
|
@@ -85,6 +85,7 @@ class Morpheus::Cli::UsageCommand
|
|
85
85
|
"Start Date" => lambda {|it| format_local_dt(it['startDate']) },
|
86
86
|
"End Date" => lambda {|it| format_local_dt(it['endDate']) },
|
87
87
|
"Usage Status" => lambda {|it| format_usage_status(it) },
|
88
|
+
"Usage Cost" => lambda {|it| format_money(it['costDetails']['cost'], it['currency'] || 'USD', {sigdig: (options[:sigdig] || 5)}) },
|
88
89
|
"Usage Price" => lambda {|it| format_money(it['price'], it['currency'] || 'USD', {sigdig: (options[:sigdig] || 5)}) },
|
89
90
|
}
|
90
91
|
print as_pretty_table(usages, list_columns.upcase_keys!, options)
|
@@ -99,6 +100,58 @@ class Morpheus::Cli::UsageCommand
|
|
99
100
|
end
|
100
101
|
end
|
101
102
|
|
103
|
+
def get(args)
|
104
|
+
params = {}
|
105
|
+
options = {}
|
106
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
107
|
+
opts.banner = subcommand_usage("[usage]")
|
108
|
+
build_standard_get_options(opts, options)
|
109
|
+
opts.footer = <<-EOT
|
110
|
+
Get details about a specific usage.
|
111
|
+
[usage] is required. This is the id of a usage record.
|
112
|
+
EOT
|
113
|
+
end
|
114
|
+
optparse.parse!(args)
|
115
|
+
verify_args!(args:args, optparse:optparse, min:1)
|
116
|
+
connect(options)
|
117
|
+
id_list = parse_id_list(args)
|
118
|
+
return run_command_for_each_arg(id_list) do |arg|
|
119
|
+
_get(arg, params, options)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def _get(id, params, options)
|
124
|
+
usage = nil
|
125
|
+
@usage_interface.setopts(options)
|
126
|
+
if options[:dry_run]
|
127
|
+
print_dry_run @usage_interface.dry.get(id, params)
|
128
|
+
return
|
129
|
+
end
|
130
|
+
json_response = @usage_interface.get(id, params)
|
131
|
+
usage = json_response[usage_object_key]
|
132
|
+
render_response(json_response, options, usage_object_key) do
|
133
|
+
print_h1 "Usage Details", [], options
|
134
|
+
print cyan
|
135
|
+
show_columns = {
|
136
|
+
"ID" => 'id',
|
137
|
+
"Cloud" => 'zoneName',
|
138
|
+
"Type" => lambda {|it| format_usage_type(it) },
|
139
|
+
"Name" => 'name',
|
140
|
+
"Plan" => 'planName',
|
141
|
+
"Start Date" => lambda {|it| format_local_dt(it['startDate']) },
|
142
|
+
"End Date" => lambda {|it| format_local_dt(it['endDate']) },
|
143
|
+
"Usage Status" => lambda {|it| format_usage_status(it) },
|
144
|
+
"Usage Cost" => lambda {|it| format_money(it['costDetails']['cost'], it['currency'] || 'USD', {sigdig: (options[:sigdig] || 5)}) },
|
145
|
+
"Usage Price" => lambda {|it| format_money(it['price'], it['currency'] || 'USD', {sigdig: (options[:sigdig] || 5)}) },
|
146
|
+
}
|
147
|
+
print_description_list(show_columns, usage)
|
148
|
+
|
149
|
+
# print_h2 "Applicable Prices"
|
150
|
+
|
151
|
+
print reset,"\n"
|
152
|
+
end
|
153
|
+
return 0, nil
|
154
|
+
end
|
102
155
|
|
103
156
|
private
|
104
157
|
|
@@ -141,9 +194,9 @@ class Morpheus::Cli::UsageCommand
|
|
141
194
|
#return usage['status'].to_s.capitalize
|
142
195
|
status_string = usage['status'].to_s
|
143
196
|
if status_string == 'stopped'
|
144
|
-
return "#{
|
197
|
+
return "#{red}#{status_string.upcase}#{return_color}"
|
145
198
|
else
|
146
|
-
return "#{
|
199
|
+
return "#{green}#{status_string.upcase}#{return_color}"
|
147
200
|
end
|
148
201
|
end
|
149
202
|
|
data/lib/morpheus/cli/version.rb
CHANGED
@@ -27,6 +27,7 @@ class Morpheus::Cli::VirtualImages
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def list(args)
|
30
|
+
params = {}
|
30
31
|
options = {}
|
31
32
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
32
33
|
opts.banner = subcommand_usage()
|
@@ -42,42 +43,32 @@ class Morpheus::Cli::VirtualImages
|
|
42
43
|
opts.on('--system', "System Images" ) do
|
43
44
|
options[:filterType] = 'System'
|
44
45
|
end
|
45
|
-
|
46
|
+
build_standard_list_options(opts, options)
|
46
47
|
opts.footer = "List virtual images."
|
47
48
|
end
|
48
49
|
optparse.parse!(args)
|
49
50
|
connect(options)
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
75
|
-
end
|
76
|
-
|
77
|
-
|
78
|
-
images = json_response['virtualImages']
|
51
|
+
# verify_args!(args:args, optparse:optparse, count:0)
|
52
|
+
if args.count > 0
|
53
|
+
options[:phrase] = args.join(" ")
|
54
|
+
end
|
55
|
+
params.merge!(parse_list_options(options))
|
56
|
+
if options[:imageType]
|
57
|
+
params[:imageType] = options[:imageType]
|
58
|
+
end
|
59
|
+
if options[:filterType]
|
60
|
+
params[:filterType] = options[:filterType]
|
61
|
+
end
|
62
|
+
@virtual_images_interface.setopts(options)
|
63
|
+
if options[:dry_run]
|
64
|
+
print_dry_run @virtual_images_interface.dry.list(params)
|
65
|
+
return
|
66
|
+
end
|
67
|
+
json_response = @virtual_images_interface.list(params)
|
68
|
+
images = json_response['virtualImages']
|
69
|
+
render_response(json_response, options, 'virtualImages') do
|
79
70
|
title = "Morpheus Virtual Images"
|
80
|
-
subtitles =
|
71
|
+
subtitles = parse_list_subtitles(options)
|
81
72
|
if options[:imageType]
|
82
73
|
subtitles << "Image Type: #{options[:imageType]}".strip
|
83
74
|
end
|
@@ -91,6 +82,7 @@ class Morpheus::Cli::VirtualImages
|
|
91
82
|
if images.empty?
|
92
83
|
print cyan,"No virtual images found.",reset,"\n"
|
93
84
|
else
|
85
|
+
# print as_pretty_table(images, virtual_image_column_definitions.upcase_keys!, options)
|
94
86
|
rows = images.collect do |image|
|
95
87
|
image_type = virtual_image_type_for_name_or_code(image['imageType'])
|
96
88
|
image_type_display = image_type ? "#{image_type['name']}" : image['imageType']
|
@@ -103,117 +95,134 @@ class Morpheus::Cli::VirtualImages
|
|
103
95
|
print_results_pagination(json_response)
|
104
96
|
end
|
105
97
|
print reset,"\n"
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
98
|
+
end
|
99
|
+
if images.empty?
|
100
|
+
return -1, "no virtual images found"
|
101
|
+
else
|
102
|
+
return 0, nil
|
111
103
|
end
|
112
104
|
end
|
113
105
|
|
114
106
|
def get(args)
|
107
|
+
params = {}
|
115
108
|
options = {}
|
116
|
-
show_details = false
|
117
109
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
118
|
-
opts.banner = subcommand_usage("[
|
110
|
+
opts.banner = subcommand_usage("[image]")
|
119
111
|
opts.on('--details', "Show more details." ) do
|
120
|
-
|
112
|
+
options[:details] = true
|
121
113
|
end
|
122
|
-
|
123
|
-
opts.footer =
|
124
|
-
|
114
|
+
build_standard_get_options(opts, options)
|
115
|
+
opts.footer = <<-EOT
|
116
|
+
Get details about a virtual image.
|
117
|
+
[image] is required. This is the name or id of a virtual image.
|
118
|
+
EOT
|
125
119
|
end
|
126
120
|
optparse.parse!(args)
|
127
|
-
|
128
|
-
puts optparse
|
129
|
-
exit 1
|
130
|
-
end
|
131
|
-
image_name = args[0]
|
121
|
+
verify_args!(args:args, optparse:optparse, min:1)
|
132
122
|
connect(options)
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
123
|
+
id_list = parse_id_list(args)
|
124
|
+
# lookup IDs if names are given
|
125
|
+
id_list = id_list.collect do |id|
|
126
|
+
if id.to_s =~ /\A\d{1,}\Z/
|
127
|
+
id
|
128
|
+
else
|
129
|
+
image = find_virtual_image_by_name_or_id(id)
|
130
|
+
if image
|
131
|
+
image['id']
|
138
132
|
else
|
139
|
-
|
133
|
+
raise_command_error "virtual image not found for name '#{id}'"
|
140
134
|
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
135
|
end
|
136
|
+
end
|
137
|
+
return run_command_for_each_arg(id_list) do |arg|
|
138
|
+
_get(arg, params, options)
|
139
|
+
end
|
140
|
+
end
|
157
141
|
|
142
|
+
def _get(id, params, options)
|
143
|
+
@virtual_images_interface.setopts(options)
|
144
|
+
if options[:dry_run]
|
145
|
+
print_dry_run @virtual_images_interface.dry.get(id.to_i)
|
146
|
+
return
|
147
|
+
end
|
148
|
+
json_response = @virtual_images_interface.get(id.to_i)
|
158
149
|
image = json_response['virtualImage']
|
150
|
+
image_config = image['config'] || {}
|
159
151
|
image_files = json_response['cloudFiles'] || json_response['files']
|
160
|
-
|
161
|
-
|
162
152
|
image_type = virtual_image_type_for_name_or_code(image['imageType'])
|
163
153
|
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
|
-
"Trial Version" => lambda {|it| format_boolean it['trialVersion'] },
|
191
|
-
"Sysprep Enabled?" => lambda {|it| format_boolean it['isSysprep'] },
|
192
|
-
}
|
193
|
-
if show_details
|
194
|
-
description_cols.merge!(advanced_description_cols)
|
195
|
-
end
|
196
|
-
print_description_list(description_cols, image)
|
197
|
-
|
198
|
-
if image_files
|
199
|
-
print_h2 "Files (#{image_files.size})"
|
200
|
-
# image_files.each {|image_file|
|
201
|
-
# pretty_filesize = Filesize.from("#{image_file['size']} B").pretty
|
202
|
-
# print cyan," = #{image_file['name']} [#{pretty_filesize}]", "\n"
|
203
|
-
# }
|
204
|
-
image_file_rows = image_files.collect do |image_file|
|
205
|
-
|
206
|
-
{filename: image_file['name'], size: Filesize.from("#{image_file['size']} B").pretty}
|
154
|
+
render_response(json_response, options, 'virtualImage') do
|
155
|
+
print_h1 "Virtual Image Details", [], options
|
156
|
+
description_cols = {
|
157
|
+
"ID" => 'id',
|
158
|
+
"Name" => 'name',
|
159
|
+
"Type" => lambda {|it| image_type_display },
|
160
|
+
"Storage" => lambda {|it| !image['storageProvider'].nil? ? image['storageProvider']['name'] : 'Default' },
|
161
|
+
"Size" => lambda {|it| image['rawSize'].nil? ? 'Unknown' : "#{Filesize.from("#{image['rawSize']} B").pretty}" },
|
162
|
+
"Azure Publisher" => lambda {|it| image_config['publisher'] },
|
163
|
+
"Azure Offer" => lambda {|it| image_config['offer'] },
|
164
|
+
"Azure Sku" => lambda {|it| image_config['sku'] },
|
165
|
+
"Azure Version" => lambda {|it| image_config['version'] },
|
166
|
+
"Source" => lambda {|it| image['userUploaded'] ? "#{green}UPLOADED#{cyan}" : (image['systemImage'] ? 'SYSTEM' : "#{white}SYNCED#{cyan}") },
|
167
|
+
# "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
168
|
+
# "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
|
169
|
+
}
|
170
|
+
if image['imageType'] == "azure-reference" || image['imageType'] == "azure"
|
171
|
+
description_cols.delete("Size")
|
172
|
+
description_cols.delete("Storage")
|
173
|
+
description_cols["Source"] = lambda {|it| "#{bold}#{cyan}AZURE#{reset}#{cyan}" }
|
174
|
+
else
|
175
|
+
description_cols.delete("Azure Marketplace")
|
176
|
+
description_cols.delete("Azure Marketplace Publisher")
|
177
|
+
description_cols.delete("Azure Marketplace Sku")
|
178
|
+
description_cols.delete("Azure Marketplace Offer")
|
179
|
+
description_cols.delete("Azure Marketplace Version")
|
207
180
|
end
|
208
|
-
|
209
|
-
|
210
|
-
|
181
|
+
advanced_description_cols = {
|
182
|
+
"OS Type" => lambda {|it| it['osType'] ? it['osType']['name'] : "" },
|
183
|
+
"Min Memory" => lambda {|it| it['minRam'].to_i != 0 ? Filesize.from("#{it['minRam']} B").pretty : "" },
|
184
|
+
"Cloud Init?" => lambda {|it| format_boolean it['osType'] },
|
185
|
+
"Install Agent?" => lambda {|it| format_boolean it['osType'] },
|
186
|
+
"SSH Username" => lambda {|it| it['sshUsername'] },
|
187
|
+
"SSH Password" => lambda {|it| it['sshPassword'] },
|
188
|
+
"User Data" => lambda {|it| it['userData'] },
|
189
|
+
"Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
|
190
|
+
"Tenants" => lambda {|it| format_tenants(it['accounts']) },
|
191
|
+
"Auto Join Domain?" => lambda {|it| format_boolean it['isAutoJoinDomain'] },
|
192
|
+
"VirtIO Drivers Loaded?" => lambda {|it| format_boolean it['virtioSupported'] },
|
193
|
+
"VM Tools Installed?" => lambda {|it| format_boolean it['vmToolsInstalled'] },
|
194
|
+
"Force Guest Customization?" => lambda {|it| format_boolean it['isForceCustomization'] },
|
195
|
+
"Trial Version" => lambda {|it| format_boolean it['trialVersion'] },
|
196
|
+
"Sysprep Enabled?" => lambda {|it| format_boolean it['isSysprep'] },
|
197
|
+
}
|
198
|
+
if options[:details]
|
199
|
+
description_cols.merge!(advanced_description_cols)
|
200
|
+
end
|
201
|
+
print_description_list(description_cols, image)
|
202
|
+
|
203
|
+
if image_files
|
204
|
+
print_h2 "Files (#{image_files.size})"
|
205
|
+
# image_files.each {|image_file|
|
206
|
+
# pretty_filesize = Filesize.from("#{image_file['size']} B").pretty
|
207
|
+
# print cyan," = #{image_file['name']} [#{pretty_filesize}]", "\n"
|
208
|
+
# }
|
209
|
+
image_file_rows = image_files.collect do |image_file|
|
210
|
+
{filename: image_file['name'], size: Filesize.from("#{image_file['size']} B").pretty}
|
211
|
+
end
|
212
|
+
print cyan
|
213
|
+
print as_pretty_table(image_file_rows, [:filename, :size])
|
214
|
+
# print reset,"\n"
|
215
|
+
end
|
216
|
+
|
217
|
+
if options[:details] && image_config && !image_config.empty?
|
218
|
+
print_h2 "Config", options
|
219
|
+
print cyan
|
220
|
+
print as_description_list(image_config, image_config.keys, options)
|
221
|
+
print "\n", reset
|
222
|
+
end
|
223
|
+
print reset,"\n"
|
211
224
|
end
|
212
|
-
|
213
|
-
rescue RestClient::Exception => e
|
214
|
-
print_rest_exception(e, options)
|
215
|
-
exit 1
|
216
|
-
end
|
225
|
+
return 0, nil
|
217
226
|
end
|
218
227
|
|
219
228
|
def update(args)
|
@@ -339,6 +348,19 @@ class Morpheus::Cli::VirtualImages
|
|
339
348
|
opts.on( '-U', '--url URL', "Image File URL. This can be used instead of uploading local files." ) do |val|
|
340
349
|
file_url = val
|
341
350
|
end
|
351
|
+
opts.on( '-c', '--cloud CLOUD', "Cloud to scope image to, certain types require a cloud to be selected, eg. Azure Reference" ) do |val|
|
352
|
+
# options[:cloud] = val
|
353
|
+
options[:options]['cloud'] = val
|
354
|
+
end
|
355
|
+
opts.on( '--azure-offer OFFER', String, "Azure Reference offer value, only applies to Azure Reference" ) do |val|
|
356
|
+
options[:options]['offer'] = val
|
357
|
+
end
|
358
|
+
opts.on( '--azure-sku SKU', String, "Azure SKU value, only applies to Azure Reference" ) do |val|
|
359
|
+
options[:options]['sku'] = val
|
360
|
+
end
|
361
|
+
opts.on( '--azure-version VERSION', String, "Azure Version value, only applies to Azure Reference" ) do |val|
|
362
|
+
options[:options]['version'] = val
|
363
|
+
end
|
342
364
|
opts.on('--tenants LIST', Array, "Tenant Access, comma separated list of account IDs") do |list|
|
343
365
|
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
344
366
|
tenants_list = []
|
@@ -346,7 +368,10 @@ class Morpheus::Cli::VirtualImages
|
|
346
368
|
tenants_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
347
369
|
end
|
348
370
|
end
|
349
|
-
|
371
|
+
# build_option_type_options(opts, options, add_virtual_image_option_types)
|
372
|
+
# build_option_type_options(opts, options, add_virtual_image_advanced_option_types)
|
373
|
+
build_standard_add_options(opts, options)
|
374
|
+
|
350
375
|
opts.footer = "Create a virtual image."
|
351
376
|
end
|
352
377
|
optparse.parse!(args)
|
@@ -368,26 +393,43 @@ class Morpheus::Cli::VirtualImages
|
|
368
393
|
options[:options]['name'] ||= image_name
|
369
394
|
end
|
370
395
|
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
396
|
+
payload = {}
|
397
|
+
if options[:payload]
|
398
|
+
payload = options[:payload]
|
399
|
+
payload.deep_merge!({'virtualImage' => parse_passed_options(options)})
|
400
|
+
else
|
401
|
+
payload.deep_merge!({'virtualImage' => parse_passed_options(options)})
|
402
|
+
virtual_image_payload = {}
|
403
|
+
# v_prompt = Morpheus::Cli::OptionTypes.prompt(add_virtual_image_option_types, options[:options], @api_client, options[:params])
|
404
|
+
if image_type_name
|
405
|
+
image_type = virtual_image_type_for_name_or_code(image_type_name)
|
406
|
+
# fix issue with api returning imageType vmware instead of vmdk
|
407
|
+
if image_type.nil? && image_type_name == 'vmware'
|
408
|
+
image_type = virtual_image_type_for_name_or_code('vmdk')
|
409
|
+
elsif image_type.nil? && image_type_name == 'vmdk'
|
410
|
+
image_type = virtual_image_type_for_name_or_code('vmware')
|
411
|
+
end
|
412
|
+
if image_type.nil?
|
413
|
+
print_red_alert "Virtual Image Type not found by code '#{image_type_name}'"
|
414
|
+
return 1
|
415
|
+
end
|
416
|
+
# options[:options] ||= {}
|
417
|
+
# options[:options]['imageType'] ||= image_type['code']
|
418
|
+
else
|
419
|
+
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,{})
|
420
|
+
image_type = virtual_image_type_for_name_or_code(image_type_prompt['imageType'])
|
378
421
|
end
|
379
|
-
|
380
|
-
|
381
|
-
|
422
|
+
|
423
|
+
# azure requires us to search the marketplace to select publisher, cloud, offerm sku
|
424
|
+
if image_type['code'] == "azure-reference" || image_type['code'] == "azure"
|
425
|
+
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'})
|
426
|
+
cloud_id = cloud_prompt['cloud'].to_i
|
427
|
+
|
428
|
+
marketplace_config = prompt_azure_marketplace(cloud_id, options)
|
429
|
+
virtual_image_payload['config'] ||= {}
|
430
|
+
virtual_image_payload['config'].deep_merge!(marketplace_config)
|
382
431
|
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
432
|
|
390
|
-
begin
|
391
433
|
my_option_types = add_virtual_image_option_types(image_type, !file_url)
|
392
434
|
# if options[:no_prompt]
|
393
435
|
# my_option_types.each do |it|
|
@@ -396,9 +438,9 @@ class Morpheus::Cli::VirtualImages
|
|
396
438
|
# end
|
397
439
|
# end
|
398
440
|
# end
|
399
|
-
|
400
|
-
|
401
|
-
virtual_image_payload
|
441
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt(my_option_types, options[:options], @api_client, options[:params])
|
442
|
+
v_prompt.deep_compact!
|
443
|
+
virtual_image_payload.deep_merge!(v_prompt)
|
402
444
|
virtual_image_files = virtual_image_payload.delete('virtualImageFiles')
|
403
445
|
virtual_image_payload['imageType'] = image_type['code']
|
404
446
|
storage_provider_id = virtual_image_payload.delete('storageProviderId')
|
@@ -412,61 +454,62 @@ class Morpheus::Cli::VirtualImages
|
|
412
454
|
if virtual_image_payload && virtual_image_payload['imageType'] == 'vmware'
|
413
455
|
virtual_image_payload['imageType'] == 'vmdk'
|
414
456
|
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
|
457
|
+
#payload = {'virtualImage' => virtual_image_payload}
|
458
|
+
payload.deep_merge!({'virtualImage' => virtual_image_payload})
|
459
|
+
end
|
437
460
|
|
438
|
-
|
461
|
+
@virtual_images_interface.setopts(options)
|
462
|
+
if options[:dry_run]
|
463
|
+
print_dry_run @virtual_images_interface.dry.create(payload)
|
439
464
|
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
|
465
|
+
print_dry_run @virtual_images_interface.dry.upload_by_url(":id", file_url, file_name)
|
447
466
|
elsif virtual_image_files && !virtual_image_files.empty?
|
448
467
|
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
|
468
|
+
print_dry_run @virtual_images_interface.dry.upload(":id", "(Contents of file #{filepath})")
|
457
469
|
end
|
458
|
-
else
|
459
|
-
puts cyan, "No files uploaded.", reset
|
460
470
|
end
|
471
|
+
return
|
472
|
+
end
|
461
473
|
|
462
|
-
|
463
|
-
|
474
|
+
json_response = @virtual_images_interface.create(payload)
|
475
|
+
virtual_image = json_response['virtualImage']
|
476
|
+
|
477
|
+
# if options[:json]
|
478
|
+
# print JSON.pretty_generate(json_response)
|
479
|
+
# elsif !options[:quiet]
|
480
|
+
# print "\n", cyan, "Virtual Image #{virtual_image['name']} created successfully", reset, "\n\n"
|
481
|
+
# end
|
482
|
+
|
483
|
+
# now upload the file, do this in the background maybe?
|
484
|
+
if file_url
|
485
|
+
unless options[:quiet]
|
486
|
+
print cyan, "Uploading file by url #{file_url} ...", reset, "\n"
|
487
|
+
end
|
488
|
+
upload_json_response = @virtual_images_interface.upload_by_url(virtual_image['id'], file_url, file_name)
|
489
|
+
# if options[:json]
|
490
|
+
# print JSON.pretty_generate(upload_json_response)
|
491
|
+
# end
|
492
|
+
elsif virtual_image_files && !virtual_image_files.empty?
|
493
|
+
virtual_image_files.each do |key, filepath|
|
494
|
+
unless options[:quiet]
|
495
|
+
print cyan, "Uploading file (#{key}) #{filepath} ...", reset, "\n"
|
496
|
+
end
|
497
|
+
image_file = File.new(filepath, 'rb')
|
498
|
+
upload_json_response = @virtual_images_interface.upload(virtual_image['id'], image_file, file_name)
|
499
|
+
# if options[:json]
|
500
|
+
# print JSON.pretty_generate(upload_json_response)
|
501
|
+
# end
|
464
502
|
end
|
503
|
+
else
|
504
|
+
# puts cyan, "No files uploaded.", reset
|
505
|
+
end
|
465
506
|
|
466
|
-
|
467
|
-
|
468
|
-
|
507
|
+
render_response(json_response, options, 'virtualImage') do
|
508
|
+
print_green_success "Added virtual image #{virtual_image['name']}"
|
509
|
+
return _get(virtual_image["id"], {}, options)
|
469
510
|
end
|
511
|
+
return 0, nil
|
512
|
+
|
470
513
|
end
|
471
514
|
|
472
515
|
def add_file(args)
|
@@ -678,11 +721,11 @@ class Morpheus::Cli::VirtualImages
|
|
678
721
|
#{'fieldName' => 'imageType', 'fieldLabel' => 'Image Type', 'type' => 'select', 'optionSource' => 'virtualImageTypes', 'required' => true, 'description' => 'Select Virtual Image Type.', 'displayOrder' => 2},
|
679
722
|
{'fieldName' => 'osType', 'fieldLabel' => 'OS Type', 'type' => 'select', 'optionSource' => 'osTypes', 'required' => false, 'description' => 'Select OS Type.', 'displayOrder' => 3},
|
680
723
|
{'fieldName' => 'minRam', 'fieldLabel' => 'Minimum Memory (MB)', 'type' => 'number', 'required' => false, 'description' => 'Minimum Memory (MB)', 'displayOrder' => 4},
|
681
|
-
{'fieldName' => 'isCloudInit', 'fieldLabel' => 'Cloud Init Enabled?', 'type' => 'checkbox', 'required' => false, 'description' => 'Cloud Init Enabled?', 'displayOrder' =>
|
682
|
-
{'fieldName' => 'installAgent', 'fieldLabel' => 'Install Agent?', 'type' => 'checkbox', 'required' => false, 'description' => 'Install Agent?', 'displayOrder' =>
|
683
|
-
{'fieldName' => 'sshUsername', 'fieldLabel' => 'SSH Username', 'type' => 'text', 'required' => false, 'description' => 'Enter an SSH Username', 'displayOrder' =>
|
684
|
-
{'fieldName' => 'sshPassword', 'fieldLabel' => 'SSH Password', 'type' => 'password', 'required' => false, 'description' => 'Enter an SSH Password', 'displayOrder' =>
|
685
|
-
{'fieldName' => 'storageProviderId', 'type' => 'select', 'fieldLabel' => 'Storage Provider', 'optionSource' => 'storageProviders', 'required' => false, 'description' => 'Select Storage Provider.', 'displayOrder' =>
|
724
|
+
{'fieldName' => 'isCloudInit', 'fieldLabel' => 'Cloud Init Enabled?', 'type' => 'checkbox', 'required' => false, 'description' => 'Cloud Init Enabled?', 'displayOrder' => 5},
|
725
|
+
{'fieldName' => 'installAgent', 'fieldLabel' => 'Install Agent?', 'type' => 'checkbox', 'required' => false, 'description' => 'Install Agent?', 'displayOrder' => 6},
|
726
|
+
{'fieldName' => 'sshUsername', 'fieldLabel' => 'SSH Username', 'type' => 'text', 'required' => false, 'description' => 'Enter an SSH Username', 'displayOrder' => 7},
|
727
|
+
{'fieldName' => 'sshPassword', 'fieldLabel' => 'SSH Password', 'type' => 'password', 'required' => false, 'description' => 'Enter an SSH Password', 'displayOrder' => 8},
|
728
|
+
{'fieldName' => 'storageProviderId', 'type' => 'select', 'fieldLabel' => 'Storage Provider', 'optionSource' => 'storageProviders', 'required' => false, 'description' => 'Select Storage Provider.', 'displayOrder' => 9},
|
686
729
|
{'fieldName' => 'userData', 'fieldLabel' => 'Cloud-Init User Data', 'type' => 'textarea', 'required' => false, 'displayOrder' => 10},
|
687
730
|
{'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
731
|
{'fieldName' => 'isAutoJoinDomain', 'fieldLabel' => 'Auto Join Domain?', 'type' => 'checkbox', 'required' => false, 'description' => 'Auto Join Domain?', 'category' => 'advanced', 'displayOrder' => 40},
|
@@ -696,22 +739,25 @@ class Morpheus::Cli::VirtualImages
|
|
696
739
|
image_type_code = image_type ? image_type['code'] : nil
|
697
740
|
if image_type_code
|
698
741
|
if image_type_code == 'ami'
|
699
|
-
tmp_option_types << {'fieldName' => 'externalId', 'fieldLabel' => 'AMI id', 'type' => 'text', 'required' => false, 'displayOrder' =>
|
742
|
+
tmp_option_types << {'fieldName' => 'externalId', 'fieldLabel' => 'AMI id', 'type' => 'text', 'required' => false, 'displayOrder' => 11}
|
700
743
|
if include_file_selection
|
701
|
-
tmp_option_types << {'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => false, 'displayOrder' =>
|
744
|
+
tmp_option_types << {'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => false, 'displayOrder' => 12}
|
702
745
|
end
|
703
746
|
elsif image_type_code == 'vmware' || image_type_code == 'vmdk'
|
704
747
|
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' =>
|
748
|
+
tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageFile', 'fieldLabel' => 'OVF File', 'type' => 'file', 'required' => false, 'displayOrder' => 11}
|
749
|
+
tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageDescriptorFile', 'fieldLabel' => 'VMDK File', 'type' => 'file', 'required' => false, 'displayOrder' => 12}
|
707
750
|
end
|
708
751
|
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' =>
|
752
|
+
tmp_option_types << {'fieldName' => 'config.menu', 'fieldLabel' => 'Menu', 'type' => 'text', 'required' => false, 'displayOrder' => 11}
|
753
|
+
tmp_option_types << {'fieldName' => 'imagePath', 'fieldLabel' => 'Image Path', 'type' => 'text', 'required' => true, 'displayOrder' => 12}
|
711
754
|
tmp_option_types.reject! {|opt| ['isCloudInit', 'installAgent', 'sshUsername', 'sshPassword'].include?(opt['fieldName'])}
|
755
|
+
elsif image_type_code == 'azure' || image_type_code == 'azure-reference'
|
756
|
+
# Azure Marketplace Prompt happens elsewhere
|
757
|
+
tmp_option_types.reject! {|opt| ['storageProviderId', 'userData', 'sshUsername', 'sshPassword'].include?(opt['fieldName'])}
|
712
758
|
else
|
713
759
|
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' =>
|
760
|
+
tmp_option_types << {'fieldContext' => 'virtualImageFiles', 'fieldName' => 'imageFile', 'fieldLabel' => 'Image File', 'type' => 'file', 'required' => false, 'description' => 'Choose an image file to upload', 'displayOrder' => 11}
|
715
761
|
end
|
716
762
|
end
|
717
763
|
end
|
@@ -735,5 +781,40 @@ class Morpheus::Cli::VirtualImages
|
|
735
781
|
""
|
736
782
|
end
|
737
783
|
end
|
784
|
+
|
785
|
+
def prompt_azure_marketplace(cloud_id, options)
|
786
|
+
rtn = {}
|
787
|
+
publisher_value, offer_value, sku_value, version_value = nil, nil, nil, nil
|
788
|
+
|
789
|
+
# Marketplace Publisher & Offer
|
790
|
+
marketplace_api_params = {'zoneId' => cloud_id}
|
791
|
+
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)
|
792
|
+
# offer_value = v_prompt['marketplace']
|
793
|
+
# actually need both offer and publisher of these to query correctly..sigh
|
794
|
+
marketplace_option = Morpheus::Cli::OptionTypes.get_last_select()
|
795
|
+
offer_value = marketplace_option['offer']
|
796
|
+
publisher_value = marketplace_option['publisher']
|
797
|
+
|
798
|
+
# SKU & VERSION
|
799
|
+
if options[:options] && options[:options]['sku'] && options[:options]['version']
|
800
|
+
# the value to match on is actually sku|version
|
801
|
+
options[:options]['sku'] = options[:options]['sku'] + '|' + options[:options]['version']
|
802
|
+
end
|
803
|
+
sku_api_params = {'zoneId' => cloud_id, publisher: publisher_value, offer: offer_value}
|
804
|
+
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)
|
805
|
+
# marketplace_option = Morpheus::Cli::OptionTypes.get_last_select()
|
806
|
+
# sku_value = marketplace_option['sku']
|
807
|
+
# version_value = marketplace_option['version']
|
808
|
+
sku_value = v_prompt['sku']
|
809
|
+
if sku_value && sku_value.include?("|")
|
810
|
+
sku_value, version_value = sku_value.split("|")
|
811
|
+
end
|
812
|
+
|
813
|
+
rtn['publisher'] = publisher_value
|
814
|
+
rtn['offer'] = offer_value
|
815
|
+
rtn['sku'] = sku_value
|
816
|
+
rtn['version'] = version_value
|
817
|
+
return rtn
|
818
|
+
end
|
738
819
|
|
739
820
|
end
|