morpheus-cli 5.5.2.2 → 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/.gitignore +2 -1
- data/Dockerfile +1 -1
- data/README.md +57 -4
- data/Rakefile +9 -0
- data/bin/morpheus +4 -4
- data/lib/morpheus/api/api_client.rb +20 -2
- data/lib/morpheus/api/appliance_settings_interface.rb +15 -0
- data/lib/morpheus/api/archive_buckets_interface.rb +1 -1
- data/lib/morpheus/api/archive_files_interface.rb +3 -3
- data/lib/morpheus/api/clients_interface.rb +2 -2
- data/lib/morpheus/api/clusters_interface.rb +8 -1
- data/lib/morpheus/api/containers_interface.rb +29 -16
- data/lib/morpheus/api/custom_instance_types_interface.rb +0 -2
- data/lib/morpheus/api/cypher_interface.rb +1 -2
- data/lib/morpheus/api/doc_interface.rb +8 -6
- data/lib/morpheus/api/file_copy_request_interface.rb +1 -1
- data/lib/morpheus/api/guidance_settings_interface.rb +17 -0
- data/lib/morpheus/api/health_interface.rb +1 -1
- data/lib/morpheus/api/image_builder_interface.rb +3 -3
- data/lib/morpheus/api/instances_interface.rb +25 -0
- data/lib/morpheus/api/logs_interface.rb +2 -4
- data/lib/morpheus/api/monitoring_interface.rb +6 -6
- data/lib/morpheus/api/monitoring_settings_interface.rb +25 -0
- data/lib/morpheus/api/network_server_groups_interface.rb +7 -0
- data/lib/morpheus/api/packages_interface.rb +1 -1
- data/lib/morpheus/api/reports_interface.rb +1 -1
- data/lib/morpheus/api/servers_interface.rb +9 -1
- data/lib/morpheus/api/storage_providers_interface.rb +2 -2
- data/lib/morpheus/api/virtual_images_interface.rb +1 -1
- data/lib/morpheus/api.rb +2 -0
- data/lib/morpheus/benchmarking.rb +1 -1
- data/lib/morpheus/cli/cli_command.rb +79 -37
- data/lib/morpheus/cli/cli_registry.rb +19 -10
- data/lib/morpheus/cli/commands/access_token_command.rb +1 -1
- data/lib/morpheus/cli/commands/appliance_settings_command.rb +57 -2
- data/lib/morpheus/cli/commands/apps.rb +1 -1
- data/lib/morpheus/cli/commands/archives_command.rb +25 -33
- data/lib/morpheus/cli/commands/backup_settings_command.rb +1 -1
- data/lib/morpheus/cli/commands/blueprints_command.rb +10 -21
- data/lib/morpheus/cli/commands/boot_scripts_command.rb +2 -2
- data/lib/morpheus/cli/commands/cat_command.rb +1 -1
- data/lib/morpheus/cli/commands/catalog_item_types_command.rb +18 -13
- data/lib/morpheus/cli/commands/clouds.rb +3 -3
- data/lib/morpheus/cli/commands/clusters.rb +154 -3
- data/lib/morpheus/cli/commands/containers_command.rb +398 -253
- data/lib/morpheus/cli/commands/cypher_command.rb +3 -0
- data/lib/morpheus/cli/commands/deployments.rb +1 -1
- data/lib/morpheus/cli/commands/deploys.rb +9 -9
- data/lib/morpheus/cli/commands/doc.rb +15 -16
- data/lib/morpheus/cli/commands/execution_request_command.rb +2 -2
- data/lib/morpheus/cli/commands/file_copy_request_command.rb +5 -5
- data/lib/morpheus/cli/commands/groups.rb +2 -2
- 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/health_command.rb +4 -4
- data/lib/morpheus/cli/commands/hosts.rb +43 -5
- data/lib/morpheus/cli/commands/image_builder_command.rb +1 -1
- data/lib/morpheus/cli/commands/instances.rb +419 -148
- data/lib/morpheus/cli/commands/integrations_command.rb +22 -20
- data/lib/morpheus/cli/commands/key_pairs.rb +2 -2
- data/lib/morpheus/cli/commands/library_container_scripts_command.rb +2 -2
- data/lib/morpheus/cli/commands/library_container_templates_command.rb +2 -2
- data/lib/morpheus/cli/commands/library_instance_types_command.rb +3 -3
- data/lib/morpheus/cli/commands/library_spec_templates_command.rb +2 -2
- data/lib/morpheus/cli/commands/log_settings_command.rb +1 -1
- data/lib/morpheus/cli/commands/login.rb +1 -1
- data/lib/morpheus/cli/commands/man_command.rb +32 -18
- 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/packages_command.rb +11 -11
- data/lib/morpheus/cli/commands/plugins.rb +1 -1
- data/lib/morpheus/cli/commands/policies_command.rb +4 -4
- data/lib/morpheus/cli/commands/preseed_scripts_command.rb +2 -2
- data/lib/morpheus/cli/commands/provisioning_settings_command.rb +1 -1
- data/lib/morpheus/cli/commands/remote.rb +1 -1
- data/lib/morpheus/cli/commands/reports_command.rb +13 -3
- data/lib/morpheus/cli/commands/security_groups.rb +1 -1
- data/lib/morpheus/cli/commands/shell.rb +40 -62
- data/lib/morpheus/cli/commands/snapshots.rb +3 -5
- data/lib/morpheus/cli/commands/source_command.rb +8 -16
- data/lib/morpheus/cli/commands/storage_providers_command.rb +7 -7
- data/lib/morpheus/cli/commands/tasks.rb +2 -2
- data/lib/morpheus/cli/commands/vdi_pools_command.rb +6 -6
- data/lib/morpheus/cli/commands/view.rb +5 -1
- data/lib/morpheus/cli/commands/whitelabel_settings_command.rb +5 -5
- data/lib/morpheus/cli/commands/whoami.rb +2 -2
- data/lib/morpheus/cli/credentials.rb +30 -8
- data/lib/morpheus/cli/dot_file.rb +8 -15
- data/lib/morpheus/cli/error_handler.rb +16 -0
- data/lib/morpheus/cli/errors.rb +8 -1
- data/lib/morpheus/cli/mixins/print_helper.rb +17 -13
- data/lib/morpheus/cli/mixins/provisioning_helper.rb +14 -12
- data/lib/morpheus/cli/mixins/rest_command.rb +23 -19
- data/lib/morpheus/cli/mixins/secondary_rest_command.rb +47 -24
- data/lib/morpheus/cli/option_parser.rb +5 -1
- data/lib/morpheus/cli/option_types.rb +59 -12
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli.rb +26 -16
- data/lib/morpheus/ext/rest_client.rb +3 -2
- data/lib/morpheus/ext/string.rb +6 -4
- data/lib/morpheus/formatters.rb +1 -1
- data/lib/morpheus/logging.rb +4 -4
- data/lib/morpheus/morpkg.rb +4 -4
- data/lib/morpheus/rest_client.rb +2 -2
- data/lib/morpheus/routes.rb +41 -9
- data/lib/morpheus/terminal.rb +65 -16
- data/lib/morpheus.rb +1 -1
- data/morpheus-cli.gemspec +1 -0
- data/test/api/containers_interface_test.rb +68 -0
- data/test/api/doc_interface_test.rb +35 -0
- data/test/api/instances_interface_test.rb +22 -0
- data/test/api/whoami_interface_test.rb +14 -0
- data/test/cli/access_token_test.rb +36 -0
- data/test/cli/auth_test.rb +82 -0
- data/test/cli/cli_test.rb +48 -0
- data/test/cli/containers_test.rb +92 -0
- data/test/cli/doc_test.rb +35 -0
- data/test/cli/help_test.rb +25 -0
- data/test/cli/instances_test.rb +36 -0
- data/test/cli/man_test.rb +14 -0
- data/test/cli/remote_test.rb +89 -0
- data/test/cli/roles_test.rb +34 -0
- data/test/cli/shell_test.rb +81 -0
- data/test/cli/version_test.rb +23 -0
- data/test/cli/view_test.rb +55 -0
- data/test/cli/whoami_test.rb +17 -0
- data/test/morpheus_test.rb +16 -0
- data/test/test_case.rb +338 -0
- data/test/test_config.rb +137 -0
- data/test/test_data_helper.rb +97 -0
- metadata +67 -3
|
@@ -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
|
|
@@ -386,7 +386,7 @@ class Morpheus::Cli::PackagesCommand
|
|
|
386
386
|
puts_error "bad argument: [morpkg-file]\nFile '#{local_file_path}' is invalid.\n#{optparse}"
|
|
387
387
|
return 1
|
|
388
388
|
end
|
|
389
|
-
if !File.
|
|
389
|
+
if !File.exist?(local_file_path)
|
|
390
390
|
print_error Morpheus::Terminal.angry_prompt
|
|
391
391
|
puts_error "bad argument: [morpkg-file]\nFile '#{local_file_path}' was not found.\n"
|
|
392
392
|
return 1
|
|
@@ -545,7 +545,7 @@ class Morpheus::Cli::PackagesCommand
|
|
|
545
545
|
end
|
|
546
546
|
end
|
|
547
547
|
outfile = File.expand_path(outfile)
|
|
548
|
-
if Dir.
|
|
548
|
+
if Dir.exist?(outfile)
|
|
549
549
|
puts_error "#{Morpheus::Terminal.angry_prompt}--file is invalid. It is the name of an existing directory: #{outfile}"
|
|
550
550
|
return 1
|
|
551
551
|
end
|
|
@@ -554,7 +554,7 @@ class Morpheus::Cli::PackagesCommand
|
|
|
554
554
|
outfile << ".morpkg"
|
|
555
555
|
end
|
|
556
556
|
destination_dir = File.dirname(outfile)
|
|
557
|
-
if !Dir.
|
|
557
|
+
if !Dir.exist?(destination_dir)
|
|
558
558
|
if do_mkdir
|
|
559
559
|
print cyan,"Creating local directory #{destination_dir}",reset,"\n"
|
|
560
560
|
FileUtils.mkdir_p(destination_dir)
|
|
@@ -563,7 +563,7 @@ class Morpheus::Cli::PackagesCommand
|
|
|
563
563
|
return 1
|
|
564
564
|
end
|
|
565
565
|
end
|
|
566
|
-
if File.
|
|
566
|
+
if File.exist?(outfile)
|
|
567
567
|
if do_overwrite
|
|
568
568
|
# uhh need to be careful wih the passed filepath here..
|
|
569
569
|
# don't delete, just overwrite.
|
|
@@ -598,7 +598,7 @@ class Morpheus::Cli::PackagesCommand
|
|
|
598
598
|
|
|
599
599
|
if do_unzip
|
|
600
600
|
package_dir = File.join(File.dirname(outfile), File.basename(outfile).sub(/\.morpkg\Z/, ''))
|
|
601
|
-
if File.
|
|
601
|
+
if File.exist?(package_dir)
|
|
602
602
|
print cyan,"Deleting existing directory #{package_dir}",reset,"\n"
|
|
603
603
|
FileUtils.rm_rf(package_dir)
|
|
604
604
|
end
|
|
@@ -619,7 +619,7 @@ class Morpheus::Cli::PackagesCommand
|
|
|
619
619
|
#response_body = (http_response.body.kind_of?(Net::ReadAdapter) ? "" : http_response.body)
|
|
620
620
|
end
|
|
621
621
|
# F it, just remove a bad result
|
|
622
|
-
if File.
|
|
622
|
+
if File.exist?(outfile) && File.file?(outfile)
|
|
623
623
|
Morpheus::Logging::DarkPrinter.puts "Deleting bad file download: #{outfile}" if Morpheus::Logging.debug?
|
|
624
624
|
File.delete(outfile)
|
|
625
625
|
end
|
|
@@ -687,7 +687,7 @@ class Morpheus::Cli::PackagesCommand
|
|
|
687
687
|
begin
|
|
688
688
|
# validate source
|
|
689
689
|
source_directory = File.expand_path(source_directory)
|
|
690
|
-
if !File.
|
|
690
|
+
if !File.exist?(source_directory)
|
|
691
691
|
puts_error "#{Morpheus::Terminal.angry_prompt}[source] is invalid. Directory not found: #{source_directory}"
|
|
692
692
|
return 1
|
|
693
693
|
end
|
|
@@ -718,7 +718,7 @@ class Morpheus::Cli::PackagesCommand
|
|
|
718
718
|
else
|
|
719
719
|
outfile = File.expand_path(outfile)
|
|
720
720
|
end
|
|
721
|
-
if Dir.
|
|
721
|
+
if Dir.exist?(outfile)
|
|
722
722
|
puts_error "#{Morpheus::Terminal.angry_prompt}[target] is invalid. It is the name of an existing directory: #{outfile}"
|
|
723
723
|
return 1
|
|
724
724
|
end
|
|
@@ -727,7 +727,7 @@ class Morpheus::Cli::PackagesCommand
|
|
|
727
727
|
outfile << ".morpkg"
|
|
728
728
|
end
|
|
729
729
|
destination_dir = File.dirname(outfile)
|
|
730
|
-
if !Dir.
|
|
730
|
+
if !Dir.exist?(destination_dir)
|
|
731
731
|
if do_mkdir
|
|
732
732
|
print cyan,"Creating local directory #{destination_dir}",reset,"\n"
|
|
733
733
|
FileUtils.mkdir_p(destination_dir)
|
|
@@ -736,7 +736,7 @@ class Morpheus::Cli::PackagesCommand
|
|
|
736
736
|
return 1
|
|
737
737
|
end
|
|
738
738
|
end
|
|
739
|
-
if File.
|
|
739
|
+
if File.exist?(outfile)
|
|
740
740
|
if do_overwrite
|
|
741
741
|
# uhh need to be careful wih the passed filepath here..
|
|
742
742
|
# don't delete, just overwrite.
|
|
@@ -783,7 +783,7 @@ class Morpheus::Cli::PackagesCommand
|
|
|
783
783
|
end
|
|
784
784
|
end
|
|
785
785
|
# F it, just remove a bad result
|
|
786
|
-
# if File.
|
|
786
|
+
# if File.exist?(outfile) && File.file?(outfile)
|
|
787
787
|
# Morpheus::Logging::DarkPrinter.puts "Deleting bad build file: #{outfile}" if Morpheus::Logging.debug?
|
|
788
788
|
# File.delete(outfile)
|
|
789
789
|
# end
|
|
@@ -30,7 +30,7 @@ EOT
|
|
|
30
30
|
connect(options)
|
|
31
31
|
filename = args[0]
|
|
32
32
|
filename = File.expand_path(filename)
|
|
33
|
-
if !File.
|
|
33
|
+
if !File.exist?(filename)
|
|
34
34
|
raise_command_error "File not found: #{filename}"
|
|
35
35
|
elsif !File.file?(filename)
|
|
36
36
|
raise_command_error "File is a directory: #{filename}"
|
|
@@ -334,7 +334,7 @@ class Morpheus::Cli::PoliciesCommand
|
|
|
334
334
|
options['eachUser'] = val.to_s == 'on' || val.to_s == 'true' || val.to_s.empty?
|
|
335
335
|
end
|
|
336
336
|
|
|
337
|
-
opts.on('-t', '--type ID', "Policy Type Name or ID") do |val|
|
|
337
|
+
opts.on('-t', '--type ID', "Policy Type Name, Code or ID") do |val|
|
|
338
338
|
options['type'] = val
|
|
339
339
|
end
|
|
340
340
|
opts.on('--name VALUE', String, "Name for this policy") do |val|
|
|
@@ -417,7 +417,7 @@ class Morpheus::Cli::PoliciesCommand
|
|
|
417
417
|
print_red_alert "No available policy types found!"
|
|
418
418
|
return 1
|
|
419
419
|
end
|
|
420
|
-
policy_types_dropdown = available_policy_types.collect {|it| {'name' => it['name'], 'value' => it['id']} }
|
|
420
|
+
policy_types_dropdown = available_policy_types.collect {|it| {'name' => it['name'], 'value' => it['code'], 'id' => it['id']} }
|
|
421
421
|
policy_type_id = nil
|
|
422
422
|
policy_type = nil
|
|
423
423
|
if options['type']
|
|
@@ -497,7 +497,7 @@ class Morpheus::Cli::PoliciesCommand
|
|
|
497
497
|
payload['policy']['config'] = options['config']
|
|
498
498
|
elsif options['configFile']
|
|
499
499
|
config_file = File.expand_path(options['configFile'])
|
|
500
|
-
if !File.
|
|
500
|
+
if !File.exist?(config_file) || !File.file?(config_file)
|
|
501
501
|
print_red_alert "File not found: #{config_file}"
|
|
502
502
|
return false
|
|
503
503
|
end
|
|
@@ -637,7 +637,7 @@ class Morpheus::Cli::PoliciesCommand
|
|
|
637
637
|
payload['policy']['config'] = options['config']
|
|
638
638
|
elsif options['configFile']
|
|
639
639
|
config_file = File.expand_path(options['configFile'])
|
|
640
|
-
if !File.
|
|
640
|
+
if !File.exist?(config_file) || !File.file?(config_file)
|
|
641
641
|
print_red_alert "File not found: #{config_file}"
|
|
642
642
|
return false
|
|
643
643
|
end
|
|
@@ -172,7 +172,7 @@ class Morpheus::Cli::PreseedScriptsCommand
|
|
|
172
172
|
params = Morpheus::Cli::OptionTypes.prompt(my_options, options[:options], @api_client, options[:params])
|
|
173
173
|
script_file = params.delete('file')
|
|
174
174
|
if script_file
|
|
175
|
-
if !File.
|
|
175
|
+
if !File.exist?(script_file)
|
|
176
176
|
print_red_alert "File not found: #{script_file}"
|
|
177
177
|
return 1
|
|
178
178
|
end
|
|
@@ -243,7 +243,7 @@ class Morpheus::Cli::PreseedScriptsCommand
|
|
|
243
243
|
# params = Morpheus::Cli::OptionTypes.prompt(my_options, options[:options], @api_client, options[:params])
|
|
244
244
|
script_file = params.delete('file')
|
|
245
245
|
if script_file
|
|
246
|
-
if !File.
|
|
246
|
+
if !File.exist?(script_file)
|
|
247
247
|
print_red_alert "File not found: #{script_file}"
|
|
248
248
|
return 1
|
|
249
249
|
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)
|
|
@@ -1512,7 +1512,7 @@ EOT
|
|
|
1512
1512
|
|
|
1513
1513
|
def save_appliances(new_config)
|
|
1514
1514
|
fn = appliances_file_path
|
|
1515
|
-
if !Dir.
|
|
1515
|
+
if !Dir.exist?(File.dirname(fn))
|
|
1516
1516
|
FileUtils.mkdir_p(File.dirname(fn))
|
|
1517
1517
|
end
|
|
1518
1518
|
File.open(fn, 'w') {|f| f.write new_config.to_yaml } #Store
|
|
@@ -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)
|
|
@@ -396,12 +406,12 @@ class Morpheus::Cli::ReportsCommand
|
|
|
396
406
|
report_format = "csv"
|
|
397
407
|
end
|
|
398
408
|
|
|
399
|
-
if Dir.
|
|
409
|
+
if Dir.exist?(outfile)
|
|
400
410
|
print_red_alert "[file] is invalid. It is the name of an existing directory: #{outfile}"
|
|
401
411
|
return 1
|
|
402
412
|
end
|
|
403
413
|
destination_dir = File.dirname(outfile)
|
|
404
|
-
if !Dir.
|
|
414
|
+
if !Dir.exist?(destination_dir)
|
|
405
415
|
if do_mkdir
|
|
406
416
|
print cyan,"Creating local directory #{destination_dir}",reset,"\n"
|
|
407
417
|
FileUtils.mkdir_p(destination_dir)
|
|
@@ -410,7 +420,7 @@ class Morpheus::Cli::ReportsCommand
|
|
|
410
420
|
return 1
|
|
411
421
|
end
|
|
412
422
|
end
|
|
413
|
-
if File.
|
|
423
|
+
if File.exist?(outfile)
|
|
414
424
|
if do_overwrite
|
|
415
425
|
# uhh need to be careful wih the passed filepath here..
|
|
416
426
|
# don't delete, just overwrite.
|
|
@@ -1156,7 +1156,7 @@ class Morpheus::Cli::SecurityGroups
|
|
|
1156
1156
|
|
|
1157
1157
|
def self.save_security_group(new_config)
|
|
1158
1158
|
fn = security_group_file_path
|
|
1159
|
-
if !Dir.
|
|
1159
|
+
if !Dir.exist?(File.dirname(fn))
|
|
1160
1160
|
FileUtils.mkdir_p(File.dirname(fn))
|
|
1161
1161
|
end
|
|
1162
1162
|
File.open(fn, 'w') {|f| f.write new_config.to_yaml } #Store
|