morpheus-cli 4.2.8 → 4.2.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/lib/morpheus/api.rb +1 -1
  4. data/lib/morpheus/api/activity_interface.rb +9 -0
  5. data/lib/morpheus/api/api_client.rb +83 -27
  6. data/lib/morpheus/api/apps_interface.rb +21 -0
  7. data/lib/morpheus/api/dashboard_interface.rb +5 -21
  8. data/lib/morpheus/api/instances_interface.rb +3 -10
  9. data/lib/morpheus/api/invoice_line_items_interface.rb +14 -0
  10. data/lib/morpheus/api/invoices_interface.rb +7 -12
  11. data/lib/morpheus/api/library_layouts_interface.rb +8 -0
  12. data/lib/morpheus/api/ping_interface.rb +20 -0
  13. data/lib/morpheus/api/projects_interface.rb +33 -0
  14. data/lib/morpheus/api/setup_interface.rb +19 -36
  15. data/lib/morpheus/api/user_settings_interface.rb +0 -6
  16. data/lib/morpheus/api/whoami_interface.rb +4 -8
  17. data/lib/morpheus/benchmarking.rb +16 -26
  18. data/lib/morpheus/cli.rb +10 -5
  19. data/lib/morpheus/cli/access_token_command.rb +5 -8
  20. data/lib/morpheus/cli/activity_command.rb +146 -0
  21. data/lib/morpheus/cli/apps.rb +312 -121
  22. data/lib/morpheus/cli/archives_command.rb +1 -1
  23. data/lib/morpheus/cli/auth_command.rb +4 -11
  24. data/lib/morpheus/cli/blueprints_command.rb +196 -137
  25. data/lib/morpheus/cli/change_password_command.rb +1 -1
  26. data/lib/morpheus/cli/cli_command.rb +225 -72
  27. data/lib/morpheus/cli/cli_registry.rb +2 -2
  28. data/lib/morpheus/cli/cloud_datastores_command.rb +1 -1
  29. data/lib/morpheus/cli/clouds.rb +5 -20
  30. data/lib/morpheus/cli/clusters.rb +4 -28
  31. data/lib/morpheus/cli/commands/standard/alias_command.rb +2 -9
  32. data/lib/morpheus/cli/commands/standard/benchmark_command.rb +2 -0
  33. data/lib/morpheus/cli/commands/standard/curl_command.rb +2 -3
  34. data/lib/morpheus/cli/commands/standard/history_command.rb +3 -6
  35. data/lib/morpheus/cli/commands/standard/man_command.rb +10 -7
  36. data/lib/morpheus/cli/commands/standard/ssl_verification_command.rb +10 -9
  37. data/lib/morpheus/cli/containers_command.rb +3 -3
  38. data/lib/morpheus/cli/credentials.rb +13 -16
  39. data/lib/morpheus/cli/error_handler.rb +18 -12
  40. data/lib/morpheus/cli/errors.rb +45 -0
  41. data/lib/morpheus/cli/execute_schedules_command.rb +1 -1
  42. data/lib/morpheus/cli/execution_request_command.rb +4 -4
  43. data/lib/morpheus/cli/groups.rb +84 -132
  44. data/lib/morpheus/cli/hosts.rb +6 -16
  45. data/lib/morpheus/cli/instances.rb +100 -183
  46. data/lib/morpheus/cli/invoices_command.rb +505 -71
  47. data/lib/morpheus/cli/library_layouts_command.rb +254 -166
  48. data/lib/morpheus/cli/library_option_lists_command.rb +0 -87
  49. data/lib/morpheus/cli/library_option_types_command.rb +0 -96
  50. data/lib/morpheus/cli/license.rb +3 -0
  51. data/lib/morpheus/cli/login.rb +17 -37
  52. data/lib/morpheus/cli/logout.rb +9 -5
  53. data/lib/morpheus/cli/mixins/accounts_helper.rb +83 -7
  54. data/lib/morpheus/cli/mixins/operations_helper.rb +41 -0
  55. data/lib/morpheus/cli/mixins/option_source_helper.rb +255 -0
  56. data/lib/morpheus/cli/mixins/print_helper.rb +18 -4
  57. data/lib/morpheus/cli/mixins/provisioning_helper.rb +222 -13
  58. data/lib/morpheus/cli/mixins/remote_helper.rb +139 -0
  59. data/lib/morpheus/cli/monitoring_checks_command.rb +11 -3
  60. data/lib/morpheus/cli/network_groups_command.rb +8 -2
  61. data/lib/morpheus/cli/option_types.rb +1 -1
  62. data/lib/morpheus/cli/ping.rb +252 -0
  63. data/lib/morpheus/cli/price_sets_command.rb +16 -27
  64. data/lib/morpheus/cli/prices_command.rb +34 -27
  65. data/lib/morpheus/cli/processes_command.rb +81 -7
  66. data/lib/morpheus/cli/projects_command.rb +607 -0
  67. data/lib/morpheus/cli/recent_activity_command.rb +87 -65
  68. data/lib/morpheus/cli/remote.rb +965 -974
  69. data/lib/morpheus/cli/reports_command.rb +3 -15
  70. data/lib/morpheus/cli/roles.rb +8 -31
  71. data/lib/morpheus/cli/service_plans_command.rb +25 -31
  72. data/lib/morpheus/cli/setup.rb +392 -0
  73. data/lib/morpheus/cli/shell.rb +144 -56
  74. data/lib/morpheus/cli/subnets_command.rb +71 -11
  75. data/lib/morpheus/cli/tasks.rb +3 -3
  76. data/lib/morpheus/cli/user_sources_command.rb +4 -4
  77. data/lib/morpheus/cli/users.rb +135 -109
  78. data/lib/morpheus/cli/version.rb +1 -1
  79. data/lib/morpheus/cli/whitelabel_settings_command.rb +7 -7
  80. data/lib/morpheus/cli/whoami.rb +90 -129
  81. data/lib/morpheus/cli/wiki_command.rb +2 -14
  82. data/lib/morpheus/ext/rest_client.rb +36 -0
  83. data/lib/morpheus/formatters.rb +42 -5
  84. data/lib/morpheus/rest_client.rb +0 -10
  85. data/lib/morpheus/terminal.rb +41 -1
  86. data/lib/morpheus/util.rb +24 -0
  87. metadata +16 -3
  88. data/lib/morpheus/cli/command_error.rb +0 -22
