morpheus-cli 3.1.1 → 3.1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -194,7 +194,7 @@ module Morpheus
194
194
  value_found = false
195
195
  value = nil
196
196
  while !value_found do
197
- print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{option_type['defaultValue'] ? ' ['+option_type['defaultValue'].to_s+']' : ''}: "
197
+ print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{!option_type['defaultValue'].to_s.empty? ? ' ['+option_type['defaultValue'].to_s+']' : ''}: "
198
198
  input = $stdin.gets.chomp!
199
199
  value = input.empty? ? option_type['defaultValue'] : input
200
200
  value = value.to_s.include?('.') ? value.to_f : value.to_i
@@ -271,7 +271,7 @@ module Morpheus
271
271
  }
272
272
  matches
273
273
  }
274
- input = Readline.readline("#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{optional_label(option_type)}#{option_type['defaultValue'] ? ' ['+option_type['defaultValue'].to_s+']' : ''} ['?' for options]: ", false).to_s
274
+ input = Readline.readline("#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{!option_type['defaultValue'].to_s.empty? ? ' ['+option_type['defaultValue'].to_s+']' : ''} ['?' for options]: ", false).to_s
275
275
  input = input.chomp.strip
276
276
  if input.empty?
277
277
  value = option_type['defaultValue']
@@ -335,7 +335,7 @@ module Morpheus
335
335
  value_found = false
336
336
  value = nil
337
337
  while !value_found do
338
- print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{optional_label(option_type)}#{option_type['defaultValue'] ? ' ['+option_type['defaultValue'].to_s+']' : ''}: "
338
+ print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{!option_type['defaultValue'].to_s.empty? ? ' ['+option_type['defaultValue'].to_s+']' : ''}: "
339
339
  input = $stdin.gets.chomp!
340
340
  value = input.empty? ? option_type['defaultValue'] : input
341
341
  if input == '?'
