morpheus-cli 3.1.1 → 3.1.1.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/lib/morpheus/api/api_client.rb +40 -0
- data/lib/morpheus/api/cloud_policies_interface.rb +47 -0
- data/lib/morpheus/api/group_policies_interface.rb +47 -0
- data/lib/morpheus/api/network_domains_interface.rb +47 -0
- data/lib/morpheus/api/network_groups_interface.rb +47 -0
- data/lib/morpheus/api/network_pool_servers_interface.rb +47 -0
- data/lib/morpheus/api/network_pools_interface.rb +47 -0
- data/lib/morpheus/api/network_proxies_interface.rb +47 -0
- data/lib/morpheus/api/network_services_interface.rb +47 -0
- data/lib/morpheus/api/networks_interface.rb +54 -0
- data/lib/morpheus/api/policies_interface.rb +63 -0
- data/lib/morpheus/cli.rb +8 -4
- data/lib/morpheus/cli/cli_command.rb +36 -1
- data/lib/morpheus/cli/instances.rb +3 -25
- data/lib/morpheus/cli/network_domains_command.rb +571 -0
- data/lib/morpheus/cli/network_groups_command.rb +602 -0
- data/lib/morpheus/cli/network_pool_servers_command.rb +430 -0
- data/lib/morpheus/cli/network_pools_command.rb +495 -0
- data/lib/morpheus/cli/network_proxies_command.rb +594 -0
- data/lib/morpheus/cli/network_services_command.rb +148 -0
- data/lib/morpheus/cli/networks_command.rb +855 -0
- data/lib/morpheus/cli/option_types.rb +3 -3
- data/lib/morpheus/cli/policies_command.rb +847 -0
- data/lib/morpheus/cli/remote.rb +0 -1
- data/lib/morpheus/cli/roles.rb +2 -2
- data/lib/morpheus/cli/version.rb +1 -1
- metadata +20 -2
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'morpheus/api/api_client'
|
2
|
+
|
3
|
+
class Morpheus::NetworksInterface < Morpheus::APIClient
|
4
|
+
def initialize(access_token, refresh_token,expires_at = nil, base_url=nil)
|
5
|
+
@access_token = access_token
|
6
|
+
@refresh_token = refresh_token
|
7
|
+
@base_url = base_url
|
8
|
+
@expires_at = expires_at
|
9
|
+
end
|
10
|
+
|
11
|
+
def get(id, params={})
|
12
|
+
raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
|
13
|
+
url = "#{@base_url}/api/networks/#{id}"
|
14
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
15
|
+
opts = {method: :get, url: url, headers: headers}
|
16
|
+
execute(opts)
|
17
|
+
end
|
18
|
+
|
19
|
+
def list(params={})
|
20
|
+
url = "#{@base_url}/api/networks"
|
21
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
22
|
+
opts = {method: :get, url: url, headers: headers}
|
23
|
+
execute(opts)
|
24
|
+
end
|
25
|
+
|
26
|
+
def create(payload)
|
27
|
+
url = "#{@base_url}/api/networks"
|
28
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
29
|
+
opts = {method: :post, url: url, headers: headers, payload: payload.to_json}
|
30
|
+
execute(opts)
|
31
|
+
end
|
32
|
+
|
33
|
+
def update(id, payload)
|
34
|
+
url = "#{@base_url}/api/networks/#{id}"
|
35
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
36
|
+
opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
|
37
|
+
execute(opts)
|
38
|
+
end
|
39
|
+
|
40
|
+
def destroy(id, params={})
|
41
|
+
url = "#{@base_url}/api/networks/#{id}"
|
42
|
+
headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
43
|
+
opts = {method: :delete, url: url, timeout: 30, headers: headers}
|
44
|
+
execute(opts)
|
45
|
+
end
|
46
|
+
|
47
|
+
def generate_pool(id, payload={})
|
48
|
+
url = "#{@base_url}/api/networks/#{id}/generate-pool"
|
49
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
50
|
+
opts = {method: :post, url: url, headers: headers, payload: payload.to_json}
|
51
|
+
execute(opts)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'morpheus/api/api_client'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
class Morpheus::PoliciesInterface < Morpheus::APIClient
|
5
|
+
def initialize(access_token, refresh_token,expires_at = nil, base_url=nil)
|
6
|
+
@access_token = access_token
|
7
|
+
@refresh_token = refresh_token
|
8
|
+
@base_url = base_url
|
9
|
+
@expires_at = expires_at
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(id, params={})
|
13
|
+
raise "#{self.class}.get() passed a blank id!" if id.to_s == ''
|
14
|
+
url = "#{@base_url}/api/policies/#{id}"
|
15
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
16
|
+
opts = {method: :get, url: url, headers: headers}
|
17
|
+
execute(opts)
|
18
|
+
end
|
19
|
+
|
20
|
+
def list(params={})
|
21
|
+
url = "#{@base_url}/api/policies"
|
22
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
23
|
+
opts = {method: :get, url: url, headers: headers}
|
24
|
+
execute(opts)
|
25
|
+
end
|
26
|
+
|
27
|
+
def create(payload)
|
28
|
+
url = "#{@base_url}/api/policies"
|
29
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
30
|
+
opts = {method: :post, url: url, headers: headers, payload: payload.to_json}
|
31
|
+
execute(opts)
|
32
|
+
end
|
33
|
+
|
34
|
+
def update(id, payload)
|
35
|
+
url = "#{@base_url}/api/policies/#{id}"
|
36
|
+
headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
37
|
+
opts = {method: :put, url: url, headers: headers, payload: payload.to_json}
|
38
|
+
execute(opts)
|
39
|
+
end
|
40
|
+
|
41
|
+
def destroy(id, params={})
|
42
|
+
url = "#{@base_url}/api/policies/#{id}"
|
43
|
+
headers = { :params => params, :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
|
44
|
+
opts = {method: :delete, url: url, timeout: 30, headers: headers}
|
45
|
+
execute(opts)
|
46
|
+
end
|
47
|
+
|
48
|
+
def list_policy_types(params={})
|
49
|
+
url = "#{@base_url}/api/policy-types"
|
50
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
51
|
+
opts = {method: :get, url: url, headers: headers}
|
52
|
+
execute(opts)
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_policy_type(id, params={})
|
56
|
+
raise "#{self.class}.get_policy_type() passed a blank id!" if id.to_s == ''
|
57
|
+
url = "#{@base_url}/api/policy-types/#{URI.escape(id.to_s)}"
|
58
|
+
headers = { params: params, authorization: "Bearer #{@access_token}" }
|
59
|
+
opts = {method: :get, url: url, headers: headers}
|
60
|
+
execute(opts)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
data/lib/morpheus/cli.rb
CHANGED
@@ -94,13 +94,17 @@ module Morpheus
|
|
94
94
|
load 'morpheus/cli/monitoring_contacts_command.rb'
|
95
95
|
load 'morpheus/cli/monitoring_groups_command.rb'
|
96
96
|
load 'morpheus/cli/monitoring_apps_command.rb'
|
97
|
-
|
98
|
-
|
97
|
+
load 'morpheus/cli/policies_command.rb'
|
98
|
+
load 'morpheus/cli/networks_command.rb'
|
99
|
+
load 'morpheus/cli/network_groups_command.rb'
|
100
|
+
load 'morpheus/cli/network_pools_command.rb'
|
101
|
+
load 'morpheus/cli/network_services_command.rb'
|
102
|
+
load 'morpheus/cli/network_pool_servers_command.rb'
|
103
|
+
load 'morpheus/cli/network_domains_command.rb'
|
104
|
+
load 'morpheus/cli/network_proxies_command.rb'
|
99
105
|
load 'morpheus/cli/image_builder_command.rb'
|
100
|
-
# load 'morpheus/cli/image_builds_command.rb'
|
101
106
|
load 'morpheus/cli/preseed_scripts_command.rb'
|
102
107
|
load 'morpheus/cli/boot_scripts_command.rb'
|
103
|
-
|
104
108
|
load 'morpheus/cli/archives_command.rb'
|
105
109
|
|
106
110
|
# nice to have commands
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'json'
|
1
3
|
require 'morpheus/logging'
|
2
4
|
require 'morpheus/cli/option_parser'
|
3
5
|
require 'morpheus/cli/cli_registry'
|
@@ -194,7 +196,7 @@ module Morpheus
|
|
194
196
|
|
195
197
|
when :options
|
196
198
|
options[:options] ||= {}
|
197
|
-
opts.on( '-O', '--option OPTION', "Option in the format
|
199
|
+
opts.on( '-O', '--option OPTION', "Option in the format -O field=\"value\"" ) do |option|
|
198
200
|
# todo: look ahead and parse ALL the option=value args after -O switch
|
199
201
|
#custom_option_args = option.split('=')
|
200
202
|
custom_option_args = option.sub(/\s?\=\s?/, '__OPTION_DELIM__').split('__OPTION_DELIM__')
|
@@ -230,6 +232,39 @@ module Morpheus
|
|
230
232
|
options[:options][:no_prompt] = true
|
231
233
|
end
|
232
234
|
|
235
|
+
when :payload
|
236
|
+
opts.on('--payload JSON', String, "Payload JSON, skip all prompting") do |val|
|
237
|
+
begin
|
238
|
+
options[:payload] = JSON.parse(val.to_s)
|
239
|
+
rescue => ex
|
240
|
+
raise ::OptionParser::InvalidOption.new("Failed to parse payload as JSON. Error: #{ex.message}")
|
241
|
+
end
|
242
|
+
end
|
243
|
+
opts.on('--payload-yaml YAML', String, "Payload YAML, skip all prompting") do |val|
|
244
|
+
begin
|
245
|
+
options[:payload] = YAML.load(val.to_s)
|
246
|
+
rescue => ex
|
247
|
+
raise ::OptionParser::InvalidOption.new("Failed to parse payload as YAML. Error: #{ex.message}")
|
248
|
+
end
|
249
|
+
end
|
250
|
+
opts.on('--payload-file FILE', String, "Payload from a local JSON or YAML file, skip all prompting") do |val|
|
251
|
+
options[:payload_file] = val.to_s
|
252
|
+
begin
|
253
|
+
payload_file = File.expand_path(options[:payload_file])
|
254
|
+
if !File.exists?(payload_file) || !File.file?(payload_file)
|
255
|
+
raise ::OptionParser::InvalidOption.new("File not found: #{payload_file}")
|
256
|
+
#return false
|
257
|
+
end
|
258
|
+
if payload_file =~ /\.ya?ml\Z/
|
259
|
+
options[:payload] = YAML.load_file(payload_file)
|
260
|
+
else
|
261
|
+
options[:payload] = JSON.parse(File.read(payload_file))
|
262
|
+
end
|
263
|
+
rescue => ex
|
264
|
+
raise ::OptionParser::InvalidOption.new("Failed to parse payload file: #{payload_file} Error: #{ex.message}")
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
233
268
|
when :list
|
234
269
|
opts.on( '-m', '--max MAX', "Max Results" ) do |max|
|
235
270
|
options[:max] = max.to_i
|
@@ -215,16 +215,7 @@ class Morpheus::Cli::Instances
|
|
215
215
|
opts.on("--create-backup on|off", String, "Automation: Create Backups. Default is off") do |val|
|
216
216
|
options[:create_backup] = ['on','true','1'].include?(val.to_s.downcase) ? 'on' : 'off'
|
217
217
|
end
|
218
|
-
opts
|
219
|
-
options['config'] = JSON.parse(val.to_s)
|
220
|
-
end
|
221
|
-
opts.on('--config-yaml YAML', String, "Instance Config YAML. This skips prompting and the above options are ignored.") do |val|
|
222
|
-
options['config'] = YAML.load(val.to_s)
|
223
|
-
end
|
224
|
-
opts.on('--config-file FILE', String, "Instance Config from a local JSON or YAML file. This skips prompting and the above options are ignored.") do |val|
|
225
|
-
options['configFile'] = val.to_s
|
226
|
-
end
|
227
|
-
build_common_options(opts, options, [:options, :json, :dry_run, :remote, :quiet])
|
218
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote, :quiet])
|
228
219
|
end
|
229
220
|
|
230
221
|
optparse.parse!(args)
|
@@ -245,21 +236,8 @@ class Morpheus::Cli::Instances
|
|
245
236
|
options[:name_required] = true
|
246
237
|
begin
|
247
238
|
payload = nil
|
248
|
-
if options[
|
249
|
-
payload = options[
|
250
|
-
elsif options['configFile']
|
251
|
-
config_file = File.expand_path(options['configFile'])
|
252
|
-
if !File.exists?(config_file) || !File.file?(config_file)
|
253
|
-
print_red_alert "File not found: #{config_file}"
|
254
|
-
return false
|
255
|
-
end
|
256
|
-
config_payload = {}
|
257
|
-
if config_file =~ /\.ya?ml\Z/
|
258
|
-
config_payload = YAML.load_file(config_file)
|
259
|
-
else
|
260
|
-
config_payload = JSON.parse(File.read(config_file))
|
261
|
-
end
|
262
|
-
payload = config_payload
|
239
|
+
if options[:payload]
|
240
|
+
payload = options[:payload]
|
263
241
|
else
|
264
242
|
# prompt for all the instance configuration options
|
265
243
|
# this provisioning helper method handles all (most) of the parsing and prompting
|
@@ -0,0 +1,571 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
require 'optparse'
|
3
|
+
require 'filesize'
|
4
|
+
require 'table_print'
|
5
|
+
require 'morpheus/cli/cli_command'
|
6
|
+
require 'morpheus/cli/mixins/infrastructure_helper'
|
7
|
+
|
8
|
+
class Morpheus::Cli::NetworkDomainsCommand
|
9
|
+
include Morpheus::Cli::CliCommand
|
10
|
+
include Morpheus::Cli::InfrastructureHelper
|
11
|
+
|
12
|
+
set_command_name :'network-domains'
|
13
|
+
|
14
|
+
register_subcommands :list, :get, :add, :update, :remove
|
15
|
+
|
16
|
+
# set_default_subcommand :list
|
17
|
+
|
18
|
+
def initialize()
|
19
|
+
# @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
20
|
+
end
|
21
|
+
|
22
|
+
def connect(opts)
|
23
|
+
@api_client = establish_remote_appliance_connection(opts)
|
24
|
+
@network_domains_interface = @api_client.network_domains
|
25
|
+
@clouds_interface = @api_client.clouds
|
26
|
+
@options_interface = @api_client.options
|
27
|
+
end
|
28
|
+
|
29
|
+
def handle(args)
|
30
|
+
handle_subcommand(args)
|
31
|
+
end
|
32
|
+
|
33
|
+
def list(args)
|
34
|
+
options = {}
|
35
|
+
params = {}
|
36
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
37
|
+
opts.banner = subcommand_usage()
|
38
|
+
build_common_options(opts, options, [:list, :json, :yaml, :csv, :fields, :json, :dry_run, :remote])
|
39
|
+
opts.footer = "List network domains."
|
40
|
+
end
|
41
|
+
optparse.parse!(args)
|
42
|
+
connect(options)
|
43
|
+
begin
|
44
|
+
[:phrase, :offset, :max, :sort, :direction].each do |k|
|
45
|
+
params[k] = options[k] unless options[k].nil?
|
46
|
+
end
|
47
|
+
if options[:dry_run]
|
48
|
+
print_dry_run @network_domains_interface.dry.list(params)
|
49
|
+
return
|
50
|
+
end
|
51
|
+
json_response = @network_domains_interface.list(params)
|
52
|
+
network_domains = json_response["networkDomains"]
|
53
|
+
if options[:include_fields]
|
54
|
+
json_response = {"networkDomains" => filter_data(network_domains, options[:include_fields]) }
|
55
|
+
end
|
56
|
+
if options[:json]
|
57
|
+
puts as_json(json_response, options)
|
58
|
+
return 0
|
59
|
+
elsif options[:yaml]
|
60
|
+
puts as_yaml(json_response, options)
|
61
|
+
return 0
|
62
|
+
elsif options[:csv]
|
63
|
+
puts records_as_csv(network_domains, options)
|
64
|
+
return 0
|
65
|
+
end
|
66
|
+
title = "Morpheus Network Domains"
|
67
|
+
subtitles = []
|
68
|
+
if params[:phrase]
|
69
|
+
subtitles << "Search: #{params[:phrase]}".strip
|
70
|
+
end
|
71
|
+
print_h1 title, subtitles
|
72
|
+
if network_domains.empty?
|
73
|
+
print cyan,"No network domains found.",reset,"\n"
|
74
|
+
else
|
75
|
+
rows = network_domains.collect {|network_domain|
|
76
|
+
row = {
|
77
|
+
id: network_domain['id'],
|
78
|
+
name: network_domain['name'],
|
79
|
+
description: network_domain['description'],
|
80
|
+
source: network_domain['refType'] ? "#{network_domain['refType']} #{network_domain['id']}" : '', # showReferenceName(refType, refId)
|
81
|
+
domainController: network_domain['domainController'] ? 'Yes' : 'No',
|
82
|
+
visibility: network_domain['visibility'].to_s.capitalize,
|
83
|
+
tenant: network_domain['account'] ? network_domain['account']['name'] : '',
|
84
|
+
owner: network_domain['owner'] ? network_domain['owner']['name'] : '',
|
85
|
+
}
|
86
|
+
row
|
87
|
+
}
|
88
|
+
columns = [:id, :name, :description, {:domainController => {:display_name => "DOMAIN CONTROLLER"} }, :visibility, :tenant]
|
89
|
+
if options[:include_fields]
|
90
|
+
columns = options[:include_fields]
|
91
|
+
rows = network_domains
|
92
|
+
end
|
93
|
+
print cyan
|
94
|
+
print as_pretty_table(rows, columns, options)
|
95
|
+
print reset
|
96
|
+
print_results_pagination(json_response, {:label => "network domain", :n_label => "network domains"})
|
97
|
+
end
|
98
|
+
print reset,"\n"
|
99
|
+
return 0
|
100
|
+
rescue RestClient::Exception => e
|
101
|
+
print_rest_exception(e, options)
|
102
|
+
exit 1
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def get(args)
|
107
|
+
options = {}
|
108
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
109
|
+
opts.banner = subcommand_usage("[network-domain]")
|
110
|
+
build_common_options(opts, options, [:json, :yaml, :csv, :fields, :dry_run, :remote])
|
111
|
+
opts.footer = "Get details about a network domain." + "\n" +
|
112
|
+
"[network-domain] is required. This is the name or id of a network domain."
|
113
|
+
end
|
114
|
+
optparse.parse!(args)
|
115
|
+
if args.count != 1
|
116
|
+
print_error Morpheus::Terminal.angry_prompt
|
117
|
+
puts_error "#{command_name} missing argument: [network-domain]\n#{optparse}"
|
118
|
+
return 1
|
119
|
+
end
|
120
|
+
connect(options)
|
121
|
+
begin
|
122
|
+
if options[:dry_run]
|
123
|
+
if args[0].to_s =~ /\A\d{1,}\Z/
|
124
|
+
print_dry_run @network_domains_interface.dry.get(args[0].to_i)
|
125
|
+
else
|
126
|
+
print_dry_run @network_domains_interface.dry.list({name:args[0]})
|
127
|
+
end
|
128
|
+
return
|
129
|
+
end
|
130
|
+
network_domain = find_network_domain_by_name_or_id(args[0])
|
131
|
+
return 1 if network_domain.nil?
|
132
|
+
json_response = {'networkDomain' => network_domain} # skip redundant request
|
133
|
+
# json_response = @network_domains_interface.get(network_domain['id'])
|
134
|
+
network_domain = json_response['networkDomain']
|
135
|
+
if options[:include_fields]
|
136
|
+
json_response = {'networkDomain' => filter_data(network_domain, options[:include_fields]) }
|
137
|
+
end
|
138
|
+
if options[:json]
|
139
|
+
puts as_json(json_response, options)
|
140
|
+
return 0
|
141
|
+
elsif options[:yaml]
|
142
|
+
puts as_yaml(json_response, options)
|
143
|
+
return 0
|
144
|
+
elsif options[:csv]
|
145
|
+
puts records_as_csv([network_domain], options)
|
146
|
+
return 0
|
147
|
+
end
|
148
|
+
print_h1 "Network Domain Details"
|
149
|
+
print cyan
|
150
|
+
description_cols = {
|
151
|
+
"ID" => 'id',
|
152
|
+
"Name" => lambda {|it| it['name'] },
|
153
|
+
"Description" => lambda {|it| it['description'] },
|
154
|
+
# "Source" => lambda {|it| it['refSource'] }, showReferenceName(refType, refId)
|
155
|
+
"Domain Controller" => lambda {|it| it['domainController'] ? 'Yes' : 'No' },
|
156
|
+
"Public Zone" => lambda {|it| it['publicZone'] ? 'Yes' : 'No' },
|
157
|
+
"Domain Username" => lambda {|it| it['domainUsername'] },
|
158
|
+
"Domain Password" => lambda {|it| it['domainPassword'] },
|
159
|
+
"DC Server" => lambda {|it| it['dcServer'] },
|
160
|
+
"OU Path" => lambda {|it| it['ouPath'] },
|
161
|
+
"Visibility" => lambda {|it| it['visibility'].to_s.capitalize },
|
162
|
+
"Tenant" => lambda {|it| it['account'] ? it['account']['name'] : '' },
|
163
|
+
}
|
164
|
+
print_description_list(description_cols, network_domain)
|
165
|
+
|
166
|
+
# print_h2 "Domain Records"
|
167
|
+
# print cyan
|
168
|
+
# if network_domain['records']
|
169
|
+
# network_domain['records'].each do |r|
|
170
|
+
# puts " * #{r['name']}\t#{r['fqdn']}\t#{r['type']}\t#{r['ttl']}"
|
171
|
+
# end
|
172
|
+
# end
|
173
|
+
print reset,"\n"
|
174
|
+
return 0
|
175
|
+
rescue RestClient::Exception => e
|
176
|
+
print_rest_exception(e, options)
|
177
|
+
return 1
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def add(args)
|
182
|
+
options = {}
|
183
|
+
ip_range_list = nil
|
184
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
185
|
+
opts.banner = subcommand_usage()
|
186
|
+
opts.on('--name VALUE', String, "Name for this network domain") do |val|
|
187
|
+
options['name'] = val
|
188
|
+
end
|
189
|
+
opts.on('--description VALUE', String, "Description for this network domain") do |val|
|
190
|
+
options['type'] = val
|
191
|
+
end
|
192
|
+
opts.on('--public-zone [on|off]', String, "Public Zone") do |val|
|
193
|
+
options['publicZone'] = val.to_s == 'on' || val.to_s == 'true'
|
194
|
+
end
|
195
|
+
opts.on('--domain-controller [on|off]', String, "Join Domain Controller") do |val|
|
196
|
+
options['domainController'] = val.to_s == 'on' || val.to_s == 'true'
|
197
|
+
end
|
198
|
+
opts.on('--domain-username VALUE', String, "Domain Username") do |val|
|
199
|
+
options['domainUsername'] = val
|
200
|
+
end
|
201
|
+
opts.on('--domain-password VALUE', String, "Domain Password") do |val|
|
202
|
+
options['domainPassword'] = val
|
203
|
+
end
|
204
|
+
opts.on('--dc-server VALUE', String, "DC Server") do |val|
|
205
|
+
options['dcServer'] = val
|
206
|
+
end
|
207
|
+
opts.on('--ou-path VALUE', String, "OU Path") do |val|
|
208
|
+
options['ouPath'] = val
|
209
|
+
end
|
210
|
+
opts.on('--visibility [private|public]', String, "Visibility") do |val|
|
211
|
+
options['visibility'] = val
|
212
|
+
end
|
213
|
+
opts.on('--tenant ID', String, "Tenant Account ID") do |val|
|
214
|
+
options['tenant'] = val
|
215
|
+
end
|
216
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :quiet, :remote])
|
217
|
+
opts.footer = "Create a new network domain." + "\n" +
|
218
|
+
"[name] is required and can be passed as --name instead."
|
219
|
+
end
|
220
|
+
optparse.parse!(args)
|
221
|
+
if args.count > 1
|
222
|
+
print_error Morpheus::Terminal.angry_prompt
|
223
|
+
puts_error "wrong number of arguments, expected 0-1 and got #{args.count}\n#{optparse}"
|
224
|
+
return 1
|
225
|
+
end
|
226
|
+
connect(options)
|
227
|
+
begin
|
228
|
+
# merge -O options into normally parsed options
|
229
|
+
options.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
230
|
+
|
231
|
+
# support [name] as first argument
|
232
|
+
if args[0]
|
233
|
+
options['name'] = args[0]
|
234
|
+
end
|
235
|
+
|
236
|
+
# construct payload
|
237
|
+
payload = nil
|
238
|
+
if options[:payload]
|
239
|
+
payload = options[:payload]
|
240
|
+
else
|
241
|
+
# prompt for network options
|
242
|
+
payload = {
|
243
|
+
'networkDomain' => {
|
244
|
+
# 'config' => {}
|
245
|
+
}
|
246
|
+
}
|
247
|
+
|
248
|
+
# allow arbitrary -O options
|
249
|
+
payload['networkDomain'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
250
|
+
|
251
|
+
# Name
|
252
|
+
if options['name']
|
253
|
+
payload['networkDomain']['name'] = options['name']
|
254
|
+
else
|
255
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Name for this network domain.'}], options)
|
256
|
+
payload['networkDomain']['name'] = v_prompt['name']
|
257
|
+
end
|
258
|
+
|
259
|
+
# Description
|
260
|
+
if options['description']
|
261
|
+
payload['networkDomain']['description'] = options['description']
|
262
|
+
else
|
263
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'description', 'fieldLabel' => 'Description', 'type' => 'text', 'required' => false, 'description' => 'Description for this network domain.'}], options)
|
264
|
+
payload['networkDomain']['description'] = v_prompt['description']
|
265
|
+
end
|
266
|
+
|
267
|
+
# Public Zone
|
268
|
+
if options['publicZone'] != nil
|
269
|
+
payload['networkDomain']['publicZone'] = options['publicZone']
|
270
|
+
else
|
271
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'publicZone', 'fieldLabel' => 'Public Zone', 'type' => 'checkbox', 'required' => false, 'description' => ''}], options)
|
272
|
+
payload['networkDomain']['publicZone'] = (v_prompt['publicZone'].to_s == 'on') unless v_prompt['publicZone'].nil?
|
273
|
+
end
|
274
|
+
|
275
|
+
# Domain Controller
|
276
|
+
join_domain_controller = false
|
277
|
+
if options['domainController'] != nil
|
278
|
+
payload['networkDomain']['domainController'] = options['domainController']
|
279
|
+
else
|
280
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'domainController', 'fieldLabel' => 'Join Domain Controller', 'type' => 'checkbox', 'required' => false, 'description' => ''}], options)
|
281
|
+
payload['networkDomain']['domainController'] = (v_prompt['domainController'].to_s == 'on') unless v_prompt['domainController'].nil?
|
282
|
+
end
|
283
|
+
join_domain_controller = !!payload['networkDomain']['domainController']
|
284
|
+
|
285
|
+
# Domain Username
|
286
|
+
if options['domainUsername'] != nil
|
287
|
+
payload['networkDomain']['domainUsername'] = options['domainUsername']
|
288
|
+
elsif join_domain_controller
|
289
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'domainUsername', 'fieldLabel' => 'Domain Username', 'type' => 'text', 'required' => false, 'description' => ''}], options)
|
290
|
+
payload['networkDomain']['domainUsername'] = v_prompt['domainUsername'] unless v_prompt['domainUsername'].nil?
|
291
|
+
end
|
292
|
+
|
293
|
+
# Domain Password
|
294
|
+
if options['domainPassword'] != nil
|
295
|
+
payload['networkDomain']['domainPassword'] = options['domainPassword']
|
296
|
+
elsif join_domain_controller
|
297
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'domainPassword', 'fieldLabel' => 'Domain Password', 'type' => 'password', 'required' => false, 'description' => ''}], options)
|
298
|
+
payload['networkDomain']['domainPassword'] = v_prompt['domainPassword'] unless v_prompt['domainPassword'].nil?
|
299
|
+
end
|
300
|
+
|
301
|
+
# DC Server
|
302
|
+
if options['dcServer'] != nil
|
303
|
+
payload['networkDomain']['dcServer'] = options['dcServer']
|
304
|
+
elsif join_domain_controller
|
305
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'dcServer', 'fieldLabel' => 'DC Server', 'type' => 'text', 'required' => false, 'description' => ''}], options)
|
306
|
+
payload['networkDomain']['dcServer'] = v_prompt['dcServer'] unless v_prompt['dcServer'].nil?
|
307
|
+
end
|
308
|
+
|
309
|
+
# OU Path
|
310
|
+
if options['ouPath'] != nil
|
311
|
+
payload['networkDomain']['ouPath'] = options['ouPath']
|
312
|
+
elsif join_domain_controller
|
313
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'ouPath', 'fieldLabel' => 'OU Path', 'type' => 'text', 'required' => false, 'description' => ''}], options)
|
314
|
+
payload['networkDomain']['ouPath'] = v_prompt['ouPath'] unless v_prompt['ouPath'].nil?
|
315
|
+
end
|
316
|
+
|
317
|
+
# Visibility
|
318
|
+
if options['visibility']
|
319
|
+
payload['networkDomain']['visibility'] = options['visibility'].to_s.downcase
|
320
|
+
else
|
321
|
+
v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'visibility', 'fieldLabel' => 'Visibility', 'type' => 'select', 'selectOptions' => [{'name' => 'Private', 'value' => 'private'},{'name' => 'Public', 'value' => 'public'}], 'required' => false, 'description' => 'Visibility', 'defaultValue' => 'private'}], options)
|
322
|
+
payload['networkDomain']['visibility'] = v_prompt['visibility'].to_s.downcase
|
323
|
+
end
|
324
|
+
|
325
|
+
# Tenant
|
326
|
+
if options['tenant']
|
327
|
+
payload['networkDomain']['account'] = {'id' => options['tenant'].to_i}
|
328
|
+
else
|
329
|
+
begin
|
330
|
+
available_accounts = @api_client.accounts.list({max:10000})['accounts'].collect {|it| {'name' => it['name'], 'value' => it['id'], 'id' => it['id']}}
|
331
|
+
account_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'tenant', 'fieldLabel' => 'Tenant', 'type' => 'select', 'selectOptions' => available_accounts, 'required' => false, 'description' => 'Tenant'}], options)
|
332
|
+
if account_prompt['tenant']
|
333
|
+
payload['networkDomain']['account'] = {'id' => account_prompt['tenant']}
|
334
|
+
end
|
335
|
+
rescue
|
336
|
+
puts "failed to load list of available tenants: #{ex.message}"
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
end
|
341
|
+
|
342
|
+
|
343
|
+
if options[:dry_run]
|
344
|
+
print_dry_run @network_domains_interface.dry.create(payload)
|
345
|
+
return
|
346
|
+
end
|
347
|
+
json_response = @network_domains_interface.create(payload)
|
348
|
+
if options[:json]
|
349
|
+
print JSON.pretty_generate(json_response)
|
350
|
+
print "\n"
|
351
|
+
elsif !options[:quiet]
|
352
|
+
network_domain = json_response['networkDomain']
|
353
|
+
print_green_success "Added network domain #{network_domain['name']}"
|
354
|
+
get([network_domain['id']])
|
355
|
+
end
|
356
|
+
return 0
|
357
|
+
rescue RestClient::Exception => e
|
358
|
+
print_rest_exception(e, options)
|
359
|
+
exit 1
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
def update(args)
|
364
|
+
options = {}
|
365
|
+
ip_range_list = nil
|
366
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
367
|
+
opts.banner = subcommand_usage("[network-domain] [options]")
|
368
|
+
opts.on('--name VALUE', String, "Name for this network domain") do |val|
|
369
|
+
options['name'] = val
|
370
|
+
end
|
371
|
+
opts.on('--type VALUE', String, "Type of network domain") do |val|
|
372
|
+
options['description'] = val
|
373
|
+
end
|
374
|
+
opts.on('--ip-ranges LIST', Array, "IP Ranges, comma separated list IP ranges in the format start-end.") do |list|
|
375
|
+
if list.size == 1 && list[0] == 'null' # hacky way to clear it
|
376
|
+
ip_range_list = []
|
377
|
+
else
|
378
|
+
ip_range_list = list.collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq
|
379
|
+
ip_range_list = ip_range_list.collect {|it|
|
380
|
+
range_parts = it.split("-")
|
381
|
+
{startAddress: range_parts[0].to_s.strip, endAddress: range_parts[1].to_s.strip}
|
382
|
+
}
|
383
|
+
end
|
384
|
+
end
|
385
|
+
build_common_options(opts, options, [:options, :payload, :json, :dry_run, :remote])
|
386
|
+
opts.footer = "Update a network domain." + "\n" +
|
387
|
+
"[network-domain] is required. This is the id of a network domain."
|
388
|
+
end
|
389
|
+
optparse.parse!(args)
|
390
|
+
if args.count != 1
|
391
|
+
print_error Morpheus::Terminal.angry_prompt
|
392
|
+
puts_error "wrong number of arguments, expected 1 and got #{args.count}\n#{optparse}"
|
393
|
+
return 1
|
394
|
+
end
|
395
|
+
connect(options)
|
396
|
+
|
397
|
+
begin
|
398
|
+
network_domain = find_network_domain_by_name_or_id(args[0])
|
399
|
+
return 1 if network_domain.nil?
|
400
|
+
|
401
|
+
# merge -O options into normally parsed options
|
402
|
+
options.deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
403
|
+
|
404
|
+
# construct payload
|
405
|
+
payload = nil
|
406
|
+
if options[:payload]
|
407
|
+
payload = options[:payload]
|
408
|
+
else
|
409
|
+
# prompt for network options
|
410
|
+
payload = {
|
411
|
+
'networkDomain' => {
|
412
|
+
}
|
413
|
+
}
|
414
|
+
|
415
|
+
# allow arbitrary -O options
|
416
|
+
payload['networkDomain'].deep_merge!(options[:options].reject {|k,v| k.is_a?(Symbol) }) if options[:options]
|
417
|
+
|
418
|
+
# Name
|
419
|
+
if options['name']
|
420
|
+
payload['networkDomain']['name'] = options['name']
|
421
|
+
else
|
422
|
+
# v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'description' => 'Name for this network domain.'}], options)
|
423
|
+
# payload['networkDomain']['name'] = v_prompt['name']
|
424
|
+
end
|
425
|
+
|
426
|
+
# Network Domain Type
|
427
|
+
# network_type_id = nil
|
428
|
+
# v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'type', 'fieldLabel' => 'Domain Type', 'type' => 'select', 'optionSource' => 'networkDomainTypes', 'required' => true, 'description' => 'Choose a network domain type.'}], options, @api_client, {})
|
429
|
+
# network_type_id = v_prompt['type']
|
430
|
+
# if network_type_id.nil? || network_type_id.to_s.empty?
|
431
|
+
# print_red_alert "Domain Type not found by id '#{options['type']}'"
|
432
|
+
# return 1
|
433
|
+
# end
|
434
|
+
# payload['networkDomain']['type'] = {'id' => network_type_id.to_i }
|
435
|
+
if options['type']
|
436
|
+
payload['networkDomain']['type'] = {'id' => options['type'].to_i }
|
437
|
+
end
|
438
|
+
|
439
|
+
# IP Ranges
|
440
|
+
if ip_range_list
|
441
|
+
ip_range_list = ip_range_list.collect {|range|
|
442
|
+
# ugh, need to allow changing an existing range by id too
|
443
|
+
if network_domain['ipRanges']
|
444
|
+
existing_range = network_domain['ipRanges'].find {|r|
|
445
|
+
range[:startAddress] == r['startAddress'] && range[:endAddress] == r['endAddress']
|
446
|
+
}
|
447
|
+
if existing_range
|
448
|
+
range[:id] = existing_range['id']
|
449
|
+
end
|
450
|
+
end
|
451
|
+
range
|
452
|
+
}
|
453
|
+
payload['networkDomain']['ipRanges'] = ip_range_list
|
454
|
+
else
|
455
|
+
# v_prompt = Morpheus::Cli::OptionTypes.prompt([{'fieldName' => 'ipRanges', 'fieldLabel' => 'IP Ranges', 'type' => 'text', 'required' => true, 'description' => 'IP Ranges in the domain, comma separated list of ranges in the format start-end.'}], options)
|
456
|
+
# payload['networkDomain']['ipRanges'] = v_prompt['ipRanges'].to_s.split(",").collect {|it| it.to_s.strip.empty? ? nil : it.to_s.strip }.compact.uniq.collect {|it|
|
457
|
+
# it
|
458
|
+
# }
|
459
|
+
end
|
460
|
+
|
461
|
+
end
|
462
|
+
|
463
|
+
if options[:dry_run]
|
464
|
+
print_dry_run @network_domains_interface.dry.update(network_domain["id"], payload)
|
465
|
+
return
|
466
|
+
end
|
467
|
+
json_response = @network_domains_interface.update(network_domain["id"], payload)
|
468
|
+
if options[:json]
|
469
|
+
puts as_json(json_response)
|
470
|
+
else
|
471
|
+
network_domain = json_response['networkDomain']
|
472
|
+
print_green_success "Updated network domain #{network_domain['name']}"
|
473
|
+
get([network_domain['id']])
|
474
|
+
end
|
475
|
+
return 0
|
476
|
+
rescue RestClient::Exception => e
|
477
|
+
print_rest_exception(e, options)
|
478
|
+
return 1
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
def remove(args)
|
483
|
+
options = {}
|
484
|
+
optparse = Morpheus::Cli::OptionParser.new do |opts|
|
485
|
+
opts.banner = subcommand_usage("[network-domain]")
|
486
|
+
build_common_options(opts, options, [:account, :auto_confirm, :json, :dry_run, :remote])
|
487
|
+
opts.footer = "Delete a network domain." + "\n" +
|
488
|
+
"[network-domain] is required. This is the name or id of a network domain."
|
489
|
+
end
|
490
|
+
optparse.parse!(args)
|
491
|
+
|
492
|
+
if args.count < 1
|
493
|
+
print_error Morpheus::Terminal.angry_prompt
|
494
|
+
puts_error "#{command_name} missing argument: [network-domain]\n#{optparse}"
|
495
|
+
return 1
|
496
|
+
end
|
497
|
+
|
498
|
+
connect(options)
|
499
|
+
begin
|
500
|
+
network_domain = find_network_domain_by_name_or_id(args[0])
|
501
|
+
return 1 if network_domain.nil?
|
502
|
+
|
503
|
+
unless options[:yes] || Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the network domain: #{network_domain['name']}?")
|
504
|
+
return 9, "aborted command"
|
505
|
+
end
|
506
|
+
if options[:dry_run]
|
507
|
+
print_dry_run @network_domains_interface.dry.destroy(network_domain['id'])
|
508
|
+
return 0
|
509
|
+
end
|
510
|
+
json_response = @network_domains_interface.destroy(network_domain['id'])
|
511
|
+
if options[:json]
|
512
|
+
print JSON.pretty_generate(json_response)
|
513
|
+
print "\n"
|
514
|
+
else
|
515
|
+
print_green_success "Removed network domain #{network_domain['name']}"
|
516
|
+
# list([])
|
517
|
+
end
|
518
|
+
return 0
|
519
|
+
rescue RestClient::Exception => e
|
520
|
+
print_rest_exception(e, options)
|
521
|
+
return 1
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
private
|
526
|
+
|
527
|
+
|
528
|
+
def find_network_domain_by_name_or_id(val)
|
529
|
+
if val.to_s =~ /\A\d{1,}\Z/
|
530
|
+
return find_network_domain_by_id(val)
|
531
|
+
else
|
532
|
+
return find_network_domain_by_name(val)
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
def find_network_domain_by_id(id)
|
537
|
+
begin
|
538
|
+
json_response = @network_domains_interface.get(id.to_i)
|
539
|
+
return json_response['networkDomain']
|
540
|
+
rescue RestClient::Exception => e
|
541
|
+
if e.response && e.response.code == 404
|
542
|
+
print_red_alert "Network Domain not found by id #{id}"
|
543
|
+
return nil
|
544
|
+
else
|
545
|
+
raise e
|
546
|
+
end
|
547
|
+
end
|
548
|
+
end
|
549
|
+
|
550
|
+
def find_network_domain_by_name(name)
|
551
|
+
json_response = @network_domains_interface.list({name: name.to_s})
|
552
|
+
network_domains = json_response['networkDomains']
|
553
|
+
if network_domains.empty?
|
554
|
+
print_red_alert "Network Domain not found by name #{name}"
|
555
|
+
return nil
|
556
|
+
elsif network_domains.size > 1
|
557
|
+
print_red_alert "#{network_domains.size} network domains found by name #{name}"
|
558
|
+
# print_networks_table(networks, {color: red})
|
559
|
+
rows = network_domains.collect do |network_domain|
|
560
|
+
{id: it['id'], name: it['name']}
|
561
|
+
end
|
562
|
+
print red
|
563
|
+
tp rows, [:id, :name]
|
564
|
+
print reset,"\n"
|
565
|
+
return nil
|
566
|
+
else
|
567
|
+
return network_domains[0]
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
end
|