morpheus-cli 3.5.2 → 3.5.3

Sign up to get free protection for your applications and to get access to all the features.
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'