morpheus-cli 2.11.3.4 → 2.12.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8748f36d9767b40c3b422772bbdc3c4e8f6e0ce0
4
- data.tar.gz: 4584547b1ceee3c8171c8e568a996c3733cd33a9
3
+ metadata.gz: b980bc7c2a00f5b68e939530252141590e2f787b
4
+ data.tar.gz: 5e29d80365f8fea25225cb12e2dd29eb40aadf87
5
5
  SHA512:
6
- metadata.gz: 5daf4b6eba4bca0a45c30febb2aa0f3bca57d571c9e383c51087b1b9265fa280ee21285e933758b41b26953fdf4359a3be17b8d4bd78cb2d990c8f14e6491e2c
7
- data.tar.gz: 584731519e2803763991b2656c66a4347ce6a8a1b6b7b348f54d9c0ffc310430631d7928578fccfe4422289557248692a50daca2d8ab2f3c068a551bad443ea6
6
+ metadata.gz: a86f6cd4acc16da2a54a6f22900ee4c4d12e010e5b7da5521b2ebe61166d53885724ab42f4a155d520468aec93bda688c45f0e71855fe27b91aee05f5bf22ceb
7
+ data.tar.gz: 75207d59b6dcb48403f95f299472a071f8ec8e84069a8303570f763bd3cb4e59a6e95896924c5196b396a16df9ef9c5a614adc8bf283c7b5fc9f68d8dda03a87
@@ -191,4 +191,16 @@ class Morpheus::APIClient
191
191
  # monitoring.incidents
192
192
  # end
193
193
 
194
+ def policies
195
+ Morpheus::PoliciesInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
196
+ end
197
+
198
+ def group_policies
199
+ Morpheus::GroupPoliciesInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
200
+ end
201
+
202
+ def cloud_policies
203
+ Morpheus::CloudPoliciesInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
204
+ end
205
+
194
206
  end
