morpheus-cli 4.2.8 → 4.2.10

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 (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