morpheus-cli 2.11.1 → 2.11.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/morpheus/api/api_client.rb +18 -1
- data/lib/morpheus/api/dashboard_interface.rb +1 -1
- data/lib/morpheus/cli/cli_command.rb +14 -0
- data/lib/morpheus/cli/groups.rb +1 -1
- data/lib/morpheus/cli/instance_types.rb +10 -5
- data/lib/morpheus/cli/instances.rb +71 -13
- data/lib/morpheus/cli/load_balancers.rb +80 -16
- data/lib/morpheus/cli/mixins/print_helper.rb +3 -1
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +82 -3
- data/lib/morpheus/cli/recent_activity_command.rb +77 -10
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/rest_client.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d561294737f605bb14714d84f21984797f012b2
|
4
|
+
data.tar.gz: 857aa6f016e8f4db4cfaea280703a7f71adac83a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 941e2fd2a2478c7af97e604f3bbea977874a585b5a4dcd0d526bce39434b4461b9859556f509054239b0fd957919f36b5606304e314f2befda86667d888aec15
|
7
|
+
data.tar.gz: 1fe0c7f8d07df32dd4ea2b771ef2b21106831115d3d3c0a51358e8b9c640be215a3057b12f8f3608524fb46aee02b8f6fa5eef2f60599b6653e1553df6e3cb16
|
@@ -3,13 +3,14 @@ require 'uri'
|
|
3
3
|
require 'rest-client'
|
4
4
|
|
5
5
|
class Morpheus::APIClient
|
6
|
-
def initialize(access_token, refresh_token=nil,expires_in = nil, base_url=nil)
|
6
|
+
def initialize(access_token, refresh_token=nil,expires_in = nil, base_url=nil, verify_ssl=true)
|
7
7
|
@access_token = access_token
|
8
8
|
@refresh_token = refresh_token
|
9
9
|
@base_url = base_url
|
10
10
|
if expires_in != nil
|
11
11
|
@expires_at = DateTime.now + expires_in.seconds
|
12
12
|
end
|
13
|
+
set_ssl_verification_enabled(verify_ssl)
|
13
14
|
end
|
14
15
|
|
15
16
|
def dry_run(val=true)
|
@@ -21,7 +22,23 @@ class Morpheus::APIClient
|
|
21
22
|
dry_run(true)
|
22
23
|
end
|
23
24
|
|
25
|
+
def ssl_verification_enabled?
|
26
|
+
@verify_ssl
|
27
|
+
end
|
28
|
+
|
29
|
+
def set_ssl_verification_enabled(val)
|
30
|
+
@verify_ssl = !!val
|
31
|
+
end
|
32
|
+
|
24
33
|
def execute(opts, parse_json=true)
|
34
|
+
# @verify_ssl is not used atm
|
35
|
+
# todo: finish this and use it instead of the global variable RestClient.ssl_verification_enabled?
|
36
|
+
# gotta clean up all APIClient subclasses new() methods to support this
|
37
|
+
# the CliCommand subclasses should be changed to @users_interface = @api_client.users
|
38
|
+
# also.. Credentials.new()
|
39
|
+
if @verify_ssl == false
|
40
|
+
opts[:verify_ssl] = OpenSSL::SSL::VERIFY_NONE
|
41
|
+
end
|
25
42
|
if @dry_run
|
26
43
|
# JD: could return a Request object instead...
|
27
44
|
return opts
|
@@ -20,7 +20,7 @@ class Morpheus::DashboardInterface < Morpheus::APIClient
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def recent_activity(account_id=nil, options={})
|
23
|
-
url = "#{@base_url}/api/dashboard/
|
23
|
+
url = "#{@base_url}/api/dashboard/recent-activity"
|
24
24
|
headers = { params: {}, authorization: "Bearer #{@access_token}" }
|
25
25
|
headers[:params].merge!(options)
|
26
26
|
headers[:params]['accountId'] = account_id if account_id
|
@@ -547,6 +547,20 @@ module Morpheus
|
|
547
547
|
@appliance_name = appliance[:name]
|
548
548
|
@appliance_url = appliance[:host] || appliance[:url] # it's :host in the YAML..heh
|
549
549
|
|
550
|
+
# instead of toggling this global value
|
551
|
+
# this should just be an attribute of the api client
|
552
|
+
# for now, this fixes the issue where passing --insecure or --remote
|
553
|
+
# would then apply to all subsequent commands...
|
554
|
+
if options[:insecure]
|
555
|
+
Morpheus::RestClient.enable_ssl_verification = false
|
556
|
+
else
|
557
|
+
if appliance[:insecure] && Morpheus::RestClient.ssl_verification_enabled?
|
558
|
+
Morpheus::RestClient.enable_ssl_verification = false
|
559
|
+
elsif !appliance[:insecure] && !Morpheus::RestClient.ssl_verification_enabled?
|
560
|
+
Morpheus::RestClient.enable_ssl_verification = true
|
561
|
+
end
|
562
|
+
end
|
563
|
+
|
550
564
|
# todo: support old way of accepting --username and --password on the command line
|
551
565
|
# it's probably better not to do that tho, just so it stays out of history files
|
552
566
|
|
data/lib/morpheus/cli/groups.rb
CHANGED
@@ -277,7 +277,7 @@ class Morpheus::Cli::Groups
|
|
277
277
|
print JSON.pretty_generate(json_response)
|
278
278
|
print "\n"
|
279
279
|
else
|
280
|
-
print_green_success "Added cloud #{cloud["
|
280
|
+
print_green_success "Added cloud #{cloud["name"]} to group #{group['name']}"
|
281
281
|
#list([])
|
282
282
|
get([group["id"]])
|
283
283
|
end
|
@@ -93,13 +93,18 @@ class Morpheus::Cli::InstanceTypes
|
|
93
93
|
|
94
94
|
if options[:json]
|
95
95
|
print JSON.pretty_generate(json_response), "\n"
|
96
|
-
return
|
96
|
+
return 0
|
97
97
|
end
|
98
98
|
|
99
99
|
instance_types = json_response['instanceTypes']
|
100
|
-
|
100
|
+
title = "Morpheus Instance Types"
|
101
|
+
subtitles = []
|
102
|
+
if params[:phrase]
|
103
|
+
subtitles << "Search: #{params[:phrase]}".strip
|
104
|
+
end
|
105
|
+
print_h1 title, subtitles
|
101
106
|
if instance_types.empty?
|
102
|
-
|
107
|
+
print yellow,"No instance types found.",reset,"\n"
|
103
108
|
else
|
104
109
|
instance_types.each do |instance_type|
|
105
110
|
versions = instance_type['versions'].join(', ')
|
@@ -113,12 +118,12 @@ class Morpheus::Cli::InstanceTypes
|
|
113
118
|
# end
|
114
119
|
#print JSON.pretty_generate(instance_type['instanceTypeLayouts'].first), "\n"
|
115
120
|
end
|
116
|
-
|
117
121
|
end
|
118
122
|
print reset,"\n"
|
123
|
+
return 0
|
119
124
|
rescue RestClient::Exception => e
|
120
125
|
print_rest_exception(e, options)
|
121
|
-
|
126
|
+
return 1
|
122
127
|
end
|
123
128
|
end
|
124
129
|
end
|
@@ -171,7 +171,8 @@ class Morpheus::Cli::Instances
|
|
171
171
|
def add(args)
|
172
172
|
options = {}
|
173
173
|
optparse = OptionParser.new do|opts|
|
174
|
-
opts.banner = subcommand_usage("[type] [name]")
|
174
|
+
# opts.banner = subcommand_usage("[type] [name]")
|
175
|
+
opts.banner = subcommand_usage("[name] -c CLOUD -t TYPE")
|
175
176
|
opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
|
176
177
|
options[:group] = val
|
177
178
|
end
|
@@ -187,32 +188,73 @@ class Morpheus::Cli::Instances
|
|
187
188
|
opts.on("--layout-size NUMBER", Integer, "Apply a multiply factor of containers/vms within the instance") do |val|
|
188
189
|
options[:layout_size] = val.to_i
|
189
190
|
end
|
191
|
+
opts.on("--workflow ID", String, "Automation: Workflow ID") do |val|
|
192
|
+
options[:workflow_id] = val.to_i
|
193
|
+
end
|
194
|
+
# opts.on('-L', "--lb", "Enable Load Balancer") do
|
195
|
+
# options[:enable_load_balancer] = true
|
196
|
+
# end
|
197
|
+
opts.on("--shutdown-days NUMBER", Integer, "Automation: Shutdown Days") do |val|
|
198
|
+
options[:expire_days] = val.to_i
|
199
|
+
end
|
200
|
+
opts.on("--expire-days NUMBER", Integer, "Automation: Expiration Days") do |val|
|
201
|
+
options[:expire_days] = val.to_i
|
202
|
+
end
|
203
|
+
opts.on("--create-backup on|off", String, "Automation: Create Backups. Default is off") do |val|
|
204
|
+
options[:create_backup] = ['on','true','1'].include?(val.to_s.downcase) ? 'on' : 'off'
|
205
|
+
end
|
190
206
|
build_common_options(opts, options, [:options, :json, :dry_run, :remote])
|
191
207
|
end
|
192
208
|
|
193
209
|
optparse.parse!(args)
|
194
210
|
connect(options)
|
195
211
|
|
196
|
-
#
|
212
|
+
# this is the old format of `instance add TYPE NAME`
|
213
|
+
# JD: it seems confusing, let's deprecate and go with `instances add [NAME] -t TYPE`
|
197
214
|
if args[0]
|
198
215
|
options[:instance_type_code] = args[0]
|
199
216
|
end
|
200
217
|
if args[1]
|
201
218
|
options[:instance_name] = args[1]
|
202
219
|
end
|
220
|
+
|
221
|
+
# if args.count > 1
|
222
|
+
# print_error Morpheus::Terminal.angry_prompt
|
223
|
+
# puts_error "#{command_name} add has just 1 (optional) argument: NAME. Got #{args.count} arguments: #{args.join(', ')}\n#{optparse}"
|
224
|
+
# return 1
|
225
|
+
# end
|
226
|
+
# if args[0]
|
227
|
+
# options[:instance_name] = args[0]
|
228
|
+
# end
|
229
|
+
|
203
230
|
# use active group by default
|
204
231
|
options[:group] ||= @active_group_id
|
205
232
|
|
206
233
|
options[:name_required] = true
|
207
234
|
begin
|
208
|
-
|
235
|
+
# this provisioning helper method handles all (most) of the parsing and prompting
|
236
|
+
# and it relies on the method to exit non-zero on error, like a bad CLOUD or TYPE value
|
209
237
|
payload = prompt_new_instance(options)
|
238
|
+
|
239
|
+
# other stuff
|
210
240
|
payload[:copies] = options[:copies] if options[:copies] && options[:copies] > 0
|
211
241
|
payload[:layoutSize] = options[:layout_size] if options[:layout_size] && options[:layout_size] > 0 # aka Scale Factor
|
242
|
+
payload[:createBackup] = options[:create_backup] ? 'on' : 'off' if options[:create_backup] == true
|
243
|
+
payload['instance']['expireDays'] = options[:expire_days] if options[:expire_days]
|
244
|
+
payload['instance']['shutdownDays'] = options[:shutdown_days] if options[:shutdown_days]
|
245
|
+
if options[:workflow_id]
|
246
|
+
payload['taskSetId'] = options[:workflow_id]
|
247
|
+
end
|
248
|
+
if options[:enable_load_balancer]
|
249
|
+
lb_payload = prompt_instance_load_balancer(payload['instance'], nil, options)
|
250
|
+
payload.deep_merge!(lb_payload)
|
251
|
+
end
|
252
|
+
|
212
253
|
if options[:dry_run]
|
213
254
|
print_dry_run @instances_interface.dry.create(payload)
|
214
|
-
return
|
255
|
+
return 0
|
215
256
|
end
|
257
|
+
|
216
258
|
json_response = @instances_interface.create(payload)
|
217
259
|
if options[:json]
|
218
260
|
puts as_json(json_response, options)
|
@@ -221,9 +263,10 @@ class Morpheus::Cli::Instances
|
|
221
263
|
print_green_success "Provisioning instance #{instance_name}"
|
222
264
|
#list([])
|
223
265
|
end
|
266
|
+
return 0
|
224
267
|
rescue RestClient::Exception => e
|
225
268
|
print_rest_exception(e, options)
|
226
|
-
|
269
|
+
return 1
|
227
270
|
end
|
228
271
|
end
|
229
272
|
|
@@ -598,6 +641,20 @@ class Morpheus::Cli::Instances
|
|
598
641
|
}
|
599
642
|
print_description_list(description_cols, instance)
|
600
643
|
|
644
|
+
if instance['statusMessage']
|
645
|
+
print_h2 "Status Message"
|
646
|
+
if instance['status'] == 'failed'
|
647
|
+
print red, instance['statusMessage'], reset
|
648
|
+
else
|
649
|
+
print instance['statusMessage']
|
650
|
+
end
|
651
|
+
print "\n"
|
652
|
+
end
|
653
|
+
if instance['errorMessage']
|
654
|
+
print_h2 "Error Message"
|
655
|
+
print red, instance['errorMessage'], reset
|
656
|
+
print "\n"
|
657
|
+
end
|
601
658
|
if stats
|
602
659
|
print_h2 "Instance Usage"
|
603
660
|
print_stats_usage(stats)
|
@@ -650,15 +707,16 @@ class Morpheus::Cli::Instances
|
|
650
707
|
if current_instance_lb
|
651
708
|
print_h2 "Load Balancer"
|
652
709
|
print cyan
|
710
|
+
# this api response is going to change again.. port is no longer returned atm.
|
653
711
|
description_cols = {
|
654
712
|
"LB ID" => lambda {|it| it['loadBalancer']['id'] },
|
655
713
|
"Name" => lambda {|it| it['loadBalancer']['name'] },
|
656
714
|
"Type" => lambda {|it| it['loadBalancer']['type'] ? it['loadBalancer']['type']['name'] : '' },
|
657
715
|
"Host Name" => lambda {|it| it['loadBalancer']['host'] }, # instance.hostName ?
|
658
|
-
"Port" => lambda {|it| it['port']['port'] },
|
659
|
-
"Protocol" => lambda {|it| it['port']['proxyProtocol'] },
|
660
|
-
"SSL Enabled" => lambda {|it| format_boolean
|
661
|
-
"Cert" => lambda {|it| it['port']['sslCert'] ? it['port']['sslCert']['name'] : '
|
716
|
+
"Port" => lambda {|it| it['port'] ? it['port']['port'] : '' },
|
717
|
+
"Protocol" => lambda {|it| it['port'] ? it['port']['proxyProtocol'] : '' },
|
718
|
+
"SSL Enabled" => lambda {|it| it['port'] ? format_boolean(it['port']['sslEnabled']) : '' },
|
719
|
+
"Cert" => lambda {|it| (it['port'] && it['port']['sslCert']) ? it['port']['sslCert']['name'] : '' }
|
662
720
|
}
|
663
721
|
print_description_list(description_cols, current_instance_lb)
|
664
722
|
print "\n", reset
|
@@ -2054,20 +2112,20 @@ class Morpheus::Cli::Instances
|
|
2054
2112
|
}
|
2055
2113
|
|
2056
2114
|
cur_host_name = instance['hostName']
|
2057
|
-
#host_name = params = Morpheus::Cli::OptionTypes.prompt([{fieldName
|
2115
|
+
#host_name = params = Morpheus::Cli::OptionTypes.prompt([{'fieldName'=>'hostName', 'label'=>'Host Name', 'defaultValue'=>cur_host_name}], options[:options], @api_client, {})
|
2058
2116
|
payload['instance']['hostName'] = instance['hostName']
|
2059
2117
|
|
2060
|
-
payload['loadBalancerId'] =
|
2118
|
+
#payload['loadBalancerId'] = params['loadBalancerId']
|
2061
2119
|
|
2062
2120
|
unless options[:yes] || ::Morpheus::Cli::OptionTypes::confirm("Are you sure you would like to update the load balancer for instance '#{instance['name']}'?", options)
|
2063
2121
|
return 9, "aborted command"
|
2064
2122
|
end
|
2065
2123
|
|
2066
2124
|
if options[:dry_run]
|
2067
|
-
print_dry_run @instances_interface.dry.
|
2125
|
+
print_dry_run @instances_interface.dry.update_load_balancer(instance['id'], payload)
|
2068
2126
|
return
|
2069
2127
|
end
|
2070
|
-
json_response = @instances_interface.
|
2128
|
+
json_response = @instances_interface.update_load_balancer(instance['id'], payload)
|
2071
2129
|
if options[:json]
|
2072
2130
|
puts as_json(json_response, options)
|
2073
2131
|
else
|
@@ -29,7 +29,7 @@ class Morpheus::Cli::LoadBalancers
|
|
29
29
|
options = {}
|
30
30
|
optparse = OptionParser.new do|opts|
|
31
31
|
opts.banner = subcommand_usage()
|
32
|
-
build_common_options(opts, options, [:list, :json, :dry_run, :remote])
|
32
|
+
build_common_options(opts, options, [:list, :json, :csv, :yaml, :fields, :dry_run, :remote])
|
33
33
|
end
|
34
34
|
optparse.parse!(args)
|
35
35
|
connect(options)
|
@@ -44,24 +44,41 @@ class Morpheus::Cli::LoadBalancers
|
|
44
44
|
end
|
45
45
|
json_response = @load_balancers_interface.get(params)
|
46
46
|
if options[:json]
|
47
|
-
|
47
|
+
if options[:include_fields]
|
48
|
+
json_response = {"loadBalancers" => filter_data(json_response["loadBalancers"], options[:include_fields]) }
|
49
|
+
end
|
50
|
+
puts as_json(json_response, options)
|
51
|
+
return 0
|
52
|
+
elsif options[:csv]
|
53
|
+
puts records_as_csv(json_response["loadBalancers"], options)
|
54
|
+
return 0
|
55
|
+
elsif options[:yaml]
|
56
|
+
if options[:include_fields]
|
57
|
+
json_response = {"loadBalancers" => filter_data(json_response["loadBalancers"], options[:include_fields]) }
|
58
|
+
end
|
59
|
+
puts as_yaml(json_response, options)
|
60
|
+
return 0
|
48
61
|
else
|
49
62
|
lbs = json_response['loadBalancers']
|
50
63
|
print_h1 "Morpheus Load Balancers"
|
51
64
|
if lbs.empty?
|
52
|
-
print
|
65
|
+
print yellow,"No load balancers found.",reset,"\n"
|
53
66
|
else
|
54
|
-
|
55
|
-
|
56
|
-
{
|
57
|
-
|
58
|
-
|
67
|
+
columns = [
|
68
|
+
{"ID" => 'id'},
|
69
|
+
{"Name" => 'name'},
|
70
|
+
{"Type" => lambda {|it| it['type'] ? it['type']['name'] : '' } },
|
71
|
+
{"Cloud" => lambda {|it| it['cloud'] ? it['cloud']['name'] : '' } },
|
72
|
+
{"Host" => lambda {|it| it['host'] } },
|
73
|
+
]
|
74
|
+
print as_pretty_table(lbs, columns, options)
|
59
75
|
end
|
60
76
|
print reset,"\n"
|
77
|
+
return 0
|
61
78
|
end
|
62
|
-
|
79
|
+
rescue RestClient::Exception => e
|
63
80
|
print_rest_exception(e, options)
|
64
|
-
|
81
|
+
return 1
|
65
82
|
end
|
66
83
|
end
|
67
84
|
|
@@ -69,7 +86,7 @@ class Morpheus::Cli::LoadBalancers
|
|
69
86
|
options = {}
|
70
87
|
optparse = OptionParser.new do|opts|
|
71
88
|
opts.banner = subcommand_usage("[name]")
|
72
|
-
build_common_options(opts, options, [:json, :dry_run, :remote])
|
89
|
+
build_common_options(opts, options, [:json, :csv, :yaml, :fields, :dry_run, :remote])
|
73
90
|
end
|
74
91
|
optparse.parse!(args)
|
75
92
|
if args.count < 1
|
@@ -89,15 +106,62 @@ class Morpheus::Cli::LoadBalancers
|
|
89
106
|
end
|
90
107
|
lb = find_lb_by_name_or_id(lb_name)
|
91
108
|
exit 1 if lb.nil?
|
109
|
+
# refetch
|
110
|
+
json_response = @load_balancers_interface.get(lb['id'])
|
92
111
|
lb_type = load_balancer_type_for_name_or_id(lb['type']['code'])
|
112
|
+
#puts "LB TYPE: #{lb_type}"
|
93
113
|
if options[:json]
|
94
114
|
puts JSON.pretty_generate({loadBalancer: lb})
|
115
|
+
if options[:include_fields]
|
116
|
+
json_response = {"loadBalancer" => filter_data(json_response["loadBalancer"], options[:include_fields]) }
|
117
|
+
end
|
118
|
+
puts as_json(json_response, options)
|
119
|
+
return 0
|
120
|
+
elsif options[:csv]
|
121
|
+
puts records_as_csv(json_response["loadBalancer"], options)
|
122
|
+
return 0
|
123
|
+
elsif options[:yaml]
|
124
|
+
if options[:include_fields]
|
125
|
+
json_response = {"loadBalancer" => filter_data(json_response["loadBalancer"], options[:include_fields]) }
|
126
|
+
end
|
127
|
+
puts as_yaml(json_response, options)
|
128
|
+
return 0
|
95
129
|
else
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
130
|
+
print_h1 "Load Balancer Details"
|
131
|
+
description_cols = {
|
132
|
+
"ID" => 'id',
|
133
|
+
"Name" => 'name',
|
134
|
+
"Description" => 'description',
|
135
|
+
"Type" => lambda {|it| it['type'] ? it['type']['name'] : '' },
|
136
|
+
"Cloud" => lambda {|it| it['cloud'] ? it['cloud']['name'] : '' },
|
137
|
+
"Visibility" => 'visibility',
|
138
|
+
"IP" => 'ip',
|
139
|
+
"Host" => 'host',
|
140
|
+
"Port" => 'port',
|
141
|
+
"Username" => 'username',
|
142
|
+
# "SSL Enabled" => lambda {|it| format_boolean it['sslEnabled'] },
|
143
|
+
# "SSL Cert" => lambda {|it| it['sslCert'] ? it['sslCert']['name'] : '' },
|
144
|
+
# "SSL" => lambda {|it| it['sslEnabled'] ? "Yes (#{it['sslCert'] ? it['sslCert']['name'] : 'none'})" : "No" },
|
145
|
+
"Created" => lambda {|it| format_local_dt(it['dateCreated']) },
|
146
|
+
"Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
|
147
|
+
}
|
148
|
+
print_description_list(description_cols, lb)
|
149
|
+
|
150
|
+
|
151
|
+
if lb['ports'] && lb['ports'].size > 0
|
152
|
+
print_h2 "LB Ports"
|
153
|
+
columns = [
|
154
|
+
{"ID" => 'id'},
|
155
|
+
{"Name" => 'name'},
|
156
|
+
#{"Description" => 'description'},
|
157
|
+
{"Port" => lambda {|it| it['port'] } },
|
158
|
+
{"Protocol" => lambda {|it| it['proxyProtocol'] } },
|
159
|
+
{"SSL" => lambda {|it| it['sslEnabled'] ? "Yes (#{it['sslCert'] ? it['sslCert']['name'] : 'none'})" : "No" } },
|
160
|
+
]
|
161
|
+
print as_pretty_table(lb['ports'], columns, options)
|
162
|
+
end
|
163
|
+
print reset,"\n"
|
164
|
+
return 0
|
101
165
|
end
|
102
166
|
rescue RestClient::Exception => e
|
103
167
|
print_rest_exception(e, options)
|
@@ -482,7 +482,7 @@ module Morpheus::Cli::PrintHelper
|
|
482
482
|
max_label_width = 0
|
483
483
|
justify = opts.key?(:justify) ? opts[:justify] : "right"
|
484
484
|
do_wrap = opts.key?(:wrap) ? !!opts[:wrap] : true
|
485
|
-
|
485
|
+
color = opts.key?(:color) ? opts[:color] : cyan
|
486
486
|
rows = []
|
487
487
|
|
488
488
|
columns.flatten.each do |column_def|
|
@@ -501,6 +501,7 @@ module Morpheus::Cli::PrintHelper
|
|
501
501
|
end
|
502
502
|
|
503
503
|
out = ""
|
504
|
+
out << color if color
|
504
505
|
rows.each do |row|
|
505
506
|
value = row[:value].to_s
|
506
507
|
if do_wrap
|
@@ -511,6 +512,7 @@ module Morpheus::Cli::PrintHelper
|
|
511
512
|
end
|
512
513
|
out << format_dt_dd(row[:label], value, label_width, justify) + "\n"
|
513
514
|
end
|
515
|
+
out << reset if color
|
514
516
|
return out
|
515
517
|
end
|
516
518
|
|
@@ -324,6 +324,12 @@ module Morpheus::Cli::ProvisioningHelper
|
|
324
324
|
payload['evars'] = evars
|
325
325
|
end
|
326
326
|
|
327
|
+
# prompt for metadata variables
|
328
|
+
metadata = prompt_metadata(options)
|
329
|
+
if !metadata.empty?
|
330
|
+
payload['metadata'] = metadata
|
331
|
+
end
|
332
|
+
|
327
333
|
return payload
|
328
334
|
end
|
329
335
|
|
@@ -806,6 +812,10 @@ module Morpheus::Cli::ProvisioningHelper
|
|
806
812
|
# puts JSON.pretty_generate(zone_network_options_json)
|
807
813
|
zone_network_data = zone_network_options_json['data'] || {}
|
808
814
|
networks = zone_network_data['networks']
|
815
|
+
network_groups = zone_network_data['networkGroups']
|
816
|
+
if network_groups
|
817
|
+
networks = network_groups + networks
|
818
|
+
end
|
809
819
|
network_interface_types = (zone_network_data['networkTypes'] || []).sort { |x,y| x['displayOrder'] <=> y['displayOrder'] }
|
810
820
|
enable_network_type_selection = (zone_network_data['enableNetworkTypeSelection'] == 'on' || zone_network_data['enableNetworkTypeSelection'] == true)
|
811
821
|
has_networks = zone_network_data["hasNetworks"] == true
|
@@ -853,8 +863,8 @@ module Morpheus::Cli::ProvisioningHelper
|
|
853
863
|
# choose network
|
854
864
|
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'networkId', 'type' => 'select', 'fieldLabel' => "Network", 'selectOptions' => network_options, 'required' => true, 'skipSingleOption' => false, 'description' => 'Choose a network for this interface.', 'defaultValue' => network_interface['networkId']}], options[:options])
|
855
865
|
network_interface['network'] = {}
|
856
|
-
network_interface['network']['id'] = v_prompt[field_context]['networkId'].
|
857
|
-
selected_network = networks.find {|it| it["id"] == network_interface['network']['id'] }
|
866
|
+
network_interface['network']['id'] = v_prompt[field_context]['networkId'].to_s
|
867
|
+
selected_network = networks.find {|it| it["id"].to_s == network_interface['network']['id'] }
|
858
868
|
|
859
869
|
if !selected_network
|
860
870
|
print_red_alert "Network not found by id #{network_interface['network']['id']}!"
|
@@ -868,7 +878,9 @@ module Morpheus::Cli::ProvisioningHelper
|
|
868
878
|
end
|
869
879
|
|
870
880
|
# choose IP unless network has a pool configured
|
871
|
-
if selected_network['
|
881
|
+
if selected_network['id'].to_s.include?('networkGroup')
|
882
|
+
puts "IP Address: Using network group." if !no_prompt
|
883
|
+
elsif selected_network['pool']
|
872
884
|
puts "IP Address: Using pool '#{selected_network['pool']['name']}'" if !no_prompt
|
873
885
|
elsif selected_network['dhcpServer']
|
874
886
|
puts "IP Address: Using DHCP" if !no_prompt
|
@@ -917,6 +929,73 @@ module Morpheus::Cli::ProvisioningHelper
|
|
917
929
|
return evars
|
918
930
|
end
|
919
931
|
|
932
|
+
# Prompts user for environment variables for new instance
|
933
|
+
# returns array of metadata objects {id: null, name: "MYTAG", value: "myvalue"}
|
934
|
+
def prompt_metadata(options={})
|
935
|
+
#puts "Configure Environment Variables:"
|
936
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
937
|
+
metadata_array = []
|
938
|
+
metadata_index = 0
|
939
|
+
has_another_metadata = options[:options] && options[:options]["metadata#{metadata_index}"]
|
940
|
+
add_another_metadata = has_another_metadata || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add a metadata tag?", {default: false}))
|
941
|
+
while add_another_metadata do
|
942
|
+
field_context = "metadata#{metadata_index}"
|
943
|
+
metadata = {}
|
944
|
+
metadata['id'] = nil
|
945
|
+
metadata_label = metadata_index == 0 ? "Metadata Tag" : "Metadata Tag [#{metadata_index+1}]"
|
946
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "#{metadata_label} Name", 'required' => true, 'description' => 'Metadata Tag Name.', 'defaultValue' => metadata['name']}], options[:options])
|
947
|
+
# todo: metadata.type ?
|
948
|
+
metadata['name'] = v_prompt[field_context]['name']
|
949
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'value', 'type' => 'text', 'fieldLabel' => "#{metadata_label} Value", 'required' => true, 'description' => 'Metadata Tag Value', 'defaultValue' => metadata['value']}], options[:options])
|
950
|
+
metadata['value'] = v_prompt[field_context]['value']
|
951
|
+
metadata_array << metadata
|
952
|
+
metadata_index += 1
|
953
|
+
has_another_metadata = options[:options] && options[:options]["metadata#{metadata_index}"]
|
954
|
+
add_another_metadata = has_another_metadata || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another metadata tag?", {default: false}))
|
955
|
+
end
|
956
|
+
|
957
|
+
return metadata_array
|
958
|
+
end
|
959
|
+
|
960
|
+
# Prompts user for load balancer settings
|
961
|
+
# returns Hash of parameters like {loadBalancerId: "-1", etc}
|
962
|
+
def prompt_instance_load_balancer(instance, default_lb_id, options)
|
963
|
+
#puts "Configure Environment Variables:"
|
964
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
965
|
+
payload = {}
|
966
|
+
api_params = {}
|
967
|
+
if instance['id']
|
968
|
+
api_params['instanceId'] = instance['id']
|
969
|
+
end
|
970
|
+
if instance['zone']
|
971
|
+
api_params['zoneId'] = instance['zone']['id']
|
972
|
+
elsif instance['cloud']
|
973
|
+
api_params['zoneId'] = instance['cloud']['id']
|
974
|
+
end
|
975
|
+
if instance['group']
|
976
|
+
api_params['siteId'] = instance['group']['id']
|
977
|
+
elsif instance['site']
|
978
|
+
api_params['siteId'] = instance['site']['id']
|
979
|
+
end
|
980
|
+
if instance['plan']
|
981
|
+
api_params['planId'] = instance['plan']['id']
|
982
|
+
end
|
983
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'loadBalancerId', 'type' => 'select', 'fieldLabel' => "Load Balancer", 'optionSource' => 'loadBalancers', 'required' => true, 'description' => 'Select Load Balancer for instance', 'defaultValue' => default_lb_id || ''}], options[:options], api_client, api_params)
|
984
|
+
lb_id = v_prompt['loadBalancerId']
|
985
|
+
payload['loadBalancerId'] = lb_id
|
986
|
+
|
987
|
+
# todo: finish implmenting this
|
988
|
+
|
989
|
+
# loadBalancerId
|
990
|
+
# loadBalancerProxyProtocol
|
991
|
+
# loadBalancerName
|
992
|
+
# loadBalancerDescription
|
993
|
+
# loadBalancerSslCert
|
994
|
+
# loadBalancerScheme
|
995
|
+
|
996
|
+
return payload
|
997
|
+
end
|
998
|
+
|
920
999
|
# reject old volume option types
|
921
1000
|
# these will eventually get removed from the associated optionTypes
|
922
1001
|
def reject_volume_option_types(option_types)
|
@@ -8,7 +8,6 @@ class Morpheus::Cli::RecentActivityCommand
|
|
8
8
|
include Morpheus::Cli::AccountsHelper
|
9
9
|
|
10
10
|
set_command_name :'recent-activity'
|
11
|
-
set_command_hidden # remove once this is done
|
12
11
|
|
13
12
|
def initialize()
|
14
13
|
# @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
@@ -37,7 +36,7 @@ class Morpheus::Cli::RecentActivityCommand
|
|
37
36
|
opts.on('--end TIMESTAMP','--end TIMESTAMP', "End timestamp. Default is now.") do |val|
|
38
37
|
options[:end] = parse_time(val).iso8601
|
39
38
|
end
|
40
|
-
build_common_options(opts, options, [:account, :list, :json, :dry_run])
|
39
|
+
build_common_options(opts, options, [:account, :list, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
41
40
|
end
|
42
41
|
optparse.parse!(args)
|
43
42
|
connect(options)
|
@@ -54,22 +53,90 @@ class Morpheus::Cli::RecentActivityCommand
|
|
54
53
|
end
|
55
54
|
json_response = @dashboard_interface.recent_activity(account_id, params)
|
56
55
|
if options[:json]
|
56
|
+
if options[:include_fields]
|
57
|
+
json_response = {"activity" => filter_data(json_response["activity"], options[:include_fields]) }
|
58
|
+
end
|
57
59
|
print JSON.pretty_generate(json_response)
|
58
60
|
print "\n"
|
59
|
-
|
60
|
-
|
61
|
-
|
61
|
+
return 0
|
62
|
+
end
|
63
|
+
if options[:csv]
|
64
|
+
puts records_as_csv(json_response["activity"], options)
|
65
|
+
return 0
|
66
|
+
end
|
67
|
+
if options[:yaml]
|
68
|
+
if options[:include_fields]
|
69
|
+
json_response = {"activity" => filter_data(json_response["activity"], options[:include_fields]) }
|
70
|
+
end
|
71
|
+
puts as_yaml(json_response, options)
|
72
|
+
return 0
|
73
|
+
end
|
62
74
|
|
63
|
-
|
64
|
-
|
65
|
-
|
75
|
+
print_h1 "Recent Activity"
|
76
|
+
print cyan
|
77
|
+
items = json_response["activity"]
|
78
|
+
if items.empty?
|
79
|
+
puts "No activity found."
|
66
80
|
print reset,"\n"
|
67
|
-
|
81
|
+
return 0
|
68
82
|
end
|
83
|
+
# JD: this api response is funky, no meta and it includes date objects
|
84
|
+
items = items.select { |item| item['_id'] || item['name'] }
|
85
|
+
print_recent_activity_table(items, options)
|
86
|
+
print reset,"\n"
|
87
|
+
return 0
|
88
|
+
|
69
89
|
rescue RestClient::Exception => e
|
70
90
|
print_rest_exception(e, options)
|
71
|
-
|
91
|
+
return 1
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def print_recent_activity_table(items, opts={})
|
96
|
+
columns = [
|
97
|
+
# {"ID" => lambda {|item| item['id'] } },
|
98
|
+
# {"SEVERITY" => lambda {|item| format_activity_severity(item['severity']) } },
|
99
|
+
{"TYPE" => lambda {|item| item['activityType'] } },
|
100
|
+
{"AUTHOR" => lambda {|item| item['userName'] || '' } },
|
101
|
+
{"MESSAGE" => lambda {|item| item['message'] || '' } },
|
102
|
+
# {"NAME" => lambda {|item| item['name'] } },
|
103
|
+
{"OBJECT" => lambda {|item| format_activity_display_object(item) } },
|
104
|
+
{"WHEN" => lambda {|item| format_local_dt(item['ts']) } }
|
105
|
+
# {"WHEN" => lambda {|item| "#{format_duration(item['ts'])} ago" } }
|
106
|
+
]
|
107
|
+
if opts[:include_fields]
|
108
|
+
columns = opts[:include_fields]
|
109
|
+
end
|
110
|
+
print as_pretty_table(items, columns, opts)
|
111
|
+
end
|
112
|
+
|
113
|
+
def format_activity_severity(severity, return_color=cyan)
|
114
|
+
out = ""
|
115
|
+
status_string = severity
|
116
|
+
if status_string == 'critical'
|
117
|
+
out << "#{red}#{status_string.capitalize}#{return_color}"
|
118
|
+
elsif status_string == 'warning'
|
119
|
+
out << "#{yellow}#{status_string.capitalize}#{return_color}"
|
120
|
+
elsif status_string == 'info'
|
121
|
+
out << "#{cyan}#{status_string.capitalize}#{return_color}"
|
122
|
+
else
|
123
|
+
out << "#{cyan}#{status_string}#{return_color}"
|
124
|
+
end
|
125
|
+
out
|
126
|
+
end
|
127
|
+
|
128
|
+
def format_activity_display_object(item)
|
129
|
+
out = ""
|
130
|
+
if item['name']
|
131
|
+
out << item['name']
|
132
|
+
end
|
133
|
+
if item['objectType']
|
134
|
+
out << " (#{item['objectType']} #{item['objectId']})"
|
135
|
+
end
|
136
|
+
if item['deleted']
|
137
|
+
out << " [deleted]"
|
72
138
|
end
|
139
|
+
out
|
73
140
|
end
|
74
141
|
|
75
142
|
end
|
data/lib/morpheus/cli/version.rb
CHANGED
data/lib/morpheus/rest_client.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: morpheus-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.11.
|
4
|
+
version: 2.11.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Estes
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2017-
|
14
|
+
date: 2017-06-26 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|