@@ -0,0 +1,47 @@
1
+ require 'morpheus/api/api_client'
2
+
3
+ class Morpheus::CloudPoliciesInterface < Morpheus::APIClient
4
+ def initialize(access_token, refresh_token,expires_at = nil, base_url=nil)
5
+ @access_token = access_token
6
+ @refresh_token = refresh_token
7
+ @base_url = base_url
8
+ @expires_at = expires_at
9
+ end
10
+
11
+ def get(cloud_id, id, params={})
12
+ raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
13
+ url = "#{@base_url}/api/zones/#{cloud_id}/policies/#{id}"
14
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
15
+ opts = {method: :get, url: url, headers: headers}
16
+ execute(opts)
17
+ end
18
+
19
+ def list(cloud_id, params={})
20
+ url = "#{@base_url}/api/zones/#{cloud_id}/policies"
21
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
22
+ opts = {method: :get, url: url, headers: headers}
23
+ execute(opts)
24
+ end
25
+
26
+ def create(cloud_id, payload)
27
+ url = "#{@base_url}/api/zones/#{cloud_id}/policies"
28
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
29
+ opts = {method: :post, url: url, headers: headers, payload: payload.to_json}
30
+ execute(opts)
31
+ end
32
+
33
+ def update(cloud_id, id, payload)
34
+ url = "#{@base_url}/api/zones/#{cloud_id}/policies/#{id}"
35
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
36
+ opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
37
+ execute(opts)
38
+ end
39
+
40
+ def destroy(cloud_id, id, params={})
41
+ url = "#{@base_url}/api/zones/#{cloud_id}/policies/#{id}"
42
+ headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
43
+ opts = {method: :delete, url: url, timeout: 30, headers: headers}
44
+ execute(opts)
45
+ end
46
+
47
+ end
@@ -0,0 +1,47 @@
1
+ require 'morpheus/api/api_client'
2
+
3
+ class Morpheus::GroupPoliciesInterface < Morpheus::APIClient
4
+ def initialize(access_token, refresh_token,expires_at = nil, base_url=nil)
5
+ @access_token = access_token
6
+ @refresh_token = refresh_token
7
+ @base_url = base_url
8
+ @expires_at = expires_at
9
+ end
10
+
11
+ def get(group_id, id, params={})
12
+ raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
13
+ url = "#{@base_url}/api/groups/#{group_id}/policies/#{id}"
14
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
15
+ opts = {method: :get, url: url, headers: headers}
16
+ execute(opts)
17
+ end
18
+
19
+ def list(group_id, params={})
20
+ url = "#{@base_url}/api/groups/#{group_id}/policies"
21
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
22
+ opts = {method: :get, url: url, headers: headers}
23
+ execute(opts)
24
+ end
25
+
26
+ def create(group_id, payload)
27
+ url = "#{@base_url}/api/groups/#{group_id}/policies"
28
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
29
+ opts = {method: :post, url: url, headers: headers, payload: payload.to_json}
30
+ execute(opts)
31
+ end
32
+
33
+ def update(group_id, id, payload)
34
+ url = "#{@base_url}/api/groups/#{group_id}/policies/#{id}"
35
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
36
+ opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
37
+ execute(opts)
38
+ end
39
+
40
+ def destroy(group_id, id, params={})
41
+ url = "#{@base_url}/api/groups/#{group_id}/policies/#{id}"
42
+ headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
43
+ opts = {method: :delete, url: url, timeout: 30, headers: headers}
44
+ execute(opts)
45
+ end
46
+
47
+ end
@@ -0,0 +1,63 @@
1
+ require 'morpheus/api/api_client'
2
+ require 'uri'
3
+
4
+ class Morpheus::PoliciesInterface < Morpheus::APIClient
5
+ def initialize(access_token, refresh_token,expires_at = nil, base_url=nil)
6
+ @access_token = access_token
7
+ @refresh_token = refresh_token
8
+ @base_url = base_url
9
+ @expires_at = expires_at
10
+ end
11
+
12
+ def get(id, params={})
13
+ raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
14
+ url = "#{@base_url}/api/policies/#{id}"
15
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
16
+ opts = {method: :get, url: url, headers: headers}
17
+ execute(opts)
18
+ end
19
+
20
+ def list(params={})
21
+ url = "#{@base_url}/api/policies"
22
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
23
+ opts = {method: :get, url: url, headers: headers}
24
+ execute(opts)
25
+ end
26
+
27
+ def create(payload)
28
+ url = "#{@base_url}/api/policies"
29
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
30
+ opts = {method: :post, url: url, headers: headers, payload: payload.to_json}
31
+ execute(opts)
32
+ end
33
+
34
+ def update(id, payload)
35
+ url = "#{@base_url}/api/policies/#{id}"
36
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
37
+ opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
38
+ execute(opts)
39
+ end
40
+
41
+ def destroy(id, params={})
42
+ url = "#{@base_url}/api/policies/#{id}"
43
+ headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
44
+ opts = {method: :delete, url: url, timeout: 30, headers: headers}
45
+ execute(opts)
46
+ end
47
+
48
+ def list_policy_types(params={})
49
+ url = "#{@base_url}/api/policy-types"
50
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
51
+ opts = {method: :get, url: url, headers: headers}
52
+ execute(opts)
53
+ end
54
+
55
+ def get_policy_type(id, params={})
56
+ raise "#{self.class}.get_policy_type() passed a blank id!" if id.to_s == ''
57
+ url = "#{@base_url}/api/policy-types/#{URI.escape(id.to_s)}"
58
+ headers = { params: params, authorization: "Bearer #{@access_token}" }
59
+ opts = {method: :get, url: url, headers: headers}
60
+ execute(opts)
61
+ end
62
+
63
+ end
@@ -51,13 +51,23 @@ class Morpheus::VirtualImagesInterface < Morpheus::APIClient
51
51
  execute(method: :delete, url: url, headers: headers)
52
52
  end
53
53
 
54
- # NOT json, multipart file upload
55
- def upload(id, image_file)
54
+ # multipart file upload
55
+ # def upload(id, image_file)
56
+ # url = "#{@base_url}/api/virtual-images/#{id}/upload"
57
+ # headers = { :params => {}, :authorization => "Bearer #{@access_token}"}
58
+ # payload = {}
59
+ # payload[:file] = image_file
60
+ # payload[:multipart] = true
61
+ # execute(method: :post, url: url, headers: headers, payload: payload)
62
+ # end
63
+
64
+ # no multipart
65
+ def upload(id, image_file, filename=nil)
66
+ filename = filename || File.basename(image_file)
56
67
  url = "#{@base_url}/api/virtual-images/#{id}/upload"
