morpheus-cli 0.0.1

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.
@@ -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