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.
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,393 @@
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::KeyPairs
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
+ end
19
+
20
+ def connect(opts)
21
+ @access_token = Morpheus::Cli::Credentials.new(@appliance_name,@appliance_url).request_credentials()
22
+ if @access_token.empty?
23
+ print red,bold, "\nInvalid Credentials. Unable to acquire access token. Please verify your credentials and try again.\n\n",reset
24
+ exit 1
25
+ end
26
+ @api_client = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url)
27
+ @accounts_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).accounts
28
+ @key_pairs_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).key_pairs
29
+ end
30
+
31
+ def handle(args)
32
+ usage = "Usage: morpheus key-pairs [list,add,update,remove] [name]"
33
+ if args.empty?
34
+ puts "\n#{usage}\n\n"
35
+ exit 1
36
+ end
37
+
38
+ case args[0]
39
+ when 'list'
40
+ list(args[1..-1])
41
+ when 'details'
42
+ details(args[1..-1])
43
+ when 'add'
44
+ add(args[1..-1])
45
+ when 'update'
46
+ update(args[1..-1])
47
+ when 'remove'
48
+ remove(args[1..-1])
49
+ else
50
+ puts "\n#{usage}\n\n"
51
+ exit 127
52
+ end
53
+ end
54
+
55
+ def list(args)
56
+ options = {}
57
+ params = {}
58
+ account = nil
59
+ optparse = OptionParser.new do|opts|
60
+ Morpheus::Cli::CliCommand.accountScopeOptions(opts,options)
61
+ Morpheus::Cli::CliCommand.genericOptions(opts,options)
62
+ end
63
+ optparse.parse(args)
64
+ connect(options)
65
+ begin
66
+
67
+ account = find_account_from_options(options)
68
+ account_id = account ? account['id'] : nil
69
+
70
+ [:phrase, :offset, :max, :sort, :direction].each do |k|
71
+ params[k] = options[k] unless options[k].nil?
72
+ end
73
+
74
+ json_response = @key_pairs_interface.list(account_id, params)
75
+ key_pairs = json_response['keyPairs']
76
+ if options[:json]
77
+ print JSON.pretty_generate(json_response)
78
+ print "\n"
79
+ else
80
+ print "\n" ,cyan, bold, "Morpheus Key Pairs\n","==================", reset, "\n\n"
81
+ if key_pairs.empty?
82
+ puts yellow,"No key pairs found.",reset
83
+ else
84
+ print_key_pairs_table(key_pairs)
85
+ end
86
+ print reset,"\n\n"
87
+ end
88
+ rescue RestClient::Exception => e
89
+ ::Morpheus::Cli::ErrorHandler.new.print_rest_exception(e)
90
+ exit 1
91
+ end
92
+ end
93
+
94
+ def details(args)
95
+ usage = "Usage: morpheus key-pairs details [name] [options]"
96
+ if args.count < 1
97
+ puts "\n#{usage}\n\n"
98
+ exit 1
99
+ end
100
+ account = nil
101
+ name = args[0]
102
+ options = {}
103
+ params = {}
104
+ optparse = OptionParser.new do|opts|
105
+ opts.banner = usage
106
+ Morpheus::Cli::CliCommand.accountScopeOptions(opts,options)
107
+ Morpheus::Cli::CliCommand.genericOptions(opts,options)
108
+ end
109
+ optparse.parse(args)
110
+ connect(options)
111
+ begin
112
+
113
+ account = find_account_from_options(options)
114
+ account_id = account ? account['id'] : nil
115
+
116
+ # todo: key_pairs_response = @key_pairs_interface.list(account_id, {name: name})
117
+ # there may be response data outside of account that needs to be displayed
118
+
119
+ # allow finding by ID since name is not unique!
120
+ key_pair = ((name.to_s =~ /\A\d{1,}\Z/) ? find_key_pair_by_id(account_id, name) : find_key_pair_by_name(account_id, name) )
121
+ exit 1 if key_pair.nil?
122
+
123
+ if options[:json]
124
+ print JSON.pretty_generate(key_pair)
125
+ print "\n"
126
+ else
127
+ print "\n" ,cyan, bold, "Key Pair Details\n","==================", reset, "\n\n"
128
+ print cyan
129
+ puts "ID: #{key_pair['id']}"
130
+ puts "Name: #{key_pair['name']}"
131
+ puts "MD5: #{key_pair['md5']}"
132
+ puts "Date Created: #{format_local_dt(key_pair['dateCreated'])}"
133
+ #puts "Last Updated: #{format_local_dt(key_pair['lastUpdated'])}"
134
+ print reset,"\n\n"
135
+
136
+ # todo: show public key
137
+
138
+ end
139
+ rescue RestClient::Exception => e
140
+ ::Morpheus::Cli::ErrorHandler.new.print_rest_exception(e)
141
+ exit 1
142
+ end
143
+ end
144
+
145
+ def add(args)
146
+ # if args.count > 0
147
+ # puts "\nUsage: morpheus hosts add [options]\n\n"
148
+ # exit 1
149
+ # end
150
+ account_name = nil
151
+ options = {}
152
+ optparse = OptionParser.new do|opts|
153
+ opts.banner = "Usage: morpheus key-pairs add [options]"
154
+
155
+ opts.on( '-a', '--account ACCOUNT', "Account Name" ) do |val|
156
+ account_name = val
157
+ end
158
+
159
+ opts.on( '', '--public-key-file FILENAME', "Public Key File" ) do |filename|
160
+ if File.exists?(filename)
161
+ options['publicKey'] = File.read(filename)
162
+ options[:options] ||= {}
163
+ options[:options]['publicKey'] = options['publicKey']
164
+ else
165
+ print_red_alert "File not found: #{filename}"
166
+ exit 1
167
+ end
168
+ end
169
+
170
+ opts.on( '', '--public-key TEXT', "Public Key Text" ) do |val|
171
+ options['publicKey'] = val
172
+ options[:options] ||= {}
173
+ options[:options]['publicKey'] = options['publicKey']
174
+ end
175
+
176
+ opts.on( '', '--private-key-file FILENAME', "Private Key File" ) do |filename|
177
+ if File.exists?(filename)
178
+ options['privateKey'] = File.read(filename)
179
+ options[:options] ||= {}
180
+ options[:options]['privateKey'] = options['privateKey']
181
+ else
182
+ print_red_alert "File not found: #{filename}"
183
+ exit 1
184
+ end
185
+ end
186
+
187
+ opts.on( '', '--private-key TEXT', "Private Key Text" ) do |val|
188
+ options['privateKey'] = val
189
+ options[:options] ||= {}
190
+ options[:options]['privateKey'] = options['privateKey']
191
+ end
192
+
193
+ Morpheus::Cli::CliCommand.genericOptions(opts,options)
194
+ end
195
+ optparse.parse(args)
196
+
197
+ connect(options)
198
+
199
+ begin
200
+
201
+ # current user account by default
202
+ account = nil
203
+ if !account_name.nil?
204
+ account = find_account_by_name(account_name)
205
+ exit 1 if account.nil?
206
+ end
207
+ account_id = account ? account['id'] : nil
208
+
209
+ params = Morpheus::Cli::OptionTypes.prompt(add_key_pair_option_types, options[:options], @api_client, options[:params]) # options[:params] is mysterious
210
+
211
+ if !params['publicKey']
212
+ print_red_alert "publicKey is required"
213
+ exit 1
214
+ elsif !params['privateKey']
215
+ print_red_alert "privateKey is required"
216
+ exit 1
217
+ end
218
+
219
+ key_pair_payload = params.select {|k,v| ['name', 'publicKey', 'privateKey'].include?(k) }
220
+
221
+ request_payload = {keyPair: key_pair_payload}
222
+ response = @key_pairs_interface.create(account_id, request_payload)
223
+ print "\n", cyan, "Account #{key_pair_payload['name']} added", reset, "\n\n"
224
+ rescue RestClient::Exception => e
225
+ ::Morpheus::Cli::ErrorHandler.new.print_rest_exception(e)
226
+ exit 1
227
+ end
228
+ end
229
+
230
+ def update(args)
231
+ usage = "Usage: morpheus hosts update [name] [options]"
232
+ if args.count < 1
233
+ puts "\n#{usage}\n\n"
234
+ exit 1
235
+ end
236
+ account_name = nil
237
+ name = args[0]
238
+ options = {}
239
+ optparse = OptionParser.new do|opts|
240
+ opts.banner = usage
241
+
242
+ opts.on( '-a', '--account ACCOUNT', "Account Name" ) do |val|
243
+ account_name = val
244
+ end
245
+
246
+ Morpheus::Cli::CliCommand.genericOptions(opts,options)
247
+ end
248
+ optparse.parse(args)
249
+
250
+ connect(options)
251
+
252
+ begin
253
+
254
+ account_id = nil
255
+ if !account_name.nil?
256
+ account = find_account_by_name(account_name)
257
+ exit 1 if account.nil?
258
+ account_id = account['id']
259
+ end
260
+
261
+ key_pair = ((name.to_s =~ /\A\d{1,}\Z/) ? find_key_pair_by_id(account_id, name) : find_key_pair_by_name(account_id, name) )
262
+ exit 1 if key_pair.nil?
263
+
264
+ #params = Morpheus::Cli::OptionTypes.prompt(update_key_pair_option_types, options[:options], @api_client, options[:params]) # options[:params] is mysterious
265
+ params = options[:options] || {}
266
+
267
+ if params.empty?
268
+ puts "\n#{usage}\n\n"
269
+ option_lines = update_key_pair_option_types.collect {|it| "\t-O #{it['fieldName']}=\"value\"" }.join("\n")
270
+ puts "\nAvailable Options:\n#{option_lines}\n\n"
271
+ exit 1
272
+ end
273
+
274
+ key_pair_payload = params.select {|k,v| ['name'].include?(k) }
275
+ request_payload = {keyPair: key_pair_payload}
276
+ response = @key_pairs_interface.update(account_id, key_pair['id'], request_payload)
277
+ print "\n", cyan, "Key Pair #{key_pair_payload['name'] || key_pair['name']} updated", reset, "\n\n"
278
+ rescue RestClient::Exception => e
279
+ ::Morpheus::Cli::ErrorHandler.new.print_rest_exception(e)
280
+ exit 1
281
+ end
282
+ end
283
+
284
+ def remove(args)
285
+ usage = "Usage: morpheus key-pairs remove [name]"
286
+ if args.count < 1
287
+ puts "\n#{usage}\n\n"
288
+ exit 1
289
+ end
290
+ account_name = nil
291
+ name = args[0]
292
+ options = {}
293
+ optparse = OptionParser.new do|opts|
294
+ opts.banner = usage
295
+
296
+ opts.on( '-a', '--account ACCOUNT', "Account Name or ID" ) do |val|
297
+ account_name = val
298
+ end
299
+
300
+ Morpheus::Cli::CliCommand.genericOptions(opts,options)
301
+ end
302
+ optparse.parse(args)
303
+ connect(options)
304
+ begin
305
+ # current user account by default
306
+ account = nil
307
+ if !account_name.nil?
308
+ account = find_account_by_name(account_name)
309
+ exit 1 if account.nil?
310
+ end
311
+ account_id = account ? account['id'] : nil
312
+ # allow finding by ID since name is not unique!
313
+ key_pair = ((name.to_s =~ /\A\d{1,}\Z/) ? find_key_pair_by_id(account_id, name) : find_key_pair_by_name(account_id, name) )
314
+ exit 1 if key_pair.nil?
315
+ exit unless Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the key pair #{key_pair['name']}?")
316
+ @key_pairs_interface.destroy(account_id, key_pair['id'])
317
+ # list([])
318
+ print "\n", cyan, "Key Pair #{key_pair['name']} removed", reset, "\n\n"
319
+ rescue RestClient::Exception => e
320
+ ::Morpheus::Cli::ErrorHandler.new.print_rest_exception(e)
321
+ exit 1
322
+ end
323
+ end
324
+
325
+ private
326
+
327
+ def find_key_pair_by_id(account_id, id)
328
+ raise "#{self.class} has not defined @key_pairs_interface" if @key_pairs_interface.nil?
329
+ begin
330
+ json_response = @key_pairs_interface.get(account_id, id.to_i)
331
+ return json_response['keyPair']
332
+ rescue RestClient::Exception => e
333
+ if e.response.code == 404
334
+ print_red_alert "Key Pair not found by id #{id}"
335
+ else
336
+ raise e
337
+ end
338
+ end
339
+ end
340
+
341
+ def find_key_pair_by_name(account_id, name)
342
+ raise "#{self.class} has not defined @key_pairs_interface" if @key_pairs_interface.nil?
343
+ key_pairs = @key_pairs_interface.list(account_id, {name: name.to_s})['keyPairs']
344
+ if key_pairs.empty?
345
+ print_red_alert "Key Pair not found by name #{name}"
346
+ return nil
347
+ elsif key_pairs.size > 1
348
+ print_red_alert "#{key_pairs.size} key_pairs by name #{name}"
349
+ print_key_pairs_table(key_pairs, {color: red})
350
+ print reset,"\n\n"
351
+ return nil
352
+ else
353
+ return key_pairs[0]
354
+ end
355
+ end
356
+
357
+ def print_key_pairs_table(key_pairs, opts={})
358
+ table_color = opts[:color] || cyan
359
+ rows = key_pairs.collect do |key_pair|
360
+ {
361
+ id: key_pair['id'],
362
+ name: key_pair['name'],
363
+ md5: key_pair['md5'],
364
+ dateCreated: format_local_dt(key_pair['dateCreated'])
365
+ }
366
+ end
367
+
368
+ print table_color
369
+ tp rows, [
370
+ :id,
371
+ :name,
372
+ :md5,
373
+ {:dateCreated => {:display_name => "Date Created"} }
374
+ ]
375
+ print reset
376
+ end
377
+
378
+
379
+ def add_key_pair_option_types
380
+ [
381
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
382
+ {'fieldName' => 'publicKey', 'fieldLabel' => 'Public Key', 'type' => 'text', 'required' => true, 'displayOrder' => 2},
383
+ {'fieldName' => 'privateKey', 'fieldLabel' => 'Private Key', 'type' => 'text', 'required' => true, 'displayOrder' => 3},
384
+ ]
385
+ end
386
+
387
+ def update_key_pair_option_types
388
+ [
389
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 1},
390
+ ]
391
+ end
392
+
393
+ end
@@ -0,0 +1,118 @@
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::License
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
+ @license_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).license
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 license [details, apply]\n\n"
37
+ return
38
+ end
39
+
40
+ case args[0]
41
+ when 'apply'
42
+ apply(args[1..-1])
43
+ when 'details'
44
+ details(args[1..-1])
45
+ else
46
+ puts "\nUsage: morpheus license [details, apply]\n\n"
47
+ exit 127
48
+ end
49
+ end
50
+
51
+
52
+ def details(args)
53
+ options = {}
54
+ optparse = OptionParser.new do|opts|
55
+ opts.banner = "Usage: morpheus license details"
56
+ Morpheus::Cli::CliCommand.genericOptions(opts,options)
57
+ end
58
+ optparse.parse(args)
59
+ connect(options)
60
+ begin
61
+ license = @license_interface.get()
62
+
63
+ if options[:json]
64
+ puts JSON.pretty_generate(license)
65
+ else
66
+ if license['license'].nil?
67
+ puts "No License Currently Applied to the appliance."
68
+ exit 1
69
+ else
70
+ print "\n", cyan, "License\n=======\n"
71
+ max_memory = Filesize.from("#{license['license']['maxMemory']} B").pretty
72
+ max_storage = Filesize.from("#{license['license']['maxStorage']} B").pretty
73
+ used_memory = Filesize.from("#{license['usedMemory']} B").pretty
74
+ puts "Account: #{license['license']['accountName']}"
75
+ puts "Start Date: #{license['license']['startDate']}"
76
+ puts "End Date: #{license['license']['endDate']}"
77
+ puts "Memory: #{used_memory} / #{max_memory}"
78
+ puts "Max Storage: #{max_storage}"
79
+ end
80
+ print reset,"\n\n"
81
+ end
82
+ rescue RestClient::Exception => e
83
+ ::Morpheus::Cli::ErrorHandler.new.print_rest_exception(e)
84
+ exit 1
85
+ end
86
+ end
87
+
88
+ def apply(args)
89
+ key = args[0]
90
+ options = {}
91
+ account_name = nil
92
+ optparse = OptionParser.new do|opts|
93
+ opts.banner = "Usage: morpheus license apply [key]"
94
+ Morpheus::Cli::CliCommand.genericOptions(opts,options)
95
+ end
96
+ if args.count < 1
97
+ puts "\n#{optparse.banner}\n\n"
98
+ exit 1
99
+ end
100
+ optparse.parse(args)
101
+
102
+ connect(options)
103
+
104
+ begin
105
+ license_results = @license_interface.apply(key)
106
+
107
+ if options[:json]
108
+ puts JSON.pretty_generate(license_results)
109
+ else
110
+ puts "License applied successfully!"
111
+ end
112
+ rescue RestClient::Exception => e
113
+ ::Morpheus::Cli::ErrorHandler.new.print_rest_exception(e)
114
+ exit 1
115
+ end
116
+ end
117
+
118
+ end