57
- headers = { :params => {}, :authorization => "Bearer #{@access_token}"}
58
- payload = {}
59
- payload[:file] = image_file
60
- payload[:multipart] = true
68
+ headers = { :params => {}, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/octet-stream'}
69
+ headers[:params][:filename] = filename
70
+ payload = image_file
61
71
  execute(method: :post, url: url, headers: headers, payload: payload)
62
72
  end
63
73
 
@@ -94,7 +94,7 @@ module Morpheus
94
94
  load 'morpheus/cli/monitoring_contacts_command.rb'
95
95
  load 'morpheus/cli/monitoring_groups_command.rb'
96
96
  load 'morpheus/cli/monitoring_apps_command.rb'
97
-
97
+ load 'morpheus/cli/policies_command.rb'
98
98
  # nice to have commands
99
99
  load 'morpheus/cli/curl_command.rb'
100
100
  load 'morpheus/cli/set_prompt_command.rb'
@@ -194,7 +194,7 @@ module Morpheus
194
194
 
195
195
  when :options
196
196
  options[:options] ||= {}
197
- opts.on( '-O', '--option OPTION', "Option in the format var=\"value\"" ) do |option|
197
+ opts.on( '-O', '--option OPTION', "Option in the format -O field=\"value\"" ) do |option|
198
198
  # todo: look ahead and parse ALL the option=value args after -O switch
199
199
  #custom_option_args = option.split('=')
200
200
  custom_option_args = option.sub(/\s?\=\s?/, '__OPTION_DELIM__').split('__OPTION_DELIM__')
@@ -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['required'] ? ' (optional)' : ''}#{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
@@ -259,7 +259,7 @@ module Morpheus
259
259
  Readline.completion_append_character = ""
260
260
  Readline.basic_word_break_characters = ''
261
261
  Readline.completion_proc = proc {|s| select_options.clone.collect{|opt| opt['name']}.grep(/^#{Regexp.escape(s)}/)}
262
- input = Readline.readline("#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{option_type['defaultValue'] ? ' ['+option_type['defaultValue'].to_s+']' : ''} ['?' for options]: ", false).to_s
262
+ 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
263
263
  input = input.chomp.strip
264
264
  if input.empty?
265
265
  value = option_type['defaultValue']
@@ -323,7 +323,7 @@ module Morpheus
323
323
  value_found = false
324
324
  value = nil
325
325
  while !value_found do
326
- print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{option_type['defaultValue'] ? ' ['+option_type['defaultValue'].to_s+']' : ''}: "
326
+ 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+']' : ''}: "
327
327
  input = $stdin.gets.chomp!
328
328
  value = input.empty? ? option_type['defaultValue'] : input
329
329
  if input == '?'
@@ -378,11 +378,11 @@ module Morpheus
378
378
  value_found = false
379
379
  value = nil
380
380
  while !value_found do
381
- print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{option_type['defaultValue'] ? ' ['+option_type['defaultValue'].to_s+']' : ''}: "
381
+ 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+']' : ''}: "
382
382
  Readline.completion_append_character = ""
383
383
  Readline.basic_word_break_characters = ''
384
384
  Readline.completion_proc = proc {|s| Readline::FILENAME_COMPLETION_PROC.call(s) }
385
- input = Readline.readline("#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}#{option_type['defaultValue'] ? ' ['+option_type['defaultValue'].to_s+']' : ''} ['?' for options]: ", false).to_s
385
+ 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
386
386
  input = input.chomp.strip
387
387
  #input = $stdin.gets.chomp!
388
388
  value = input.empty? ? option_type['defaultValue'] : input.to_s
@@ -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
+ policy_type_id = v_prompt['type']
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
@@ -463,10 +463,10 @@ class Morpheus::Cli::Roles
463
463
  end
464
464
 
465
465
  def update_feature_access(args)
466
- usage = "Usage: morpheus roles update-feature-access [name] [code] [full|read|none]"
466
+ usage = "Usage: morpheus roles update-feature-access [name] [code] [full|read|user|yes|no|none]"
467
467
  options = {}
468
468
  optparse = OptionParser.new do|opts|
469
- opts.banner = subcommand_usage("[name] [code] [full|read|none]")
469
+ opts.banner = subcommand_usage("[name] [code] [full|read|user|yes|no|none]")
470
470
  build_common_options(opts, options, [:json, :dry_run])
471
471
  end
472
472
  optparse.parse!(args)
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Morpheus
3
3
  module Cli
4
- VERSION = "2.11.3.4"
4
+ VERSION = "2.12.4"
5
5
  end
6
6
  end
@@ -82,13 +82,14 @@ class Morpheus::Cli::VirtualImages
82
82
  if images.empty?
83
83
  print yellow,"No virtual images found.",reset,"\n"
84
84
  else
85
- print cyan
86
- image_table_data = images.collect do |image|
85
+ rows = images.collect do |image|
87
86
  image_type = virtual_image_type_for_name_or_code(image['imageType'])
88
87
  image_type_display = image_type ? "#{image_type['name']}" : image['imageType']
