morpheus-cli 0.1.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/lib/morpheus/api/accounts_interface.rb +55 -0
  3. data/lib/morpheus/api/api_client.rb +48 -3
  4. data/lib/morpheus/api/apps_interface.rb +13 -13
  5. data/lib/morpheus/api/{zones_interface.rb → clouds_interface.rb} +10 -10
  6. data/lib/morpheus/api/deploy_interface.rb +4 -4
  7. data/lib/morpheus/api/groups_interface.rb +3 -3
  8. data/lib/morpheus/api/instance_types_interface.rb +2 -2
  9. data/lib/morpheus/api/instances_interface.rb +35 -19
  10. data/lib/morpheus/api/key_pairs_interface.rb +60 -0
  11. data/lib/morpheus/api/license_interface.rb +29 -0
  12. data/lib/morpheus/api/load_balancers_interface.rb +72 -0
  13. data/lib/morpheus/api/logs_interface.rb +37 -0
  14. data/lib/morpheus/api/options_interface.rb +20 -0
  15. data/lib/morpheus/api/provision_types_interface.rb +27 -0
  16. data/lib/morpheus/api/roles_interface.rb +73 -0
  17. data/lib/morpheus/api/security_group_rules_interface.rb +3 -3
  18. data/lib/morpheus/api/security_groups_interface.rb +5 -5
  19. data/lib/morpheus/api/servers_interface.rb +67 -3
  20. data/lib/morpheus/api/task_sets_interface.rb +46 -0
  21. data/lib/morpheus/api/tasks_interface.rb +72 -0
  22. data/lib/morpheus/api/users_interface.rb +72 -0
  23. data/lib/morpheus/cli.rb +27 -4
  24. data/lib/morpheus/cli/accounts.rb +306 -0
  25. data/lib/morpheus/cli/apps.rb +58 -1
  26. data/lib/morpheus/cli/cli_command.rb +87 -0
  27. data/lib/morpheus/cli/cli_registry.rb +6 -1
  28. data/lib/morpheus/cli/{zones.rb → clouds.rb} +99 -70
  29. data/lib/morpheus/cli/credentials.rb +23 -11
  30. data/lib/morpheus/cli/error_handler.rb +31 -11
  31. data/lib/morpheus/cli/groups.rb +1 -0
  32. data/lib/morpheus/cli/hosts.rb +567 -0
  33. data/lib/morpheus/cli/instances.rb +588 -292
  34. data/lib/morpheus/cli/key_pairs.rb +393 -0
  35. data/lib/morpheus/cli/license.rb +118 -0
  36. data/lib/morpheus/cli/load_balancers.rb +366 -0
  37. data/lib/morpheus/cli/mixins/accounts_helper.rb +193 -0
  38. data/lib/morpheus/cli/option_types.rb +260 -0
  39. data/lib/morpheus/cli/roles.rb +164 -0
  40. data/lib/morpheus/cli/security_group_rules.rb +4 -9
  41. data/lib/morpheus/cli/shell.rb +108 -0
  42. data/lib/morpheus/cli/tasks.rb +370 -0
  43. data/lib/morpheus/cli/users.rb +325 -0
  44. data/lib/morpheus/cli/version.rb +1 -1
  45. data/lib/morpheus/cli/workflows.rb +100 -0
  46. data/lib/morpheus/formatters.rb +43 -0
  47. data/morpheus-cli.gemspec +1 -1
  48. metadata +33 -10
  49. data/lib/morpheus/cli/servers.rb +0 -265
