morpheus-cli 5.5.3 → 5.5.3.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 +4 -4
- data/Dockerfile +1 -1
- data/lib/morpheus/api/api_client.rb +12 -0
- data/lib/morpheus/api/appliance_settings_interface.rb +15 -0
- data/lib/morpheus/api/cypher_interface.rb +1 -2
- data/lib/morpheus/api/guidance_settings_interface.rb +17 -0
- data/lib/morpheus/api/monitoring_settings_interface.rb +25 -0
- data/lib/morpheus/api/network_server_groups_interface.rb +7 -0
- data/lib/morpheus/cli/cli_command.rb +10 -1
- data/lib/morpheus/cli/commands/appliance_settings_command.rb +57 -2
- data/lib/morpheus/cli/commands/backup_settings_command.rb +1 -1
- data/lib/morpheus/cli/commands/catalog_item_types_command.rb +6 -1
- data/lib/morpheus/cli/commands/cypher_command.rb +3 -0
- data/lib/morpheus/cli/commands/guidance_command.rb +2 -2
- data/lib/morpheus/cli/commands/guidance_settings.rb +148 -0
- data/lib/morpheus/cli/commands/log_settings_command.rb +1 -1
- data/lib/morpheus/cli/commands/monitoring_settings.rb +228 -0
- data/lib/morpheus/cli/commands/network_server_groups_command.rb +222 -0
- data/lib/morpheus/cli/commands/provisioning_settings_command.rb +1 -1
- data/lib/morpheus/cli/commands/reports_command.rb +10 -0
- data/lib/morpheus/cli/commands/whitelabel_settings_command.rb +1 -1
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +14 -12
- data/lib/morpheus/cli/mixins/rest_command.rb +5 -1
- data/lib/morpheus/cli/mixins/secondary_rest_command.rb +35 -12
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/ext/string.rb +6 -4
- data/lib/morpheus/routes.rb +39 -7
- metadata +8 -2
@@ -0,0 +1,228 @@
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
2
|
+
|
3
|
+
class Morpheus::Cli::MonitoringSettings
|
4
|
+
include Morpheus::Cli::CliCommand
|
5
|
+
include Morpheus::Cli::AccountsHelper
|
6
|
+
|
7
|
+
set_command_name :'monitor-settings'
|
8
|
+
set_command_description "View and manage monitoring settings"
|
9
|
+
register_subcommands :get, :update
|
10
|
+
|
11
|
+
def connect(opts)
|
12
|
+
@api_client = establish_remote_appliance_connection(opts)
|
13
|
+
@monitoring_settings_interface = @api_client.monitoring_settings
|
14
|
+
@options_interface = @api_client.options
|
15
|
+
end
|
16
|
+
|
17
|
+
def handle(args)
|
18
|
+
handle_subcommand(args)
|
19
|
+
end
|
20
|
+
|
21
|
+
def get(args)
|
22
|
+
params = {}
|
23
|
+
options = {}
|
24
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
25
|
+
opts.banner = subcommand_usage()
|
26
|
+
build_standard_get_options(opts, options)
|
27
|
+
opts.footer = "Get monitoring settings."
|
28
|
+
end
|
29
|
+
optparse.parse!(args)
|
30
|
+
connect(options)
|
31
|
+
verify_args!(args:args, optparse:optparse, count:0)
|
32
|
+
params.merge!(parse_query_options(options))
|
33
|
+
@monitoring_settings_interface.setopts(options)
|
34
|
+
if options[:dry_run]
|
35
|
+
print_dry_run @monitoring_settings_interface.dry.get(options)
|
36
|
+
return
|
37
|
+
end
|
38
|
+
json_response = @monitoring_settings_interface.get(options)
|
39
|
+
render_response(json_response, options, 'monitoringSettings') do
|
40
|
+
monitoring_settings = json_response['monitoringSettings']
|
41
|
+
service_now_settings = monitoring_settings['serviceNow']
|
42
|
+
new_relic_settings = monitoring_settings['newRelic']
|
43
|
+
print_h1 "Monitoring Settings"
|
44
|
+
print cyan
|
45
|
+
description_cols = {
|
46
|
+
"Auto Create Checks" => lambda {|it| format_boolean(it['autoManageChecks']) },
|
47
|
+
"Availability Time Frame" => lambda {|it| it['availabilityTimeFrame'] ? it['availabilityTimeFrame'].to_s + ' days' : '' },
|
48
|
+
"Availability Precision" => lambda {|it| it['availabilityPrecision'] ? it['availabilityPrecision'].to_s : '' },
|
49
|
+
"Default Check Interval" => lambda {|it| it['defaultCheckInterval'] ? it['defaultCheckInterval'].to_s + ' minutes' : '' },
|
50
|
+
}
|
51
|
+
print_description_list(description_cols, monitoring_settings, options)
|
52
|
+
|
53
|
+
print_h2 "ServiceNow Settings", options.merge(:border_style => :thin)
|
54
|
+
description_cols = {
|
55
|
+
"Enabled" => lambda {|it| format_boolean(it['enabled']) },
|
56
|
+
"Integration" => lambda {|it| it['integration'] ? it['integration']['name'] : '' },
|
57
|
+
"New Incident Action" => lambda {|it| format_service_now_action(it['newIncidentAction']) },
|
58
|
+
"Close Incident Action" => lambda {|it| format_service_now_action(it['closeIncidentAction']) },
|
59
|
+
"Info Mapping" => lambda {|it| format_service_now_mapping(it['infoMapping']) },
|
60
|
+
"Warning Mapping" => lambda {|it| format_service_now_mapping(it['warningMapping']) },
|
61
|
+
"Critical Mapping" => lambda {|it| format_service_now_mapping(it['criticalMapping']) },
|
62
|
+
}
|
63
|
+
print_description_list(description_cols, service_now_settings)
|
64
|
+
|
65
|
+
print_h2 "New Relic Settings", options.merge(:border_style => :thin)
|
66
|
+
description_cols = {
|
67
|
+
"Enabled" => lambda {|it| format_boolean(it['enabled']) },
|
68
|
+
"License Key" => lambda {|it| it['licenseKey'] },
|
69
|
+
}
|
70
|
+
print_description_list(description_cols, new_relic_settings, options)
|
71
|
+
|
72
|
+
print reset, "\n"
|
73
|
+
end
|
74
|
+
return 0, nil
|
75
|
+
end
|
76
|
+
|
77
|
+
def update(args)
|
78
|
+
params = {}
|
79
|
+
options = {}
|
80
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
81
|
+
opts.banner = opts.banner = subcommand_usage()
|
82
|
+
opts.on('--auto-create-checks [on|off]', String, "Auto Create Checks") do |val|
|
83
|
+
params['autoManageChecks'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
84
|
+
end
|
85
|
+
opts.on("--availability-time-frame DAYS", Integer, "Availability Time Frame. The number of days availability should be calculated for. Changes will not take effect until your checks have passed their check interval.") do |val|
|
86
|
+
params['availabilityTimeFrame'] = val.to_i
|
87
|
+
end
|
88
|
+
opts.on("--availability-precision DIGITS", Integer, "Availability Precision. The number of decimal places availability should be displayed in. Can be anywhere between 0 and 5.") do |val|
|
89
|
+
params['availabilityPrecision'] = val.to_i
|
90
|
+
end
|
91
|
+
opts.on("--default-check-interval MINUTES", Integer, "Default Check Interval. The default interval to use when creating new checks. Value is in minutes.") do |val|
|
92
|
+
params['defaultCheckInterval'] = val.to_i
|
93
|
+
end
|
94
|
+
opts.on('--service-now-enabled [on|off]', String, "ServiceNow: Enabled (on) or disabled (off)") do |val|
|
95
|
+
params['serviceNow'] ||= {}
|
96
|
+
params['serviceNow']['enabled'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
97
|
+
end
|
98
|
+
opts.on('--service-now-integration ID', String, "ServiceNow: Integration ID or Name") do |val|
|
99
|
+
params['serviceNow'] ||= {}
|
100
|
+
params['serviceNow']['integration'] = val # {'id' => val.to_i}
|
101
|
+
end
|
102
|
+
opts.on("--service-now-new-incident-action create|none", String, "ServiceNow: New Incident Action") do |val|
|
103
|
+
# allowed_values = 'create|none'.split('|') #get_service_now_actions().keys
|
104
|
+
# if !allowed_values.include?(val)
|
105
|
+
# raise ::OptionParser::InvalidOption.new("New Incident Action value '#{val}' is invalid.\nThe allowed values are: #{allowed_values.join(', ')}")
|
106
|
+
# end
|
107
|
+
params['serviceNow'] ||= {}
|
108
|
+
params['serviceNow']['newIncidentAction'] = val
|
109
|
+
end
|
110
|
+
opts.on("--service-now-close-incident-action close|activity|none", String, "ServiceNow: Close Incident Action") do |val|
|
111
|
+
# allowed_values = 'close|activity|none'.split('|') #get_service_now_mappings().keys
|
112
|
+
# if !allowed_values.include?(val)
|
113
|
+
# raise ::OptionParser::InvalidOption.new("Close Incident Action value '#{val}' is invalid.\nThe allowed values are: #{allowed_values.join(', ')}")
|
114
|
+
# end
|
115
|
+
params['serviceNow'] ||= {}
|
116
|
+
params['serviceNow']['closeIncidentAction'] = val
|
117
|
+
end
|
118
|
+
opts.on("--service-now-info-mapping low|medium|high", String, "ServiceNow: Info Mapping") do |val|
|
119
|
+
# allowed_values = 'low|medium|high'.split('|') # get_service_now_mappings().keys
|
120
|
+
# if !allowed_values.include?(val)
|
121
|
+
# raise ::OptionParser::InvalidOption.new("Info Mapping value '#{val}' is invalid.\nThe allowed values are: #{allowed_values.join(', ')}")
|
122
|
+
# end
|
123
|
+
params['serviceNow'] ||= {}
|
124
|
+
params['serviceNow']['infoMapping'] = val
|
125
|
+
end
|
126
|
+
opts.on("--service-now-warning-mapping low|medium|high", String, "ServiceNow: Warning Mapping") do |val|
|
127
|
+
# allowed_values = 'low|medium|high'.split('|') # get_service_now_mappings().keys
|
128
|
+
# if !allowed_values.include?(val)
|
129
|
+
# raise ::OptionParser::InvalidOption.new("Warning Info Mapping value '#{val}' is invalid.\nThe allowed values are: #{allowed_values.join(', ')}")
|
130
|
+
# end
|
131
|
+
params['serviceNow'] ||= {}
|
132
|
+
params['serviceNow']['warningMapping'] = val
|
133
|
+
end
|
134
|
+
opts.on("--service-now-critical-mapping low|medium|high", String, "ServiceNow: Critical Mapping") do |val|
|
135
|
+
# allowed_values = 'low|medium|high'.split('|') # get_service_now_mappings().keys
|
136
|
+
# if !allowed_values.include?(val)
|
137
|
+
# raise ::OptionParser::InvalidOption.new("Critical Info Mapping value '#{val}' is invalid.\nThe allowed values are: #{allowed_values.join(', ')}")
|
138
|
+
# end
|
139
|
+
params['serviceNow'] ||= {}
|
140
|
+
params['serviceNow']['criticalMapping'] = val
|
141
|
+
end
|
142
|
+
opts.on('--new-relic-enabled [on|off]', String, "New Relic: Enabled (on) or disabled (off)") do |val|
|
143
|
+
params['newRelic'] ||= {}
|
144
|
+
params['newRelic']['enabled'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s == '1' || val.to_s == ''
|
145
|
+
end
|
146
|
+
opts.on("--new-relic-license-key [VALUE]", String, "New Relic: License Key") do |val|
|
147
|
+
params['newRelic'] ||= {}
|
148
|
+
params['newRelic']['licenseKey'] = val
|
149
|
+
end
|
150
|
+
build_standard_update_options(opts, options)
|
151
|
+
opts.footer = "Update monitoring settings."
|
152
|
+
end
|
153
|
+
optparse.parse!(args)
|
154
|
+
connect(options)
|
155
|
+
verify_args!(args:args, optparse:optparse, count:0)
|
156
|
+
payload = parse_payload(options)
|
157
|
+
if !payload
|
158
|
+
payload = {}
|
159
|
+
payload.deep_merge!({object_key => parse_passed_options(options)}) # inject options passed with -O foo=bar
|
160
|
+
if params['serviceNow'] && params['serviceNow']['integration']
|
161
|
+
integration = find_by_name_or_id(:integration, params['serviceNow']['integration'])
|
162
|
+
if integration.nil?
|
163
|
+
exit 1 #return 1, "Integration not found by '#{options[:servicenow_integration]}'"
|
164
|
+
else
|
165
|
+
if integration['integrationType']['code'] != 'serviceNow'
|
166
|
+
raise_command_error "Integration '#{integration['id']}' must be a Service Now integration"
|
167
|
+
end
|
168
|
+
params['serviceNow'] ||= {}
|
169
|
+
params['serviceNow']['integration'] = {'id' => integration['id'].to_i}
|
170
|
+
end
|
171
|
+
end
|
172
|
+
payload.deep_merge!({object_key => params})
|
173
|
+
end
|
174
|
+
if payload[object_key].empty?
|
175
|
+
raise_command_error "Specify at least one option to update.\n#{optparse}"
|
176
|
+
end
|
177
|
+
@monitoring_settings_interface.setopts(options)
|
178
|
+
if options[:dry_run]
|
179
|
+
print_dry_run @monitoring_settings_interface.dry.update(payload)
|
180
|
+
return
|
181
|
+
end
|
182
|
+
json_response = @monitoring_settings_interface.update(payload)
|
183
|
+
exit_code, err = 0, nil
|
184
|
+
render_response(json_response, options, object_key) do
|
185
|
+
if json_response['success']
|
186
|
+
print_green_success "Updated monitoring settings"
|
187
|
+
get([] + (options[:remote] ? ["-r",options[:remote]] : []))
|
188
|
+
else
|
189
|
+
exit_code, err = 1, "Error updating monitoring settings: #{json_response['msg'] || json_response['errors']}"
|
190
|
+
print_rest_errors(json_response)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
return exit_code, err
|
194
|
+
end
|
195
|
+
|
196
|
+
private
|
197
|
+
|
198
|
+
def get_service_now_actions()
|
199
|
+
{
|
200
|
+
'create' => 'Create new incident in ServiceNow',
|
201
|
+
'close' => 'Resolve Incident in ServiceNow',
|
202
|
+
'activity' => 'Add Activity to Incident in ServiceNow',
|
203
|
+
'none' => 'No action',
|
204
|
+
}
|
205
|
+
end
|
206
|
+
|
207
|
+
def format_service_now_action(action_value)
|
208
|
+
get_service_now_actions()[action_value].to_s
|
209
|
+
end
|
210
|
+
|
211
|
+
def get_service_now_mappings()
|
212
|
+
{
|
213
|
+
'low' => 'Low',
|
214
|
+
'medium' => 'Medium',
|
215
|
+
'high' => 'High',
|
216
|
+
}
|
217
|
+
end
|
218
|
+
|
219
|
+
def format_service_now_mapping(mapping_value)
|
220
|
+
get_service_now_mappings()[mapping_value].to_s
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
def object_key
|
225
|
+
'monitoringSettings'
|
226
|
+
end
|
227
|
+
|
228
|
+
end
|
@@ -0,0 +1,222 @@
|
|
1
|
+
require 'morpheus/cli/cli_command'
|
2
|
+
|
3
|
+
class Morpheus::Cli::NetworkServerGroups
|
4
|
+
include Morpheus::Cli::CliCommand
|
5
|
+
include Morpheus::Cli::WhoamiHelper
|
6
|
+
include Morpheus::Cli::RestCommand
|
7
|
+
include Morpheus::Cli::SecondaryRestCommand
|
8
|
+
include Morpheus::Cli::ProvisioningHelper
|
9
|
+
|
10
|
+
set_command_description "View and manage network server groups."
|
11
|
+
set_command_name :'network-server-groups'
|
12
|
+
register_subcommands :list, :get, :add, :update, :remove
|
13
|
+
register_interfaces :network_servers, :network_server_groups, :accounts
|
14
|
+
set_rest_perms_config({enabled:true, excludes:['groups', 'plans', 'visibility', 'resource'], context: 'permissions'})
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
NSXT_CRITERIA_TYPES = ['Condition', 'NestedExpression'] unless defined? NSXT_CRITERIA_TYPES
|
19
|
+
NSXT_MEMBER_TYPES = ['Path', 'ExternalID'] unless defined? NSXT_MEMBER_TYPES
|
20
|
+
NSXT_IP_TYPES = ['IPAddress', 'MACAddress'] unless defined? NSXT_IP_TYPES
|
21
|
+
NSXT_AD_GROUP_TYPES = ['IdentityGroup'] unless defined? NSXT_AD_GROUP_TYPES
|
22
|
+
|
23
|
+
def network_server_group_list_key
|
24
|
+
'groups'
|
25
|
+
end
|
26
|
+
|
27
|
+
def network_server_group_object_key
|
28
|
+
'group'
|
29
|
+
end
|
30
|
+
|
31
|
+
def network_server_group_field_context
|
32
|
+
network_server_group_object_key
|
33
|
+
end
|
34
|
+
|
35
|
+
def load_option_types_for_network_server_group(record_type, parent_record)
|
36
|
+
parent_record['type']['groupOptionTypes']
|
37
|
+
end
|
38
|
+
|
39
|
+
def network_server_group_list_column_definitions(options)
|
40
|
+
if options[:parent_record]['type']['code'] == 'nsx-t'
|
41
|
+
members_lambda = lambda do |group|
|
42
|
+
members = []
|
43
|
+
{
|
44
|
+
'Criteria' => NSXT_CRITERIA_TYPES,
|
45
|
+
'Members' => NSXT_MEMBER_TYPES,
|
46
|
+
'IPS / MACS' => NSXT_IP_TYPES,
|
47
|
+
'AD Groups' => NSXT_AD_GROUP_TYPES
|
48
|
+
}.each do |label, types|
|
49
|
+
if (count = group['members'].select{|member| types.include?(member['type'])}.count) > 0
|
50
|
+
members << "#{count} #{label}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
members.join(', ')
|
54
|
+
end
|
55
|
+
else
|
56
|
+
members_lambda = lambda do |group|
|
57
|
+
group['members'].collect{|member| member['type']}.join(', ')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
columns = {
|
62
|
+
'ID' => 'id',
|
63
|
+
'Name' => 'name',
|
64
|
+
'Description' => {:label => 'Description', :max_width => 50, :display_method => lambda {|group| group['description']}},
|
65
|
+
'Members' => members_lambda
|
66
|
+
}
|
67
|
+
|
68
|
+
if is_master_account
|
69
|
+
columns['Visibility'] = lambda {|it| it['visibility'].capitalize}
|
70
|
+
columns['Tenants'] = lambda do |it|
|
71
|
+
tenants = []
|
72
|
+
if it['permissions'] and it['permissions']['tenantPermissions']
|
73
|
+
tenants = @accounts_interface.list({:ids => it['permissions']['tenantPermissions']['accounts']})['accounts'].collect{|account| account['name']}
|
74
|
+
end
|
75
|
+
tenants.join(', ')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
columns
|
79
|
+
end
|
80
|
+
|
81
|
+
def network_server_group_column_definitions(options)
|
82
|
+
if options[:parent_record]['type']['code'] == 'nsx-t'
|
83
|
+
tags_lambda = lambda{|group|
|
84
|
+
(group['tags'] || []).collect{|tag|
|
85
|
+
"#{tag['name']}#{(tag['value'] || '').length > 0 ? " (scope: #{tag['value']})" : ''}"
|
86
|
+
}.join(', ')
|
87
|
+
}
|
88
|
+
else
|
89
|
+
tags_lambda = lambda {|group| group['tags'] ? format_metadata(group['tags']) : '' }
|
90
|
+
end
|
91
|
+
columns = {
|
92
|
+
"ID" => 'id',
|
93
|
+
"Name" => 'name',
|
94
|
+
"Description" => 'description',
|
95
|
+
"Tags" => tags_lambda
|
96
|
+
}
|
97
|
+
columns
|
98
|
+
end
|
99
|
+
|
100
|
+
def network_server_group_add_prompt(record_payload, record_type, parent_record, options)
|
101
|
+
unless parent_record['type']['code'] != 'nsx-t' or options[:no_prompt]
|
102
|
+
nsxt_add_prompt(record_payload, record_type, parent_record, options)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def nsxt_add_prompt(record_payload, record_type, parent_record, options)
|
107
|
+
# criteria
|
108
|
+
criteria = []
|
109
|
+
while criteria.count < 5 && Morpheus::Cli::OptionTypes.confirm("Add#{criteria.count == 0 ? '': ' another'} criteria?", {:default => false})
|
110
|
+
if true #members.count == 0 or members.last['memberValue'] == 'OR' # Can't have nested follow AND conjunction
|
111
|
+
type = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'fieldLabel' => 'Criteria Type', 'type' => 'select', 'selectOptions' => ['Condition', 'Nested Expression'].map{|it| {'name' => it, 'value' => it.sub(' ', '')}}, 'required' => true, 'defaultValue' => 'Condition'}], options[:options])['type']
|
112
|
+
end
|
113
|
+
prompt_condition = lambda do
|
114
|
+
compare_type = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'memberType', 'fieldLabel' => 'Criteria Item', 'type' => 'select', 'selectOptions' => ['Virtual Machine', 'Segment Port', 'Segment', 'IP Set'].map{|it| {'name' => it, 'value' => it.sub(' ', '')}}, 'required' => true, 'defaultValue' => 'VirtualMachine'}], options[:options])['memberType']
|
115
|
+
compare_key = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'key', 'fieldLabel' => "#{compare_type} Field", 'type' => 'select', 'selectOptions' => (compare_type == 'VirtualMachine' ? ['Name', 'Tag', 'OS Name', 'Computer Name'] : ['Tag'] ).map{|it| {'name' => it, 'value' => it.sub(' ', '')}}, 'required' => true, 'defaultValue' => 'Tag'}], options[:options])['key']
|
116
|
+
compare_operator = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'operator', 'fieldLabel' => "#{compare_key} Operator", 'type' => 'select', 'selectOptions' => (compare_type == 'VirtualMachine' ? ['Equals', 'Contains', 'Starts With', 'Ends With'] : ['Equals']).map{|it| {'name' => it, 'value' => it.sub(' ', '').upcase}}, 'required' => true, 'defaultValue' => 'EQUALS'}], options[:options])['operator']
|
117
|
+
compare_value = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'value', 'type' => 'text', 'fieldLabel' => "#{compare_key} Value", 'required' => true, 'description' => 'Value to compare.'}], options[:options])['value']
|
118
|
+
compare_scope = nil
|
119
|
+
if compare_key == 'Tag'
|
120
|
+
compare_scope = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'scope', 'type' => 'text', 'fieldLabel' => "#{compare_key} Scope", 'required' => false}], options[:options], @api_client, {}, false, true)['scope']
|
121
|
+
end
|
122
|
+
compare_expr = {key: compare_key, operator: compare_operator, value: compare_value}
|
123
|
+
compare_expr.merge!({scope: compare_scope}) if compare_scope
|
124
|
+
{'type' => 'Condition', 'memberType' => compare_type, 'memberExpression' => JSON.generate(compare_expr)}
|
125
|
+
end
|
126
|
+
|
127
|
+
if criteria.count > 0
|
128
|
+
criteria.last['memberValue'] = 'OR'
|
129
|
+
end
|
130
|
+
|
131
|
+
if type == 'Condition'
|
132
|
+
prev_criteria = criteria.count > 0 ? criteria.last : nil
|
133
|
+
criteria << prompt_condition.call
|
134
|
+
if prev_criteria and prev_criteria['type'] != 'NestedExpression' and prev_criteria['memberType'] == criteria.last['memberType']
|
135
|
+
prev_criteria['memberValue'] = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'memberValue', 'fieldLabel' => 'And/Or', 'type' => 'select', 'selectOptions' => ['and', 'or'].map{|it| {'name' => it, 'value' => it.upcase}}, 'required' => true, 'defaultValue' => 'AND', 'description' => 'Conjunction to use between this condition and the previous condition'}], options[:options])['memberValue']
|
136
|
+
end
|
137
|
+
else
|
138
|
+
# just prompt for conditions w/
|
139
|
+
nested_members = [prompt_condition.call]
|
140
|
+
while nested_members.count < 5 && Morpheus::Cli::OptionTypes.confirm("Add another criteria to nested expression?", {:default => false})
|
141
|
+
nested_members.last['memberValue'] = 'AND'
|
142
|
+
nested_members << prompt_condition.call
|
143
|
+
end
|
144
|
+
criteria << {'type' => type, 'members' => nested_members}
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
members = []
|
149
|
+
while members.count < 500 && Morpheus::Cli::OptionTypes.confirm("Add#{members.count == 0 ? '': ' another'} member?", {:default => false})
|
150
|
+
member_type = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'memberType', 'fieldLabel' => 'Member Type', 'type' => 'select', 'selectOptions' => ['Group', 'Segment', 'Segment Port', 'Virtual Network Interface', 'Virtual Machine', 'Physical Server'].map{|it| {'name' => it, 'value' => it.gsub(' ', '')}}, 'required' => true, 'defaultValue' => 'Group'}], options[:options])['memberType']
|
151
|
+
member_value = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'memberValue', 'fieldLabel' => member_type, 'type' => 'select', 'optionSource' => 'nsxtGroupMembers', 'optionSourceType' => 'nsxt', 'required' => true}], options[:options], @api_client, {networkServerId: parent_record['id'], memberType: member_type}, false, true)['memberValue']
|
152
|
+
type = ['Group', 'Segment', 'SegmentPort'].include?(member_type) ? 'Path' : 'ExternalID'
|
153
|
+
members << {'type' => type, 'memberType' => member_type, 'memberValue' => member_value}
|
154
|
+
end
|
155
|
+
|
156
|
+
# ip/mac
|
157
|
+
ips = []
|
158
|
+
while members.count + ips.count < 500 && Morpheus::Cli::OptionTypes.confirm("Add#{ips.count == 0 ? '': ' another'} IP/MAC address?", {:default => false})
|
159
|
+
member_value = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'ipAddress', 'type' => 'text', 'fieldLabel' => "IP/MAC Address", 'required' => true, 'description' => 'Enter an IP or MAC address. x.x.x.x'}], options[:options])['ipAddress']
|
160
|
+
type = member_value.match(/[a-fA-F0-9]{2}(:[a-fA-F0-9]{2}){5}/) ? 'MACAddress' : 'IPAddress'
|
161
|
+
ips << {'type' => type, 'memberValue' => member_value}
|
162
|
+
end
|
163
|
+
|
164
|
+
# ad groups
|
165
|
+
ad_groups = []
|
166
|
+
while members.count + ips.count + ad_groups.count < 500 && Morpheus::Cli::OptionTypes.confirm("Add#{ad_groups.count == 0 ? '': ' another'} AD Group?", {:default => false})
|
167
|
+
member_value = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'identityGroup', 'type' => 'select', 'optionSource' => 'nsxtIdentityGroups', 'optionSourceType' => 'nsxt', 'required' => true, 'fieldLabel' => "AD Group"}], options[:options], @api_client, {networkServerId: parent_record['id'], memberType: member_type}, false, true)['identityGroup']
|
168
|
+
ad_groups << {'type' => 'IdentityGroup', 'memberValue' => member_value}
|
169
|
+
end
|
170
|
+
|
171
|
+
record_payload['members'] = criteria + members + ips + ad_groups
|
172
|
+
record_payload
|
173
|
+
end
|
174
|
+
|
175
|
+
def render_response_details_for_get(record, options)
|
176
|
+
if options[:parent_record]['type']['code'] == 'nsx-t'
|
177
|
+
members = record['members'].select{|member| NSXT_CRITERIA_TYPES.include?(member['type'])}
|
178
|
+
if members.count > 0
|
179
|
+
cond_criteria = lambda do |member|
|
180
|
+
expr = JSON.parse(member['memberExpression'])
|
181
|
+
"#{member['memberType']} #{expr['key']} #{expr['operator']} #{expr['value']}#{expr['scope'].nil? ? '' : " w/ #{expr['scope']} scope"}"
|
182
|
+
end
|
183
|
+
criteria_parts = []
|
184
|
+
members.each_with_index do |member, index|
|
185
|
+
if member['type'] == 'NestedExpression'
|
186
|
+
criteria_parts << "("
|
187
|
+
member['members'].each do |child_member|
|
188
|
+
criteria_parts << " #{cond_criteria.call(child_member)}"
|
189
|
+
criteria_parts << " #{child_member['memberValue']}"
|
190
|
+
end
|
191
|
+
criteria_parts.pop # remove last conjunction
|
192
|
+
criteria_parts << ")"
|
193
|
+
else
|
194
|
+
criteria_parts << cond_criteria.call(member)
|
195
|
+
criteria_parts << member['memberValue']
|
196
|
+
end
|
197
|
+
end
|
198
|
+
criteria_parts.pop if ['AND', 'OR'].include?(criteria_parts.last) # remove last conjunction
|
199
|
+
print_h2 "Criteria (#{members.count})", options
|
200
|
+
print "#{cyan}#{criteria_parts.join("\n")}\n"
|
201
|
+
end
|
202
|
+
|
203
|
+
members = record['members'].select{|member| NSXT_MEMBER_TYPES.include?(member['type'])}
|
204
|
+
if members.count > 0
|
205
|
+
print_h2 "Members (#{members.count})", options
|
206
|
+
print as_pretty_table(members, {'Type' => 'memberType', 'Path/ExternalID' => 'memberValue'}, options)
|
207
|
+
end
|
208
|
+
|
209
|
+
members = record['members'].select{|member| NSXT_IP_TYPES.include?(member['type'])}
|
210
|
+
if members.count > 0
|
211
|
+
print_h2 "IP/MAC Addresses (#{members.count})", options
|
212
|
+
print "#{cyan}#{members.collect{|member| "#{member['memberValue']}"}.join("\n")}\n"
|
213
|
+
end
|
214
|
+
|
215
|
+
members = record['members'].select{|member| NSXT_AD_GROUP_TYPES.include?(member['type'])}
|
216
|
+
if members.count > 0
|
217
|
+
print_h2 "AD Groups (#{members.count})", options
|
218
|
+
print "#{cyan}#{members.collect{|member| "#{member['memberValue']}"}.join("\n")}\n"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
@@ -83,7 +83,7 @@ class Morpheus::Cli::ProvisioningSettingsCommand
|
|
83
83
|
"Default Blueprint Type" => lambda {|it| it['defaultTemplateType'] ? it['defaultTemplateType']['name'].capitalize : 'Morpheus'}
|
84
84
|
}
|
85
85
|
print_description_list(description_cols, settings)
|
86
|
-
print reset "\n"
|
86
|
+
print reset, "\n"
|
87
87
|
return 0
|
88
88
|
rescue RestClient::Exception => e
|
89
89
|
print_rest_exception(e, options)
|
@@ -303,6 +303,16 @@ class Morpheus::Cli::ReportsCommand
|
|
303
303
|
|
304
304
|
end
|
305
305
|
|
306
|
+
if payload['report']['startMonth'].size > 7 || payload['report']['endMonth'].size > 7
|
307
|
+
print_green_success "The CLI generates a query that will use only month and year. However, the API does support yyyy-mm-dd from a previous version of Morpheus.\nReplace startMonth/endMonth keys with startDate,endDate ie:"
|
308
|
+
payload['report'].delete('startMonth')
|
309
|
+
payload['report'].delete('endMonth')
|
310
|
+
payload['report']['startDate'] = 'yyyy-mm-dd'
|
311
|
+
payload['report']['endDate'] = 'yyyy-mm-dd'
|
312
|
+
print_dry_run @reports_interface.dry.create(payload)
|
313
|
+
return 0
|
314
|
+
end
|
315
|
+
|
306
316
|
@reports_interface.setopts(options)
|
307
317
|
if options[:dry_run]
|
308
318
|
print_dry_run @reports_interface.dry.create(payload)
|
@@ -137,7 +137,7 @@ class Morpheus::Cli::WhitelabelSettingsCommand
|
|
137
137
|
print cyan
|
138
138
|
print options[:details] ? content : truncate_string(content, trunc_len), "\n"
|
139
139
|
end
|
140
|
-
print reset "\n"
|
140
|
+
print reset, "\n"
|
141
141
|
return 0
|
142
142
|
rescue RestClient::Exception => e
|
143
143
|
print_rest_exception(e, options)
|
@@ -1435,7 +1435,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
1435
1435
|
'id' => current_volume['id'].to_i,
|
1436
1436
|
'rootVolume' => false,
|
1437
1437
|
'name' => current_volume['name'],
|
1438
|
-
'size' => current_volume['size']
|
1438
|
+
'size' => current_volume['size'] ? current_volume['size'] : (plan_size || 0),
|
1439
1439
|
'sizeId' => nil,
|
1440
1440
|
'storageType' => (current_volume['type'] || current_volume['storageType']),
|
1441
1441
|
'datastoreId' => current_volume['datastoreId']
|
@@ -2003,9 +2003,10 @@ module Morpheus::Cli::ProvisioningHelper
|
|
2003
2003
|
group_access = nil
|
2004
2004
|
all_plans = nil
|
2005
2005
|
plan_access = nil
|
2006
|
+
permissions = {}
|
2006
2007
|
|
2007
2008
|
# Group Access
|
2008
|
-
|
2009
|
+
unless excludes.include?('groups')
|
2009
2010
|
if !options[:groupAccessAll].nil?
|
2010
2011
|
all_groups = options[:groupAccessAll]
|
2011
2012
|
end
|
@@ -2055,7 +2056,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
2055
2056
|
end
|
2056
2057
|
|
2057
2058
|
# Plan Access
|
2058
|
-
|
2059
|
+
unless excludes.include?('plans')
|
2059
2060
|
if !options[:planAccessAll].nil?
|
2060
2061
|
all_plans = options[:planAccessAll]
|
2061
2062
|
end
|
@@ -2101,13 +2102,14 @@ module Morpheus::Cli::ProvisioningHelper
|
|
2101
2102
|
end
|
2102
2103
|
end
|
2103
2104
|
|
2104
|
-
|
2105
|
-
|
2106
|
-
|
2107
|
-
|
2108
|
-
|
2109
|
-
|
2110
|
-
|
2105
|
+
unless excludes.include?('resource')
|
2106
|
+
resource_perms = {}
|
2107
|
+
resource_perms['all'] = all_groups if !all_groups.nil?
|
2108
|
+
resource_perms['sites'] = group_access if !group_access.nil?
|
2109
|
+
resource_perms['allPlans'] = all_plans if !all_plans.nil?
|
2110
|
+
resource_perms['plans'] = plan_access if !plan_access.nil?
|
2111
|
+
permissions['resourcePermissions'] = resource_perms
|
2112
|
+
end
|
2111
2113
|
|
2112
2114
|
available_accounts = get_available_accounts() #.collect {|it| {'name' => it['name'], 'value' => it['id']}}
|
2113
2115
|
accounts = []
|
@@ -2115,7 +2117,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
2115
2117
|
# Prompts for multi tenant
|
2116
2118
|
if available_accounts.count > 1
|
2117
2119
|
visibility = options[:visibility]
|
2118
|
-
|
2120
|
+
unless excludes.include?('visibility')
|
2119
2121
|
if !visibility && !options[:no_prompt]
|
2120
2122
|
visibility = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'visibility', 'fieldLabel' => 'Tenant Permissions Visibility', 'type' => 'select', 'defaultValue' => 'private', 'required' => true, 'selectOptions' => [{'name' => 'Private', 'value' => 'private'},{'name' => 'Public', 'value' => 'public'}]}], options[:options], @api_client, {})['visibility']
|
2121
2123
|
end
|
@@ -2123,7 +2125,7 @@ module Morpheus::Cli::ProvisioningHelper
|
|
2123
2125
|
end
|
2124
2126
|
|
2125
2127
|
# Tenants
|
2126
|
-
|
2128
|
+
unless excludes.include?('tenants')
|
2127
2129
|
if !options[:tenants].nil?
|
2128
2130
|
accounts = options[:tenants].collect {|id| id.to_i}
|
2129
2131
|
elsif !options[:no_prompt]
|
@@ -720,9 +720,13 @@ EOT
|
|
720
720
|
else
|
721
721
|
perms = prompt_permissions(options.deep_merge(rest_perms_config[:options] || {}), rest_perms_config[:excludes] || [])
|
722
722
|
end
|
723
|
-
|
723
|
+
unless rest_perms_config[:name].nil?
|
724
724
|
perms.transform_keys! {|k| k == 'resourcePermissions' ? rest_perms_config[:name] : k}
|
725
725
|
end
|
726
|
+
unless rest_perms_config[:context].nil?
|
727
|
+
perms_context = {}
|
728
|
+
perms_context[rest_perms_config[:context]] = perms
|
729
|
+
end
|
726
730
|
record_payload.merge!(perms)
|
727
731
|
end
|
728
732
|
payload[rest_object_key] = record_payload
|