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,108 @@
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
+ require "shellwords"
9
+
10
+
11
+ class Morpheus::Cli::Shell
12
+ include Morpheus::Cli::CliCommand
13
+ include Term::ANSIColor
14
+ def initialize()
15
+ @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
16
+ end
17
+
18
+ def handle(args)
19
+ usage = "Usage: morpheus shell"
20
+ @command_options = {}
21
+ optparse = OptionParser.new do|opts|
22
+ opts.banner = usage
23
+ opts.on('-a','--account ACCOUNT', "Account Name") do |val|
24
+ @command_options[:account_name] = val
25
+ end
26
+ opts.on('-A','--account-id ID', "Account ID") do |val|
27
+ @command_options[:account_id] = val
28
+ end
29
+ opts.on('-C','--nocolor', "ANSI") do
30
+ @command_options[:nocolor] = true
31
+ Term::ANSIColor::coloring = false
32
+ end
33
+ opts.on( '-h', '--help', "Prints this help" ) do
34
+ puts opts
35
+ exit
36
+ end
37
+ end
38
+ optparse.parse(args)
39
+
40
+ history = []
41
+ exit = false
42
+ while !exit do
43
+ print cyan,"morpheus > ",reset
44
+ input = $stdin.gets.chomp!
45
+ if !input.empty?
46
+
47
+ if input == 'exit'
48
+ break
49
+ elsif input == 'history'
50
+ commands = history.last(100)
51
+ puts "Last #{commands.size} commands"
52
+ commands.reverse.each do |cmd|
53
+ puts "#{cmd}"
54
+ end
55
+ next
56
+ elsif input == 'clear'
57
+ print "\e[H\e[2J"
58
+ next
59
+ elsif input == '!'
60
+ input = history[-1]
61
+ end
62
+
63
+ begin
64
+ history << input
65
+ argv = Shellwords.shellsplit(input)
66
+ if @command_options[:account_name]
67
+ argv.push "--account", @command_options[:account_name]
68
+ end
69
+ if @command_options[:account_id]
70
+ argv.push "--account-id", @command_options[:account_id]
71
+ end
72
+ if @command_options[:nocolor]
73
+ argv.push "--nocolor"
74
+ end
75
+ #puts "cmd: #{argv.join(' ')}"
76
+ if Morpheus::Cli::CliRegistry.has_command?(argv[0])
77
+ Morpheus::Cli::CliRegistry.exec(argv[0], argv[1..-1])
78
+ else
79
+ puts "Unrecognized Command."
80
+ end
81
+ rescue ArgumentError
82
+ puts "Argument Syntax Error..."
83
+ rescue SystemExit, Interrupt
84
+ # nothing to do
85
+ rescue => e
86
+ print red, "\n", e.message, "\n", reset
87
+ print e.backtrace.join("\n"), "\n"
88
+ end
89
+
90
+ end
91
+ end
92
+ end
93
+
94
+
95
+ def get_prompt
96
+ input = ''
97
+ while char=STDIN.getch do
98
+ if char == '\n'
99
+ print "\r\n"
100
+ puts "executing..."
101
+ break
102
+ end
103
+ print char
104
+ input << char
105
+ end
106
+ return input
107
+ end
108
+ end
@@ -0,0 +1,370 @@
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::Tasks
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
+ @tasks_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).tasks
26
+ @task_sets_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).task_sets
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 tasks [list,add, update,remove, details, task-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 'task-types'
52
+ task_types(args[1..-1])
53
+ else
54
+ puts "\nUsage: morpheus tasks [list,add, update,remove, details, task-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 tasks 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 = @tasks_interface.get(params)
79
+ if options[:json]
80
+ print JSON.pretty_generate(json_response)
81
+ else
82
+ tasks = json_response['tasks']
83
+ print "\n" ,cyan, bold, "Morpheus Tasks\n","==================", reset, "\n\n"
84
+ if tasks.empty?
85
+ puts yellow,"No tasks currently configured.",reset
86
+ else
87
+ print cyan
88
+ tasks_table_data = tasks.collect do |task|
89
+ {name: task['name'], id: task['id'], type: task['taskType']['name']}
90
+ end
91
+ tp tasks_table_data, :id, :name, :type
92
+ end
93
+ print reset,"\n\n"
94
+ end
95
+
96
+
97
+ rescue => 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
+ task_name = args[0]
110
+ options = {}
111
+ optparse = OptionParser.new do|opts|
112
+ opts.banner = "Usage: morpheus tasks details [task]"
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
+ task = find_task_by_name_or_code_or_id(task_name)
123
+
124
+ exit 1 if task.nil?
125
+ task_type = find_task_type_by_name(task['taskType']['name'])
126
+ if options[:json]
127
+ puts JSON.pretty_generate({task:task})
128
+ else
129
+ print "\n", cyan, "Task #{task['name']} - #{task['taskType']['name']}\n\n"
130
+ task_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
+ task_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(task_name)
166
+ exit 1 if task.nil?
167
+ task_type = find_task_type_by_name(task['taskType']['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(task_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 = @tasks_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 task_types(args)
214
+ options = {}
215
+ optparse = OptionParser.new do|opts|
216
+ opts.banner = "Usage: morpheus tasks task-types"
217
+ Morpheus::Cli::CliCommand.genericOptions(opts,options)
218
+ end
219
+ optparse.parse(args)
220
+ connect(options)
221
+ begin
222
+ json_response = @tasks_interface.task_types()
223
+ if options[:json]
224
+ print JSON.pretty_generate(json_response)
225
+ else
226
+ task_types = json_response['taskTypes']
227
+ print "\n" ,cyan, bold, "Morpheus Task Types\n","==================", reset, "\n\n"
228
+ if task_types.nil? || task_types.empty?
229
+ puts yellow,"No task types currently exist on this appliance. This could be a seed issue.",reset
230
+ else
231
+ print cyan
232
+ tasks_table_data = task_types.collect do |task_type|
233
+ {name: task_type['name'], id: task_type['id'], code: task_type['code'], description: task_type['description']}
234
+ end
235
+ tp tasks_table_data, :id, :name, :code, :description
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
+ task_name = args[0]
255
+ task_type_name = nil
256
+ options = {}
257
+ optparse = OptionParser.new do|opts|
258
+ opts.banner = "Usage: morpheus tasks add [task] -t TASK_TYPE"
259
+ opts.on( '-t', '--type TASK_TYPE', "Task Type" ) do |val|
260
+ task_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 task_type_name.nil?
272
+ puts "Task Type must be specified...\n#{optparse.banner}"
273
+ exit 1
274
+ end
275
+
276
+ task_type = find_task_type_by_name(task_type_name)
277
+ if task_type.nil?
278
+ puts "Task Type not found!"
279
+ exit 1
280
+ end
281
+ input_options = Morpheus::Cli::OptionTypes.prompt(task_type['optionTypes'],options[:options],@api_client, options[:params])
282
+ payload = {task: {name: task_name, taskOptions: input_options['taskOptions'], taskType: {code: task_type['code'], id: task_type['id']}}}
283
+ json_response = @tasks_interface.create(payload)
284
+ if options[:json]
285
+ print JSON.pretty_generate(json_response)
286
+ else
287
+ if json_response['success']
288
+ print "\n", cyan, "Task #{json_response['task']['name']} created successfully", reset, "\n\n"
289
+ else
290
+ print "\n", red, "Error Creating Task #{json_response['errors']}", reset, "\n\n"
291
+ end
292
+ end
293
+ end
294
+
295
+ def remove(args)
296
+ task_name = args[0]
297
+ options = {}
298
+ optparse = OptionParser.new do|opts|
299
+ opts.banner = "Usage: morpheus tasks remove [task]"
300
+ Morpheus::Cli::CliCommand.genericOptions(opts,options)
301
+ end
302
+ if args.count < 1
303
+ puts "\n#{optparse.banner}\n\n"
304
+ exit 1
305
+ end
306
+ optparse.parse(args)
307
+ connect(options)
308
+ begin
309
+ task = find_task_by_name_or_code_or_id(task_name)
310
+ exit 1 if task.nil?
311
+ exit unless Morpheus::Cli::OptionTypes.confirm("Are you sure you want to delete the task #{task['name']}?")
312
+ json_response = @tasks_interface.destroy(task['id'])
313
+ if options[:json]
314
+ print JSON.pretty_generate(json_response)
315
+ else
316
+ print "\n", cyan, "Task #{task['name']} removed", reset, "\n\n"
317
+ end
318
+ rescue RestClient::Exception => e
319
+ if e.response.code == 400
320
+ error = JSON.parse(e.response.to_s)
321
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error,options)
322
+ else
323
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
324
+ end
325
+ exit 1
326
+ end
327
+ end
328
+
329
+
330
+ private
331
+ def find_task_by_name_or_code_or_id(val)
332
+ raise "find_task_by_name_or_code_or_id passed a bad name: #{val.inspect}" if val.to_s == ''
333
+ results = @tasks_interface.get(val)
334
+ result = nil
335
+ if !results['tasks'].nil? && !results['tasks'].empty?
336
+ result = results['tasks'][0]
337
+ elsif val.to_i.to_s == val
338
+ results = @tasks_interface.get(val.to_i)
339
+ result = results['task']
340
+ end
341
+ if result.nil?
342
+ print red,bold, "\nTask not found by '#{val}'\n\n",reset
343
+ return nil
344
+ end
345
+ return result
346
+ end
347
+
348
+ def find_task_type_by_name(val)
349
+ raise "find_task_type_by_name passed a bad name: #{val.inspect}" if val.to_s == ''
350
+ results = @tasks_interface.task_types(val)
351
+ result = nil
352
+ if !results['taskTypes'].nil? && !results['taskTypes'].empty?
353
+ result = results['taskTypes'][0]
354
+ elsif val.to_i.to_s == val
355
+ results = @tasks_interface.task_types(val.to_i)
356
+ result = results['taskType']
357
+ end
358
+ if result.nil?
359
+ print red,bold, "\nTask Type not found by '#{val}'\n\n",reset
360
+ return nil
361
+ end
362
+ return result
363
+ end
364
+
365
+ def update_task_option_types(task_type)
366
+ [
367
+ {'fieldName' => 'name', 'fieldLabel' => 'Name', 'type' => 'text', 'required' => true, 'displayOrder' => 0}
368
+ ] + task_type['optionTypes']
369
+ end
370
+ end