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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/morpheus/api/api_client.rb +16 -0
  3. data/lib/morpheus/api/blueprints_interface.rb +84 -0
  4. data/lib/morpheus/api/execution_request_interface.rb +33 -0
  5. data/lib/morpheus/api/instances_interface.rb +21 -0
  6. data/lib/morpheus/api/packages_interface.rb +25 -5
  7. data/lib/morpheus/api/processes_interface.rb +34 -0
  8. data/lib/morpheus/api/roles_interface.rb +7 -0
  9. data/lib/morpheus/api/servers_interface.rb +8 -0
  10. data/lib/morpheus/api/user_settings_interface.rb +76 -0
  11. data/lib/morpheus/cli.rb +5 -1
  12. data/lib/morpheus/cli/alias_command.rb +1 -1
  13. data/lib/morpheus/cli/app_templates.rb +2 -1
  14. data/lib/morpheus/cli/apps.rb +173 -19
  15. data/lib/morpheus/cli/blueprints_command.rb +2134 -0
  16. data/lib/morpheus/cli/cli_command.rb +3 -1
  17. data/lib/morpheus/cli/clouds.rb +4 -10
  18. data/lib/morpheus/cli/coloring_command.rb +14 -8
  19. data/lib/morpheus/cli/containers_command.rb +92 -5
  20. data/lib/morpheus/cli/execution_request_command.rb +313 -0
  21. data/lib/morpheus/cli/hosts.rb +188 -7
  22. data/lib/morpheus/cli/instances.rb +472 -9
  23. data/lib/morpheus/cli/login.rb +1 -1
  24. data/lib/morpheus/cli/mixins/print_helper.rb +8 -0
  25. data/lib/morpheus/cli/mixins/processes_helper.rb +134 -0
  26. data/lib/morpheus/cli/option_types.rb +21 -16
  27. data/lib/morpheus/cli/packages_command.rb +469 -17
  28. data/lib/morpheus/cli/processes_command.rb +313 -0
  29. data/lib/morpheus/cli/remote.rb +20 -9
  30. data/lib/morpheus/cli/roles.rb +186 -6
  31. data/lib/morpheus/cli/shell.rb +10 -1
  32. data/lib/morpheus/cli/tasks.rb +4 -1
  33. data/lib/morpheus/cli/user_settings_command.rb +431 -0
  34. data/lib/morpheus/cli/version.rb +1 -1
  35. data/lib/morpheus/cli/whoami.rb +1 -1
  36. data/lib/morpheus/formatters.rb +14 -0
  37. data/lib/morpheus/morpkg.rb +119 -0
  38. data/morpheus-cli.gemspec +1 -0
  39. 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
@@ -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
- {:host => {:width => 40} },
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
- "Url" => :host,
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, "\n", " => This is the current appliance.", "\n"
520
+ print cyan, " => This is the current appliance.", reset, "\n\n"
511
521
  end
512
522
 
513
- print reset, "\n"
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
- is_ssl = app_map[:host].to_s =~ /^https/
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, app_map[:host]
975
+ return app_name, app_url
965
976
  else
966
- return app_name, nil
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] # || app_map[:url] maybe??
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
@@ -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(nil,'--feature-access', "Display Feature Access") do |val|
91
+ opts.on('-f','--feature-access', "Display Feature Access") do |val|
91
92
  options[:include_feature_access] = true
92
93
  end
93
- opts.on(nil,'--group-access', "Display Group Access") do
94
+ opts.on('-g','--group-access', "Display Group Access") do
94
95
  options[:include_group_access] = true
95
96
  end
96
- opts.on(nil,'--cloud-access', "Display Cloud Access") do
97
+ opts.on('-c','--cloud-access', "Display Cloud Access") do
97
98
  options[:include_cloud_access] = true
98
99
  end
99
- opts.on(nil,'--instance-type-access', "Display Instance Type Access") do
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(nil,'--all-access', "Display All Access Lists") do
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'