@@ -6,11 +6,14 @@ require 'morpheus/cli/mixins/library_helper'
6
6
 
7
7
  class Morpheus::Cli::LibraryLayoutsCommand
8
8
  include Morpheus::Cli::CliCommand
9
+ include Morpheus::Cli::ProvisioningHelper
10
+ # make sure LibraryHelper is loaded after ProvisioningHelper because it overwrites some methods like find_instance_type_by_name
11
+ # ProvisioningHelper is needed just for permissions (resourcePermissions)
9
12
  include Morpheus::Cli::LibraryHelper
10
13
 
11
14
  set_command_name :'library-layouts'
12
15
 
13
- register_subcommands :list, :get, :add, :update, :remove
16
+ register_subcommands :list, :get, :add, :update, :remove, :update_permissions
14
17
 
15
18
  def initialize()
16
19
  # @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
@@ -108,14 +111,18 @@ class Morpheus::Cli::LibraryLayoutsCommand
108
111
  def get(args)
109
112
  options = {}
110
113
  optparse = Morpheus::Cli::OptionParser.new do |opts|
111
- opts.banner = subcommand_usage("[name]")
112
- build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
114
+ opts.banner = subcommand_usage("[layout]")
115
+ # opts.on( nil, '--permissions', "Display permissions" ) do
116
+ # options[:show_perms] = true
117
+ # end
118
+ build_standard_get_options(opts, options)
119
+ opts.footer = <<-EOT
120
+ Get details about a layout.
121
+ [layout] is required. This is the name or id of a layout.
122
+ EOT
113
123
  end
124
+ verify_args!(args:args, optparse:optparse, min:1)
114
125
  optparse.parse!(args)