89
88
  {name: image['name'], id: image['id'], type: image_type_display, source: image['userUploaded'] ? "#{green}UPLOADED#{cyan}" : (image['systemImage'] ? 'SYSTEM' : "#{white}SYNCED#{cyan}"), storage: !image['storageProvider'].nil? ? image['storageProvider']['name'] : 'Default', size: image['rawSize'].nil? ? 'Unknown' : "#{Filesize.from("#{image['rawSize']} B").pretty}"}
90
89
  end
91
- tp image_table_data, :id, :name, :type, :storage, :size, :source
90
+ columns = [:id, :name, :type, :storage, :size, :source]
91
+ print cyan
92
+ print as_pretty_table(rows, columns, options)
92
93
  print_results_pagination(json_response)
93
94
  end
94
95
  print reset,"\n"
@@ -274,7 +275,6 @@ class Morpheus::Cli::VirtualImages
274
275
  # exit 1
275
276
  # end
276
277
 
277
- #
278
278
  if image_name
279
279
  options[:options] ||= {}
280
280
  options[:options]['name'] ||= image_name
@@ -291,13 +291,13 @@ class Morpheus::Cli::VirtualImages
291
291
  end
292
292
 
293
293
  begin
294
- my_option_types = add_virtual_image_option_types(image_type)
294
+ my_option_types = add_virtual_image_option_types(image_type)
295
295
  params = Morpheus::Cli::OptionTypes.prompt(add_virtual_image_option_types(image_type), options[:options], @api_client, options[:params])
296
296
  virtual_image_payload = {}.merge(params)
297
297
  virtual_image_files = virtual_image_payload.delete('virtualImageFiles')
298
298
  virtual_image_payload['imageType'] = image_type['code']
299
299
  storage_provider_id = virtual_image_payload.delete('storageProviderId')
300
- if !storage_provider_id.empty?
300
+ if !storage_provider_id.to_s.empty?
301
301
  virtual_image_payload['storageProvider'] = {id: storage_provider_id}
302
302
  end
303
303
  payload = {virtualImage: virtual_image_payload}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: morpheus-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.11.3.4
4
+ version: 2.12.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Estes
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2017-08-31 00:00:00.000000000 Z
14
+ date: 2017-11-09 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -146,12 +146,14 @@ files:
146
146
  - lib/morpheus/api/apps_interface.rb
147
147
  - lib/morpheus/api/auth_interface.rb
148
148
  - lib/morpheus/api/checks_interface.rb
149
+ - lib/morpheus/api/cloud_policies_interface.rb
149
150
  - lib/morpheus/api/clouds_interface.rb
150
151
  - lib/morpheus/api/containers_interface.rb
151
152
  - lib/morpheus/api/custom_instance_types_interface.rb
152
153
  - lib/morpheus/api/dashboard_interface.rb
153
154
  - lib/morpheus/api/deploy_interface.rb
154
155
  - lib/morpheus/api/deployments_interface.rb
156
+ - lib/morpheus/api/group_policies_interface.rb
155
157
  - lib/morpheus/api/groups_interface.rb
156
158
  - lib/morpheus/api/incidents_interface.rb
157
159
  - lib/morpheus/api/instance_types_interface.rb
@@ -167,6 +169,7 @@ files:
167
169
  - lib/morpheus/api/option_type_lists_interface.rb
168
170
  - lib/morpheus/api/option_types_interface.rb
169
171
  - lib/morpheus/api/options_interface.rb
172
+ - lib/morpheus/api/policies_interface.rb
170
173
  - lib/morpheus/api/provision_types_interface.rb
171
174
  - lib/morpheus/api/roles_interface.rb
172
175
  - lib/morpheus/api/security_group_rules_interface.rb
@@ -222,6 +225,7 @@ files:
222
225
  - lib/morpheus/cli/monitoring_incidents_command.rb
223
226
  - lib/morpheus/cli/option_parser.rb
224
227
  - lib/morpheus/cli/option_types.rb
228
+ - lib/morpheus/cli/policies_command.rb
225
229
  - lib/morpheus/cli/recent_activity_command.rb
226
230
  - lib/morpheus/cli/remote.rb
227
231
  - lib/morpheus/cli/roles.rb
@@ -266,7 +270,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
266
270
  version: '0'
267
271
  requirements: []
268
272
  rubyforge_project:
269
- rubygems_version: 2.5.1
273
+ rubygems_version: 2.4.8
270
274
  signing_key:
271
275
  specification_version: 4
272
276
  summary: Provides CLI Interface to the Morpheus Public/Private Cloud Appliance