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.
@@ -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