morpheus-cli 3.5.2 → 3.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/morpheus/api/api_client.rb +16 -0
- data/lib/morpheus/api/blueprints_interface.rb +84 -0
- data/lib/morpheus/api/execution_request_interface.rb +33 -0
- data/lib/morpheus/api/instances_interface.rb +21 -0
- data/lib/morpheus/api/packages_interface.rb +25 -5
- data/lib/morpheus/api/processes_interface.rb +34 -0
- data/lib/morpheus/api/roles_interface.rb +7 -0
- data/lib/morpheus/api/servers_interface.rb +8 -0
- data/lib/morpheus/api/user_settings_interface.rb +76 -0
- data/lib/morpheus/cli.rb +5 -1
- data/lib/morpheus/cli/alias_command.rb +1 -1
- data/lib/morpheus/cli/app_templates.rb +2 -1
- data/lib/morpheus/cli/apps.rb +173 -19
- data/lib/morpheus/cli/blueprints_command.rb +2134 -0
- data/lib/morpheus/cli/cli_command.rb +3 -1
- data/lib/morpheus/cli/clouds.rb +4 -10
- data/lib/morpheus/cli/coloring_command.rb +14 -8
- data/lib/morpheus/cli/containers_command.rb +92 -5
- data/lib/morpheus/cli/execution_request_command.rb +313 -0
- data/lib/morpheus/cli/hosts.rb +188 -7
- data/lib/morpheus/cli/instances.rb +472 -9
- data/lib/morpheus/cli/login.rb +1 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +8 -0
- data/lib/morpheus/cli/mixins/processes_helper.rb +134 -0
- data/lib/morpheus/cli/option_types.rb +21 -16
- data/lib/morpheus/cli/packages_command.rb +469 -17
- data/lib/morpheus/cli/processes_command.rb +313 -0
- data/lib/morpheus/cli/remote.rb +20 -9
- data/lib/morpheus/cli/roles.rb +186 -6
- data/lib/morpheus/cli/shell.rb +10 -1
- data/lib/morpheus/cli/tasks.rb +4 -1
- data/lib/morpheus/cli/user_settings_command.rb +431 -0
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/whoami.rb +1 -1
- data/lib/morpheus/formatters.rb +14 -0
- data/lib/morpheus/morpkg.rb +119 -0
- data/morpheus-cli.gemspec +1 -0
- metadata +26 -2
@@ -0,0 +1,313 @@
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
2
|
+
require 'morpheus/cli/mixins/processes_helper'
|
3
|
+
|
4
|
+
class Morpheus::Cli::Processes
|
5
|
+
include Morpheus::Cli::CliCommand
|
6
|
+
include Morpheus::Cli::ProcessesHelper
|
7
|
+
|
8
|
+
set_command_name :'process'
|
9
|
+
|
10
|
+
register_subcommands :list, :get, {:'get-event' => :event_details}
|
11
|
+
|
12
|
+
# alias_subcommand :details, :get
|
13
|
+
# set_default_subcommand :list
|
14
|
+
|
15
|
+
def initialize()
|
16
|
+
#@appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
17
|
+
end
|
18
|
+
|
19
|
+
def connect(opts)
|
20
|
+
@api_client = establish_remote_appliance_connection(opts)
|
21
|
+
@processes_interface = @api_client.processes
|
22
|
+
end
|
23
|
+
|
24
|
+
def handle(args)
|
25
|
+
handle_subcommand(args)
|
26
|
+
end
|
27
|
+
|
28
|
+
def list(args)
|
29
|
+
params = {}
|
30
|
+
options = {}
|
31
|
+
#options[:show_output] = true
|
32
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
33
|
+
opts.banner = subcommand_usage()
|
34
|
+
opts.on( nil, '--events', "Display sub processes (events)." ) do
|
35
|
+
options[:show_events] = true
|
36
|
+
end
|
37
|
+
opts.on( nil, '--output', "Display process output." ) do
|
38
|
+
options[:show_output] = true
|
39
|
+
end
|
40
|
+
opts.on('--instance ID', String, "Limit results to specific instance(s).") do |val|
|
41
|
+
params['instanceIds'] = val.split(',').collect {|it| it.to_s.strip }.reject { |it| it.empty? }
|
42
|
+
end
|
43
|
+
opts.on('--container ID', String, "Limit results to specific container(s).") do |val|
|
44
|
+
params['containerIds'] = val.split(',').collect {|it| it.to_s.strip }.reject { |it| it.empty? }
|
45
|
+
end
|
46
|
+
opts.on('--host ID', String, "Limit results to specific host(s).") do |val|
|
47
|
+
params['serverIds'] = val.split(',').collect {|it| it.to_s.strip }.reject { |it| it.empty? }
|
48
|
+
end
|
49
|
+
opts.on('--cloud ID', String, "Limit results to specific cloud(s).") do |val|
|
50
|
+
params['zoneIds'] = val.split(',').collect {|it| it.to_s.strip }.reject { |it| it.empty? }
|
51
|
+
end
|
52
|
+
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
53
|
+
opts.footer = "List historical processes."
|
54
|
+
end
|
55
|
+
optparse.parse!(args)
|
56
|
+
|
57
|
+
if args.count != 0
|
58
|
+
puts optparse
|
59
|
+
return 1
|
60
|
+
end
|
61
|
+
connect(options)
|
62
|
+
begin
|
63
|
+
params.merge!(parse_list_options(options))
|
64
|
+
# params[:query] = params.delete(:phrase) unless params[:phrase].nil?
|
65
|
+
if options[:dry_run]
|
66
|
+
print_dry_run @processes_interface.dry.list(params)
|
67
|
+
return
|
68
|
+
end
|
69
|
+
json_response = @processes_interface.list(params)
|
70
|
+
if options[:json]
|
71
|
+
puts as_json(json_response, options, "processes")
|
72
|
+
return 0
|
73
|
+
elsif options[:yaml]
|
74
|
+
puts as_yaml(json_response, options, "processes")
|
75
|
+
return 0
|
76
|
+
elsif options[:csv]
|
77
|
+
puts records_as_csv(json_response['processes'], options)
|
78
|
+
return 0
|
79
|
+
else
|
80
|
+
|
81
|
+
title = "Process List"
|
82
|
+
subtitles = []
|
83
|
+
if params[:query]
|
84
|
+
subtitles << "Search: #{params[:query]}".strip
|
85
|
+
end
|
86
|
+
subtitles += parse_list_subtitles(options)
|
87
|
+
print_h1 title, subtitles
|
88
|
+
if json_response['processes'].empty?
|
89
|
+
print "#{cyan}No process history found.#{reset}\n\n"
|
90
|
+
return 0
|
91
|
+
else
|
92
|
+
history_records = []
|
93
|
+
json_response["processes"].each do |process|
|
94
|
+
row = {
|
95
|
+
id: process['id'],
|
96
|
+
eventId: nil,
|
97
|
+
uniqueId: process['uniqueId'],
|
98
|
+
name: process['displayName'],
|
99
|
+
description: process['description'],
|
100
|
+
processType: process['processType'] ? (process['processType']['name'] || process['processType']['code']) : process['processTypeName'],
|
101
|
+
createdBy: process['createdBy'] ? (process['createdBy']['displayName'] || process['createdBy']['username']) : '',
|
102
|
+
startDate: format_local_dt(process['startDate']),
|
103
|
+
duration: format_process_duration(process),
|
104
|
+
status: format_process_status(process),
|
105
|
+
error: format_process_error(process),
|
106
|
+
output: format_process_output(process)
|
107
|
+
}
|
108
|
+
history_records << row
|
109
|
+
process_events = process['events'] || process['processEvents']
|
110
|
+
if options[:show_events]
|
111
|
+
if process_events
|
112
|
+
process_events.each do |process_event|
|
113
|
+
event_row = {
|
114
|
+
id: process['id'],
|
115
|
+
eventId: process_event['id'],
|
116
|
+
uniqueId: process_event['uniqueId'],
|
117
|
+
name: process_event['displayName'], # blank like the UI
|
118
|
+
description: process_event['description'],
|
119
|
+
processType: process_event['processType'] ? (process_event['processType']['name'] || process_event['processType']['code']) : process['processTypeName'],
|
120
|
+
createdBy: process_event['createdBy'] ? (process_event['createdBy']['displayName'] || process_event['createdBy']['username']) : '',
|
121
|
+
startDate: format_local_dt(process_event['startDate']),
|
122
|
+
duration: format_process_duration(process_event),
|
123
|
+
status: format_process_status(process_event),
|
124
|
+
error: format_process_error(process_event),
|
125
|
+
output: format_process_output(process_event)
|
126
|
+
}
|
127
|
+
history_records << event_row
|
128
|
+
end
|
129
|
+
else
|
130
|
+
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
columns = [
|
135
|
+
{:id => {:display_name => "PROCESS ID"} },
|
136
|
+
:name,
|
137
|
+
:description,
|
138
|
+
{:processType => {:display_name => "PROCESS TYPE"} },
|
139
|
+
{:createdBy => {:display_name => "CREATED BY"} },
|
140
|
+
{:startDate => {:display_name => "START DATE"} },
|
141
|
+
{:duration => {:display_name => "ETA/DURATION"} },
|
142
|
+
:status,
|
143
|
+
:error
|
144
|
+
]
|
145
|
+
if options[:show_events]
|
146
|
+
columns.insert(1, {:eventId => {:display_name => "EVENT ID"} })
|
147
|
+
end
|
148
|
+
if options[:show_output]
|
149
|
+
columns << :output
|
150
|
+
end
|
151
|
+
# custom pretty table columns ...
|
152
|
+
if options[:include_fields]
|
153
|
+
columns = options[:include_fields]
|
154
|
+
end
|
155
|
+
print cyan
|
156
|
+
print as_pretty_table(history_records, columns, options)
|
157
|
+
#print_results_pagination(json_response)
|
158
|
+
if options[:show_events]
|
159
|
+
print_results_pagination({size: history_records.size, total: history_records.size}, {:label => "process", :n_label => "processes"})
|
160
|
+
else
|
161
|
+
print_results_pagination(json_response, {:label => "process", :n_label => "processes"})
|
162
|
+
end
|
163
|
+
print reset, "\n"
|
164
|
+
return 0
|
165
|
+
end
|
166
|
+
end
|
167
|
+
rescue RestClient::Exception => e
|
168
|
+
print_rest_exception(e, options)
|
169
|
+
exit 1
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def get(args)
|
174
|
+
options = {}
|
175
|
+
params = {}
|
176
|
+
process_id = nil
|
177
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
178
|
+
opts.banner = subcommand_usage("[id]")
|
179
|
+
build_common_options(opts, options, [:query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
180
|
+
opts.footer = "Display details for a specific process.\n"
|
181
|
+
"[id] is required. This is the id of the process."
|
182
|
+
end
|
183
|
+
optparse.parse!(args)
|
184
|
+
if args.count != 1
|
185
|
+
puts_error optparse
|
186
|
+
return 1
|
187
|
+
end
|
188
|
+
connect(options)
|
189
|
+
begin
|
190
|
+
process_id = args[0]
|
191
|
+
params.merge!(parse_list_options(options))
|
192
|
+
params[:query] = params.delete(:phrase) unless params[:phrase].nil?
|
193
|
+
if options[:dry_run]
|
194
|
+
print_dry_run @processes_interface.dry.get(process_id, params)
|
195
|
+
return
|
196
|
+
end
|
197
|
+
json_response = @processes_interface.get(process_id, params)
|
198
|
+
if options[:json]
|
199
|
+
puts as_json(json_response, options, "process")
|
200
|
+
return 0
|
201
|
+
elsif options[:yaml]
|
202
|
+
puts as_yaml(json_response, options, "process")
|
203
|
+
return 0
|
204
|
+
elsif options[:csv]
|
205
|
+
puts records_as_csv(json_response['process'], options)
|
206
|
+
return 0
|
207
|
+
else
|
208
|
+
process = json_response["process"]
|
209
|
+
title = "Process Details"
|
210
|
+
subtitles = []
|
211
|
+
subtitles << " Process ID: #{process_id}"
|
212
|
+
subtitles += parse_list_subtitles(options)
|
213
|
+
print_h1 title, subtitles
|
214
|
+
print_process_details(process)
|
215
|
+
|
216
|
+
print_h2 "Process Events"
|
217
|
+
process_events = process['events'] || process['processEvents'] || []
|
218
|
+
history_records = []
|
219
|
+
if process_events.empty?
|
220
|
+
puts "#{cyan}No events found.#{reset}"
|
221
|
+
else
|
222
|
+
process_events.each do |process_event|
|
223
|
+
event_row = {
|
224
|
+
id: process_event['id'],
|
225
|
+
eventId: process_event['id'],
|
226
|
+
uniqueId: process_event['uniqueId'],
|
227
|
+
name: process_event['displayName'], # blank like the UI
|
228
|
+
description: process_event['description'],
|
229
|
+
processType: process_event['processType'] ? (process_event['processType']['name'] || process_event['processType']['code']) : process['processTypeName'],
|
230
|
+
createdBy: process_event['createdBy'] ? (process_event['createdBy']['displayName'] || process_event['createdBy']['username']) : '',
|
231
|
+
startDate: format_local_dt(process_event['startDate']),
|
232
|
+
duration: format_process_duration(process_event),
|
233
|
+
status: format_process_status(process_event),
|
234
|
+
error: format_process_error(process_event),
|
235
|
+
output: format_process_output(process_event)
|
236
|
+
}
|
237
|
+
history_records << event_row
|
238
|
+
end
|
239
|
+
columns = [
|
240
|
+
{:id => {:display_name => "EVENT ID"} },
|
241
|
+
:name,
|
242
|
+
:description,
|
243
|
+
{:processType => {:display_name => "PROCESS TYPE"} },
|
244
|
+
{:createdBy => {:display_name => "CREATED BY"} },
|
245
|
+
{:startDate => {:display_name => "START DATE"} },
|
246
|
+
{:duration => {:display_name => "ETA/DURATION"} },
|
247
|
+
:status,
|
248
|
+
:error,
|
249
|
+
:output
|
250
|
+
]
|
251
|
+
print cyan
|
252
|
+
print as_pretty_table(history_records, columns, options)
|
253
|
+
print_results_pagination({size: process_events.size, total: process_events.size})
|
254
|
+
print reset, "\n"
|
255
|
+
return 0
|
256
|
+
end
|
257
|
+
end
|
258
|
+
rescue RestClient::Exception => e
|
259
|
+
print_rest_exception(e, options)
|
260
|
+
exit 1
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
def event_details(args)
|
265
|
+
options = {}
|
266
|
+
params = {}
|
267
|
+
process_event_id = nil
|
268
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
269
|
+
opts.banner = subcommand_usage("[event-id]")
|
270
|
+
build_common_options(opts, options, [:query, :json, :yaml, :csv, :fields, :dry_run, :remote])
|
271
|
+
opts.footer = "Display details for a specific process event.\n" +
|
272
|
+
"[event-id] is required. This is the id of the process event."
|
273
|
+
end
|
274
|
+
optparse.parse!(args)
|
275
|
+
if args.count != 1
|
276
|
+
puts_error optparse
|
277
|
+
return 1
|
278
|
+
end
|
279
|
+
connect(options)
|
280
|
+
begin
|
281
|
+
process_event_id = args[0]
|
282
|
+
params.merge!(parse_list_options(options))
|
283
|
+
if options[:dry_run]
|
284
|
+
print_dry_run @processes_interface.dry.get_event(process_event_id, params)
|
285
|
+
return
|
286
|
+
end
|
287
|
+
json_response = @processes_interface.get_event(process_event_id, params)
|
288
|
+
if options[:json]
|
289
|
+
puts as_json(json_response, options, "processEvent")
|
290
|
+
return 0
|
291
|
+
elsif options[:yaml]
|
292
|
+
puts as_yaml(json_response, options, "processEvent")
|
293
|
+
return 0
|
294
|
+
elsif options[:csv]
|
295
|
+
puts records_as_csv(json_response['processEvent'], options)
|
296
|
+
return 0
|
297
|
+
else
|
298
|
+
process_event = json_response['processEvent'] || json_response['event']
|
299
|
+
title = "Process Event Details"
|
300
|
+
subtitles = []
|
301
|
+
subtitles += parse_list_subtitles(options)
|
302
|
+
print_h1 title, subtitles
|
303
|
+
print_process_event_details(process_event)
|
304
|
+
print reset, "\n"
|
305
|
+
return 0
|
306
|
+
end
|
307
|
+
rescue RestClient::Exception => e
|
308
|
+
print_rest_exception(e, options)
|
309
|
+
exit 1
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
data/lib/morpheus/cli/remote.rb
CHANGED
@@ -75,7 +75,7 @@ EOT
|
|
75
75
|
columns = [
|
76
76
|
{:active => {:display_name => "", :display_method => lambda {|it| it[:active] ? "=>" : "" } } },
|
77
77
|
{:name => {:width => 16} },
|
78
|
-
{:
|
78
|
+
{:url => {display_method: lambda {|it| it[:host] || it[:url] }, :width => 40 } },
|
79
79
|
{:version => lambda {|it| it[:build_version] } },
|
80
80
|
{:status => lambda {|it| format_appliance_status(it, cyan) } },
|
81
81
|
:username,
|
@@ -234,6 +234,9 @@ EOT
|
|
234
234
|
if ::Morpheus::Cli::OptionTypes::confirm("Would you like to login now?", options.merge({default: true}))
|
235
235
|
login_result = ::Morpheus::Cli::Login.new.handle(["--remote", appliance[:name].to_s])
|
236
236
|
keep_trying = true
|
237
|
+
if login_result == 0
|
238
|
+
keep_trying = false
|
239
|
+
end
|
237
240
|
while keep_trying do
|
238
241
|
if ::Morpheus::Cli::OptionTypes::confirm("Login was unsuccessful. Would you like to try again?", options.merge({default: true}))
|
239
242
|
login_result = ::Morpheus::Cli::Login.new.handle(["--remote", appliance[:name].to_s])
|
@@ -246,6 +249,13 @@ EOT
|
|
246
249
|
end
|
247
250
|
|
248
251
|
end
|
252
|
+
|
253
|
+
if !appliance[:active]
|
254
|
+
if ::Morpheus::Cli::OptionTypes::confirm("Would you like to switch to using this remote now?", options.merge({default: true}))
|
255
|
+
use([appliance[:name]])
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
249
259
|
else
|
250
260
|
#puts "Status is #{format_appliance_status(appliance)}"
|
251
261
|
end
|
@@ -487,7 +497,7 @@ EOT
|
|
487
497
|
print cyan
|
488
498
|
description_cols = {
|
489
499
|
"Name" => :name,
|
490
|
-
"
|
500
|
+
"URL" => :host,
|
491
501
|
"Secure" => lambda {|it| format_appliance_secure(it) },
|
492
502
|
"Version" => lambda {|it| it[:build_version] ? "#{it[:build_version]}" : 'unknown' },
|
493
503
|
"Status" => lambda {|it| format_appliance_status(it, cyan) },
|
@@ -507,11 +517,10 @@ EOT
|
|
507
517
|
|
508
518
|
if appliance[:active]
|
509
519
|
# print cyan
|
510
|
-
print cyan, "
|
520
|
+
print cyan, " => This is the current appliance.", reset, "\n\n"
|
511
521
|
end
|
512
522
|
|
513
|
-
|
514
|
-
|
523
|
+
return 0
|
515
524
|
rescue RestClient::Exception => e
|
516
525
|
print_rest_exception(e, options)
|
517
526
|
exit 1
|
@@ -865,7 +874,8 @@ EOT
|
|
865
874
|
def format_appliance_secure(app_map, return_color=cyan)
|
866
875
|
return "" if !app_map
|
867
876
|
out = ""
|
868
|
-
|
877
|
+
app_url = (app_map[:host] || app_map[:url]).to_s
|
878
|
+
is_ssl = app_url =~ /^https/
|
869
879
|
if !is_ssl
|
870
880
|
out << "No (no SSL)"
|
871
881
|
else
|
@@ -960,10 +970,11 @@ EOT
|
|
960
970
|
return nil, nil
|
961
971
|
end
|
962
972
|
app_name, app_map = self.appliances.find {|k,v| v[:active] == true }
|
973
|
+
app_url = app_map ? (app_map[:host] || app_map[:url]).to_s : nil
|
963
974
|
if app_name
|
964
|
-
return app_name,
|
975
|
+
return app_name, app_url
|
965
976
|
else
|
966
|
-
return
|
977
|
+
return nil, nil
|
967
978
|
end
|
968
979
|
end
|
969
980
|
|
@@ -1141,7 +1152,7 @@ EOT
|
|
1141
1152
|
app_name = app_name.to_sym
|
1142
1153
|
cur_appliances = self.appliances
|
1143
1154
|
app_map = cur_appliances[app_name] || {}
|
1144
|
-
app_url = app_map[:host]
|
1155
|
+
app_url = (app_map[:host] || app_map[:url]).to_s
|
1145
1156
|
|
1146
1157
|
if !app_url
|
1147
1158
|
raise "appliance config is missing url!" # should not need this
|
data/lib/morpheus/cli/roles.rb
CHANGED
@@ -10,7 +10,7 @@ require 'json'
|
|
10
10
|
class Morpheus::Cli::Roles
|
11
11
|
include Morpheus::Cli::CliCommand
|
12
12
|
include Morpheus::Cli::AccountsHelper
|
13
|
-
register_subcommands :list, :get, :add, :update, :remove, :'update-feature-access', :'update-global-group-access', :'update-group-access', :'update-global-cloud-access', :'update-cloud-access', :'update-global-instance-type-access', :'update-instance-type-access'
|
13
|
+
register_subcommands :list, :get, :add, :update, :remove, :'update-feature-access', :'update-global-group-access', :'update-group-access', :'update-global-cloud-access', :'update-cloud-access', :'update-global-instance-type-access', :'update-instance-type-access', :'update-global-blueprint-access', :'update-blueprint-access'
|
14
14
|
alias_subcommand :details, :get
|
15
15
|
set_default_subcommand :list
|
16
16
|
|
@@ -24,6 +24,7 @@ class Morpheus::Cli::Roles
|
|
24
24
|
@options_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).options
|
25
25
|
#@clouds_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
|
26
26
|
@instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
|
27
|
+
@blueprints_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).blueprints
|
27
28
|
@active_group_id = Morpheus::Cli::Groups.active_group
|
28
29
|
end
|
29
30
|
|
@@ -87,23 +88,27 @@ class Morpheus::Cli::Roles
|
|
87
88
|
options = {}
|
88
89
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
89
90
|
opts.banner = subcommand_usage("[name]")
|
90
|
-
opts.on(
|
91
|
+
opts.on('-f','--feature-access', "Display Feature Access") do |val|
|
91
92
|
options[:include_feature_access] = true
|
92
93
|
end
|
93
|
-
opts.on(
|
94
|
+
opts.on('-g','--group-access', "Display Group Access") do
|
94
95
|
options[:include_group_access] = true
|
95
96
|
end
|
96
|
-
opts.on(
|
97
|
+
opts.on('-c','--cloud-access', "Display Cloud Access") do
|
97
98
|
options[:include_cloud_access] = true
|
98
99
|
end
|
99
|
-
opts.on(
|
100
|
+
opts.on('-i','--instance-type-access', "Display Instance Type Access") do
|
100
101
|
options[:include_instance_type_access] = true
|
101
102
|
end
|
102
|
-
opts.on(
|
103
|
+
opts.on('-b','--blueprint-access', "Display Blueprint Access") do
|
104
|
+
options[:include_blueprint_access] = true
|
105
|
+
end
|
106
|
+
opts.on('-a','--all-access', "Display All Access Lists") do
|
103
107
|
options[:include_feature_access] = true
|
104
108
|
options[:include_group_access] = true
|
105
109
|
options[:include_cloud_access] = true
|
106
110
|
options[:include_instance_type_access] = true
|
111
|
+
options[:include_blueprint_access] = true
|
107
112
|
end
|
108
113
|
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
109
114
|
opts.footer = "Get details about a role.\n" +
|
@@ -250,6 +255,25 @@ class Morpheus::Cli::Roles
|
|
250
255
|
end
|
251
256
|
end
|
252
257
|
|
258
|
+
blueprint_global_access = json_response['globalAppTemplateAccess'] || json_response['globalBlueprintAccess']
|
259
|
+
blueprint_permissions = json_response['appTemplatePermissions'] || json_response['blueprintPermissions'] || []
|
260
|
+
print_h2 "Blueprint Access"
|
261
|
+
print cyan
|
262
|
+
puts "Global Blueprint Access: #{get_access_string(json_response['globalAppTemplateAccess'])}\n\n"
|
263
|
+
if blueprint_global_access == 'custom'
|
264
|
+
if options[:include_blueprint_access]
|
265
|
+
rows = blueprint_permissions.collect do |it|
|
266
|
+
{
|
267
|
+
name: it['name'],
|
268
|
+
access: get_access_string(it['access']),
|
269
|
+
}
|
270
|
+
end
|
271
|
+
tp rows, [:name, :access]
|
272
|
+
else
|
273
|
+
puts "Use --blueprint-access to list custom access"
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
253
277
|
print reset,"\n"
|
254
278
|
return 0
|
255
279
|
rescue RestClient::Exception => e
|
@@ -971,6 +995,162 @@ class Morpheus::Cli::Roles
|
|
971
995
|
end
|
972
996
|
end
|
973
997
|
|
998
|
+
def update_global_blueprint_access(args)
|
999
|
+
usage = "Usage: morpheus roles update-global-blueprint-access [name] [full|custom|none]"
|
1000
|
+
options = {}
|
1001
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1002
|
+
opts.banner = subcommand_usage("[name] [full|custom|none]")
|
1003
|
+
build_common_options(opts, options, [:json, :dry_run, :remote])
|
1004
|
+
end
|
1005
|
+
optparse.parse!(args)
|
1006
|
+
|
1007
|
+
if args.count < 2
|
1008
|
+
puts optparse
|
1009
|
+
exit 1
|
1010
|
+
end
|
1011
|
+
name = args[0]
|
1012
|
+
access_value = args[1].to_s.downcase
|
1013
|
+
if !['full', 'custom', 'none'].include?(access_value)
|
1014
|
+
puts optparse
|
1015
|
+
exit 1
|
1016
|
+
end
|
1017
|
+
|
1018
|
+
|
1019
|
+
connect(options)
|
1020
|
+
begin
|
1021
|
+
account = find_account_from_options(options)
|
1022
|
+
account_id = account ? account['id'] : nil
|
1023
|
+
role = find_role_by_name_or_id(account_id, name)
|
1024
|
+
exit 1 if role.nil?
|
1025
|
+
|
1026
|
+
params = {permissionCode: 'AppTemplate', access: access_value}
|
1027
|
+
if options[:dry_run]
|
1028
|
+
print_dry_run @roles_interface.dry.update_permission(account_id, role['id'], params)
|
1029
|
+
return
|
1030
|
+
end
|
1031
|
+
json_response = @roles_interface.update_permission(account_id, role['id'], params)
|
1032
|
+
|
1033
|
+
if options[:json]
|
1034
|
+
print JSON.pretty_generate(json_response)
|
1035
|
+
print "\n"
|
1036
|
+
else
|
1037
|
+
print_green_success "Role #{role['authority']} global blueprint access updated"
|
1038
|
+
end
|
1039
|
+
rescue RestClient::Exception => e
|
1040
|
+
print_rest_exception(e, options)
|
1041
|
+
exit 1
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
def update_blueprint_access(args)
|
1046
|
+
options = {}
|
1047
|
+
blueprint_id = nil
|
1048
|
+
access_value = nil
|
1049
|
+
do_all = false
|
1050
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
1051
|
+
opts.banner = subcommand_usage("[name]")
|
1052
|
+
opts.on( '--blueprint ID', String, "Blueprint ID or Name" ) do |val|
|
1053
|
+
blueprint_id = val
|
1054
|
+
end
|
1055
|
+
opts.on( nil, '--all', "Update all blueprints at once." ) do
|
1056
|
+
do_all = true
|
1057
|
+
end
|
1058
|
+
opts.on( '--access VALUE', String, "Access value [full|read|none]" ) do |val|
|
1059
|
+
access_value = val
|
1060
|
+
end
|
1061
|
+
build_common_options(opts, options, [:json, :dry_run, :remote])
|
1062
|
+
opts.footer = "Update role access for an blueprint or all blueprints.\n" +
|
1063
|
+
"[name] is required. This is the name or id of a role.\n" +
|
1064
|
+
"--blueprint or --all is required. This is the name or id of a blueprint.\n" +
|
1065
|
+
"--access is required. This is the new access value."
|
1066
|
+
end
|
1067
|
+
optparse.parse!(args)
|
1068
|
+
|
1069
|
+
if args.count < 1
|
1070
|
+
puts optparse
|
1071
|
+
return 1
|
1072
|
+
end
|
1073
|
+
name = args[0]
|
1074
|
+
# support old usage: [name] [blueprint] [access]
|
1075
|
+
blueprint_id ||= args[1]
|
1076
|
+
access_value ||= args[2]
|
1077
|
+
|
1078
|
+
if (!blueprint_id && !do_all) || !access_value
|
1079
|
+
puts_error optparse
|
1080
|
+
return 1
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
access_value = access_value.to_s.downcase
|
1084
|
+
|
1085
|
+
if !['full', 'none'].include?(access_value)
|
1086
|
+
puts optparse
|
1087
|
+
return 1
|
1088
|
+
end
|
1089
|
+
|
1090
|
+
connect(options)
|
1091
|
+
begin
|
1092
|
+
account = find_account_from_options(options)
|
1093
|
+
account_id = account ? account['id'] : nil
|
1094
|
+
role = find_role_by_name_or_id(account_id, name)
|
1095
|
+
return 1 if role.nil?
|
1096
|
+
|
1097
|
+
role_json = @roles_interface.get(account_id, role['id'])
|
1098
|
+
blueprint_global_access = role_json['globalAppTemplateAccess'] || role_json['globalBlueprintAccess']
|
1099
|
+
blueprint_permissions = role_json['appTemplatePermissions'] || role_json['blueprintPermissions'] || []
|
1100
|
+
if blueprint_global_access != 'custom'
|
1101
|
+
print "\n", red, "Global Blueprint Access is currently: #{blueprint_global_access.to_s.capitalize}"
|
1102
|
+
print "\n", "You must first set it to Custom via `morpheus roles update-global-blueprint-access \"#{name}\" custom`"
|
1103
|
+
print "\n\n", reset
|
1104
|
+
return 1
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
# hacky, but support name or code lookup via the list returned in the show payload
|
1108
|
+
blueprint = nil
|
1109
|
+
if !do_all
|
1110
|
+
if blueprint_id.to_s =~ /\A\d{1,}\Z/
|
1111
|
+
blueprint = blueprint_permissions.find {|b| b['id'] == blueprint_id.to_i }
|
1112
|
+
else
|
1113
|
+
blueprint = blueprint_permissions.find {|b| b['name'] == blueprint_id || b['code'] == blueprint_id }
|
1114
|
+
end
|
1115
|
+
if blueprint.nil?
|
1116
|
+
print_red_alert "Blueprint not found: '#{blueprint_id}'"
|
1117
|
+
return 1
|
1118
|
+
end
|
1119
|
+
end
|
1120
|
+
|
1121
|
+
params = {}
|
1122
|
+
if do_all
|
1123
|
+
params['allAppTemplates'] = true
|
1124
|
+
#params['allBlueprints'] = true
|
1125
|
+
else
|
1126
|
+
params['appTemplateId'] = blueprint['id']
|
1127
|
+
# params['blueprintId'] = blueprint['id']
|
1128
|
+
end
|
1129
|
+
params['access'] = access_value
|
1130
|
+
|
1131
|
+
if options[:dry_run]
|
1132
|
+
print_dry_run @roles_interface.dry.update_blueprint(account_id, role['id'], params)
|
1133
|
+
return
|
1134
|
+
end
|
1135
|
+
json_response = @roles_interface.update_blueprint(account_id, role['id'], params)
|
1136
|
+
|
1137
|
+
if options[:json]
|
1138
|
+
print JSON.pretty_generate(json_response)
|
1139
|
+
print "\n"
|
1140
|
+
else
|
1141
|
+
if do_all
|
1142
|
+
print_green_success "Role #{role['authority']} access updated for all blueprints"
|
1143
|
+
else
|
1144
|
+
print_green_success "Role #{role['authority']} access updated for blueprint #{blueprint['name']}"
|
1145
|
+
end
|
1146
|
+
end
|
1147
|
+
return 0
|
1148
|
+
rescue RestClient::Exception => e
|
1149
|
+
print_rest_exception(e, options)
|
1150
|
+
exit 1
|
1151
|
+
end
|
1152
|
+
end
|
1153
|
+
|
974
1154
|
private
|
975
1155
|
# def get_access_string(val)
|
976
1156
|
# val ||= 'none'
|