115
- if args.count < 1
116
- puts optparse
117
- return 1
118
- end
119
126
  connect(options)
120
127
  id_list = parse_id_list(args)
121
128
  return run_command_for_each_arg(id_list) do |arg|
@@ -124,149 +131,153 @@ class Morpheus::Cli::LibraryLayoutsCommand
124
131
  end
125
132
 
126
133
  def _get(id, options)
134
+ exit_code, err = 0, nil
127
135
  instance_type_id = nil
128
- begin
129
- @library_layouts_interface.setopts(options)
130
- if options[:dry_run]
131
- if id.to_s =~ /\A\d{1,}\Z/
132
- print_dry_run @library_layouts_interface.dry.get(instance_type_id, id.to_i)
136
+ params = {}
137
+ params.merge!(parse_query_options(options))
138
+ @library_layouts_interface.setopts(options)
139
+ if options[:dry_run]
140
+ if id.to_s =~ /\A\d{1,}\Z/
141
+ print_dry_run @library_layouts_interface.dry.get(instance_type_id, id.to_i, params)
142
+ else
143
+ print_dry_run @library_layouts_interface.dry.list(instance_type_id, params.merge({name:id}))
144
+ end
145
+ return
146
+ end
147
+ layout = find_layout_by_name_or_id(instance_type_id, id)
148
+ if layout.nil?
149
+ return 1
150
+ end
151
+ # skip redundant request
152
+ #json_response = @library_layouts_interface.get(instance_type_id, layout['id'])
153
+ json_response = {'instanceTypeLayout' => layout}
154
+ #layout = json_response['instanceTypeLayout']
155
+ if options[:json]
156
+ puts as_json(json_response, options, "instanceTypeLayout")
157
+ return 0
158
+ elsif options[:yaml]
159
+ puts as_yaml(json_response, options, "instanceTypeLayout")
160
+ return 0
161
+ elsif options[:csv]
162
+ puts records_as_csv([json_response['instanceTypeLayout']], options)
163
+ return 0
164
+ end
165
+
166
+ print_h1 "Layout Details"
167
+ print cyan
168
+ description_cols = {
169
+ "ID" => lambda {|it| it['id'] },
170
+ "Name" => lambda {|it| it['name'] },
171
+ "Instance Type" => lambda {|it| it['instanceType']['name'] rescue '' },
172
+ #"Code" => lambda {|it| it['code'] },
173
+ "Version" => lambda {|it| it['instanceVersion'] },
174
+ "Description" => lambda {|it| it['description'] },
175
+ "Technology" => lambda {|it| format_layout_technology(it) },
176
+ "Min Memory" => lambda {|it|
177
+ if it['memoryRequirement'].to_i != 0
178
+ (it['memoryRequirement'].to_i / (1024*1024)).to_s + " MB"
133
179
  else
134
- print_dry_run @library_layouts_interface.dry.list(instance_type_id, {name:id})
180
+ ""
135
181
  end
136
- return
137
- end
138
- layout = find_layout_by_name_or_id(instance_type_id, id)
139
- if layout.nil?
140
- return 1
141
- end
142
- # skip redundant request
143
- #json_response = @library_layouts_interface.get(instance_type_id, layout['id'])
144
- json_response = {'instanceTypeLayout' => layout}
145
- #layout = json_response['instanceTypeLayout']
146
- if options[:json]
147
- puts as_json(json_response, options, "instanceTypeLayout")
148
- return 0
149
- elsif options[:yaml]
150
- puts as_yaml(json_response, options, "instanceTypeLayout")
151
- return 0
152
- elsif options[:csv]
153
- puts records_as_csv([json_response['instanceTypeLayout']], options)
154
- return 0
155
- end
182
+ },
183
+ "Workflow" => lambda {|it|
184
+ if it['taskSets']
185
+ it['taskSets'][0]['name'] rescue ""
186
+ else
187
+ ""
188
+ end
189
+ },
190
+ # "Category" => lambda {|it| it['category'].to_s.capitalize },
191
+ # # "Logo" => lambda {|it| it['logo'].to_s },
192
+ # "Visiblity" => lambda {|it| it['visibility'].to_s.capitalize },
193
+ # "Environment Prefix" => lambda {|it| it['environmentPrefix'] },
194
+ # "Enable Settings" => lambda {|it| format_boolean it['hasSettings'] },
195
+ # "Enable Scaling" => lambda {|it| format_boolean it['hasAutoScale'] },
196
+ # "Supports Deployments" => lambda {|it| format_boolean it['hasDeployment'] },
197
+ # "Featured" => lambda {|it| format_boolean it['featured'] },
198
+ # "Owner" => lambda {|it| it['account'] ? it['account']['name'] : '' },
199
+ # "Active" => lambda {|it| format_boolean it['active'] },
200
+ # "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
201
+ # "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
202
+ }
203
+ print_description_list(description_cols, layout)
204
+
205
+
206
+
207
+ layout_evars = layout['environmentVariables']
208
+ if layout_evars && layout_evars.size > 0
209
+ print_h2 "Environment Variables"
210
+ evar_columns = [
211
+ {"NAME" => lambda {|it| it['name'] } },
212
+ {"VALUE" => lambda {|it| it['defaultValue'] } },
213
+ {"TYPE" => lambda {|it| it['valueType'].to_s.capitalize } },
214
+ {"EXPORT" => lambda {|it| format_boolean it['export'] } },
215
+ {"MASKED" => lambda {|it| format_boolean it['mask'] } },
216
+ ]
217
+ print as_pretty_table(layout_evars, evar_columns)
218
+ else
219
+ # print yellow,"No environment variables found for this instance type.","\n",reset
220
+ end
156
221
 
