morpheus-cli 3.1.1 → 3.1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- # maybe scope all of these to image-builder or something
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 var=\"value\"" ) do |option|
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.on('--config JSON', String, "Instance Config JSON. This skips prompting and the above options are ignored.") do |val|
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['config']
249
- payload = options['config']
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