morpheus-cli 0.1.1 → 0.9.0
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/accounts_interface.rb +55 -0
- data/lib/morpheus/api/api_client.rb +48 -3
- data/lib/morpheus/api/apps_interface.rb +13 -13
- data/lib/morpheus/api/{zones_interface.rb → clouds_interface.rb} +10 -10
- data/lib/morpheus/api/deploy_interface.rb +4 -4
- data/lib/morpheus/api/groups_interface.rb +3 -3
- data/lib/morpheus/api/instance_types_interface.rb +2 -2
- data/lib/morpheus/api/instances_interface.rb +35 -19
- data/lib/morpheus/api/key_pairs_interface.rb +60 -0
- data/lib/morpheus/api/license_interface.rb +29 -0
- data/lib/morpheus/api/load_balancers_interface.rb +72 -0
- data/lib/morpheus/api/logs_interface.rb +37 -0
- data/lib/morpheus/api/options_interface.rb +20 -0
- data/lib/morpheus/api/provision_types_interface.rb +27 -0
- data/lib/morpheus/api/roles_interface.rb +73 -0
- data/lib/morpheus/api/security_group_rules_interface.rb +3 -3
- data/lib/morpheus/api/security_groups_interface.rb +5 -5
- data/lib/morpheus/api/servers_interface.rb +67 -3
- data/lib/morpheus/api/task_sets_interface.rb +46 -0
- data/lib/morpheus/api/tasks_interface.rb +72 -0
- data/lib/morpheus/api/users_interface.rb +72 -0
- data/lib/morpheus/cli.rb +27 -4
- data/lib/morpheus/cli/accounts.rb +306 -0
- data/lib/morpheus/cli/apps.rb +58 -1
- data/lib/morpheus/cli/cli_command.rb +87 -0
- data/lib/morpheus/cli/cli_registry.rb +6 -1
- data/lib/morpheus/cli/{zones.rb → clouds.rb} +99 -70
- data/lib/morpheus/cli/credentials.rb +23 -11
- data/lib/morpheus/cli/error_handler.rb +31 -11
- data/lib/morpheus/cli/groups.rb +1 -0
- data/lib/morpheus/cli/hosts.rb +567 -0
- data/lib/morpheus/cli/instances.rb +588 -292
- data/lib/morpheus/cli/key_pairs.rb +393 -0
- data/lib/morpheus/cli/license.rb +118 -0
- data/lib/morpheus/cli/load_balancers.rb +366 -0
- data/lib/morpheus/cli/mixins/accounts_helper.rb +193 -0
- data/lib/morpheus/cli/option_types.rb +260 -0
- data/lib/morpheus/cli/roles.rb +164 -0
- data/lib/morpheus/cli/security_group_rules.rb +4 -9
- data/lib/morpheus/cli/shell.rb +108 -0
- data/lib/morpheus/cli/tasks.rb +370 -0
- data/lib/morpheus/cli/users.rb +325 -0
- data/lib/morpheus/cli/version.rb +1 -1
- data/lib/morpheus/cli/workflows.rb +100 -0
- data/lib/morpheus/formatters.rb +43 -0
- data/morpheus-cli.gemspec +1 -1
- metadata +33 -10
- data/lib/morpheus/cli/servers.rb +0 -265
@@ -0,0 +1,260 @@
|
|
1
|
+
require 'term/ansicolor'
|
2
|
+
|
3
|
+
module Morpheus
|
4
|
+
module Cli
|
5
|
+
module OptionTypes
|
6
|
+
include Term::ANSIColor
|
7
|
+
|
8
|
+
|
9
|
+
def self.confirm(message,options={})
|
10
|
+
if options[:yes] == true
|
11
|
+
return true
|
12
|
+
end
|
13
|
+
value_found = false
|
14
|
+
while value_found == false do
|
15
|
+
print "#{message} (yes/no): "
|
16
|
+
input = $stdin.gets.chomp!
|
17
|
+
if input.downcase == 'yes'
|
18
|
+
return true
|
19
|
+
elsif input.downcase == 'no'
|
20
|
+
return false
|
21
|
+
else
|
22
|
+
puts "Invalid Option... Please try again."
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.prompt(option_types, options={}, api_client=nil,api_params={})
|
28
|
+
results = {}
|
29
|
+
options = options || {}
|
30
|
+
# puts "Options Prompt #{options}"
|
31
|
+
option_types.sort { |x,y| x['displayOrder'].to_i <=> y['displayOrder'].to_i }.each do |option_type|
|
32
|
+
context_map = results
|
33
|
+
value = nil
|
34
|
+
value_found=false
|
35
|
+
if option_type['fieldContext']
|
36
|
+
results[option_type['fieldContext']] ||= {}
|
37
|
+
context_map = results[option_type['fieldContext']]
|
38
|
+
if options[option_type['fieldContext']] and options[option_type['fieldContext']].key?(option_type['fieldLabel'])
|
39
|
+
value = options[option_type['fieldContext']][option_type['fieldLabel']]
|
40
|
+
value_found = true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
if value_found == false && options.key?(option_type['fieldName'])
|
45
|
+
value = options[option_type['fieldName']]
|
46
|
+
value_found = true
|
47
|
+
end
|
48
|
+
|
49
|
+
if !value_found
|
50
|
+
if option_type['type'] == 'number'
|
51
|
+
value = number_prompt(option_type)
|
52
|
+
elsif option_type['type'] == 'password'
|
53
|
+
value = password_prompt(option_type)
|
54
|
+
elsif option_type['type'] == 'checkbox'
|
55
|
+
value = checkbox_prompt(option_type)
|
56
|
+
elsif option_type['type'] == 'radio'
|
57
|
+
value = radio_prompt(option_type)
|
58
|
+
elsif option_type['type'] == 'textarea'
|
59
|
+
value = multiline_prompt(option_type)
|
60
|
+
elsif option_type['type'] == 'code-editor'
|
61
|
+
value = multiline_prompt(option_type)
|
62
|
+
elsif option_type['type'] == 'select'
|
63
|
+
value = select_prompt(option_type,api_client, api_params)
|
64
|
+
elsif option_type['type'] == 'hidden'
|
65
|
+
value = option_type['defaultValue']
|
66
|
+
input = value
|
67
|
+
else
|
68
|
+
value = generic_prompt(option_type)
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
context_map[option_type['fieldName']] = value
|
73
|
+
end
|
74
|
+
|
75
|
+
return results
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
def self.radio_prompt(option_type)
|
80
|
+
value_found = false
|
81
|
+
value = nil
|
82
|
+
options = []
|
83
|
+
if option_type['config'] and option_type['config']['radioOptions']
|
84
|
+
option_type['config']['radioOptions'].each do |radio_option|
|
85
|
+
options << {key: radio_option['key'], checked: radio_option['checked']}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
optionString = options.collect{ |b| b[:checked] ? "(#{b[:key]})" : b[:key]}.join(', ')
|
89
|
+
while !value_found do
|
90
|
+
print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }[#{optionString}]: "
|
91
|
+
input = $stdin.gets.chomp!
|
92
|
+
if input == '?'
|
93
|
+
help_prompt(option_type)
|
94
|
+
else
|
95
|
+
if input.nil? || input.empty?
|
96
|
+
selectedOption = options.find{|o| o[:checked] == true}
|
97
|
+
else
|
98
|
+
selectedOption = options.find{|o| o[:key].downcase == input.downcase}
|
99
|
+
end
|
100
|
+
|
101
|
+
if selectedOption
|
102
|
+
value = selectedOption[:key]
|
103
|
+
else
|
104
|
+
puts "Invalid Option. Please select from #{optionString}."
|
105
|
+
end
|
106
|
+
if !value.nil? || option_type['required'] != true
|
107
|
+
value_found = true
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
return value
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.number_prompt(option_type)
|
115
|
+
value_found = false
|
116
|
+
value = nil
|
117
|
+
while !value_found do
|
118
|
+
print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}: "
|
119
|
+
input = $stdin.gets.chomp!
|
120
|
+
value = input.empty? ? option_type['defaultValue'] : input.to_i
|
121
|
+
if input == '?'
|
122
|
+
help_prompt(option_type)
|
123
|
+
elsif !value.nil? || option_type['required'] != true
|
124
|
+
value_found = true
|
125
|
+
end
|
126
|
+
end
|
127
|
+
return value
|
128
|
+
end
|
129
|
+
|
130
|
+
def self.select_prompt(option_type,api_client, api_params={})
|
131
|
+
value_found = false
|
132
|
+
value = nil
|
133
|
+
if option_type['optionSource']
|
134
|
+
source_options = load_source_options(option_type['optionSource'],api_client,api_params)
|
135
|
+
end
|
136
|
+
if !source_options['data'].nil? && !source_options['data'].count == 1 && option_type['skipSingleOption'] == true
|
137
|
+
value_found = true
|
138
|
+
value = source_option['value']
|
139
|
+
end
|
140
|
+
while !value_found do
|
141
|
+
print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''} ['?' for options]: "
|
142
|
+
input = $stdin.gets.chomp!
|
143
|
+
if option_type['optionSource']
|
144
|
+
source_option = source_options.find{|b| b['name'] == input || (!b['value'].nil? && b['value'].to_s == input) || (b['value'].nil? && input.empty?)}
|
145
|
+
if source_option
|
146
|
+
value = source_option['value']
|
147
|
+
elsif !input.nil? && !input.empty?
|
148
|
+
input = '?'
|
149
|
+
end
|
150
|
+
else
|
151
|
+
value = input.empty? ? option_type['defaultValue'] : input
|
152
|
+
end
|
153
|
+
|
154
|
+
if input == '?'
|
155
|
+
help_prompt(option_type)
|
156
|
+
display_select_options(source_options)
|
157
|
+
elsif !value.nil? || option_type['required'] != true
|
158
|
+
value_found = true
|
159
|
+
end
|
160
|
+
end
|
161
|
+
return value
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.checkbox_prompt(option_type)
|
165
|
+
value_found = false
|
166
|
+
value = nil
|
167
|
+
while !value_found do
|
168
|
+
print "#{option_type['fieldLabel']} (yes/no) [#{option_type['defaultValue'] == 'on' ? 'yes' : 'no'}]: "
|
169
|
+
input = $stdin.gets.chomp!
|
170
|
+
if input.downcase == 'yes'
|
171
|
+
value = 'on'
|
172
|
+
elsif input.downcase == 'no'
|
173
|
+
value = 'off'
|
174
|
+
else
|
175
|
+
value = option_type['defaultValue']
|
176
|
+
end
|
177
|
+
if input == '?'
|
178
|
+
help_prompt(option_type)
|
179
|
+
elsif !value.nil? || option_type['required'] != true
|
180
|
+
value_found = true
|
181
|
+
end
|
182
|
+
end
|
183
|
+
return value
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.generic_prompt(option_type)
|
187
|
+
value_found = false
|
188
|
+
value = nil
|
189
|
+
while !value_found do
|
190
|
+
print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}: "
|
191
|
+
input = $stdin.gets.chomp!
|
192
|
+
value = input.empty? ? option_type['defaultValue'] : input
|
193
|
+
if input == '?'
|
194
|
+
help_prompt(option_type)
|
195
|
+
elsif !value.nil? || option_type['required'] != true
|
196
|
+
value_found = true
|
197
|
+
end
|
198
|
+
end
|
199
|
+
return value
|
200
|
+
end
|
201
|
+
|
202
|
+
def self.multiline_prompt(option_type)
|
203
|
+
value_found = false
|
204
|
+
value = nil
|
205
|
+
while !value_found do
|
206
|
+
if value.nil?
|
207
|
+
print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''} [Type 'EOF' to stop input]: \n"
|
208
|
+
end
|
209
|
+
input = $stdin.gets.chomp!
|
210
|
+
# value = input.empty? ? option_type['defaultValue'] : input
|
211
|
+
if input == '?' && value.nil?
|
212
|
+
help_prompt(option_type)
|
213
|
+
elsif (!value.nil? || option_type['required'] != true) && input.chomp == 'EOF'
|
214
|
+
value_found = true
|
215
|
+
else
|
216
|
+
if value.nil?
|
217
|
+
value = ''
|
218
|
+
end
|
219
|
+
value << input + "\n"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
return value
|
223
|
+
end
|
224
|
+
|
225
|
+
def self.password_prompt(option_type)
|
226
|
+
value_found = false
|
227
|
+
while !value_found do
|
228
|
+
print "#{option_type['fieldLabel']}#{option_type['fieldAddOn'] ? ('(' + option_type['fieldAddOn'] + ') ') : '' }#{!option_type['required'] ? ' (optional)' : ''}: "
|
229
|
+
input = STDIN.noecho(&:gets).chomp!
|
230
|
+
value = input
|
231
|
+
print "\n"
|
232
|
+
if input == '?'
|
233
|
+
help_prompt(option_type)
|
234
|
+
elsif !value.nil? || option_type['required'] != true
|
235
|
+
value_found = true
|
236
|
+
end
|
237
|
+
end
|
238
|
+
return value
|
239
|
+
end
|
240
|
+
|
241
|
+
def self.help_prompt(option_type)
|
242
|
+
print Term::ANSIColor.green," * #{option_type['fieldLabel']} [-O #{option_type['fieldName']}=] - ", Term::ANSIColor.reset , "#{option_type['description']}\n"
|
243
|
+
end
|
244
|
+
|
245
|
+
|
246
|
+
def self.load_source_options(source,api_client,params)
|
247
|
+
api_client.options.options_for_source(source,params)['data']
|
248
|
+
end
|
249
|
+
|
250
|
+
def self.display_select_options(select_options = [])
|
251
|
+
puts "\nOptions"
|
252
|
+
puts "==============="
|
253
|
+
select_options.each do |option|
|
254
|
+
puts " * #{option['name']} [#{option['value']}]"
|
255
|
+
end
|
256
|
+
puts "\n\n"
|
257
|
+
end
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
# require 'yaml'
|
2
|
+
require 'io/console'
|
3
|
+
require 'rest_client'
|
4
|
+
require 'term/ansicolor'
|
5
|
+
require 'optparse'
|
6
|
+
require 'morpheus/cli/cli_command'
|
7
|
+
require 'morpheus/cli/option_types'
|
8
|
+
require 'morpheus/cli/mixins/accounts_helper'
|
9
|
+
require 'json'
|
10
|
+
|
11
|
+
class Morpheus::Cli::Roles
|
12
|
+
include Term::ANSIColor
|
13
|
+
include Morpheus::Cli::CliCommand
|
14
|
+
include Morpheus::Cli::AccountsHelper
|
15
|
+
|
16
|
+
def initialize()
|
17
|
+
@appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
|
18
|
+
#@active_groups = ::Morpheus::Cli::Groups.load_group_file
|
19
|
+
end
|
20
|
+
|
21
|
+
def connect(opts)
|
22
|
+
@access_token = Morpheus::Cli::Credentials.new(@appliance_name,@appliance_url).request_credentials()
|
23
|
+
if @access_token.empty?
|
24
|
+
print red,bold, "\nInvalid Credentials. Unable to acquire access token. Please verify your credentials and try again.\n\n",reset
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
@api_client = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url)
|
28
|
+
@users_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).users
|
29
|
+
@accounts_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).accounts
|
30
|
+
@roles_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).roles
|
31
|
+
end
|
32
|
+
|
33
|
+
def handle(args)
|
34
|
+
if args.empty?
|
35
|
+
puts "\nUsage: morpheus roles [list]\n\n"
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
|
39
|
+
case args[0]
|
40
|
+
when 'list'
|
41
|
+
list(args[1..-1])
|
42
|
+
when 'details'
|
43
|
+
details(args[1..-1])
|
44
|
+
when 'add'
|
45
|
+
add(args[1..-1])
|
46
|
+
when 'remove'
|
47
|
+
remove(args[1..-1])
|
48
|
+
else
|
49
|
+
puts "\nUsage: morpheus hosts [list] \n\n"
|
50
|
+
exit 127
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def list(args)
|
55
|
+
account_name = nil
|
56
|
+
options = {}
|
57
|
+
params = {}
|
58
|
+
optparse = OptionParser.new do|opts|
|
59
|
+
Morpheus::Cli::CliCommand.accountScopeOptions(opts,options)
|
60
|
+
Morpheus::Cli::CliCommand.genericOptions(opts,options)
|
61
|
+
end
|
62
|
+
optparse.parse(args)
|
63
|
+
connect(options)
|
64
|
+
begin
|
65
|
+
account_id = nil
|
66
|
+
if !account_name.nil?
|
67
|
+
account = find_account_by_name(account_name)
|
68
|
+
exit 1 if account.nil?
|
69
|
+
account_id = account['id']
|
70
|
+
end
|
71
|
+
|
72
|
+
[:phrase, :offset, :max, :sort, :direction].each do |k|
|
73
|
+
params[k] = options[k] unless options[k].nil?
|
74
|
+
end
|
75
|
+
|
76
|
+
json_response = @roles_interface.list(account_id, params)
|
77
|
+
roles = json_response['roles']
|
78
|
+
|
79
|
+
if options[:json]
|
80
|
+
print JSON.pretty_generate(json_response)
|
81
|
+
print "\n"
|
82
|
+
else
|
83
|
+
print "\n" ,cyan, bold, "Morpheus Roles\n","==================", reset, "\n\n"
|
84
|
+
if roles.empty?
|
85
|
+
puts yellow,"No roles found.",reset
|
86
|
+
else
|
87
|
+
print_roles_table(roles)
|
88
|
+
end
|
89
|
+
print reset,"\n\n"
|
90
|
+
end
|
91
|
+
rescue RestClient::Exception => e
|
92
|
+
::Morpheus::Cli::ErrorHandler.new.print_rest_exception(e)
|
93
|
+
exit 1
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def details(args)
|
98
|
+
usage = "Usage: morpheus roles details [name] [options]"
|
99
|
+
if args.count < 1
|
100
|
+
puts "\n#{usage}\n\n"
|
101
|
+
exit 1
|
102
|
+
end
|
103
|
+
account = nil
|
104
|
+
name = args[0]
|
105
|
+
options = {}
|
106
|
+
params = {}
|
107
|
+
optparse = OptionParser.new do|opts|
|
108
|
+
opts.banner = usage
|
109
|
+
Morpheus::Cli::CliCommand.accountScopeOptions(opts,options)
|
110
|
+
Morpheus::Cli::CliCommand.genericOptions(opts,options)
|
111
|
+
end
|
112
|
+
optparse.parse(args)
|
113
|
+
connect(options)
|
114
|
+
begin
|
115
|
+
|
116
|
+
account = find_account_from_options(options)
|
117
|
+
account_id = account ? account['id'] : nil
|
118
|
+
|
119
|
+
# todo: roles_response = @roles_interface.list(account_id, {name: name}) instead
|
120
|
+
# there may be response data outside of role that needs to be displayed
|
121
|
+
role = find_role_by_name(account_id, name)
|
122
|
+
exit 1 if role.nil?
|
123
|
+
|
124
|
+
if options[:json]
|
125
|
+
print JSON.pretty_generate(role)
|
126
|
+
print "\n"
|
127
|
+
else
|
128
|
+
print "\n" ,cyan, bold, "Role Details\n","==================", reset, "\n\n"
|
129
|
+
print cyan
|
130
|
+
puts "ID: #{role['id']}"
|
131
|
+
puts "Name: #{role['authority']}"
|
132
|
+
puts "Description: #{role['description']}"
|
133
|
+
puts "Scope: #{role['scope']}"
|
134
|
+
puts "Owner: #{role['owner'] ? role['owner']['name'] : nil}"
|
135
|
+
puts "Date Created: #{format_local_dt(role['dateCreated'])}"
|
136
|
+
puts "Last Updated: #{format_local_dt(role['lastUpdated'])}"
|
137
|
+
print "\n" ,cyan, bold, "Role Instance Limits\n","==================", reset, "\n\n"
|
138
|
+
print cyan
|
139
|
+
puts "Max Storage (bytes): #{role['instanceLimits'] ? role['instanceLimits']['maxStorage'] : 0}"
|
140
|
+
puts "Max Memory (bytes): #{role['instanceLimits'] ? role['instanceLimits']['maxMemory'] : 0}"
|
141
|
+
puts "CPU Count: #{role['instanceLimits'] ? role['instanceLimits']['maxCpu'] : 0}"
|
142
|
+
print cyan
|
143
|
+
print reset,"\n\n"
|
144
|
+
end
|
145
|
+
rescue RestClient::Exception => e
|
146
|
+
::Morpheus::Cli::ErrorHandler.new.print_rest_exception(e)
|
147
|
+
exit 1
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def add(args)
|
152
|
+
print red,bold, "\nNOT YET IMPLEMENTED!\n\n",reset
|
153
|
+
exit 1
|
154
|
+
end
|
155
|
+
|
156
|
+
def remove(args)
|
157
|
+
print red,bold, "\nNOT YET IMPLEMENTED!\n\n",reset
|
158
|
+
exit 1
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
|
164
|
+
end
|
@@ -58,7 +58,7 @@ EOT
|
|
58
58
|
security_group_id = nil
|
59
59
|
optparse = OptionParser.new do|opts|
|
60
60
|
opts.banner = "\nUsage: morpheus security-group-rules add_custom_rule SOURCE_CIDR PORT_RANGE PROTOCOL [options]"
|
61
|
-
opts.on( '-s', '--secgroup
|
61
|
+
opts.on( '-s', '--secgroup SECGROUP', "Security Group ID (Use will use security as set with 'security-groups use id'" ) do |id|
|
62
62
|
security_group_id = id
|
63
63
|
end
|
64
64
|
opts.on( '-h', '--help', "Prints this help" ) do
|
@@ -158,15 +158,10 @@ EOT
|
|
158
158
|
options = {}
|
159
159
|
security_group_id = nil
|
160
160
|
optparse = OptionParser.new do|opts|
|
161
|
-
opts.banner = "\nUsage: morpheus security-group-rules list [
|
162
|
-
|
163
|
-
security_group_id = id
|
164
|
-
end
|
165
|
-
opts.on( '-h', '--help', "Prints this help" ) do
|
166
|
-
puts opts
|
167
|
-
exit
|
168
|
-
end
|
161
|
+
opts.banner = "\nUsage: morpheus security-group-rules list [ID]"
|
162
|
+
Morpheus::Cli::CliCommand.genericOptions(opts,options)
|
169
163
|
end
|
164
|
+
security_group_id = args[0].to_i
|
170
165
|
optparse.parse(args)
|
171
166
|
|
172
167
|
if security_group_id.nil?
|