157
- print_h1 "Layout Details"
158
- print cyan
159
- description_cols = {
160
- "ID" => lambda {|it| it['id'] },
161
- "Name" => lambda {|it| it['name'] },
162
- "Instance Type" => lambda {|it| it['instanceType']['name'] rescue '' },
163
- #"Code" => lambda {|it| it['code'] },
164
- "Version" => lambda {|it| it['instanceVersion'] },
165
- "Description" => lambda {|it| it['description'] },
166
- "Technology" => lambda {|it| format_layout_technology(it) },
167
- "Min Memory" => lambda {|it|
168
- if it['memoryRequirement'].to_i != 0
169
- (it['memoryRequirement'].to_i / (1024*1024)).to_s + " MB"
170
- else
171
- ""
172
- end
173
- },
174
- "Workflow" => lambda {|it|
175
- if it['taskSets']
176
- it['taskSets'][0]['name'] rescue ""
177
- else
178
- ""
179
- end
180
- },
181
- # "Category" => lambda {|it| it['category'].to_s.capitalize },
182
- # # "Logo" => lambda {|it| it['logo'].to_s },
183
- # "Visiblity" => lambda {|it| it['visibility'].to_s.capitalize },
184
- # "Environment Prefix" => lambda {|it| it['environmentPrefix'] },
185
- # "Enable Settings" => lambda {|it| format_boolean it['hasSettings'] },
186
- # "Enable Scaling" => lambda {|it| format_boolean it['hasAutoScale'] },
187
- # "Supports Deployments" => lambda {|it| format_boolean it['hasDeployment'] },
188
- # "Featured" => lambda {|it| format_boolean it['featured'] },
189
- # "Owner" => lambda {|it| it['account'] ? it['account']['name'] : '' },
190
- # "Active" => lambda {|it| format_boolean it['active'] },
191
- # "Created" => lambda {|it| format_local_dt(it['dateCreated']) },
192
- # "Updated" => lambda {|it| format_local_dt(it['lastUpdated']) }
193
- }
194
- print_description_list(description_cols, layout)
222
+ layout_option_types = layout['optionTypes']
223
+ if layout_option_types && layout_option_types.size > 0
224
+ print_h2 "Option Types"
225
+ columns = [
226
+ {"ID" => lambda {|it| it['id'] } },
227
+ {"NAME" => lambda {|it| it['name'] } },
228
+ {"TYPE" => lambda {|it| it['type'] } },
229
+ {"FIELD NAME" => lambda {|it| it['fieldName'] } },
230
+ {"FIELD LABEL" => lambda {|it| it['fieldLabel'] } },
231
+ {"DEFAULT" => lambda {|it| it['defaultValue'] } },
232
+ {"REQUIRED" => lambda {|it| format_boolean it['required'] } },
233
+ ]
234
+ print as_pretty_table(layout_option_types, columns)
235
+ else
236
+ # print yellow,"No option types found for this layout.","\n",reset
237
+ end
195
238
 