@@ -0,0 +1,847 @@
1
+ require 'json'
2
+ require 'yaml'
3
+ require 'rest_client'
4
+ require 'optparse'
5
+ require 'filesize'
6
+ require 'table_print'
7
+ require 'morpheus/cli/cli_command'
8
+ require 'morpheus/cli/mixins/infrastructure_helper'
9
+
10
+ class Morpheus::Cli::PoliciesCommand
11
+ include Morpheus::Cli::CliCommand
12
+ include Morpheus::Cli::InfrastructureHelper
13
+
14
+ set_command_name :policies
15
+
16
+ register_subcommands :list, :get, :add, :update, :remove #, :generate_pool
17
+ register_subcommands :'list-types' => :list_types
18
+ register_subcommands :'get-type' => :get_type
19
+
20
+ # set_default_subcommand :list
21
+
22
+ def initialize()
23
+ # @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
24
+ end
25
+
26
+ def connect(opts)
27
+ @api_client = establish_remote_appliance_connection(opts)
28
+ # @policies_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).policies
29
+ @policies_interface = @api_client.policies
30
+ @group_policies_interface = @api_client.group_policies
31
+ @cloud_policies_interface = @api_client.cloud_policies
32
+ @clouds_interface = @api_client.clouds
33
+ @groups_interface = @api_client.groups
34
+ @active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
35
+ end
36
+
37
+ def handle(args)
38
+ handle_subcommand(args)
39
+ end
40
+
41
+ def list(args)
42
+ options = {}
43
+ params = {}
44
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
45
+ opts.banner = subcommand_usage()
46
+ opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
47
+ options[:group] = val
48
+ end
49
+ opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID" ) do |val|
50
+ options[:cloud] = val
51
+ end
52
+ opts.on( '-G', '--global', "Exclude policies scoped to a group or cloud" ) do
53
+ params[:global] = true
54
+ end
55
+ build_common_options(opts, options, [:list, :json, :yaml, :csv, :fields, :json, :dry_run, :remote])
56
+ opts.footer = "List policies."
57
+ end
58
+ optparse.parse!(args)
59
+ connect(options)
60
+ begin
61
+ group, cloud = nil, nil
62
+ if options[:group]
63
+ group = find_group_by_name_or_id(options[:group])
64
+ elsif options[:cloud]
65
+ cloud = find_cloud_by_name_or_id(options[:cloud])
66
+ end
67
+ [:phrase, :offset, :max, :sort, :direction].each do |k|
68
+ params[k] = options[k] unless options[k].nil?
69
+ end
70
+ if options[:dry_run]
71
+ if group
72
+ print_dry_run @group_policies_interface.dry.list(group['id'], params)
73
+ elsif cloud
74
+ print_dry_run @cloud_policies_interface.dry.list(cloud['id'], params)
75
+ else
76
+ # global
77
+ print_dry_run @policies_interface.dry.list(params)
78
+ end
79
+ return 0
80
+ end
81
+ json_response = nil
82
+ if group
83
+ json_response = @group_policies_interface.list(group['id'], params)
84
+ elsif cloud
85
+ json_response = @cloud_policies_interface.list(cloud['id'], params)
86
+ else
87
+ json_response = @policies_interface.list(params)
88
+ end
89
+ policies = json_response["policies"]
90
+ if options[:include_fields]
91
+ json_response = {"policies" => filter_data(policies, options[:include_fields]) }
92
+ end
93
+ if options[:json]
94
+ puts as_json(json_response, options)
95
+ return 0
96
+ elsif options[:yaml]
97
+ puts as_yaml(json_response, options)
98
+ return 0
99
+ elsif options[:csv]
100
+ puts records_as_csv(policies, options)
101
+ return 0
102
+ end
103
+ title = "Morpheus Policies"
104
+ subtitles = []
105
+ if group
106
+ subtitles << "Group: #{group['name']}".strip
107
+ end
108
+ if cloud
109
+ subtitles << "Cloud: #{cloud['name']}".strip
110
+ end
111
+ if params[:global]
112
+ subtitles << "(Global)".strip
113
+ end
114
+ if params[:phrase]
115
+ subtitles << "Search: #{params[:phrase]}".strip
116
+ end
117
+ print_h1 title, subtitles
118
+ if policies.empty?
119
+ print cyan,"No policies found.",reset,"\n"
120
+ else
121
+ rows = policies.collect {|policy|
122
+ # we got a policy.site and policy.zone now!
123
+ # ref_type, ref_id = policy['refType'], policy['refId']
124
+ # ref_str = ""
125
+ # if ref_type == 'ComputeZone'
126
+ # ref_str = "Cloud #{ref_id}"
127
+ # elsif ref_type == 'ComputeSite'
128
+ # ref_str = "Group #{ref_id}"
129
+ # end
130
+ config_str = JSON.generate(policy['config'] || {})
131
+ row = {
132
+ id: policy['id'],
133
+ name: policy['name'], # always blank right now?
134
+ description: policy['description'], # always blank right now?
135
+ type: policy['policyType'] ? policy['policyType']['name'] : '',
136
+ #for: ref_str,
137
+ group: policy['site'] ? policy['site']['name'] : '',
138
+ cloud: policy['zone'] ? policy['zone']['name'] : '',
139
+ tenants: truncate_string(format_tenants(policy['accounts']), 15),
140
+ config: truncate_string(config_str, 50),
141
+ enabled: policy['enabled'] ? 'Yes' : 'No',
142
+ }
143
+ row
144
+ }
145
+ columns = [:id, :name, :description, :group, :cloud, :tenants, :type, :config, :enabled]
146
+ if group || cloud
147
+ columns = [:id, :description, :type, :config]
148
+ end
149
+ if options[:include_fields]
150
+ columns = options[:include_fields]
151
+ end
152
+ print cyan
153
+ print as_pretty_table(rows, columns, options)
154
+ print reset
155
+ print_results_pagination(json_response, {:label => "policy", :n_label => "policies"})
156
+ end
157
+ print reset,"\n"
158
+ return 0
159
+ rescue RestClient::Exception => e
160
+ print_rest_exception(e, options)
161
+ exit 1
162
+ end
163
+ end
164
+
165
+ def get(args)
166
+ options = {}
167
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
168
+ opts.banner = subcommand_usage("[policy]")
169
+ build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
170
+ opts.footer = "Get details about a policy." + "\n" +
171
+ "[policy] is required. This is the id of a policy."
172
+ end
173
+ optparse.parse!(args)
174
+ if args.count != 1
175
+ print_error Morpheus::Terminal.angry_prompt
176
+ puts_error "wrong number of arguments, expected 1 and got #{args.count}\n#{optparse}"
177
+ return 1
178
+ end
179
+ connect(options)
180
+ begin
181
+ if options[:dry_run]
182
+ if args[0].to_s =~ /\A\d{1,}\Z/
183
+ print_dry_run @policies_interface.dry.get(args[0].to_i)
184
+ else
185
+ print_dry_run @policies_interface.dry.list({name:args[0]})
186
+ end
187
+ return
188
+ end
189
+ policy = find_policy_by_name_or_id(args[0])
190
+ return 1 if policy.nil?
191
+ json_response = {'policy' => policy} # skip redundant request
192
+ # json_response = @policies_interface.get(policy['id'])
193
+ policy = json_response['policy']
194
+ if options[:include_fields]
195
+ json_response = {'policy' => filter_data(policy, options[:include_fields]) }
196
+ end
197
+ if options[:json]
198
+ puts as_json(json_response, options)
199
+ return 0
200
+ elsif options[:yaml]
201
+ puts as_yaml(json_response, options)
202
+ return 0
203
+ elsif options[:csv]
204
+ puts records_as_csv([policy], options)
205
+ return 0
206
+ end
207
+ print_h1 "Policy Details"
208
+ print cyan
209
+ description_cols = {
210
+ "ID" => 'id',
211
+ "Name" => 'name',
212
+ "Description" => 'description',
213
+ "Type" => lambda {|it| it['policyType'] ? it['policyType']['name'] : '' },
214
+ "Group" => lambda {|it| it['site'] ? it['site']['name'] : '' },
215
+ "Cloud" => lambda {|it| it['zone'] ? it['zone']['name'] : '' },
216
+ "Enabled" => lambda {|it| it['enabled'] ? 'Yes' : 'No' },
217
+ # "All Accounts" => lambda {|it| it['allAccounts'] ? 'Yes' : 'No' },
218
+ # "Ref Type" => 'refType',
219
+ # "Ref ID" => 'refId',
220
+ # "Owner" => lambda {|it| it['owner'] ? it['owner']['name'] : '' },
221
+ "Tenants" => lambda {|it| format_tenants(policy["accounts"]) },
222
+ }
223
+ print_description_list(description_cols, policy)
224
+ # print reset,"\n"
225
+
226
+ print_h2 "Policy Config"
227
+ print cyan
228
+ puts as_json(policy['config'])
229
+ print reset, "\n"
230
+ return 0
231
+ rescue RestClient::Exception => e
232
+ print_rest_exception(e, options)
233
+ return 1
234
+ end
235
+ end
236
+
237
+ def add(args)
238
+ options = {}
239
+ policy_type_id = nil
240
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
241
+ opts.banner = subcommand_usage("-t TYPE")
242
+ opts.on( '-g', '--group GROUP', "Group Name or ID, for scoping the policy to a group." ) do |val|
243
+ options[:group] = val
244
+ end
245
+ opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID, for scoping the policy to a cloud" ) do |val|
246
+ options[:cloud] = val
247
+ end
248
+ opts.on('-t', '--type ID', "Policy Type Name or ID") do |val|
249
+ options['type'] = val
250
+ end
251
+ opts.on('--name VALUE', String, "Name for this policy") do |val|
252
+ options['name'] = val
253
+ end
254
+ opts.on('--description VALUE', String, "Description of policy") do |val|
255
+ options['description'] = val
256
+ end
257
+ opts.on('--accounts LIST', Array, "Tenant accounts, comma separated list of account IDs") do |list|
258
+ if list.size == 1 && list[0] == 'null' # hacky way to clear it
259
+ options['accounts'] = []
260
+ else
261
+ options['accounts'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
262
+ end
263
+ end
264
+ opts.on('--enabled [on|off]', String, "Can be used to disable a policy") do |val|
265
+ options['enabled'] = val.to_s == 'on' || val.to_s == 'true'
266
+ end
267
+ opts.on('--config JSON', String, "Policy Config JSON") do |val|
268
+ options['config'] = JSON.parse(val.to_s)
269
+ end
270
+ opts.on('--config-yaml YAML', String, "Policy Config YAML") do |val|
271
+ options['config'] = YAML.load(val.to_s)
272
+ end
273
+ opts.on('--config-file FILE', String, "Policy Config from a local JSON or YAML file") do |val|
274
+ options['configFile'] = val.to_s
275
+ end
276
+ build_common_options(opts, options, [:options, :json, :dry_run, :quiet, :remote])
277
+ opts.footer = "Create a new policy." + "\n" +
278
+ "[name] is optional and can be passed as --name instead."
279
+ end
280
+ optparse.parse!(args)
281
+ if args.count > 1
282
+ print_error Morpheus::Terminal.angry_prompt
283
+ puts_error "wrong number of arguments, expected 0-1 and got #{args.count}\n#{optparse}"
284
+ return 1
285
+ end
286
+ connect(options)
287
+ begin
288
+ group, cloud = nil, nil
289
+ if options[:group]
290
+ group = find_group_by_name_or_id(options[:group])
291
+ elsif options[:cloud]
292
+ cloud = find_cloud_by_name_or_id(options[:cloud])
293
+ end
294
+
295
+ # merge -O options into normally parsed options
296
+ options.deep_merge!(options[:options]) if options[:options] && options[:options].keys.size > 0
297
+
298
+ # support [name] as first argument
299
+ if args[0]
300
+ options['name'] = args[0]
301
+ end
302
+
303
+ # construct payload
304
+ payload = {
305
+ 'policy' => {
306
+ 'config' => {}
307
+ }
308
+ }
309
+
310
+ # prompt for policy options
311
+
312
+ # Policy Type
313
+ # allow user as id, name or code
314
+ available_policy_types = @policies_interface.list_policy_types({})['policyTypes']
315
+ if available_policy_types.empty?
316
+ print_red_alert "No available policy types found!"
317
+ return 1
318
+ end
319
+ policy_types_dropdown = available_policy_types.collect {|it| {'name' => it['name'], 'value' => it['id']} }
320
+ policy_type_id = nil
321
+ policy_type = nil
322
+ if options['type']
323
+ policy_type_id = options['type']
324
+ else
325
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'fieldLabel' => 'Policy Type', 'type' => 'select', 'selectOptions' => policy_types_dropdown, 'required' => true, 'description' => 'Choose a policy type.'}], options[:options])
326
+ policy_type_id = v_prompt['type']
327
+ end
328
+ if !policy_type_id.to_s.empty?
329
+ policy_type = available_policy_types.find {|it|
330
+ it['id'] == policy_type_id.to_i || it['name'] == policy_type_id.to_s || it['code'] == policy_type_id.to_s
331
+ }
332
+ end
333
+ if !policy_type
334
+ print_red_alert "Policy Type not found by id '#{policy_type_id}'"
335
+ return 1
336
+ end
337
+ # payload['policy']['policyTypeId'] = policy_type['id']
338
+ payload['policy']['policyType'] = {'id' => policy_type['id']}
339
+
340
+ # Name (this is not even used at the moment!)
341
+ if options['name']
342
+ payload['policy']['name'] = options['name']
343
+ else
344
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => false, 'description' => 'Name for this policy.'}], options)
345
+ payload['policy']['name'] = v_prompt['name']
346
+ end
347
+
348
+ # Description (this is not even used at the moment!)
349
+ if options['description']
350
+ payload['policy']['description'] = options['description']
351
+ else
352
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false, 'description' => 'Description of policy.'}], options)
353
+ payload['policy']['description'] = v_prompt['description']
354
+ end
355
+
356
+ # Enabled
357
+ if options['enabled']
358
+ payload['policy']['enabled'] = options['enabled']
359
+ else
360
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'enabled', 'fieldLabel' => 'Enabled', 'type' => 'checkbox', 'required' => false, 'description' => 'Can be used to disable a policy', 'defaultValue' => true}], options)
361
+ payload['policy']['enabled'] = v_prompt['enabled']
362
+ end
363
+
364
+ # Tenants
365
+ if options['accounts']
366
+ # payload['policy']['accounts'] = options['accounts'].collect {|it| {'id' => it } }
367
+ payload['policy']['accounts'] = options['accounts']
368
+ else
369
+ v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'accounts', 'fieldLabel' => 'Tenants', 'type' => 'text', 'required' => false, 'description' => 'Tenant accounts, comma separated list of account IDs'}], options)
370
+ payload['policy']['accounts'] = v_prompt['accounts']
371
+ end
372
+
373
+ # Config
374
+ if options['config']
375
+ payload['policy']['config'] = options['config']
376
+ elsif options['configFile']
377
+ config_file = File.expand_path(options['configFile'])
378
+ if !File.exists?(config_file) || !File.file?(config_file)
379
+ print_red_alert "File not found: #{config_file}"
380
+ return false
381
+ end
382
+ if config_file =~ /\.ya?ml\Z/
383
+ payload['policy']['config'] = YAML.load_file(config_file)
384
+ else
385
+ payload['policy']['config'] = JSON.parse(File.read(config_file))
386
+ end
387
+ else
388
+ # prompt for policy specific options
389
+ policy_type_option_types = policy_type['optionTypes']
390
+ # puts "POLICY OPTION TYPES:\n #{policy_type_option_types.inspect}"
391
+ if policy_type_option_types
392
+ config_prompt = Morpheus::Cli::OptionTypes.prompt(policy_type_option_types, options, @api_client)
393
+ # everything should be under fieldContext:'config'
394
+ # payload['policy'].deep_merge!(config_prompt)
395
+ if config_prompt['config']
396
+ payload['policy']['config'].deep_merge!(config_prompt['config'])
397
+ end
398
+ else
399
+ puts "No options found for policy type! Proceeding without config options..."
400
+ end
401
+ end
402
+
403
+
404
+ if options[:dry_run]
405
+ if group
406
+ print_dry_run @group_policies_interface.dry.create(group['id'], payload)
407
+ elsif cloud
408
+ print_dry_run @cloud_policies_interface.dry.create(cloud['id'], payload)
409
+ else
410
+ # global
411
+ print_dry_run @policies_interface.dry.create(payload)
412
+ end
413
+ return
414
+ end
415
+ json_response = nil
416
+ if group
417
+ json_response = @group_policies_interface.create(group['id'], payload)
418
+ elsif cloud
419
+ json_response = @cloud_policies_interface.create(cloud['id'], payload)
420
+ else
421
+ # global
422
+ json_response = @policies_interface.create(payload)
423
+ end
424
+ if options[:json]
425
+ print JSON.pretty_generate(json_response)
426
+ print "\n"
427
+ elsif !options[:quiet]
428
+ print_green_success "Added policy"
429
+ # list([])
430
+ policy = json_response['policy']
431
+ get([policy['id']])
432
+ end
433
+ return 0
434
+ rescue RestClient::Exception => e
435
+ print_rest_exception(e, options)
436
+ exit 1
437
+ end
438
+ end
439
+
440
+ def update(args)
441
+ options = {}
442
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
443
+ opts.banner = subcommand_usage("[policy] [options]")
444
+ # opts.on('-t', '--type ID', "Policy Type Name or ID") do |val|
445
+ # options['type'] = val
446
+ # end
447
+ opts.on('--name VALUE', String, "Name for this policy") do |val|
448
+ options['name'] = val
449
+ end
450
+ opts.on('--description VALUE', String, "Description of policy") do |val|
451
+ options['description'] = val
452
+ end
453
+ opts.on('--accounts LIST', Array, "Tenant accounts, comma separated list of account IDs") do |list|
454
+ if list.size == 1 && list[0] == 'null' # hacky way to clear it
455
+ options['accounts'] = []
456
+ else
457
+ options['accounts'] = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
458
+ end
459
+ end
460
+ opts.on('--enabled [on|off]', String, "Can be used to disable a policy") do |val|
461
+ options['enabled'] = val.to_s == 'on' || val.to_s == 'true'
462
+ end
463
+ opts.on('--config JSON', String, "Policy Config JSON") do |val|
464
+ options['config'] = JSON.parse(val.to_s)
465
+ end
466
+ opts.on('--config-yaml YAML', String, "Policy Config YAML") do |val|
467
+ options['config'] = YAML.load(val.to_s)
468
+ end
469
+ opts.on('--config-file FILE', String, "Policy Config from a local JSON or YAML file") do |val|
470
+ options['configFile'] = val.to_s
471
+ end
472
+ build_common_options(opts, options, [:options, :json, :dry_run, :remote])
473
+ opts.footer = "Update a policy." + "\n" +
474
+ "[policy] is required. This is the id of a policy."
475
+ end
476
+ optparse.parse!(args)
477
+ if args.count != 1
478
+ print_error Morpheus::Terminal.angry_prompt
479
+ puts_error "wrong number of arguments, expected 1 and got #{args.count}\n#{optparse}"
480
+ return 1
481
+ end
482
+ connect(options)
483
+
484
+ begin
485
+ policy = find_policy_by_name_or_id(args[0])
486
+ return 1 if policy.nil?
487
+ group = policy['site'] || policy['group']
488
+ cloud = policy['zone'] || policy['cloud']
489
+
490
+ payload = {
491
+ 'policy' => {}
492
+ }
493
+
494
+ # no prompting, just collect all user passed options
495
+ params = {}
496
+ params.deep_merge!(options.reject {|k,v| k.is_a?(Symbol) })
497
+ params.deep_merge!(options[:options]) if options[:options]
498
+
499
+ if params.empty?
500
+ print_error Morpheus::Terminal.angry_prompt
501
+ puts_error "Specify atleast one option to update\n#{optparse}"
502
+ return 1
503
+ end
504
+ payload['policy'].deep_merge!(params)
505
+
506
+ # Config
507
+ if options['config']
508
+ payload['policy']['config'] = options['config']
509
+ elsif options['configFile']
510
+ config_file = File.expand_path(options['configFile'])
511
+ if !File.exists?(config_file) || !File.file?(config_file)
512
+ print_red_alert "File not found: #{config_file}"
513
+ return false
514
+ end
515
+ if config_file =~ /\.ya?ml\Z/
516
+ payload['policy']['config'] = YAML.load_file(config_file)
517
+ else
518
+ payload['policy']['config'] = JSON.parse(File.read(config_file))
519
+ end
520
+ else
521
+ # this allows adding/updating a single config setting.
522
+ # use --config or --configFile to overwrite the entire config
523
+ if policy['config'] && payload['policy']['config']
524
+ payload['policy']['config'] = policy['config'].merge(payload['policy']['config'])
525
+ end
526
+ end
527
+
528
+ # if options[:dry_run]
529
+ # print_dry_run @policies_interface.dry.update(policy["id"], payload)
530
+ # return
531
+ # end
532
+ # json_response = @policies_interface.update(policy["id"], payload)
533
+
534
+ if options[:dry_run]
535
+ if group
536
+ print_dry_run @group_policies_interface.dry.update(group['id'], policy["id"], payload)
537
+ elsif cloud
538
+ print_dry_run @cloud_policies_interface.dry.update(cloud['id'], policy["id"], payload)
539
+ else
540
+ print_dry_run @policies_interface.dry.update(policy["id"], payload)
541
+ end
542
+ return
543
+ end
544
+ json_response = nil
545
+ if group
546
+ json_response = @group_policies_interface.update(group['id'], policy["id"], payload)
547
+ elsif cloud
548
+ json_response = @cloud_policies_interface.update(cloud['id'], policy["id"], payload)
549
+ else
550
+ json_response = @policies_interface.update(policy["id"], payload)
551
+ end
552
+ if options[:json]
553
+ puts as_json(json_response)
554
+ else
555
+ print_green_success "Updated policy #{policy['id']}"
556
+ get([policy['id']])
557
+ end
558
+ return 0
559
+ rescue RestClient::Exception => e
560
+ print_rest_exception(e, options)
561
+ return 1
562
+ end
563
+ end
564
+
565
+ def remove(args)
566
+ options = {}
567
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
568
+ opts.banner = subcommand_usage("[policy]")
569
+ build_common_options(opts, options, [:account, :auto_confirm, :json, :dry_run, :remote])
570
+ opts.footer = "Delete a policy." + "\n" +
571
+ "[policy] is required. This is the id of a policy."
572
+ end
573
+ optparse.parse!(args)
574
+
575
+ if args.count != 1
576
+ print_error Morpheus::Terminal.angry_prompt
577
+ puts_error "wrong number of arguments, expected 1 and got #{args.count}\n#{optparse}"
578
+ return 1
579
+ end
580
+
581
+ connect(options)
582
+ begin
583
+ policy = find_policy_by_name_or_id(args[0])
584
+ return 1 if policy.nil?
585
+ group = policy['site'] || policy['group']
586
+ cloud = policy['zone'] || policy['cloud']
587
+
588
+ unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the policy: #{policy['id']}?")
589
+ return 9, "aborted command"
590
+ end
591
+ # if options[:dry_run]
592
+ # print_dry_run @policies_interface.dry.destroy(policy['id'])
593
+ # return 0
594
+ # end
595
+ # json_response = @policies_interface.destroy(policy['id'])
596
+ if options[:dry_run]
597
+ if group
598
+ print_dry_run @group_policies_interface.dry.destroy(group['id'], policy["id"])
599
+ elsif cloud
600
+ print_dry_run @cloud_policies_interface.dry.destroy(cloud['id'], policy["id"])
601
+ else
602
+ print_dry_run @policies_interface.dry.destroy(policy["id"])
603
+ end
604
+ return
605
+ end
606
+ json_response = nil
607
+ if group
608
+ json_response = @group_policies_interface.destroy(group['id'], policy["id"])
609
+ elsif cloud
610
+ json_response = @cloud_policies_interface.destroy(cloud['id'], policy["id"])
611
+ else
612
+ json_response = @policies_interface.destroy(policy["id"])
613
+ end
614
+ if options[:json]
615
+ print JSON.pretty_generate(json_response)
616
+ print "\n"
617
+ else
618
+ print_green_success "Deleted policy #{policy['id']}"
619
+ # list([])
620
+ end
621
+ return 0
622
+ rescue RestClient::Exception => e
623
+ print_rest_exception(e, options)
624
+ return 1
625
+ end
626
+ end
627
+
628
+ def list_types(args)
629
+ params = {}
630
+ options = {}
631
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
632
+ opts.banner = subcommand_usage()
633
+ build_common_options(opts, options, [:json, :dry_run, :remote])
634
+ opts.footer = "List policy types."
635
+ end
636
+ optparse.parse!(args)
637
+
638
+ if args.count != 0
639
+ print_error Morpheus::Terminal.angry_prompt
640
+ puts_error "wrong number of arguments, expected 0 and got #{args.count}\n#{optparse}"
641
+ return 1
642
+ end
643
+
644
+ connect(options)
645
+ begin
646
+ if options[:dry_run]
647
+ print_dry_run @policies_interface.dry.list_policy_types(params)
648
+ return 0
649
+ end
650
+ json_response = @policies_interface.list_policy_types()
651
+ policy_types = json_response['policyTypes']
652
+ if options[:json]
653
+ puts as_json(json_response)
654
+ else
655
+ print_h1 "Morpheus Policy Types"
656
+ rows = policy_types.collect {|policy_type|
657
+ row = {
658
+ id: policy_type['id'],
659
+ name: policy_type['name'],
660
+ code: policy_type['code'],
661
+ description: policy_type['description']
662
+ }
663
+ row
664
+ }
665
+ columns = [:id, :name]
666
+ if options[:include_fields]
667
+ columns = options[:include_fields]
668
+ end
669
+ print cyan
670
+ print as_pretty_table(rows, columns, options)
671
+ print_results_pagination(json_response, {:label => "policy type", :n_label => "policy types"})
672
+ print reset, "\n"
673
+ end
674
+ return 0
675
+ rescue RestClient::Exception => e
676
+ print_rest_exception(e, options)
677
+ return 1
678
+ end
679
+ @policies_interface.list_policy_types
680
+ end
681
+
682
+ def get_type(args)
683
+ params = {}
684
+ options = {}
685
+ optparse = Morpheus::Cli::OptionParser.new do |opts|
686
+ opts.banner = subcommand_usage("[policy-type]")
687
+ build_common_options(opts, options, [:json, :dry_run, :remote])
688
+ opts.footer = "Get details about a policy type." + "\n" +
689
+ "[policy-type] is required. This is ID of a policy type."
690
+ end
691
+ optparse.parse!(args)
692
+
693
+ if args.count != 1
694
+ print_error Morpheus::Terminal.angry_prompt
695
+ puts_error "wrong number of arguments, expected 1 and got #{args.count}\n#{optparse}"
696
+ return 1
697
+ end
698
+
699
+ connect(options)
700
+ begin
701
+ policy_type_id = args[0].to_s
702
+ if options[:dry_run]
703
+ print_dry_run @policies_interface.dry.get_policy_type(policy_type_id, params)
704
+ return 0
705
+ end
706
+ json_response = @policies_interface.get_policy_type(policy_type_id, params)
707
+ policy_type = json_response['policyType']
708
+ if options[:json]
709
+ puts as_json(json_response)
710
+ else
711
+ print_h1 "Policy Type Details"
712
+ print cyan
713
+ description_cols = {
714
+ "ID" => 'id',
715
+ "Name" => 'name',
716
+ # "Description" => 'description',
717
+ "Code" => 'code',
718
+ "Category" => 'category',
719
+ # "Load Method" => 'loadMethod',
720
+ # "Enforce Method" => 'enforceMethod',
721
+ # "Prepare Method" => 'prepareMethod',
722
+ # "Validate Method" => 'validateMethod',
723
+ "Provision Enforced" => lambda {|it| it['enforceOnProvision'] ? 'Yes' : 'No' },
724
+ "Managed Enforced" => lambda {|it| it['enforceOnManaged'] ? 'Yes' : 'No' },
725
+ }
726
+ print_description_list(description_cols, policy_type)
727
+ print reset,"\n"
728
+
729
+ # show option types
730
+ print_h2 "Policy Type Options"
731
+ policy_type_option_types = policy_type['optionTypes']
732
+ if !policy_type_option_types || policy_type_option_types.size() == 0
733
+ puts "No options found for policy type"
734
+ else
735
+ rows = policy_type_option_types.collect {|option_type|
736
+ field_str = option_type['fieldName'].to_s
737
+ if !option_type['fieldContext'].to_s.empty?
738
+ field_str = option_type['fieldContext'] + "." + field_str
739
+ end
740
+ description_str = option_type['description'].to_s
741
+ if option_type['helpBlock']
742
+ if description_str.empty?
743
+ description_str = option_type['helpBlock']
744
+ else
745
+ description_str += " " + option_type['helpBlock']
746
+ end
747
+ end
748
+ row = {
749
+ #code: option_type['code'],
750
+ field: field_str,
751
+ type: option_type['type'],
752
+ description: description_str,
753
+ default: option_type['defaultValue'],
754
+ required: option_type['required'] ? 'Yes' : 'No'
755
+ }
756
+ row
757
+ }
758
+ columns = [:field, :type, :description, :default, :required]
759
+ print cyan
760
+ print as_pretty_table(rows, columns)
761
+ print reset,"\n"
762
+ end
763
+ return 0
764
+ end
765
+ return 0
766
+ rescue RestClient::Exception => e
767
+ print_rest_exception(e, options)
768
+ return 1
769
+ end
770
+ @policies_interface.list_policy_types
771
+ end
772
+
773
+ private
774
+
775
+ def find_policy_by_name_or_id(val)
776
+ if val.to_s =~ /\A\d{1,}\Z/
777
+ return find_policy_by_id(val)
778
+ else
779
+ return find_policy_by_name(val)
780
+ end
781
+ end
782
+
783
+ def find_policy_by_id(id)
784
+ begin
785
+ json_response = @policies_interface.get(id.to_i)
786
+ return json_response['policy']
787
+ rescue RestClient::Exception => e
788
+ if e.response && e.response.code == 404
789
+ print_red_alert "Policy not found by id #{id}"
790
+ return nil
791
+ else
792
+ raise e
793
+ end
794
+ end
795
+ end
796
+
797
+ def find_policy_by_name(name)
798
+ json_response = @policies_interface.list({name: name.to_s})
799
+ policies = json_response['policies']
800
+ if policies.empty?
801
+ print_red_alert "Policy not found by name #{name}"
802
+ return nil
803
+ elsif policies.size > 1
804
+ print_red_alert "#{policies.size} policies found by name #{name}"
805
+ # print_policies_table(policies, {color: red})
806
+ rows = policies.collect do |policy|
807
+ {id: policy['id'], name: policy['name']}
808
+ end
809
+ print red
810
+ tp rows, [:id, :name]
811
+ print reset,"\n"
812
+ return nil
813
+ else
814
+ policy = policies[0]
815
+ # merge in tenants map
816
+ if json_response['tenants'] && json_response['tenants'][policy['id']]
817
+ policy['tenants'] = json_response['tenants'][policy['id']]
818
+ end
819
+ return policy
820
+ end
821
+ end
822
+
823
+ def find_policy_type_by_id(id)
824
+ begin
825
+ json_response = @policies_interface.get_type(id.to_s)
826
+ return json_response['policyType']
827
+ rescue RestClient::Exception => e
828
+ if e.response && e.response.code == 404
829
+ print_red_alert "Policy Type not found by id #{id}"
830
+ return nil
831
+ else
832
+ raise e
833
+ end
834
+ end
835
+ end
836
+
837
+ def format_tenants(accounts)
838
+ if accounts && accounts.size > 0
839
+ account_ids = accounts.collect {|it| it['id'] }.uniq
840
+ account_names = accounts.collect {|it| it['name'] }.uniq
841
+ "(#{account_ids.join(',')}) #{account_names.join(',')}"
842
+ else
843
+ ""
844
+ end
845
+ end
846
+
847
+ end