morpheus-cli 3.4.1.10 → 3.5.1
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 +5 -5
- data/lib/morpheus/api/api_client.rb +4 -0
- data/lib/morpheus/api/cypher_interface.rb +55 -0
- data/lib/morpheus/api/storage_providers_interface.rb +113 -0
- data/lib/morpheus/cli.rb +1 -0
- data/lib/morpheus/cli/archives_command.rb +5 -6
- data/lib/morpheus/cli/cli_command.rb +10 -1
- data/lib/morpheus/cli/clouds.rb +1 -0
- data/lib/morpheus/cli/cypher_command.rb +412 -0
- data/lib/morpheus/cli/echo_command.rb +1 -1
- data/lib/morpheus/cli/library_option_lists_command.rb +109 -30
- data/lib/morpheus/cli/policies_command.rb +208 -118
- data/lib/morpheus/cli/set_prompt_command.rb +1 -1
- data/lib/morpheus/cli/shell.rb +3 -2
- data/lib/morpheus/cli/storage_providers_command.rb +788 -5
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/terminal.rb +1 -1
- metadata +5 -3
@@ -11,7 +11,7 @@ class Morpheus::Cli::Echo
|
|
11
11
|
set_command_hidden
|
12
12
|
|
13
13
|
unless defined?(DEFAULT_VARIABLE_MAP)
|
14
|
-
DEFAULT_VARIABLE_MAP = {'%cyan' => Term::ANSIColor.cyan, '%magenta' => Term::ANSIColor.magenta, '%red' => Term::ANSIColor.red, '%green' => Term::ANSIColor.green, '%yellow' => Term::ANSIColor.yellow, '%dark' => Term::ANSIColor.dark, '%reset' => Term::ANSIColor.reset}
|
14
|
+
DEFAULT_VARIABLE_MAP = {'%cyan' => Term::ANSIColor.cyan, '%magenta' => Term::ANSIColor.magenta, '%red' => Term::ANSIColor.red, '%green' => Term::ANSIColor.green, '%yellow' => Term::ANSIColor.yellow, '%white' => Term::ANSIColor.white, '%dark' => Term::ANSIColor.dark, '%reset' => Term::ANSIColor.reset}
|
15
15
|
end
|
16
16
|
|
17
17
|
def self.variable_map
|
@@ -129,25 +129,38 @@ class Morpheus::Cli::LibraryOptionListsCommand
|
|
129
129
|
# print_h2 "Initial Dataset"
|
130
130
|
# print bright_black,"#{option_type_list['initialDataset']}","\n",reset
|
131
131
|
else
|
132
|
-
|
132
|
+
option_list_columns = {
|
133
133
|
"ID" => 'id',
|
134
134
|
"Name" => 'name',
|
135
135
|
"Description" => 'description',
|
136
136
|
"Type" => lambda {|it| it['type'].to_s.capitalize },
|
137
137
|
"Source URL" => 'sourceUrl',
|
138
|
+
"Real Time" => lambda {|it| format_boolean it['realTime'] },
|
138
139
|
"Ignore SSL Errors" => lambda {|it| format_boolean it['ignoreSSLErrors'] },
|
139
|
-
"Source Method" => lambda {|it| it['sourceMethod'].to_s.upcase }
|
140
|
-
}
|
140
|
+
"Source Method" => lambda {|it| it['sourceMethod'].to_s.upcase }
|
141
|
+
}
|
142
|
+
source_headers = []
|
143
|
+
if option_type_list['config'] && option_type_list['config']['sourceHeaders']
|
144
|
+
source_headers = option_type_list['config']['sourceHeaders'].collect do |header|
|
145
|
+
{name: header['name'], value: header['value'], masked: format_boolean(header['masked'])}
|
146
|
+
end
|
147
|
+
#option_list_columns["Source Headers"] = lambda {|it| source_headers.collect {|it| "#{it[:name]} #{it[:value]}"}.join("\n") }
|
148
|
+
end
|
149
|
+
print_description_list(option_list_columns, option_type_list)
|
150
|
+
if source_headers && !source_headers.empty?
|
151
|
+
print cyan
|
152
|
+
print_h2 "Source Headers"
|
153
|
+
print as_pretty_table(source_headers, [:name, :value, :masked])
|
154
|
+
end
|
141
155
|
if !option_type_list['initialDataset'].empty?
|
142
156
|
print_h2 "Initial Dataset"
|
143
|
-
print bright_black,"
|
157
|
+
print bright_black,"#{option_type_list['initialDataset']}","\n",reset
|
144
158
|
end
|
145
159
|
if !option_type_list['translationScript'].empty?
|
146
160
|
print_h2 "Translation Script"
|
147
|
-
print bright_black,"
|
161
|
+
print bright_black,"#{option_type_list['translationScript']}","\n",reset
|
148
162
|
end
|
149
163
|
end
|
150
|
-
|
151
164
|
print_h2 "List Items"
|
152
165
|
if option_type_list['listItems']
|
153
166
|
# puts "\tNAME\tVALUE"
|
@@ -181,7 +194,7 @@ class Morpheus::Cli::LibraryOptionListsCommand
|
|
181
194
|
# options[:options]['type'] = val
|
182
195
|
end
|
183
196
|
build_option_type_options(opts, options, new_option_type_list_option_types())
|
184
|
-
build_common_options(opts, options, [:options, :json, :dry_run, :remote])
|
197
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
185
198
|
end
|
186
199
|
optparse.parse!(args)
|
187
200
|
|
@@ -192,13 +205,31 @@ class Morpheus::Cli::LibraryOptionListsCommand
|
|
192
205
|
|
193
206
|
connect(options)
|
194
207
|
begin
|
195
|
-
|
196
|
-
if
|
197
|
-
|
208
|
+
payload = nil
|
209
|
+
if options[:payload]
|
210
|
+
payload = options[:payload]
|
211
|
+
# support -O OPTION switch on top of --payload
|
212
|
+
if options[:options]
|
213
|
+
payload['optionTypeList'] ||= {}
|
214
|
+
payload['optionTypeList'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) })
|
215
|
+
end
|
216
|
+
else
|
217
|
+
params = Morpheus::Cli::OptionTypes.prompt(new_option_type_list_option_types(list_type), options[:options], @api_client, options[:params])
|
218
|
+
params['type'] = list_type
|
219
|
+
if params['type'] == 'rest'
|
220
|
+
# prompt for Source Headers
|
221
|
+
source_headers = prompt_source_headers(options)
|
222
|
+
if !source_headers.empty?
|
223
|
+
params['config'] ||= {}
|
224
|
+
params['config']['sourceHeaders'] = source_headers
|
225
|
+
end
|
226
|
+
end
|
227
|
+
if params.key?('required')
|
228
|
+
params['required'] = ['on','true'].include?(params['required'].to_s)
|
229
|
+
end
|
230
|
+
list_payload = params
|
231
|
+
payload = {'optionTypeList' => list_payload}
|
198
232
|
end
|
199
|
-
params['type'] = list_type
|
200
|
-
list_payload = params
|
201
|
-
payload = {'optionTypeList' => list_payload}
|
202
233
|
if options[:dry_run]
|
203
234
|
print_dry_run @option_type_lists_interface.dry.create(payload)
|
204
235
|
return
|
@@ -227,7 +258,7 @@ class Morpheus::Cli::LibraryOptionListsCommand
|
|
227
258
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
228
259
|
opts.banner = subcommand_usage("[name] [options]")
|
229
260
|
build_option_type_options(opts, options, update_option_type_list_option_types())
|
230
|
-
build_common_options(opts, options, [:options, :json, :dry_run, :remote])
|
261
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
231
262
|
end
|
232
263
|
optparse.parse!(args)
|
233
264
|
connect(options)
|
@@ -235,20 +266,39 @@ class Morpheus::Cli::LibraryOptionListsCommand
|
|
235
266
|
option_type_list = find_option_type_list_by_name_or_id(args[0])
|
236
267
|
exit 1 if option_type_list.nil?
|
237
268
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
269
|
+
payload = nil
|
270
|
+
if options[:payload]
|
271
|
+
payload = options[:payload]
|
272
|
+
# support -O OPTION switch on top of --payload
|
273
|
+
if options[:options]
|
274
|
+
payload['optionTypeList'] ||= {}
|
275
|
+
payload['optionTypeList'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) })
|
276
|
+
end
|
277
|
+
else
|
278
|
+
list_type = option_type_list['type']
|
279
|
+
prompt_options = update_option_type_list_option_types(list_type)
|
280
|
+
#params = options[:options] || {}
|
281
|
+
params = Morpheus::Cli::OptionTypes.no_prompt(prompt_options, options[:options], @api_client, options[:params])
|
282
|
+
if list_type == 'rest'
|
283
|
+
# parse Source Headers
|
284
|
+
source_headers = prompt_source_headers(options.merge({no_prompt: true}))
|
285
|
+
if !source_headers.empty?
|
286
|
+
#params['config'] ||= option_type_list['config'] || {}
|
287
|
+
params['config'] ||= {}
|
288
|
+
params['config']['sourceHeaders'] = source_headers
|
289
|
+
end
|
290
|
+
end
|
291
|
+
if params.empty?
|
292
|
+
print_red_alert "Specify atleast one option to update"
|
293
|
+
puts optparse
|
294
|
+
exit 1
|
295
|
+
end
|
296
|
+
if params.key?('required')
|
297
|
+
params['required'] = ['on','true'].include?(params['required'].to_s)
|
298
|
+
end
|
299
|
+
list_payload = params
|
300
|
+
payload = {'optionTypeList' => list_payload}
|
249
301
|
end
|
250
|
-
list_payload = params
|
251
|
-
payload = {optionTypeList: list_payload}
|
252
302
|
if options[:dry_run]
|
253
303
|
print_dry_run @option_type_lists_interface.dry.update(option_type_list['id'], payload)
|
254
304
|
return
|
@@ -446,9 +496,10 @@ class Morpheus::Cli::LibraryOptionListsCommand
|
|
446
496
|
#{'fieldName' => 'type', 'fieldLabel' => 'Type', 'type' => 'select', 'selectOptions' => get_available_option_list_types, 'defaultValue' => 'rest', 'required' => true, 'displayOrder' => 3},
|
447
497
|
{'fieldName' => 'sourceUrl', 'fieldLabel' => 'Source Url', 'type' => 'text', 'required' => true, 'description' => "A REST URL can be used to fetch list data and is cached in the appliance database.", 'displayOrder' => 4},
|
448
498
|
{'fieldName' => 'ignoreSSLErrors', 'fieldLabel' => 'Ignore SSL Errors', 'type' => 'checkbox', 'defaultValue' => 'off', 'displayOrder' => 5},
|
449
|
-
{'fieldName' => '
|
450
|
-
{'fieldName' => '
|
451
|
-
{'fieldName' => '
|
499
|
+
{'fieldName' => 'realTime', 'fieldLabel' => 'Real Time', 'type' => 'checkbox', 'defaultValue' => 'off', 'displayOrder' => 6},
|
500
|
+
{'fieldName' => 'sourceMethod', 'fieldLabel' => 'Source Method', 'type' => 'select', 'selectOptions' => [{'name' => 'GET', 'value' => 'GET'}, {'name' => 'POST', 'value' => 'POST'}], 'defaultValue' => 'GET', 'required' => true, 'displayOrder' => 7},
|
501
|
+
{'fieldName' => 'initialDataset', 'fieldLabel' => 'Initial Dataset', 'type' => 'code-editor', 'description' => "Create an initial json dataset to be used as the collection for this option list. It should be a list containing objects with properties 'name', and 'value'. However, if there is a translation script, that will also be passed through.", 'displayOrder' => 8},
|
502
|
+
{'fieldName' => 'translationScript', 'fieldLabel' => 'Translation Script', 'type' => 'code-editor', 'description' => "Create a js script to translate the result data object into an Array containing objects with properties name, and value. The input data is provided as data and the result should be put on the global variable results.", 'displayOrder' => 9},
|
452
503
|
]
|
453
504
|
elsif list_type.to_s.downcase == 'manual'
|
454
505
|
[
|
@@ -473,4 +524,32 @@ class Morpheus::Cli::LibraryOptionListsCommand
|
|
473
524
|
list
|
474
525
|
end
|
475
526
|
|
527
|
+
# returns array of header objects {name: "Auth", value: "somevalue", masked: false}
|
528
|
+
def prompt_source_headers(options={})
|
529
|
+
#puts "Source Headers:"
|
530
|
+
no_prompt = (options[:no_prompt] || (options[:options] && options[:options][:no_prompt]))
|
531
|
+
source_headers = []
|
532
|
+
source_header_index = 0
|
533
|
+
has_another_source_header = options[:options] && options[:options]["sourceHeader#{source_header_index}"]
|
534
|
+
add_another_source_header = has_another_source_header || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add a Source Header?", {default: false}))
|
535
|
+
while add_another_source_header do
|
536
|
+
field_context = "sourceHeader#{source_header_index}"
|
537
|
+
source_header = {}
|
538
|
+
source_header['id'] = nil
|
539
|
+
source_header_label = source_header_index == 0 ? "Header" : "Header [#{source_header_index+1}]"
|
540
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'name', 'type' => 'text', 'fieldLabel' => "#{source_header_label} Name", 'required' => true, 'description' => 'HTTP Header Name.', 'defaultValue' => source_header['name']}], options[:options])
|
541
|
+
source_header['name'] = v_prompt[field_context]['name']
|
542
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'value', 'type' => 'text', 'fieldLabel' => "#{source_header_label} Value", 'required' => true, 'description' => 'HTTP Header Value', 'defaultValue' => source_header['value']}], options[:options])
|
543
|
+
source_header['value'] = v_prompt[field_context]['value']
|
544
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldContext' => field_context, 'fieldName' => 'masked', 'type' => 'checkbox', 'fieldLabel' => "#{source_header_label} Masked", 'required' => true, 'description' => 'Header value is secret and should not be displayed', 'defaultValue' => source_header['masked'] ? 'yes' : 'no'}], options[:options])
|
545
|
+
source_header['masked'] = v_prompt[field_context]['masked'] if !v_prompt[field_context]['masked'].nil?
|
546
|
+
source_headers << source_header
|
547
|
+
source_header_index += 1
|
548
|
+
has_another_source_header = options[:options] && options[:options]["sourceHeader#{source_header_index}"]
|
549
|
+
add_another_source_header = has_another_source_header || (!no_prompt && Morpheus::Cli::OptionTypes.confirm("Add another Source Header?", {default: false}))
|
550
|
+
end
|
551
|
+
|
552
|
+
return source_headers
|
553
|
+
end
|
554
|
+
|
476
555
|
end
|
@@ -6,10 +6,12 @@ require 'filesize'
|
|
6
6
|
require 'table_print'
|
7
7
|
require 'morpheus/cli/cli_command'
|
8
8
|
require 'morpheus/cli/mixins/infrastructure_helper'
|
9
|
+
require 'morpheus/cli/mixins/accounts_helper'
|
9
10
|
|
10
11
|
class Morpheus::Cli::PoliciesCommand
|
11
12
|
include Morpheus::Cli::CliCommand
|
12
13
|
include Morpheus::Cli::InfrastructureHelper
|
14
|
+
include Morpheus::Cli::AccountsHelper
|
13
15
|
|
14
16
|
set_command_name :policies
|
15
17
|
|
@@ -31,6 +33,7 @@ class Morpheus::Cli::PoliciesCommand
|
|
31
33
|
@cloud_policies_interface = @api_client.cloud_policies
|
32
34
|
@clouds_interface = @api_client.clouds
|
33
35
|
@groups_interface = @api_client.groups
|
36
|
+
@users_interface = @api_client.users
|
34
37
|
@active_group_id = Morpheus::Cli::Groups.active_groups[@appliance_name]
|
35
38
|
end
|
36
39
|
|
@@ -49,22 +52,32 @@ class Morpheus::Cli::PoliciesCommand
|
|
49
52
|
opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID" ) do |val|
|
50
53
|
options[:cloud] = val
|
51
54
|
end
|
52
|
-
opts.on( '-
|
55
|
+
opts.on( '-u', '--user USER', "Username or ID" ) do |val|
|
56
|
+
options[:user] = val
|
57
|
+
end
|
58
|
+
opts.on( '-G', '--global', "Global policies only" ) do
|
53
59
|
params[:global] = true
|
54
60
|
end
|
55
|
-
build_common_options(opts, options, [:list, :json, :yaml, :csv, :fields, :json, :dry_run, :remote])
|
61
|
+
build_common_options(opts, options, [:list, :query, :json, :yaml, :csv, :fields, :json, :dry_run, :remote])
|
56
62
|
opts.footer = "List policies."
|
57
63
|
end
|
58
64
|
optparse.parse!(args)
|
59
65
|
connect(options)
|
60
66
|
begin
|
61
|
-
group, cloud = nil, nil
|
67
|
+
group, cloud, user = nil, nil, nil
|
62
68
|
if options[:group]
|
63
69
|
group = find_group_by_name_or_id(options[:group])
|
64
70
|
elsif options[:cloud]
|
65
71
|
cloud = find_cloud_by_name_or_id(options[:cloud])
|
72
|
+
elsif options[:user]
|
73
|
+
user = find_user_by_username_or_id(nil, options[:user])
|
74
|
+
return 1 if user.nil?
|
66
75
|
end
|
67
76
|
params.merge!(parse_list_options(options))
|
77
|
+
if user
|
78
|
+
params['refType'] = 'User'
|
79
|
+
params['refId'] = user['id']
|
80
|
+
end
|
68
81
|
if options[:dry_run]
|
69
82
|
if group
|
70
83
|
print_dry_run @group_policies_interface.dry.list(group['id'], params)
|
@@ -72,6 +85,10 @@ class Morpheus::Cli::PoliciesCommand
|
|
72
85
|
print_dry_run @cloud_policies_interface.dry.list(cloud['id'], params)
|
73
86
|
else
|
74
87
|
# global
|
88
|
+
if user
|
89
|
+
params['refType'] = 'User'
|
90
|
+
params['refId'] = user['id']
|
91
|
+
end
|
75
92
|
print_dry_run @policies_interface.dry.list(params)
|
76
93
|
end
|
77
94
|
return 0
|
@@ -103,6 +120,9 @@ class Morpheus::Cli::PoliciesCommand
|
|
103
120
|
if cloud
|
104
121
|
subtitles << "Cloud: #{cloud['name']}".strip
|
105
122
|
end
|
123
|
+
if user
|
124
|
+
subtitles << "User: #{user['username']}".strip
|
125
|
+
end
|
106
126
|
if params[:global]
|
107
127
|
subtitles << "(Global)".strip
|
108
128
|
end
|
@@ -129,15 +149,16 @@ class Morpheus::Cli::PoliciesCommand
|
|
129
149
|
#for: ref_str,
|
130
150
|
group: policy['site'] ? policy['site']['name'] : '',
|
131
151
|
cloud: policy['zone'] ? policy['zone']['name'] : '',
|
152
|
+
user: policy['user'] ? policy['user']['username'] : '',
|
132
153
|
tenants: truncate_string(format_tenants(policy['accounts']), 15),
|
133
154
|
config: truncate_string(config_str, 50),
|
134
155
|
enabled: policy['enabled'] ? 'Yes' : 'No',
|
135
156
|
}
|
136
157
|
row
|
137
158
|
}
|
138
|
-
columns = [:id, :name, :description, :group, :cloud, :tenants, :type, :config, :enabled]
|
139
|
-
if group || cloud
|
140
|
-
columns = [:
|
159
|
+
columns = [:id, :name, :description, :group, :cloud, :user, :tenants, :type, :config, :enabled]
|
160
|
+
if group || cloud || user
|
161
|
+
columns = columns - [:group, :cloud, :user]
|
141
162
|
end
|
142
163
|
if options[:include_fields]
|
143
164
|
columns = options[:include_fields]
|
@@ -159,6 +180,15 @@ class Morpheus::Cli::PoliciesCommand
|
|
159
180
|
options = {}
|
160
181
|
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
161
182
|
opts.banner = subcommand_usage("[policy]")
|
183
|
+
opts.on( '-g', '--group GROUP', "Group Name or ID" ) do |val|
|
184
|
+
options[:group] = val
|
185
|
+
end
|
186
|
+
opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID" ) do |val|
|
187
|
+
options[:cloud] = val
|
188
|
+
end
|
189
|
+
# opts.on( '-u', '--user USER', "Username or ID" ) do |val|
|
190
|
+
# options[:user] = val
|
191
|
+
# end
|
162
192
|
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
163
193
|
opts.footer = "Get details about a policy." + "\n" +
|
164
194
|
"[policy] is required. This is the id of a policy."
|
@@ -171,15 +201,38 @@ class Morpheus::Cli::PoliciesCommand
|
|
171
201
|
end
|
172
202
|
connect(options)
|
173
203
|
begin
|
204
|
+
group, cloud, user = nil, nil, nil
|
205
|
+
if options[:group]
|
206
|
+
group = find_group_by_name_or_id(options[:group])
|
207
|
+
return 1 if group.nil?
|
208
|
+
elsif options[:cloud]
|
209
|
+
cloud = find_cloud_by_name_or_id(options[:cloud])
|
210
|
+
return 1 if cloud.nil?
|
211
|
+
elsif options[:user]
|
212
|
+
user = find_user_by_username_or_id(nil, options[:user])
|
213
|
+
return 1 if user.nil?
|
214
|
+
end
|
174
215
|
if options[:dry_run]
|
175
216
|
if args[0].to_s =~ /\A\d{1,}\Z/
|
176
|
-
|
217
|
+
if group
|
218
|
+
print_dry_run @group_policies_interface.dry.get(group['id'], args[0].to_i)
|
219
|
+
elsif cloud
|
220
|
+
print_dry_run @cloud_policies_interface.dry.get(cloud['id'], args[0].to_i)
|
221
|
+
else
|
222
|
+
print_dry_run @policies_interface.dry.get(args[0].to_i)
|
223
|
+
end
|
177
224
|
else
|
178
|
-
|
225
|
+
if group
|
226
|
+
print_dry_run @group_policies_interface.dry.list(group['id'], {name:args[0]})
|
227
|
+
elsif cloud
|
228
|
+
print_dry_run @cloud_policies_interface.dry.list(cloud['id'], {name:args[0]})
|
229
|
+
else
|
230
|
+
print_dry_run @policies_interface.dry.list({name:args[0]})
|
231
|
+
end
|
179
232
|
end
|
180
233
|
return
|
181
234
|
end
|
182
|
-
policy = find_policy_by_name_or_id(args[0])
|
235
|
+
policy = find_policy_by_name_or_id(args[0], {cloud:cloud,group:group})
|
183
236
|
return 1 if policy.nil?
|
184
237
|
json_response = {'policy' => policy} # skip redundant request
|
185
238
|
# json_response = @policies_interface.get(policy['id'])
|
@@ -203,12 +256,12 @@ class Morpheus::Cli::PoliciesCommand
|
|
203
256
|
"Type" => lambda {|it| it['policyType'] ? it['policyType']['name'] : '' },
|
204
257
|
"Group" => lambda {|it| it['site'] ? it['site']['name'] : '' },
|
205
258
|
"Cloud" => lambda {|it| it['zone'] ? it['zone']['name'] : '' },
|
206
|
-
"Enabled" => lambda {|it| it['enabled'] ? 'Yes' : 'No' },
|
207
259
|
# "All Accounts" => lambda {|it| it['allAccounts'] ? 'Yes' : 'No' },
|
208
260
|
# "Ref Type" => 'refType',
|
209
261
|
# "Ref ID" => 'refId',
|
210
262
|
# "Owner" => lambda {|it| it['owner'] ? it['owner']['name'] : '' },
|
211
263
|
"Tenants" => lambda {|it| format_tenants(policy["accounts"]) },
|
264
|
+
"Enabled" => lambda {|it| it['enabled'] ? 'Yes' : 'No' }
|
212
265
|
}
|
213
266
|
print_description_list(description_cols, policy)
|
214
267
|
# print reset,"\n"
|
@@ -235,6 +288,9 @@ class Morpheus::Cli::PoliciesCommand
|
|
235
288
|
opts.on( '-c', '--cloud CLOUD', "Cloud Name or ID, for scoping the policy to a cloud" ) do |val|
|
236
289
|
options[:cloud] = val
|
237
290
|
end
|
291
|
+
opts.on( '-u', '--user USER', "Username or ID, for scoping the policy to a user" ) do |val|
|
292
|
+
options[:user] = val
|
293
|
+
end
|
238
294
|
opts.on('-t', '--type ID', "Policy Type Name or ID") do |val|
|
239
295
|
options['type'] = val
|
240
296
|
end
|
@@ -263,7 +319,7 @@ class Morpheus::Cli::PoliciesCommand
|
|
263
319
|
opts.on('--config-file FILE', String, "Policy Config from a local JSON or YAML file") do |val|
|
264
320
|
options['configFile'] = val.to_s
|
265
321
|
end
|
266
|
-
build_common_options(opts, options, [:options, :json, :dry_run, :quiet, :remote])
|
322
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :quiet, :remote])
|
267
323
|
opts.footer = "Create a new policy." + "\n" +
|
268
324
|
"[name] is optional and can be passed as --name instead."
|
269
325
|
end
|
@@ -275,118 +331,134 @@ class Morpheus::Cli::PoliciesCommand
|
|
275
331
|
end
|
276
332
|
connect(options)
|
277
333
|
begin
|
278
|
-
|
279
|
-
if options[:
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
334
|
+
payload = nil
|
335
|
+
if options[:payload]
|
336
|
+
payload = options[:payload]
|
337
|
+
# support -O OPTION switch on top of --payload
|
338
|
+
payload.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
339
|
+
else
|
340
|
+
group, cloud, user = nil, nil, nil
|
341
|
+
if options[:group]
|
342
|
+
group = find_group_by_name_or_id(options[:group])
|
343
|
+
elsif options[:cloud]
|
344
|
+
cloud = find_cloud_by_name_or_id(options[:cloud])
|
345
|
+
elsif options[:user]
|
346
|
+
user = find_user_by_username_or_id(nil, options[:user])
|
347
|
+
return 1 if user.nil?
|
348
|
+
end
|
292
349
|
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
# prompt for policy options
|
350
|
+
# merge -O options into normally parsed options
|
351
|
+
options.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options] && options[:options].keys.size > 0
|
352
|
+
|
353
|
+
# support [name] as first argument
|
354
|
+
if args[0]
|
355
|
+
options['name'] = args[0]
|
356
|
+
end
|
301
357
|
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
return 1
|
308
|
-
end
|
309
|
-
policy_types_dropdown = available_policy_types.collect {|it| {'name' => it['name'], 'value' => it['id']} }
|
310
|
-
policy_type_id = nil
|
311
|
-
policy_type = nil
|
312
|
-
if options['type']
|
313
|
-
policy_type_id = options['type']
|
314
|
-
else
|
315
|
-
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])
|
316
|
-
policy_type_id = v_prompt['type']
|
317
|
-
end
|
318
|
-
if !policy_type_id.to_s.empty?
|
319
|
-
policy_type = available_policy_types.find {|it|
|
320
|
-
it['id'] == policy_type_id.to_i || it['name'] == policy_type_id.to_s || it['code'] == policy_type_id.to_s
|
358
|
+
# construct payload
|
359
|
+
payload = {
|
360
|
+
'policy' => {
|
361
|
+
'config' => {}
|
362
|
+
}
|
321
363
|
}
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
364
|
+
|
365
|
+
# prompt for policy options
|
366
|
+
|
367
|
+
# Policy Type
|
368
|
+
# allow user as id, name or code
|
369
|
+
available_policy_types = @policies_interface.list_policy_types({})['policyTypes']
|
370
|
+
if available_policy_types.empty?
|
371
|
+
print_red_alert "No available policy types found!"
|
372
|
+
return 1
|
373
|
+
end
|
374
|
+
policy_types_dropdown = available_policy_types.collect {|it| {'name' => it['name'], 'value' => it['id']} }
|
375
|
+
policy_type_id = nil
|
376
|
+
policy_type = nil
|
377
|
+
if options['type']
|
378
|
+
policy_type_id = options['type']
|
379
|
+
else
|
380
|
+
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])
|
381
|
+
policy_type_id = v_prompt['type']
|
382
|
+
end
|
383
|
+
if !policy_type_id.to_s.empty?
|
384
|
+
policy_type = available_policy_types.find {|it|
|
385
|
+
it['id'] == policy_type_id.to_i || it['name'] == policy_type_id.to_s || it['code'] == policy_type_id.to_s
|
386
|
+
}
|
387
|
+
end
|
388
|
+
if !policy_type
|
389
|
+
print_red_alert "Policy Type not found by id '#{policy_type_id}'"
|
390
|
+
return 1
|
391
|
+
end
|
392
|
+
# payload['policy']['policyTypeId'] = policy_type['id']
|
393
|
+
payload['policy']['policyType'] = {'id' => policy_type['id']}
|
337
394
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
payload['policy']['description'] = v_prompt['description']
|
344
|
-
end
|
395
|
+
# Scope
|
396
|
+
if user
|
397
|
+
payload['policy']['refType'] = 'User'
|
398
|
+
payload['policy']['refId'] = user['id']
|
399
|
+
end
|
345
400
|
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
401
|
+
# Name (this is not even used at the moment!)
|
402
|
+
if options['name']
|
403
|
+
payload['policy']['name'] = options['name']
|
404
|
+
else
|
405
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => false, 'description' => 'Name for this policy.'}], options)
|
406
|
+
payload['policy']['name'] = v_prompt['name']
|
407
|
+
end
|
353
408
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
end
|
409
|
+
# Description (this is not even used at the moment!)
|
410
|
+
if options['description']
|
411
|
+
payload['policy']['description'] = options['description']
|
412
|
+
else
|
413
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false, 'description' => 'Description of policy.'}], options)
|
414
|
+
payload['policy']['description'] = v_prompt['description']
|
415
|
+
end
|
362
416
|
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
print_red_alert "File not found: #{config_file}"
|
370
|
-
return false
|
417
|
+
# Enabled
|
418
|
+
if options['enabled']
|
419
|
+
payload['policy']['enabled'] = options['enabled']
|
420
|
+
else
|
421
|
+
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)
|
422
|
+
payload['policy']['enabled'] = v_prompt['enabled']
|
371
423
|
end
|
372
|
-
|
373
|
-
|
424
|
+
|
425
|
+
# Tenants
|
426
|
+
if options['accounts']
|
427
|
+
# payload['policy']['accounts'] = options['accounts'].collect {|it| {'id' => it } }
|
428
|
+
payload['policy']['accounts'] = options['accounts']
|
374
429
|
else
|
375
|
-
|
430
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'accounts', 'fieldLabel' => 'Tenants', 'type' => 'text', 'required' => false, 'description' => 'Tenant accounts, comma separated list of account IDs'}], options)
|
431
|
+
payload['policy']['accounts'] = v_prompt['accounts']
|
376
432
|
end
|
377
|
-
|
378
|
-
#
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
433
|
+
|
434
|
+
# Config
|
435
|
+
if options['config']
|
436
|
+
payload['policy']['config'] = options['config']
|
437
|
+
elsif options['configFile']
|
438
|
+
config_file = File.expand_path(options['configFile'])
|
439
|
+
if !File.exists?(config_file) || !File.file?(config_file)
|
440
|
+
print_red_alert "File not found: #{config_file}"
|
441
|
+
return false
|
442
|
+
end
|
443
|
+
if config_file =~ /\.ya?ml\Z/
|
444
|
+
payload['policy']['config'] = YAML.load_file(config_file)
|
445
|
+
else
|
446
|
+
payload['policy']['config'] = JSON.parse(File.read(config_file))
|
387
447
|
end
|
388
448
|
else
|
389
|
-
|
449
|
+
# prompt for policy specific options
|
450
|
+
policy_type_option_types = policy_type['optionTypes']
|
451
|
+
# puts "POLICY OPTION TYPES:\n #{policy_type_option_types.inspect}"
|
452
|
+
if policy_type_option_types
|
453
|
+
config_prompt = Morpheus::Cli::OptionTypes.prompt(policy_type_option_types, options, @api_client)
|
454
|
+
# everything should be under fieldContext:'config'
|
455
|
+
# payload['policy'].deep_merge!(config_prompt)
|
456
|
+
if config_prompt['config']
|
457
|
+
payload['policy']['config'].deep_merge!(config_prompt['config'])
|
458
|
+
end
|
459
|
+
else
|
460
|
+
puts "No options found for policy type! Proceeding without config options..."
|
461
|
+
end
|
390
462
|
end
|
391
463
|
end
|
392
464
|
|
@@ -762,17 +834,26 @@ class Morpheus::Cli::PoliciesCommand
|
|
762
834
|
|
763
835
|
private
|
764
836
|
|
765
|
-
def find_policy_by_name_or_id(val)
|
837
|
+
def find_policy_by_name_or_id(val, scope_by={})
|
766
838
|
if val.to_s =~ /\A\d{1,}\Z/
|
767
|
-
return find_policy_by_id(val)
|
839
|
+
return find_policy_by_id(val, scope_by)
|
768
840
|
else
|
769
|
-
return find_policy_by_name(val)
|
841
|
+
return find_policy_by_name(val, scope_by)
|
770
842
|
end
|
771
843
|
end
|
772
844
|
|
773
|
-
def find_policy_by_id(id)
|
845
|
+
def find_policy_by_id(id, scope_by={})
|
774
846
|
begin
|
775
|
-
|
847
|
+
group = scope_by[:group]
|
848
|
+
cloud = scope_by[:cloud]
|
849
|
+
json_response = nil
|
850
|
+
if group
|
851
|
+
json_response = @group_policies_interface.get(group['id'], id.to_i)
|
852
|
+
elsif cloud
|
853
|
+
json_response = @cloud_policies_interface.get(cloud['id'], id.to_i)
|
854
|
+
else
|
855
|
+
json_response = @policies_interface.get(id.to_i)
|
856
|
+
end
|
776
857
|
return json_response['policy']
|
777
858
|
rescue RestClient::Exception => e
|
778
859
|
if e.response && e.response.code == 404
|
@@ -784,8 +865,17 @@ class Morpheus::Cli::PoliciesCommand
|
|
784
865
|
end
|
785
866
|
end
|
786
867
|
|
787
|
-
def find_policy_by_name(name)
|
788
|
-
|
868
|
+
def find_policy_by_name(name, scope_by={})
|
869
|
+
group = scope_by[:group]
|
870
|
+
cloud = scope_by[:cloud]
|
871
|
+
json_response = nil
|
872
|
+
if group
|
873
|
+
json_response = @group_policies_interface.list(group['id'], {name: name.to_s})
|
874
|
+
elsif cloud
|
875
|
+
json_response = @cloud_policies_interface.list(cloud['id'], {name: name.to_s})
|
876
|
+
else
|
877
|
+
json_response = @policies_interface.list({name: name.to_s})
|
878
|
+
end
|
789
879
|
policies = json_response['policies']
|
790
880
|
if policies.empty?
|
791
881
|
print_red_alert "Policy not found by name #{name}"
|