196
-
239
+ layout_node_types = layout['containerTypes']
240
+ if layout_node_types && layout_node_types.size > 0
241
+ print_h2 "Node Types"
242
+ # match UI sorting [version desc, name asc]
243
+ # or use something simpler like one of these
244
+ layout_node_types = layout_node_types.sort { |a,b| a['name'] <=> b['name'] }
245
+ # layout_node_types = layout_node_types.sort { |a,b| a['sortOrder'] <=> b['sortOrder'] }
246
+ node_type_columns = [
247
+ {"ID" => lambda {|it| it['id'] } },
248
+ {"NAME" => lambda {|it| it['name'] } },
249
+ {"SHORT NAME" => lambda {|it| it['shortName'] } },
250
+ {"VERSION" => lambda {|it| it['containerVersion'] } },
251
+ {"TECHNOLOGY" => lambda {|it| it['provisionType'] ? it['provisionType']['name'] : '' } },
252
+ {"CATEGORY" => lambda {|it| it['category'] } },
253
+ ]
254
+ print as_pretty_table(layout_node_types, node_type_columns)
255
+ else
256
+ # print yellow,"No node types for this layout.","\n",reset
257
+ end
197
258
 
198
- layout_evars = layout['environmentVariables']
199
- if layout_evars && layout_evars.size > 0
200
- print_h2 "Environment Variables"
201
- evar_columns = [
202
- {"NAME" => lambda {|it| it['name'] } },
203
- {"VALUE" => lambda {|it| it['defaultValue'] } },
204
- {"TYPE" => lambda {|it| it['valueType'].to_s.capitalize } },
205
- {"EXPORT" => lambda {|it| format_boolean it['export'] } },
206
- {"MASKED" => lambda {|it| format_boolean it['mask'] } },
207
- ]
208
- print as_pretty_table(layout_evars, evar_columns)
209
- else
210
- # print yellow,"No environment variables found for this instance type.","\n",reset
211
- end
212
-
213
- layout_option_types = layout['optionTypes']
214
- if layout_option_types && layout_option_types.size > 0
215
- print_h2 "Option Types"
216
- columns = [
217
- {"ID" => lambda {|it| it['id'] } },
218
- {"NAME" => lambda {|it| it['name'] } },
219
- {"TYPE" => lambda {|it| it['type'] } },
220
- {"FIELD NAME" => lambda {|it| it['fieldName'] } },
221
- {"FIELD LABEL" => lambda {|it| it['fieldLabel'] } },
222
- {"DEFAULT" => lambda {|it| it['defaultValue'] } },
223
- {"REQUIRED" => lambda {|it| format_boolean it['required'] } },
224
- ]
225
- print as_pretty_table(layout_option_types, columns)
226
- else
227
- # print yellow,"No option types found for this layout.","\n",reset
228
- end
229
-
230
- layout_node_types = layout['containerTypes']
231
- if layout_node_types && layout_node_types.size > 0
232
- print_h2 "Node Types"
233
- # match UI sorting [version desc, name asc]
234
- # or use something simpler like one of these
235
- layout_node_types = layout_node_types.sort { |a,b| a['name'] <=> b['name'] }
236
- # layout_node_types = layout_node_types.sort { |a,b| a['sortOrder'] <=> b['sortOrder'] }
237
- node_type_columns = [
238
- {"ID" => lambda {|it| it['id'] } },
239
- {"NAME" => lambda {|it| it['name'] } },
240
- {"SHORT NAME" => lambda {|it| it['shortName'] } },
241
- {"VERSION" => lambda {|it| it['containerVersion'] } },
242
- {"TECHNOLOGY" => lambda {|it| it['provisionType'] ? it['provisionType']['name'] : '' } },
243
- {"CATEGORY" => lambda {|it| it['category'] } },
244
- ]
245
- print as_pretty_table(layout_node_types, node_type_columns)
246
- else
247
- # print yellow,"No node types for this layout.","\n",reset
248
- end
249
-
250
- layout_spec_templates = layout['specTemplates']
251
- if layout_spec_templates && layout_spec_templates.size > 0
252
- print_h2 "Spec Templates"
253
- layout_spec_templates = layout_spec_templates.sort { |a,b| a['name'] <=> b['name'] }
254
- spec_template_columns = [
255
- {"ID" => lambda {|it| it['id'] } },
256
- {"NAME" => lambda {|it| it['name'] } },
257
- {"TYPE" => lambda {|it| it['type']['name'] rescue '' } }
258
- ]
259
- print as_pretty_table(layout_spec_templates, spec_template_columns)
260
- else
261
- # print yellow,"No spec templates for this layout.","\n",reset
262
- end
259
+ layout_spec_templates = layout['specTemplates']
260
+ if layout_spec_templates && layout_spec_templates.size > 0
261
+ print_h2 "Spec Templates"
262
+ layout_spec_templates = layout_spec_templates.sort { |a,b| a['name'] <=> b['name'] }
263
+ spec_template_columns = [
264
+ {"ID" => lambda {|it| it['id'] } },
265
+ {"NAME" => lambda {|it| it['name'] } },
266
+ {"TYPE" => lambda {|it| it['type']['name'] rescue '' } }
267
+ ]
268
+ print as_pretty_table(layout_spec_templates, spec_template_columns)
269
+ else
270
+ # print yellow,"No spec templates for this layout.","\n",reset
271
+ end
263
272
 
