morpheus-cli 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,459 @@
1
+ # require 'yaml'
2
+ require 'io/console'
3
+ require 'rest_client'
4
+ require 'term/ansicolor'
5
+ require 'optparse'
6
+ require 'filesize'
7
+ require 'table_print'
8
+
9
+ class Morpheus::Cli::Instances
10
+ include Term::ANSIColor
11
+ def initialize()
12
+ @appliance_name, @appliance_url = Morpheus::Cli::Remote.active_appliance
13
+ @access_token = Morpheus::Cli::Credentials.new(@appliance_name,@appliance_url).request_credentials()
14
+ @instances_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instances
15
+ @instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
16
+ @groups_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).groups
17
+ @active_groups = ::Morpheus::Cli::Groups.load_group_file
18
+ end
19
+
20
+
21
+ def handle(args)
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
+ return 1
25
+ end
26
+ if args.empty?
27
+ puts "\nUsage: morpheus instances [list,add,remove,stop,start,restart,resize,upgrade,clone,envs,setenv,delenv] [name]\n\n"
28
+ end
29
+
30
+ case args[0]
31
+ when 'list'
32
+ list(args[1..-1])
33
+ when 'add'
34
+ add(args[1..-1])
35
+ when 'remove'
36
+ remove(args[1..-1])
37
+ when 'stop'
38
+ stop(args[1..-1])
39
+ when 'start'
40
+ start(args[1..-1])
41
+ when 'restart'
42
+ restart(args[1..-1])
43
+ when 'stats'
44
+ stats(args[1..-1])
45
+ when 'details'
46
+ details(args[1..-1])
47
+ when 'envs'
48
+ envs(args[1..-1])
49
+ when 'setenv'
50
+ setenv(args[1..-1])
51
+ when 'delenv'
52
+ delenv(args[1..-1])
53
+ else
54
+ puts "\nUsage: morpheus instances [list,add,remove,stop,start,restart,resize,upgrade,clone,envs,setenv,delenv] [name]\n\n"
55
+ end
56
+ end
57
+
58
+ def add(args)
59
+ if args.count < 2
60
+ puts "\nUsage: morpheus instances add NAME TYPE\n\n"
61
+ return
62
+ end
63
+
64
+ instance_name = args[0]
65
+ instance_type_code = args[1]
66
+ instance_type = find_instance_type_by_code(instance_type_code)
67
+ if instance_type.nil?
68
+ print reset,"\n\n"
69
+ return
70
+ end
71
+
72
+ groupId = @active_groups[@appliance_name.to_sym]
73
+
74
+ options = {
75
+ :servicePlan => nil,
76
+ :instance => {
77
+ :name => instance_name,
78
+ :site => {
79
+ :id => groupId
80
+ },
81
+ :instanceType => {
82
+ :code => instance_type_code
83
+ }
84
+ }
85
+ }
86
+
87
+ instance_type['instanceTypeLayouts'].sort! { |x,y| y['sortOrder'] <=> x['sortOrder'] }
88
+ puts "Configurations: "
89
+ instance_type['instanceTypeLayouts'].each_with_index do |layout, index|
90
+ puts " #{index+1}) #{layout['name']} (#{layout['code']})"
91
+ end
92
+ print "Selection: "
93
+ layout_selection = nil
94
+ layout = nil
95
+ while true do
96
+ layout_selection = $stdin.gets.chomp!
97
+ if layout_selection.to_i.to_s == layout_selection
98
+ layout_selection = layout_selection.to_i
99
+ break
100
+ end
101
+ end
102
+ layout = instance_type['instanceTypeLayouts'][layout_selection-1]['id']
103
+ options[:instance][:layout] = {id: layout}
104
+ print "\n"
105
+ if options[:servicePlan].nil?
106
+ plans = @instance_types_interface.service_plans(layout)
107
+ puts "Select a Plan: "
108
+ plans['servicePlans'].each_with_index do |plan, index|
109
+ puts " #{index+1}) #{plan['name']}"
110
+ end
111
+ print "Selection: "
112
+ plan_selection = nil
113
+ while true do
114
+ plan_selection = $stdin.gets.chomp!
115
+ if plan_selection.to_i.to_s == plan_selection
116
+ plan_selection = plan_selection.to_i
117
+ break
118
+ end
119
+ end
120
+ options[:servicePlan] = plans['servicePlans'][plan_selection-1]['id']
121
+ print "\n"
122
+ end
123
+
124
+ if !instance_type['config'].nil?
125
+ instance_type_config = JSON.parse(instance_type['config'])
126
+ if instance_type_config['options'].nil? == false
127
+ instance_type_config['options'].each do |opt|
128
+ print "#{opt['label']}: "
129
+ if(opt['name'].downcase.include?("password"))
130
+ options[opt['name']] = STDIN.noecho(&:gets).chomp!
131
+ print "\n"
132
+ else
133
+ options[opt['name']] = $stdin.gets.chomp!
134
+ end
135
+
136
+ end
137
+ end
138
+ end
139
+ begin
140
+ @instances_interface.create(options)
141
+ rescue => e
142
+ if e.response.code == 400
143
+ error = JSON.parse(e.response.to_s)
144
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
145
+ else
146
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
147
+ end
148
+ return nil
149
+ end
150
+ list([])
151
+ end
152
+
153
+ def stats(args)
154
+ if args.count < 1
155
+ puts "\nUsage: morpheus instances stats [name]\n\n"
156
+ return
157
+ end
158
+ begin
159
+ instance_results = @instances_interface.get({name: args[0]})
160
+ if instance_results['instances'].empty?
161
+ puts "Instance not found by name #{args[0]}"
162
+ return
163
+ end
164
+ instance = instance_results['instances'][0]
165
+ instance_id = instance['id']
166
+ stats = instance_results['stats'][instance_id.to_s]
167
+ print "\n" ,cyan, bold, "#{instance['name']} (#{instance['instanceType']['name']})\n","==================", reset, "\n\n"
168
+ print cyan, "Memory: \t#{Filesize.from("#{stats['usedMemory']} B").pretty} / #{Filesize.from("#{stats['maxMemory']} B").pretty}\n"
169
+ print cyan, "Storage: \t#{Filesize.from("#{stats['usedStorage']} B").pretty} / #{Filesize.from("#{stats['maxStorage']} B").pretty}\n\n",reset
170
+ puts
171
+ rescue RestClient::Exception => e
172
+ if e.response.code == 400
173
+ error = JSON.parse(e.response.to_s)
174
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
175
+ else
176
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
177
+ end
178
+ return nil
179
+ end
180
+ end
181
+
182
+ def details(args)
183
+ if args.count < 1
184
+ puts "\nUsage: morpheus instances stats [name]\n\n"
185
+ return
186
+ end
187
+ begin
188
+ instance_results = @instances_interface.get({name: args[0]})
189
+ if instance_results['instances'].empty?
190
+ puts "Instance not found by name #{args[0]}"
191
+ return
192
+ end
193
+ instance = instance_results['instances'][0]
194
+ instance_id = instance['id']
195
+ stats = instance_results['stats'][instance_id.to_s]
196
+ print "\n" ,cyan, bold, "#{instance['name']} (#{instance['instanceType']['name']})\n","==================", reset, "\n\n"
197
+ print cyan, "Memory: \t#{Filesize.from("#{stats['usedMemory']} B").pretty} / #{Filesize.from("#{stats['maxMemory']} B").pretty}\n"
198
+ print cyan, "Storage: \t#{Filesize.from("#{stats['usedStorage']} B").pretty} / #{Filesize.from("#{stats['maxStorage']} B").pretty}\n\n",reset
199
+ puts instance
200
+ rescue RestClient::Exception => e
201
+ if e.response.code == 400
202
+ error = JSON.parse(e.response.to_s)
203
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
204
+ else
205
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
206
+ end
207
+ return nil
208
+ end
209
+ end
210
+
211
+ def envs(args)
212
+ if args.count < 1
213
+ puts "\nUsage: morpheus instances envs [name]\n\n"
214
+ return
215
+ end
216
+ begin
217
+ instance_results = @instances_interface.get({name: args[0]})
218
+ if instance_results['instances'].empty?
219
+ puts "Instance not found by name #{args[0]}"
220
+ return
221
+ end
222
+ instance = instance_results['instances'][0]
223
+ instance_id = instance['id']
224
+ env_results = @instances_interface.get_envs(instance_id)
225
+ print "\n" ,cyan, bold, "#{instance['name']} (#{instance['instanceType']['name']})\n","==================", "\n\n", reset, cyan
226
+ envs = env_results['envs'] || {}
227
+ if env_results['readOnlyEnvs']
228
+ envs += env_results['readOnlyEnvs'].map { |k,v| {:name => k, :value => k.downcase.include?("password") ? "********" : v, :export => true}}
229
+ end
230
+ tp envs, :name, :value, :export
231
+ print "\n" ,cyan, bold, "Importad Envs\n","==================", "\n\n", reset, cyan
232
+ imported_envs = env_results['importedEnvs'].map { |k,v| {:name => k, :value => k.downcase.include?("password") ? "********" : v}}
233
+ tp imported_envs
234
+ print reset, "\n"
235
+
236
+ rescue RestClient::Exception => e
237
+ if e.response.code == 400
238
+ error = JSON.parse(e.response.to_s)
239
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
240
+ else
241
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
242
+ end
243
+ return nil
244
+ end
245
+ end
246
+
247
+ def setenv(args)
248
+ if args.count < 3
249
+ puts "\nUsage: morpheus instances setenv INSTANCE NAME VALUE [-e]\n\n"
250
+ return
251
+ end
252
+ begin
253
+ instance_results = @instances_interface.get({name: args[0]})
254
+ if instance_results['instances'].empty?
255
+ puts "Instance not found by name #{args[0]}"
256
+ return
257
+ end
258
+ instance = instance_results['instances'][0]
259
+ instance_id = instance['id']
260
+ evar = {name: args[1], value: args[2], export: false}
261
+ params = {}
262
+ optparse = OptionParser.new do|opts|
263
+ opts.on( '-e', "Exportable" ) do |exportable|
264
+ evar[:export] = exportable
265
+ end
266
+ end
267
+ optparse.parse(args)
268
+
269
+ @instances_interface.create_env(instance_id, [evar])
270
+ envs([args[0]])
271
+ rescue RestClient::Exception => e
272
+ if e.response.code == 400
273
+ error = JSON.parse(e.response.to_s)
274
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
275
+ else
276
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
277
+ end
278
+ return nil
279
+ end
280
+ end
281
+
282
+ def delenv(args)
283
+ if args.count < 2
284
+ puts "\nUsage: morpheus instances setenv INSTANCE NAME\n\n"
285
+ return
286
+ end
287
+ begin
288
+ instance_results = @instances_interface.get({name: args[0]})
289
+ if instance_results['instances'].empty?
290
+ puts "Instance not found by name #{args[0]}"
291
+ return
292
+ end
293
+ instance = instance_results['instances'][0]
294
+ instance_id = instance['id']
295
+ name = args[1]
296
+
297
+ @instances_interface.del_env(instance_id, name)
298
+ envs([args[0]])
299
+ rescue RestClient::Exception => e
300
+ if e.response.code == 400
301
+ error = JSON.parse(e.response.to_s)
302
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
303
+ else
304
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
305
+ end
306
+ return nil
307
+ end
308
+ end
309
+
310
+ def stop(args)
311
+ if args.count < 1
312
+ puts "\nUsage: morpheus instances stop [name]\n\n"
313
+ return
314
+ end
315
+ begin
316
+ instance_results = @instances_interface.get({name: args[0]})
317
+ if instance_results['instances'].empty?
318
+ puts "Instance not found by name #{args[0]}"
319
+ return
320
+ end
321
+ @instances_interface.stop(instance_results['instances'][0]['id'])
322
+ list([])
323
+ rescue RestClient::Exception => e
324
+ if e.response.code == 400
325
+ error = JSON.parse(e.response.to_s)
326
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
327
+ else
328
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
329
+ end
330
+ return nil
331
+ end
332
+ end
333
+
334
+ def start(args)
335
+ if args.count < 1
336
+ puts "\nUsage: morpheus instances start [name]\n\n"
337
+ return
338
+ end
339
+ begin
340
+ instance_results = @instances_interface.get({name: args[0]})
341
+ if instance_results['instances'].empty?
342
+ puts "Instance not found by name #{args[0]}"
343
+ return
344
+ end
345
+ @instances_interface.start(instance_results['instances'][0]['id'])
346
+ list([])
347
+ rescue RestClient::Exception => e
348
+ if e.response.code == 400
349
+ error = JSON.parse(e.response.to_s)
350
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
351
+ else
352
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
353
+ end
354
+ return nil
355
+ end
356
+ end
357
+
358
+ def restart(args)
359
+ if args.count < 1
360
+ puts "\nUsage: morpheus instances restart [name]\n\n"
361
+ return
362
+ end
363
+ begin
364
+ instance_results = @instances_interface.get({name: args[0]})
365
+ if instance_results['instances'].empty?
366
+ puts "Instance not found by name #{args[0]}"
367
+ return
368
+ end
369
+ @instances_interface.restart(instance_results['instances'][0]['id'])
370
+ list([])
371
+ rescue RestClient::Exception => e
372
+ if e.response.code == 400
373
+ error = JSON.parse(e.response.to_s)
374
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
375
+ else
376
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
377
+ end
378
+ return nil
379
+ end
380
+ end
381
+
382
+ def list(args)
383
+ options = {}
384
+ optparse = OptionParser.new do|opts|
385
+ opts.on( '-g', '--group GROUP', "Group Name" ) do |group|
386
+ options[:group] = group
387
+ end
388
+ end
389
+ optparse.parse(args)
390
+ begin
391
+ params = {}
392
+ if !options[:group].nil?
393
+ group = find_group_by_name(options[:group])
394
+ if !group.nil?
395
+ params['site'] = group['id']
396
+ end
397
+ end
398
+
399
+ json_response = @instances_interface.get(params)
400
+ instances = json_response['instances']
401
+ print "\n" ,cyan, bold, "Morpheus Instances\n","==================", reset, "\n\n"
402
+ if instances.empty?
403
+ puts yellow,"No instances currently configured.",reset
404
+ else
405
+ instances.each do |instance|
406
+ print cyan, "= #{instance['name']} (#{instance['instanceType']['name']}) - #{instance['status']['name']}\n"
407
+ end
408
+ end
409
+ print reset,"\n\n"
410
+
411
+ rescue => e
412
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
413
+ return nil
414
+ end
415
+ end
416
+
417
+ def remove(args)
418
+ if args.count < 1
419
+ puts "\nUsage: morpheus instances remove [name]\n\n"
420
+ return
421
+ end
422
+ begin
423
+ instance_results = @instances_interface.get({name: args[0]})
424
+ if instance_results['instances'].empty?
425
+ puts "Instance not found by name #{args[0]}"
426
+ return
427
+ end
428
+ @instances_interface.destroy(instance_results['instances'][0]['id'])
429
+ list([])
430
+ rescue RestClient::Exception => e
431
+ if e.response.code == 400
432
+ error = JSON.parse(e.response.to_s)
433
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
434
+ else
435
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
436
+ end
437
+ return nil
438
+ end
439
+ end
440
+
441
+ private
442
+ def find_group_by_name(name)
443
+ group_results = @groups_interface.get(name)
444
+ if group_results['groups'].empty?
445
+ puts "Group not found by name #{name}"
446
+ return nil
447
+ end
448
+ return group_results['groups'][0]
449
+ end
450
+
451
+ def find_instance_type_by_code(code)
452
+ instance_type_results = @instance_types_interface.get({code: code})
453
+ if instance_type_results['instanceTypes'].empty?
454
+ puts "Instance Type not found by code #{code}"
455
+ return nil
456
+ end
457
+ return instance_type_results['instanceTypes'][0]
458
+ end
459
+ end
@@ -0,0 +1,163 @@
1
+ require 'yaml'
2
+ require 'io/console'
3
+ require 'rest_client'
4
+ require 'term/ansicolor'
5
+ require 'optparse'
6
+
7
+
8
+ class Morpheus::Cli::Remote
9
+ include Term::ANSIColor
10
+ def initialize()
11
+ @appliances = ::Morpheus::Cli::Remote.load_appliance_file
12
+ end
13
+
14
+ def handle(args)
15
+ if args.empty?
16
+ puts "\nUsage: morpheus remote [list,add,remove,use] [name] [host]\n\n"
17
+ end
18
+
19
+ case args[0]
20
+ when 'list'
21
+ list(args[1..-1])
22
+ when 'add'
23
+ add(args[1..-1])
24
+ when 'remove'
25
+ remove(args[1..-1])
26
+ when 'use'
27
+ use(args[1..-1])
28
+ else
29
+ puts "\nUsage: morpheus remote [list,add,remove,use] [name] [host]\n\n"
30
+ end
31
+ end
32
+
33
+ def list(args)
34
+ print "\n" ,cyan, bold, "Morpheus Appliances\n","==================", reset, "\n\n"
35
+ # print red, bold, "red bold", reset, "\n"
36
+ if @appliances == nil || @appliances.empty?
37
+ else
38
+ end
39
+ @appliances.each do |app_name, v|
40
+ print cyan
41
+ if v[:active] == true
42
+ print bold, "=> #{app_name}\t#{v[:host]}",reset,"\n"
43
+ else
44
+ print "= #{app_name}\t#{v[:host]}",reset,"\n"
45
+ end
46
+ end
47
+ print "\n\n# => - current\n\n"
48
+ end
49
+
50
+ def add(args)
51
+ if args.count < 2
52
+ puts "\nUsage: morpheus remote add [name] [host] [--default]\n\n"
53
+ return
54
+ end
55
+ params = {}
56
+ optparse = OptionParser.new do|opts|
57
+ params[:default] = false
58
+ opts.on( '-d', '--default', "Default has been set" ) do
59
+ params[:default] = true
60
+ end
61
+ end
62
+ optparse.parse(args)
63
+
64
+ name = args[0].to_sym
65
+ if @appliances[name] != nil
66
+ print red, "Remote appliance already configured for #{args[0]}", reset, "\n"
67
+ else
68
+ @appliances[name] = {
69
+ host: args[1],
70
+ active: false
71
+ }
72
+ if params[:default] == true
73
+ set_active_appliance name
74
+ end
75
+ end
76
+ ::Morpheus::Cli::Remote.save_appliances(@appliances)
77
+ list([])
78
+ end
79
+
80
+ def remove(args)
81
+ if args.empty?
82
+ puts "\nUsage: morpheus remote remove [name]\n\n"
83
+ return
84
+ end
85
+ name = args[0].to_sym
86
+ if @appliances[name] == nil
87
+ print red, "Remote appliance not configured for #{args[0]}", reset, "\n"
88
+ else
89
+ active = false
90
+ if @appliances[name][:active]
91
+ active = true
92
+ end
93
+ @appliances.delete(name)
94
+ if active && !@appliances.empty?
95
+ @appliances[@appliances.keys.first][:active] = true
96
+ end
97
+ end
98
+ ::Morpheus::Cli::Remote.save_appliances(@appliances)
99
+ list([])
100
+ end
101
+
102
+ def use(args)
103
+ if args.empty?
104
+ puts "Usage: morpheus remote use [name]"
105
+ return
106
+ end
107
+ name = args[0].to_sym
108
+ if @appliances[name] == nil
109
+ print red, "Remote appliance not configured for #{args[0]}", reset, "\n"
110
+ else
111
+ set_active_appliance name
112
+ end
113
+ ::Morpheus::Cli::Remote.save_appliances(@appliances)
114
+ list([])
115
+ end
116
+
117
+ def set_active_appliance(name)
118
+ @appliances.each do |k,v|
119
+ if k == name
120
+ v[:active] = true
121
+ else
122
+ v[:active] = false
123
+ end
124
+ end
125
+ end
126
+
127
+ # Provides the current active appliance url information
128
+ def self.active_appliance
129
+ if !defined?(@@appliance)
130
+ @@appliance = load_appliance_file.select { |k,v| v[:active] == true}
131
+ end
132
+ return @@appliance.keys[0], @@appliance[@@appliance.keys[0]][:host]
133
+ end
134
+
135
+
136
+
137
+ def self.load_appliance_file
138
+ remote_file = appliances_file_path
139
+ if File.exist? remote_file
140
+ return YAML.load_file(remote_file)
141
+ else
142
+ return {
143
+ morpheus: {
144
+ host: 'https://api.gomorpheus.com',
145
+ active: true
146
+ }
147
+ }
148
+ end
149
+ end
150
+
151
+ def self.appliances_file_path
152
+ home_dir = Dir.home
153
+ morpheus_dir = File.join(home_dir,".morpheus")
154
+ if !Dir.exist?(morpheus_dir)
155
+ Dir.mkdir(morpheus_dir)
156
+ end
157
+ return File.join(morpheus_dir,"appliances")
158
+ end
159
+
160
+ def self.save_appliances(appliance_map)
161
+ File.open(appliances_file_path, 'w') {|f| f.write appliance_map.to_yaml } #Store
162
+ end
163
+ end