morpheus-cli 2.11.3.4 → 2.12.4

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