264
- print reset,"\n"
265
273
 
266
- rescue RestClient::Exception => e
267
- print_rest_exception(e, options)
268
- return 1
274
+ if options[:show_perms] || (layout['permissions'] && !layout['permissions'].empty?)
275
+ print_permissions(layout['permissions'], layout_permission_excludes)
276
+ print reset
277
+ else
278
+ print reset,"\n"
269
279
  end
280
+ return exit_code, err
270
281
  end
271
282
 
272
283
  def add(args)
@@ -327,9 +338,12 @@ class Morpheus::Cli::LibraryLayoutsCommand
327
338
  params['specTemplates'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
328
339
  end
329
340
  end
330
- build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
331
- opts.footer = "Create a new layout." + "\n" +
332
- "[instance-type] is required and can be passed as --instance-type instead."
341
+ add_perms_options(opts, options, layout_permission_excludes)
342
+ build_standard_add_options(opts, options)
343
+ opts.footer = <<-EOT
344
+ Create a new layout.
345
+ [instance-type] is required and can be passed as --instance-type instead.
346
+ EOT
333
347
  end
334
348
  optparse.parse!(args)
335
349
  if args.count > 1
@@ -442,6 +456,15 @@ class Morpheus::Cli::LibraryLayoutsCommand
442
456
 
443
457
  payload = {'instanceTypeLayout' => params}
444
458
 
459
+ # Resource Permissions (Groups only for layouts)
460
+ perms = prompt_permissions(options.merge({}), layout_permission_excludes)
461
+ perms_payload = {}
462
+ perms_payload['resourcePermissions'] = perms['resourcePermissions'] if !perms['resourcePermissions'].empty?
463
+ #perms_payload['tenantPermissions'] = perms['tenantPermissions'] if !perms['tenantPermissions'].nil?
464
+
465
+ payload['instanceTypeLayout']['permissions'] = perms_payload
466
+ payload['instanceTypeLayout']['visibility'] = perms['resourcePool']['visibility'] if !perms['resourcePool'].nil? && !perms['resourcePool']['visibility'].nil?
467
+
445
468
  end
446
469
  @library_layouts_interface.setopts(options)
447
470
  if options[:dry_run]
@@ -456,7 +479,7 @@ class Morpheus::Cli::LibraryLayoutsCommand
456
479
  return
457
480
  end
458
481
 
459
- print_green_success "Added Layout #{params['name']}"
482
+ print_green_success "Added layout #{params['name']}"
460
483
 
461
484
  #get([json_response['instanceTypeLayout']['id']])
462
485
 
@@ -472,7 +495,7 @@ class Morpheus::Cli::LibraryLayoutsCommand
472
495
  instance_type_id = nil
473
496
  evars = nil
474
497
  optparse = Morpheus::Cli::OptionParser.new do|opts|
475
- opts.banner = subcommand_usage("[name] [options]")
498
+ opts.banner = subcommand_usage("[layout] [options]")
476
499
  opts.on('--name VALUE', String, "Name for this layout") do |val|
477
500
  params['name'] = val
478
501
  end
@@ -521,16 +544,18 @@ class Morpheus::Cli::LibraryLayoutsCommand
521
544
  params['specTemplates'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
522
545
  end
523
546
  end
524
- build_common_options(opts, options, [:options, :json, :dry_run, :remote])
525
- opts.footer = "Update a layout."
547
+ add_perms_options(opts, options, layout_permission_excludes)
548
+ build_standard_update_options(opts, options)
549
+ opts.footer = <<-EOT
550
+ Update a layout.
551
+ [layout] is required. This is the name or id of a layout.
552
+ EOT
526
553
  end
527
554
  optparse.parse!(args)
528
- if args.count < 1
529
- puts optparse
530
- exit 1
531
- end
555
+ verify_args!(args:args, optparse:optparse, count:1)
532
556
  connect(options)
533
- begin
557
+ exit_code, err = 0, nil
558
+
534
559
  layout = find_layout_by_name_or_id(nil, args[0])
535
560
  exit 1 if layout.nil?
536
561
  payload = nil
@@ -576,6 +601,16 @@ class Morpheus::Cli::LibraryLayoutsCommand
576
601
  end
577
602
  end
578
603
 
604
+ # perms
605
+ if options[:groupAccessAll] != nil || options[:groupAccessList]
606
+ perms = prompt_permissions(options.merge({no_prompt:true}), layout_permission_excludes)
607
+ perms_payload = {}
608
+ perms_payload['resourcePermissions'] = perms['resourcePermissions'] if !perms['resourcePermissions'].empty?
609
+ params.deep_merge!({'permissions' => perms_payload}) if !perms_payload.empty?
610
+ end
611
+
612
+ params['visibility'] = options[:visibility] if !options[:visibility].nil?
613
+
579
614
  if params.empty?
580
615
  raise_command_error "Specify at least one option to update.\n#{optparse}"
581
616
  end
@@ -596,12 +631,61 @@ class Morpheus::Cli::LibraryLayoutsCommand
596
631
  return
597
632
  end
598
633
 
599
- print_green_success "Updated Layout #{params['name'] || layout['name']}"
634
+ print_green_success "Updated layout #{params['name'] || layout['name']}"
600
635
  #list([])
601
- rescue RestClient::Exception => e
602
- print_rest_exception(e, options)
603
- exit 1
636
+ return exit_code, err
637
+ end
638
+
639
+ def update_permissions(args)
640
+ options = {}
641
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
642
+ opts.banner = subcommand_usage( "[layout]")
643
+ add_perms_options(opts, options, layout_permission_excludes)
644
+ build_standard_update_options(opts, options)
645
+ opts.footer = <<-EOT
646
+ Update layout permissions.
647
+ [layout] is required. This is the name or id of a layout.
648
+ EOT
649
+ end
650
+ optparse.parse!(args)
651
+ verify_args!(args:args, optparse:optparse, count:1)
652
+ connect(options)
653
+ exit_code, err = 0, nil
654
+ # if !is_master_account
655
+ # print_red_alert "Permissions only available for master account"
656
+ # return 1
657
+ # end
658
+ layout = find_layout_by_name_or_id(nil, args[0])
659
+ return 1, "layout not found for #{args[0]}" if layout.nil?
660
+ payload = {}
661
+ if options[:payload]
662
+ payload = options[:payload]
663
+ payload.deep_merge!(parse_passed_options(options))
664
+ else
665
+ payload.deep_merge!(parse_passed_options(options))
666
+
667
+ perms = prompt_permissions(options.merge({}), layout_permission_excludes)
668
+ perms_payload = {}
669
+ perms_payload['resourcePermissions'] = perms['resourcePermissions'] if !perms['resourcePermissions'].empty?
670
+ payload.deep_merge!({'permissions' => perms_payload}) if !perms_payload.empty?
671
+ end
672
+
673
+ @library_layouts_interface.setopts(options)
674
+ if options[:dry_run]
675
+ print_dry_run @library_layouts_interface.dry.update_permissions(layout['id'], payload)
676
+ return
604
677
  end
678
+ json_response = @library_layouts_interface.update_permissions(layout['id'], payload)
679
+ render_response(json_response, options, 'instanceTypeLayout') do
680
+ # note: this api does not return 400 when it fails?
681
+ if json_response['success']
682
+ print_green_success "Updated layout permissions"
683
+ else
684
+ print_rest_errors(json_response, options)
685
+ exit_code, err = 3, (json_response['msg'] || "api did not return success:true")
686
+ end
687
+ end
688
+ return exit_code, err
605
689
  end
606
690
 
607
691
  def remove(args)
@@ -637,7 +721,7 @@ class Morpheus::Cli::LibraryLayoutsCommand
637
721
  return
638
722
  end
639
723
 
640
- print_green_success "Removed Layout #{layout['name']}"
724
+ print_green_success "Removed layout #{layout['name']}"
641
725
  #list([])
642
726
  rescue RestClient::Exception => e
643
727
  print_rest_exception(e, options)
@@ -647,29 +731,30 @@ class Morpheus::Cli::LibraryLayoutsCommand
647
731
 
648
732
  private
649
733
 
650
- def find_layout_by_name_or_id(instance_type_id, val)
734
+ def find_layout_by_name_or_id(instance_type_id, val, params={})
651
735
  if val.to_s =~ /\A\d{1,}\Z/
652
- return find_layout_by_id(instance_type_id, val)
736
+ return find_layout_by_id(instance_type_id, val, params)
653
737
  else
654
- return find_layout_by_name(instance_type_id, val)
738
+ return find_layout_by_name(instance_type_id, val, params)
655
739
  end
656
740
  end
657
741
 
658
- def find_layout_by_id(instance_type_id, id)
742
+ def find_layout_by_id(instance_type_id, id, params={})
659
743
  begin
660
- json_response = @library_layouts_interface.get(instance_type_id, id.to_i)
744
+ json_response = @library_layouts_interface.get(instance_type_id, id.to_i, params)
661
745
  return json_response['instanceTypeLayout']
662
746
  rescue RestClient::Exception => e
663
747
  if e.response && e.response.code == 404
664
- print_red_alert "Instance Type not found by id #{id}"
748
+ print_rest_exception(e)
749
+ #print_red_alert "Layout not found by id #{id}"
665
750
  else
666
751
  raise e
667
752
  end
668
753
  end
669
754
  end
670
755
 
671
- def find_layout_by_name(instance_type_id, name)
672
- layouts = @library_layouts_interface.list(instance_type_id, {name: name.to_s})['instanceTypeLayouts']
756
+ def find_layout_by_name(instance_type_id, name, params={})
757
+ layouts = @library_layouts_interface.list(instance_type_id, params.merge({name: name.to_s}))['instanceTypeLayouts']
673
758
  if layouts.empty?
674
759
  print_red_alert "Layout not found by name #{name}"
675
760
  return nil
@@ -712,4 +797,7 @@ class Morpheus::Cli::LibraryLayoutsCommand
712
797
  val.to_s # .capitalize
713
798
  end
714
799
 
800
+ def layout_permission_excludes
801
+ ['plans', 'groupDefaults', 'visibility', 'tenants']
802
+ end
715
803
  end