@@ -0,0 +1,366 @@
1
+ # require 'yaml'
2
+ require 'io/console'
3
+ require 'rest_client'
4
+ require 'term/ansicolor'
5
+ require 'optparse'
6
+ require 'table_print'
7
+ require 'morpheus/cli/cli_command'
8
+
9
+ class Morpheus::Cli::LoadBalancers
10
+ include Morpheus::Cli::CliCommand
11
+ include Term::ANSIColor
12
+ def initialize()
13
+ @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
14
+ end
15
+
16
+ def connect(opts)
17
+ if opts[:remote]
18
+ @appliance_url = opts[:remote]
19
+ @appliance_name = opts[:remote]
20
+ @access_token = Morpheus::Cli::Credentials.new(@appliance_name,@appliance_url).request_credentials(opts)
21
+ else
22
+ @access_token = Morpheus::Cli::Credentials.new(@appliance_name,@appliance_url).request_credentials(opts)
23
+ end
24
+ @api_client = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url)
25
+ @load_balancers_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).load_balancers
26
+
27
+ if @access_token.empty?
28
+ print red,bold, "\nInvalid Credentials. Unable to acquire access token. Please verify your credentials and try again.\n\n",reset
29
+ exit 1
30
+ end
31
+ end
32
+
33
+
34
+ def handle(args)
35
+ if args.empty?
36
+ puts "\nUsage: morpheus load-balancers [list,add, update,remove, details, lb-types]\n\n"
37
+ return
38
+ end
39
+
40
+ case args[0]
41
+ when 'list'
42
+ list(args[1..-1])
43
+ when 'add'
44
+ add(args[1..-1])
45
+ when 'update'
46
+ # update(args[1..-1])
47
+ when 'details'
48
+ details(args[1..-1])
49
+ when 'remove'
50
+ remove(args[1..-1])
51
+ when 'lb-types'
52
+ lb_types(args[1..-1])
53
+ else
54
+ puts "\nUsage: morpheus load-balancers [list,add, update,remove, details, lb-types]\n\n"
55
+ exit 127
56
+ end
57
+ end
58
+
59
+ def list(args)
60
+ options = {}
61
+ optparse = OptionParser.new do|opts|
62
+ opts.banner = "Usage: morpheus load-balancers list [-s] [-o] [-m]"
63
+ Morpheus::Cli::CliCommand.genericOptions(opts,options)
64
+ end
65
+ optparse.parse(args)
66
+ connect(options)
67
+ begin
68
+ params = {}
69
+ if options[:offset]
70
+ params[:offset] = options[:offset]
71
+ end
72
+ if options[:max]
73
+ params[:max] = options[:max]
74
+ end
75
+ if options[:phrase]
76
+ params[:phrase] = options[:phrase]
77
+ end
78
+ json_response = @load_balancers_interface.get(params)
79
+ if options[:json]
80
+ print JSON.pretty_generate(json_response)
81
+ else
82
+ lbs = json_response['loadBalancers']
83
+ print "\n" ,cyan, bold, "Morpheus Load Balancers\n","==================", reset, "\n\n"
84
+ if lbs.empty?
85
+ puts yellow,"No load balancers currently configured.",reset
86
+ else
87
+ print cyan
88
+ lb_table_data = lbs.collect do |lb|
89
+ {name: lb['name'], id: lb['id'], type: lb['type']['name']}
90
+ end
91
+ tp lb_table_data, :id, :name, :type
92
+ end
93
+ print reset,"\n\n"
94
+ end
95
+
96
+
97
+ rescue RestClient::Exception => e
98
+ if e.response.code == 400
99
+ error = JSON.parse(e.response.to_s)
100
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error,options)
101
+ else
102
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
103
+ end
104
+ exit 1
105
+ end
106
+ end
107
+
108
+ def details(args)
109
+ lb_name = args[0]
110
+ options = {}
111
+ optparse = OptionParser.new do|opts|
112
+ opts.banner = "Usage: morpheus load-balancers details [name]"
113
+ Morpheus::Cli::CliCommand.genericOptions(opts,options)
114
+ end
115
+ if args.count < 1
116
+ puts "\n#{optparse.banner}\n\n"
117
+ exit 1
118
+ end
119
+ optparse.parse(args)
120
+ connect(options)
121
+ begin
122
+ lb = find_lb_by_name(lb_name)
123
+
124
+ exit 1 if lb.nil?
125
+ lb_type = find_lb_type_by_name(lb['type']['name'])
126
+ if options[:json]
127
+ puts JSON.pretty_generate({task:task})
128
+ else
129
+ print "\n", cyan, "Lb #{lb['name']} - #{lb['type']['name']}\n\n"
130
+ lb_type['optionTypes'].sort { |x,y| x['displayOrder'].to_i <=> y['displayOrder'].to_i }.each do |optionType|
131
+ puts " #{optionType['fieldLabel']} : " + (optionType['type'] == 'password' ? "#{task['taskOptions'][optionType['fieldName']] ? '************' : ''}" : "#{task['taskOptions'][optionType['fieldName']] || optionType['defaultValue']}")
132
+ end
133
+ print reset,"\n\n"
134
+ end
135
+ rescue RestClient::Exception => e
136
+ if e.response.code == 400
137
+ error = JSON.parse(e.response.to_s)
138
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error,options)
139
+ else
140
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
141
+ end
142
+ exit 1
143
+ end
144
+ end
145
+
146
+ def update(args)
147
+ lb_name = args[0]
148
+ options = {}
149
+ account_name = nil
150
+ optparse = OptionParser.new do|opts|
151
+ opts.banner = "Usage: morpheus tasks update [task] [options]"
152
+ Morpheus::Cli::CliCommand.genericOptions(opts,options)
153
+ end
154
+ if args.count < 1
155
+ puts "\n#{optparse.banner}\n\n"
156
+ exit 1
157
+ end
158
+ optparse.parse(args)
159
+
160
+ connect(options)
161
+
162
+ begin
163
+
164
+
165
+ task = find_task_by_name_or_code_or_id(lb_name)
166
+ exit 1 if task.nil?
167
+ lb_type = find_lb_type_by_name(task['type']['name'])
168
+
169
+ #params = Morpheus::Cli::OptionTypes.prompt(add_user_option_types, options[:options], @api_client, options[:params]) # options[:params] is mysterious
170
+ params = options[:options] || {}
171
+
172
+ if params.empty?
173
+ puts "\n#{optparse.banner}\n\n"
174
+ option_lines = update_task_option_types(lb_type).collect {|it| "\t-O #{it['fieldContext'] ? (it['fieldContext'] + '.') : ''}#{it['fieldName']}=\"value\"" }.join("\n")
175
+ puts "\nAvailable Options:\n#{option_lines}\n\n"
176
+ exit 1
177
+ end
178
+
179
+ #puts "parsed params is : #{params.inspect}"
180
+ task_keys = ['name']
181
+ changes_payload = (params.select {|k,v| task_keys.include?(k) })
182
+ task_payload = task
183
+ if changes_payload
184
+ task_payload.merge!(changes_payload)
185
+ end
186
+ puts params
187
+ if params['taskOptions']
188
+ task_payload['taskOptions'].merge!(params['taskOptions'])
189
+ end
190
+
191
+ request_payload = {task: task_payload}
192
+ response = @load_balancers_interface.update(task['id'], request_payload)
193
+ if options[:json]
194
+ print JSON.pretty_generate(json_response)
195
+ if !response['success']
196
+ exit 1
197
+ end
198
+ else
199
+ print "\n", cyan, "Task #{response['task']['name']} updated", reset, "\n\n"
200
+ end
201
+ rescue RestClient::Exception => e
202
+ if e.response.code == 400
203
+ error = JSON.parse(e.response.to_s)
204
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
205
+ else
206
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
207
+ end
208
+ exit 1
209
+ end
210
+ end
211
+
212
+
213
+ def lb_types(args)
214
+ options = {}
215
+ optparse = OptionParser.new do|opts|
216
+ opts.banner = "Usage: morpheus load-balancers lb-types"
217
+ Morpheus::Cli::CliCommand.genericOptions(opts,options)
218
+ end
219
+ optparse.parse(args)
220
+ connect(options)
221
+ begin
222
+ json_response = @load_balancers_interface.load_balancer_types()
223
+ if options[:json]
224
+ print JSON.pretty_generate(json_response)
225
+ else
226
+ lb_types = json_response['loadBalancerTypes']
227
+ print "\n" ,cyan, bold, "Morpheus Load Balancer Types\n","============================", reset, "\n\n"
228
+ if lb_types.nil? || lb_types.empty?
229
+ puts yellow,"No lb types currently exist on this appliance. This could be a seed issue.",reset
230
+ else
231
+ print cyan
232
+ lb_table_data = lb_types.collect do |lb_type|
233
+ {name: lb_type['name'], id: lb_type['id'], code: lb_type['code']}
234
+ end
235
+ tp lb_table_data, :id, :name, :code
236
+ end
237
+
238
+ print reset,"\n\n"
239
+ end
240
+
241
+
242
+ rescue => e
243
+ if e.response.code == 400
244
+ error = JSON.parse(e.response.to_s)
245
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error,options)
246
+ else
247
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
248
+ end
249
+ exit 1
250
+ end
251
+ end
252
+
253
+ def add(args)
254
+ lb_name = args[0]
255
+ lb_type_name = nil
256
+ options = {}
257
+ optparse = OptionParser.new do|opts|
258
+ opts.banner = "Usage: morpheus load-balancers add [lb] -t LB_TYPE"
259
+ opts.on( '-t', '--type LB_TYPE', "Lb Type" ) do |val|
260
+ lb_type_name = val
261
+ end
262
+ Morpheus::Cli::CliCommand.genericOptions(opts,options)
263
+ end
264
+ if args.count < 1
265
+ puts "\n#{optparse.banner}\n\n"
266
+ exit 1
267
+ end
268
+ optparse.parse(args)
269
+ connect(options)
270
+
271
+ if lb_type_name.nil?
272
+ puts "LB Type must be specified...\n#{optparse.banner}"
273
+ exit 1
274
+ end
275
+
276
+ lb_type = find_lb_type_by_name(lb_type_name)
277
+ if lb_type.nil?
278
+ puts "LB Type not found!"
279
+ exit 1
280
+ end
281
+ input_options = Morpheus::Cli::OptionTypes.prompt(lb_type['optionTypes'],options[:options],@api_client, options[:params])
282
+ payload = {task: {name: lb_name, taskOptions: input_options['taskOptions'], type: {code: lb_type['code'], id: lb_type['id']}}}
283
+ begin
284
+ json_response = @load_balancers_interface.create(payload)
285
+ if options[:json]
286
+ print JSON.pretty_generate(json_response)
287
+ else
288
+ print "\n", cyan, "LB #{json_response['loadBalancer']['name']} created successfully", reset, "\n\n"
289
+ end
290
+ rescue RestClient::Exception => e
291
+ ::Morpheus::Cli::ErrorHandler.new.print_rest_exception(e)
292
+ exit 1
293
+ end
294
+ end
295
+
296
+ def remove(args)
297
+ lb_name = args[0]
298
+ options = {}
299
+ optparse = OptionParser.new do|opts|
300
+ opts.banner = "Usage: morpheus load-balancers remove [name]"
301
+ Morpheus::Cli::CliCommand.genericOptions(opts,options)
302
+ end
303
+ if args.count < 1
304
+ puts "\n#{optparse.banner}\n\n"
305
+ exit 1
306
+ end
307
+ optparse.parse(args)
308
+ connect(options)
309
+ begin
310
+ lb = find_lb_by_name_or_code_or_id(lb_name)
311
+ exit 1 if lb.nil?
312
+ exit unless Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the load balancer #{lb['name']}?")
313
+ json_response = @load_balancers_interface.destroy(lb['id'])
314
+ if options[:json]
315
+ print JSON.pretty_generate(json_response)
316
+ else
317
+ print "\n", cyan, "Load Balancer #{lb['name']} removed", reset, "\n\n"
318
+ end
319
+ rescue RestClient::Exception => e
320
+ if e.response.code == 400
321
+ error = JSON.parse(e.response.to_s)
322
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error,options)
323
+ else
324
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
325
+ end
326
+ exit 1
327
+ end
328
+ end
329
+
330
+
331
+ private
332
+ def find_lb_by_name(val)
333
+ raise "find_lb_by_name passed a bad name: #{val.inspect}" if val.to_s == ''
334
+ results = @load_balancers_interface.get(val)
335
+ result = nil
336
+ if !results['loadBalancers'].nil? && !results['loadBalancers'].empty?
337
+ result = results['loadBalancers'][0]
338
+ elsif val.to_i.to_s == val
339
+ results = @load_balancers_interface.get(val.to_i)
340
+ result = results['loadBalancer']
341
+ end
342
+ if result.nil?
343
+ print red,bold, "\nLB not found by '#{val}'\n\n",reset
344
+ return nil
345
+ end
346
+ return result
347
+ end
348
+
349
+ def find_lb_type_by_name(val)
350
+ raise "find_lb_type_by_name passed a bad name: #{val.inspect}" if val.to_s == ''
351
+ results = @load_balancers_interface.load_balancer_types(val)
352
+ result = nil
353
+ if !results['loadBalancerTypes'].nil? && !results['loadBalancerTypes'].empty?
354
+ result = results['loadBalancerTypes'][0]
355
+ elsif val.to_i.to_s == val
356
+ results = @load_balancers_interface.load_balancer_types(val.to_i)
357
+ result = results['loadBalancerType']
358
+ end
359
+ if result.nil?
360
+ print red,bold, "\nLB Type not found by '#{val}'\n\n",reset
361
+ return nil
362
+ end
363
+ return result
364
+ end
365
+
366
+ end
@@ -0,0 +1,193 @@
1
+ # Mixin for Morpheus::Cli command classes
2
+ # Provides common methods for fetching and printing accounts, roles, and users.
3
+ # The including class must establish @accounts_interface, @roles_interface, @users_interface
4
+ module Morpheus::Cli::AccountsHelper
5
+
6
+ def find_account_by_id(id)
7
+ raise "#{self.class} has not defined @accounts_interface" if @accounts_interface.nil?
8
+ begin
9
+ json_response = @accounts_interface.get(id.to_i)
10
+ return json_response['account']
11
+ rescue RestClient::Exception => e
12
+ if e.response.code == 404
13
+ print_red_alert "Account not found by id #{id}"
14
+ else
15
+ raise e
16
+ end
17
+ end
18
+ end
19
+
20
+ def find_account_by_name(name)
21
+ raise "#{self.class} has not defined @accounts_interface" if @accounts_interface.nil?
22
+ accounts = @accounts_interface.list({name: name.to_s})['accounts']
23
+ if accounts.empty?
24
+ print_red_alert "Account not found by name #{name}"
25
+ return nil
26
+ elsif accounts.size > 1
27
+ print_red_alert "#{accounts.size} accounts found by name #{name}"
28
+ print_accounts_table(accounts, {color: red})
29
+ print_red_alert "Try using -A ID instead"
30
+ print reset,"\n"
31
+ return nil
32
+ else
33
+ return accounts[0]
34
+ end
35
+ end
36
+
37
+ def find_account_from_options(options)
38
+ account = nil
39
+ if options[:account_name]
40
+ account = find_account_by_name(options[:account_name])
41
+ exit 1 if account.nil?
42
+ elsif options[:account_id]
43
+ account = find_account_by_id(options[:account_id])
44
+ exit 1 if account.nil?
45
+ else
46
+ account = nil # use current account
47
+ end
48
+ return account
49
+ end
50
+
51
+ def find_role_by_id(account_id, id)
52
+ raise "#{self.class} has not defined @roles_interface" if @roles_interface.nil?
53
+ begin
54
+ json_response = @roles_interface.get(account_id, id.to_i)
55
+ return json_response['role']
56
+ rescue RestClient::Exception => e
57
+ if e.response.code == 404
58
+ print_red_alert "Role not found by id #{id}"
59
+ else
60
+ raise e
61
+ end
62
+ end
63
+ end
64
+
65
+ def find_role_by_name(account_id, name)
66
+ raise "#{self.class} has not defined @roles_interface" if @roles_interface.nil?
67
+ roles = @roles_interface.list(account_id, {authority: name.to_s})['roles']
68
+ if roles.empty?
69
+ print_red_alert "Role not found by name #{name}"
70
+ return nil
71
+ elsif roles.size > 1
72
+ print_red_alert "#{roles.size} roles by name #{name}"
73
+ print_roles_table(roles, {color: red})
74
+ print reset,"\n\n"
75
+ return nil
76
+ else
77
+ return roles[0]
78
+ end
79
+ end
80
+
81
+ alias_method :find_role_by_authority, :find_role_by_name
82
+
83
+ def find_user_by_id(account_id, id)
84
+ raise "#{self.class} has not defined @users_interface" if @users_interface.nil?
85
+ begin
86
+ json_response = @users_interface.get(account_id, id.to_i)
87
+ return json_response['user']
88
+ rescue RestClient::Exception => e
89
+ if e.response.code == 404
90
+ print_red_alert "User not found by id #{id}"
91
+ else
92
+ raise e
93
+ end
94
+ end
95
+ end
96
+
97
+ def find_user_by_username(account_id, username)
98
+ raise "#{self.class} has not defined @users_interface" if @users_interface.nil?
99
+ users = @users_interface.list(account_id, {username: username.to_s})['users']
100
+ if users.empty?
101
+ print_red_alert "User not found by username #{username}"
102
+ return nil
103
+ elsif users.size > 1
104
+ print_red_alert "#{users.size} users by username #{username}"
105
+ print_users_table(users, {color: red})
106
+ print reset,"\n\n"
107
+ return nil
108
+ else
109
+ return users[0]
110
+ end
111
+ end
112
+
113
+ def print_accounts_table(accounts, opts={})
114
+ table_color = opts[:color] || cyan
115
+ rows = accounts.collect do |account|
116
+ status_state = nil
117
+ if account['active']
118
+ status_state = "#{green}ACTIVE#{table_color}"
119
+ else
120
+ status_state = "#{red}INACTIVE#{table_color}"
121
+ end
122
+ {
123
+ id: account['id'],
124
+ name: account['name'],
125
+ description: account['description'],
126
+ role: account['role'] ? account['role']['authority'] : nil,
127
+ status: status_state,
128
+ dateCreated: format_local_dt(account['dateCreated'])
129
+ }
130
+ end
131
+
132
+ print table_color
133
+ tp rows, [
134
+ :id,
135
+ :name,
136
+ :description,
137
+ :role,
138
+ {:dateCreated => {:display_name => "Date Created"} },
139
+ :status
140
+ ]
141
+ print reset
142
+ end
143
+
144
+ def print_roles_table(roles, opts={})
145
+ table_color = opts[:color] || cyan
146
+ # tp roles, [
147
+ # 'id',
148
+ # 'name',
149
+ # 'description',
150
+ # 'scope',
151
+ # {'dateCreated' => {:display_name => "Date Created", :display_method => lambda{|it| format_local_dt(it['dateCreated']) } } }
152
+ # ]
153
+ rows = roles.collect do |role|
154
+ {
155
+ id: role['id'],
156
+ name: role['authority'],
157
+ description: role['description'],
158
+ scope: role['scope'],
159
+ owner: role['owner'] ? role['owner']['name'] : nil,
160
+ dateCreated: format_local_dt(role['dateCreated'])
161
+ }
162
+ end
163
+ print table_color
164
+ tp rows, [
165
+ :id,
166
+ :name,
167
+ :description,
168
+ :scope,
169
+ :owner,
170
+ {:dateCreated => {:display_name => "Date Created"} }
171
+ ]
172
+ print reset
173
+ end
174
+
175
+ def print_users_table(users, opts={})
176
+ table_color = opts[:color] || cyan
177
+ rows = users.collect do |user|
178
+ {id: user['id'], username: user['username'], first: user['firstName'], last: user['lastName'], email: user['email'], role: user['role'] ? user['role']['authority'] : nil, account: user['account'] ? user['account']['name'] : nil}
179
+ end
180
+ print table_color
181
+ tp rows, :id, :account, :first, :last, :username, :email, :role
182
+ print reset
183
+ end
184
+
185
+ def print_red_alert(msg)
186
+ print red, bold, "\n#{msg}\n\n", reset
187
+ end
188
+
189
+ def print_green_success(msg)
190
+ print green, bold, "\n#{msg}\n\n", reset
191
+ end
192
+
193
+ end