morpheus-cli 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e66add7b4d8599a88bb70d080e22aa749f938160
4
- data.tar.gz: 3d9a5ef82ef5328e8540c389d758b276c6d9096e
3
+ metadata.gz: ec2a0c7f7c355d73f29610ee9ce39ba75a8aa2ef
4
+ data.tar.gz: 5459548b4682698ffdd9def0761c1f9c0afb0d3d
5
5
  SHA512:
6
- metadata.gz: e07a7987235f1e2ec370919a792dd2de3415b1d34089ad2f9db63f7217346b1d2514fe12b5e8095736515c243eb373d99a855eee1d00fda02eb787815401910b
7
- data.tar.gz: a18fcee3f5ec31fb9e02f32360442aebc2745cdc810774a0459cc0074ec7f5925cd92b8116cdc89ed7026e41cc0120820b4775fbcc5639ece5d91e98cf6f0a99
6
+ metadata.gz: 37f0bf316ee216eb9b0a1709f9eef19ee9f08029cc7675dc088112ee05a369f554ef9ffd80341ad95589eae987de06868f235176a19de95cccc1478adcd5f8a8
7
+ data.tar.gz: 6e7c76c946b1cd791b24fe036c63ca0dfb271bda465a166ede5e9c7a4889653eeb59d655ff9c04d4f3638548475b703be71a845815b0b9d617332bb76c93e52f
data/bin/morpheus CHANGED
@@ -19,6 +19,18 @@ case ARGV[0]
19
19
  Morpheus::Cli::Instances.new().handle(ARGV[1..-1])
20
20
  when 'instance-types'
21
21
  Morpheus::Cli::InstanceTypes.new().handle(ARGV[1..-1])
22
+ when 'apps'
23
+ Morpheus::Cli::Apps.new().handle(ARGV[1..-1])
24
+ when 'deploy'
25
+ Morpheus::Cli::Deploys.new().handle(ARGV[1..-1])
26
+ when 'logout'
27
+ appliance_name, appliance_url = Morpheus::Cli::Remote.active_appliance
28
+ creds = Morpheus::Cli::Credentials.new(appliance_name,appliance_url).load_saved_credentials()
29
+ if !creds
30
+ puts "\nYou are not logged in.\n"
31
+ else
32
+ Morpheus::Cli::Credentials.new(appliance_name,appliance_url).logout()
33
+ end
22
34
  else
23
35
  puts "\nUsage: morpheus [command] [options]\n"
24
36
  end
@@ -30,4 +30,12 @@ class Morpheus::APIClient
30
30
  def instance_types
31
31
  Morpheus::InstanceTypesInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
32
32
  end
33
+
34
+ def apps
35
+ Morpheus::AppsInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
36
+ end
37
+
38
+ def deploy
39
+ Morpheus::DeployInterface.new(@access_token, @refresh_token, @expires_at, @base_url)
40
+ end
33
41
  end
@@ -0,0 +1,98 @@
1
+ require 'json'
2
+ require 'rest-client'
3
+
4
+ class Morpheus::AppsInterface < Morpheus::APIClient
5
+ def initialize(access_token, refresh_token,expires_at = nil, base_url=nil)
6
+ @access_token = access_token
7
+ @refresh_token = refresh_token
8
+ @base_url = base_url
9
+ @expires_at = expires_at
10
+ end
11
+
12
+
13
+ def get(options=nil)
14
+ url = "#{@base_url}/api/apps"
15
+ headers = { params: {}, authorization: "Bearer #{@access_token}" }
16
+
17
+ if options.is_a?(Hash)
18
+ headers[:params].merge!(options)
19
+ elsif options.is_a?(Numeric)
20
+ url = "#{@base_url}/api/apps/#{options}"
21
+ elsif options.is_a?(String)
22
+ headers[:params]['name'] = options
23
+ end
24
+ response = RestClient::Request.execute(method: :get, url: url,
25
+ timeout: 10, headers: headers)
26
+ JSON.parse(response.to_s)
27
+ end
28
+
29
+ def get_envs(id, options=nil)
30
+ url = "#{@base_url}/api/apps/#{id}/envs"
31
+ headers = { params: {}, authorization: "Bearer #{@access_token}" }
32
+ response = RestClient::Request.execute(method: :get, url: url,
33
+ timeout: 10, headers: headers)
34
+ JSON.parse(response.to_s)
35
+ end
36
+
37
+ def create_env(id, options)
38
+ url = "#{@base_url}/api/apps/#{id}/envs"
39
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
40
+
41
+ payload = {envs: options}
42
+ response = RestClient::Request.execute(method: :post, url: url,
43
+ timeout: 10, headers: headers, payload: payload.to_json)
44
+ JSON.parse(response.to_s)
45
+ end
46
+
47
+ def del_env(id, name)
48
+ url = "#{@base_url}/api/apps/#{id}/envs/#{name}"
49
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
50
+
51
+ response = RestClient::Request.execute(method: :delete, url: url,
52
+ timeout: 10, headers: headers)
53
+ JSON.parse(response.to_s)
54
+ end
55
+
56
+
57
+ def create(options)
58
+ url = "#{@base_url}/api/apps"
59
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
60
+
61
+ payload = options
62
+ response = RestClient::Request.execute(method: :post, url: url,
63
+ timeout: 10, headers: headers, payload: payload.to_json)
64
+ JSON.parse(response.to_s)
65
+ end
66
+
67
+ def destroy(id)
68
+ url = "#{@base_url}/api/apps/#{id}"
69
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
70
+ response = RestClient::Request.execute(method: :delete, url: url,
71
+ timeout: 10, headers: headers)
72
+ JSON.parse(response.to_s)
73
+ end
74
+
75
+ def stop(id)
76
+ url = "#{@base_url}/api/apps/#{id}/stop"
77
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
78
+ response = RestClient::Request.execute(method: :put, url: url,
79
+ timeout: 10, headers: headers)
80
+ JSON.parse(response.to_s)
81
+ end
82
+
83
+ def start(id)
84
+ url = "#{@base_url}/api/apps/#{id}/start"
85
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
86
+ response = RestClient::Request.execute(method: :put, url: url,
87
+ timeout: 10, headers: headers)
88
+ JSON.parse(response.to_s)
89
+ end
90
+
91
+ def restart(id)
92
+ url = "#{@base_url}/api/apps/#{id}/restart"
93
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
94
+ response = RestClient::Request.execute(method: :put, url: url,
95
+ timeout: 10, headers: headers)
96
+ JSON.parse(response.to_s)
97
+ end
98
+ end
@@ -0,0 +1,89 @@
1
+ require 'json'
2
+ require 'rest-client'
3
+
4
+ class Morpheus::DeployInterface < Morpheus::APIClient
5
+ def initialize(access_token, refresh_token,expires_at = nil, base_url=nil)
6
+ @access_token = access_token
7
+ @refresh_token = refresh_token
8
+ @base_url = base_url
9
+ @expires_at = expires_at
10
+ end
11
+
12
+
13
+ def get(instanceId, options=nil)
14
+ url = "#{@base_url}/api/instances/#{instanceId}/deploy"
15
+ headers = { params: {}, authorization: "Bearer #{@access_token}" }
16
+
17
+ if options.is_a?(Hash)
18
+ headers[:params].merge!(options)
19
+ elsif options.is_a?(String)
20
+ headers[:params]['name'] = options
21
+ end
22
+ response = RestClient::Request.execute(method: :get, url: url,
23
+ timeout: 10, headers: headers)
24
+ JSON.parse(response.to_s)
25
+ end
26
+
27
+
28
+ def create(instanceId, options=nil)
29
+ url = "#{@base_url}/api/instances/#{instanceId}/deploy"
30
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
31
+
32
+ payload = options || {}
33
+ response = RestClient::Request.execute(method: :post, url: url,
34
+ timeout: 10, headers: headers, payload: payload.to_json)
35
+ JSON.parse(response.to_s)
36
+ end
37
+
38
+ def list_files(id)
39
+ url = "#{@base_url}/api/deploy/#{id}/files"
40
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
41
+
42
+ payload = options
43
+ response = RestClient::Request.execute(method: :get, url: url,
44
+ timeout: 10, headers: headers)
45
+ JSON.parse(response.to_s)
46
+ end
47
+
48
+ def upload_file(id,path,destination=nil)
49
+ url = "#{@base_url}/api/deploy/#{id}/files"
50
+ if !destination.empty?
51
+ url += "/#{destination}"
52
+ end
53
+
54
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
55
+
56
+ payload = nil
57
+ # TODO: Setup payload to be contents of file appropriately
58
+ response = RestClient::Request.execute(
59
+ method: :post,
60
+ url: url,
61
+ headers: headers,
62
+ payload: {
63
+ multipart: true,
64
+ file: File.new(path, 'rb')
65
+ })
66
+ JSON.parse(response.to_s)
67
+ end
68
+
69
+ def destroy(id)
70
+ url = "#{@base_url}/api/deploy/#{id}"
71
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
72
+ response = RestClient::Request.execute(method: :delete, url: url,
73
+ timeout: 10, headers: headers)
74
+ JSON.parse(response.to_s)
75
+ end
76
+
77
+ def deploy(id, options)
78
+ url = "#{@base_url}/api/deploy/#{id}/deploy"
79
+ payload = options
80
+ if !options[:appDeploy].nil?
81
+ if !options[:appDeploy][:config].nil?
82
+ options[:appDeploy][:config] = options[:appDeploy][:config].to_json
83
+ end
84
+ end
85
+ headers = { :authorization => "Bearer #{@access_token}", 'Content-Type' => 'application/json' }
86
+ response = RestClient::Request.execute(method: :post, url: url, headers: headers, payload: payload.to_json)
87
+ JSON.parse(response.to_s)
88
+ end
89
+ end
data/lib/morpheus/cli.rb CHANGED
@@ -8,6 +8,8 @@ module Morpheus
8
8
  require 'morpheus/api/servers_interface'
9
9
  require 'morpheus/api/instances_interface'
10
10
  require 'morpheus/api/instance_types_interface'
11
+ require 'morpheus/api/apps_interface'
12
+ require 'morpheus/api/deploy_interface'
11
13
  require 'morpheus/cli/credentials'
12
14
  require 'morpheus/cli/error_handler'
13
15
  require 'morpheus/cli/remote'
@@ -15,6 +17,8 @@ module Morpheus
15
17
  require 'morpheus/cli/zones'
16
18
  require 'morpheus/cli/servers'
17
19
  require 'morpheus/cli/instances'
20
+ require 'morpheus/cli/apps'
21
+ require 'morpheus/cli/deploys'
18
22
  require 'morpheus/cli/instance_types'
19
23
  # Your code goes here...
20
24
  end
@@ -0,0 +1,454 @@
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::Apps
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
+ @apps_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).apps
15
+ @instance_types_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).instance_types
16
+ @apps_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).apps
17
+ @groups_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).groups
18
+ @active_groups = ::Morpheus::Cli::Groups.load_group_file
19
+ end
20
+
21
+
22
+ def handle(args)
23
+ if @access_token.empty?
24
+ print red,bold, "\nInvalid Credentials. Unable to acquire access token. Please verify your credentials and try again.\n\n",reset
25
+ return 1
26
+ end
27
+ if args.empty?
28
+ puts "\nUsage: morpheus apps [list,add,remove,stop,start,restart,resize,upgrade,clone,envs,setenv,delenv] [name]\n\n"
29
+ end
30
+
31
+ case args[0]
32
+ when 'list'
33
+ list(args[1..-1])
34
+ when 'add'
35
+ add(args[1..-1])
36
+ when 'remove'
37
+ remove(args[1..-1])
38
+ when 'stop'
39
+ stop(args[1..-1])
40
+ when 'start'
41
+ start(args[1..-1])
42
+ when 'restart'
43
+ restart(args[1..-1])
44
+ when 'stats'
45
+ stats(args[1..-1])
46
+ when 'details'
47
+ details(args[1..-1])
48
+ when 'envs'
49
+ envs(args[1..-1])
50
+ when 'setenv'
51
+ setenv(args[1..-1])
52
+ when 'delenv'
53
+ delenv(args[1..-1])
54
+ else
55
+ puts "\nUsage: morpheus apps [list,add,remove,stop,start,restart,resize,upgrade,clone,envs,setenv,delenv] [name]\n\n"
56
+ end
57
+ end
58
+
59
+ def add(args)
60
+ if args.count < 2
61
+ puts "\nUsage: morpheus apps add NAME TYPE\n\n"
62
+ return
63
+ end
64
+
65
+ app_name = args[0]
66
+ instance_type_code = args[1]
67
+ instance_type = find_instance_type_by_code(instance_type_code)
68
+ if instance_type.nil?
69
+ print reset,"\n\n"
70
+ return
71
+ end
72
+
73
+ groupId = @active_groups[@appliance_name.to_sym]
74
+
75
+ options = {
76
+ :servicePlan => nil,
77
+ :app => {
78
+ :name => app_name,
79
+ :site => {
80
+ :id => groupId
81
+ },
82
+ :appType => {
83
+ :code => instance_type_code
84
+ }
85
+ }
86
+ }
87
+
88
+ instance_type['appTypeLayouts'].sort! { |x,y| y['sortOrder'] <=> x['sortOrder'] }
89
+ puts "Configurations: "
90
+ instance_type['appTypeLayouts'].each_with_index do |layout, index|
91
+ puts " #{index+1}) #{layout['name']} (#{layout['code']})"
92
+ end
93
+ print "Selection: "
94
+ layout_selection = nil
95
+ layout = nil
96
+ while true do
97
+ layout_selection = $stdin.gets.chomp!
98
+ if layout_selection.to_i.to_s == layout_selection
99
+ layout_selection = layout_selection.to_i
100
+ break
101
+ end
102
+ end
103
+ layout = instance_type['appTypeLayouts'][layout_selection-1]['id']
104
+ options[:app][:layout] = {id: layout}
105
+ print "\n"
106
+ if options[:servicePlan].nil?
107
+ plans = @instance_types_interface.service_plans(layout)
108
+ puts "Select a Plan: "
109
+ plans['servicePlans'].each_with_index do |plan, index|
110
+ puts " #{index+1}) #{plan['name']}"
111
+ end
112
+ print "Selection: "
113
+ plan_selection = nil
114
+ while true do
115
+ plan_selection = $stdin.gets.chomp!
116
+ if plan_selection.to_i.to_s == plan_selection
117
+ plan_selection = plan_selection.to_i
118
+ break
119
+ end
120
+ end
121
+ options[:servicePlan] = plans['servicePlans'][plan_selection-1]['id']
122
+ print "\n"
123
+ end
124
+
125
+ if !instance_type['config'].nil?
126
+ instance_type_config = JSON.parse(instance_type['config'])
127
+ if instance_type_config['options'].nil? == false
128
+ instance_type_config['options'].each do |opt|
129
+ print "#{opt['label']}: "
130
+ if(opt['name'].downcase.include?("password"))
131
+ options[opt['name']] = STDIN.noecho(&:gets).chomp!
132
+ print "\n"
133
+ else
134
+ options[opt['name']] = $stdin.gets.chomp!
135
+ end
136
+
137
+ end
138
+ end
139
+ end
140
+ begin
141
+ @apps_interface.create(options)
142
+ rescue => e
143
+ if e.response.code == 400
144
+ error = JSON.parse(e.response.to_s)
145
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
146
+ else
147
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
148
+ end
149
+ return nil
150
+ end
151
+ list([])
152
+ end
153
+
154
+ def stats(args)
155
+ if args.count < 1
156
+ puts "\nUsage: morpheus apps stats [name]\n\n"
157
+ return
158
+ end
159
+ begin
160
+ app_results = @apps_interface.get({name: args[0]})
161
+ if app_results['apps'].empty?
162
+ puts "Instance not found by name #{args[0]}"
163
+ return
164
+ end
165
+ app = app_results['apps'][0]
166
+ app_id = app['id']
167
+ stats = app_results['stats'][app_id.to_s]
168
+ print "\n" ,cyan, bold, "#{app['name']} (#{app['appType']['name']})\n","==================", reset, "\n\n"
169
+ print cyan, "Memory: \t#{Filesize.from("#{stats['usedMemory']} B").pretty} / #{Filesize.from("#{stats['maxMemory']} B").pretty}\n"
170
+ print cyan, "Storage: \t#{Filesize.from("#{stats['usedStorage']} B").pretty} / #{Filesize.from("#{stats['maxStorage']} B").pretty}\n\n",reset
171
+ puts
172
+ rescue RestClient::Exception => e
173
+ if e.response.code == 400
174
+ error = JSON.parse(e.response.to_s)
175
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
176
+ else
177
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
178
+ end
179
+ return nil
180
+ end
181
+ end
182
+
183
+ def details(args)
184
+ if args.count < 1
185
+ puts "\nUsage: morpheus apps stats [name]\n\n"
186
+ return
187
+ end
188
+ begin
189
+ app_results = @apps_interface.get({name: args[0]})
190
+ if app_results['apps'].empty?
191
+ puts "Instance not found by name #{args[0]}"
192
+ return
193
+ end
194
+ app = app_results['apps'][0]
195
+ app_id = app['id']
196
+ stats = app_results['stats'][app_id.to_s]
197
+ print "\n" ,cyan, bold, "#{app['name']} (#{app['appType']['name']})\n","==================", reset, "\n\n"
198
+ print cyan, "Memory: \t#{Filesize.from("#{stats['usedMemory']} B").pretty} / #{Filesize.from("#{stats['maxMemory']} B").pretty}\n"
199
+ print cyan, "Storage: \t#{Filesize.from("#{stats['usedStorage']} B").pretty} / #{Filesize.from("#{stats['maxStorage']} B").pretty}\n\n",reset
200
+ puts app
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
+ return nil
209
+ end
210
+ end
211
+
212
+ def envs(args)
213
+ if args.count < 1
214
+ puts "\nUsage: morpheus apps envs [name]\n\n"
215
+ return
216
+ end
217
+ begin
218
+ app_results = @apps_interface.get({name: args[0]})
219
+ if app_results['apps'].empty?
220
+ puts "Instance not found by name #{args[0]}"
221
+ return
222
+ end
223
+ app = app_results['apps'][0]
224
+ app_id = app['id']
225
+ env_results = @apps_interface.get_envs(app_id)
226
+ print "\n" ,cyan, bold, "#{app['name']} (#{app['appType']['name']})\n","==================", "\n\n", reset, cyan
227
+ envs = env_results['envs'] || {}
228
+ if env_results['readOnlyEnvs']
229
+ envs += env_results['readOnlyEnvs'].map { |k,v| {:name => k, :value => k.downcase.include?("password") ? "********" : v, :export => true}}
230
+ end
231
+ tp envs, :name, :value, :export
232
+ print "\n" ,cyan, bold, "Importad Envs\n","==================", "\n\n", reset, cyan
233
+ imported_envs = env_results['importedEnvs'].map { |k,v| {:name => k, :value => k.downcase.include?("password") ? "********" : v}}
234
+ tp imported_envs
235
+ print reset, "\n"
236
+
237
+ rescue RestClient::Exception => e
238
+ if e.response.code == 400
239
+ error = JSON.parse(e.response.to_s)
240
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
241
+ else
242
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
243
+ end
244
+ return nil
245
+ end
246
+ end
247
+
248
+ def setenv(args)
249
+ if args.count < 3
250
+ puts "\nUsage: morpheus apps setenv INSTANCE NAME VALUE [-e]\n\n"
251
+ return
252
+ end
253
+ begin
254
+ app_results = @apps_interface.get({name: args[0]})
255
+ if app_results['apps'].empty?
256
+ puts "Instance not found by name #{args[0]}"
257
+ return
258
+ end
259
+ app = app_results['apps'][0]
260
+ app_id = app['id']
261
+ evar = {name: args[1], value: args[2], export: false}
262
+ params = {}
263
+ optparse = OptionParser.new do|opts|
264
+ opts.on( '-e', "Exportable" ) do |exportable|
265
+ evar[:export] = exportable
266
+ end
267
+ end
268
+ optparse.parse(args)
269
+
270
+ @apps_interface.create_env(app_id, [evar])
271
+ envs([args[0]])
272
+ rescue RestClient::Exception => e
273
+ if e.response.code == 400
274
+ error = JSON.parse(e.response.to_s)
275
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
276
+ else
277
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
278
+ end
279
+ return nil
280
+ end
281
+ end
282
+
283
+ def delenv(args)
284
+ if args.count < 2
285
+ puts "\nUsage: morpheus apps setenv INSTANCE NAME\n\n"
286
+ return
287
+ end
288
+ begin
289
+ app_results = @apps_interface.get({name: args[0]})
290
+ if app_results['apps'].empty?
291
+ puts "Instance not found by name #{args[0]}"
292
+ return
293
+ end
294
+ app = app_results['apps'][0]
295
+ app_id = app['id']
296
+ name = args[1]
297
+
298
+ @apps_interface.del_env(app_id, name)
299
+ envs([args[0]])
300
+ rescue RestClient::Exception => e
301
+ if e.response.code == 400
302
+ error = JSON.parse(e.response.to_s)
303
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
304
+ else
305
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
306
+ end
307
+ return nil
308
+ end
309
+ end
310
+
311
+ def stop(args)
312
+ if args.count < 1
313
+ puts "\nUsage: morpheus apps stop [name]\n\n"
314
+ return
315
+ end
316
+ begin
317
+ app_results = @apps_interface.get({name: args[0]})
318
+ if app_results['apps'].empty?
319
+ puts "Instance not found by name #{args[0]}"
320
+ return
321
+ end
322
+ @apps_interface.stop(app_results['apps'][0]['id'])
323
+ list([])
324
+ rescue RestClient::Exception => e
325
+ if e.response.code == 400
326
+ error = JSON.parse(e.response.to_s)
327
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
328
+ else
329
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
330
+ end
331
+ return nil
332
+ end
333
+ end
334
+
335
+ def start(args)
336
+ if args.count < 1
337
+ puts "\nUsage: morpheus apps start [name]\n\n"
338
+ return
339
+ end
340
+ begin
341
+ app_results = @apps_interface.get({name: args[0]})
342
+ if app_results['apps'].empty?
343
+ puts "Instance not found by name #{args[0]}"
344
+ return
345
+ end
346
+ @apps_interface.start(app_results['apps'][0]['id'])
347
+ list([])
348
+ rescue RestClient::Exception => e
349
+ if e.response.code == 400
350
+ error = JSON.parse(e.response.to_s)
351
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
352
+ else
353
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
354
+ end
355
+ return nil
356
+ end
357
+ end
358
+
359
+ def restart(args)
360
+ if args.count < 1
361
+ puts "\nUsage: morpheus apps restart [name]\n\n"
362
+ return
363
+ end
364
+ begin
365
+ app_results = @apps_interface.get({name: args[0]})
366
+ if app_results['apps'].empty?
367
+ puts "Instance not found by name #{args[0]}"
368
+ return
369
+ end
370
+ @apps_interface.restart(app_results['apps'][0]['id'])
371
+ list([])
372
+ rescue RestClient::Exception => e
373
+ if e.response.code == 400
374
+ error = JSON.parse(e.response.to_s)
375
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
376
+ else
377
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
378
+ end
379
+ return nil
380
+ end
381
+ end
382
+
383
+ def list(args)
384
+ options = {}
385
+ optparse = OptionParser.new do|opts|
386
+ opts.on( '-g', '--group GROUP', "Group Name" ) do |group|
387
+ options[:group] = group
388
+ end
389
+ end
390
+ optparse.parse(args)
391
+ begin
392
+ params = {}
393
+
394
+ json_response = @apps_interface.get(params)
395
+ apps = json_response['apps']
396
+ print "\n" ,cyan, bold, "Morpheus Instances\n","==================", reset, "\n\n"
397
+ if apps.empty?
398
+ puts yellow,"No apps currently configured.",reset
399
+ else
400
+ apps.each do |app|
401
+ print cyan, "= #{app['name']} (#{app['appType']['name']}) - #{app['status']['name']}\n"
402
+ end
403
+ end
404
+ print reset,"\n\n"
405
+
406
+ rescue => e
407
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
408
+ return nil
409
+ end
410
+ end
411
+
412
+ def remove(args)
413
+ if args.count < 1
414
+ puts "\nUsage: morpheus apps remove [name]\n\n"
415
+ return
416
+ end
417
+ begin
418
+ app_results = @apps_interface.get({name: args[0]})
419
+ if app_results['apps'].empty?
420
+ puts "Instance not found by name #{args[0]}"
421
+ return
422
+ end
423
+ @apps_interface.destroy(app_results['apps'][0]['id'])
424
+ list([])
425
+ rescue RestClient::Exception => e
426
+ if e.response.code == 400
427
+ error = JSON.parse(e.response.to_s)
428
+ ::Morpheus::Cli::ErrorHandler.new.print_errors(error)
429
+ else
430
+ puts "Error Communicating with the Appliance. Please try again later. #{e}"
431
+ end
432
+ return nil
433
+ end
434
+ end
435
+
436
+ private
437
+ def find_group_by_name(name)
438
+ group_results = @groups_interface.get(name)
439
+ if group_results['groups'].empty?
440
+ puts "Group not found by name #{name}"
441
+ return nil
442
+ end
443
+ return group_results['groups'][0]
444
+ end
445
+
446
+ def find_instance_type_by_code(code)
447
+ instance_type_results = @instance_types_interface.get({code: code})
448
+ if instance_type_results['appTypes'].empty?
449
+ puts "Instance Type not found by code #{code}"
450
+ return nil
451
+ end
452
+ return instance_type_results['appTypes'][0]
453
+ end
454
+ end
@@ -46,6 +46,9 @@ module Morpheus
46
46
  request_credentials
47
47
  end
48
48
 
49
+ def logout()
50
+ clear_saved_credentials
51
+ end
49
52
 
50
53
  def clear_saved_credentials()
51
54
  credential_map = load_credential_file
@@ -0,0 +1,145 @@
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::Deploys
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
+ @deploy_interface = Morpheus::APIClient.new(@access_token,nil,nil, @appliance_url).deploy
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
+ def handle(args)
21
+ if @access_token.empty?
22
+ print red,bold, "\nInvalid Credentials. Unable to acquire access token. Please verify your credentials and try again.\n\n",reset
23
+ return 1
24
+ end
25
+
26
+ deploy(args)
27
+ end
28
+
29
+ def deploy(args)
30
+ environment = 'production'
31
+ if args.count > 0
32
+ environment = args[0]
33
+ end
34
+ if load_deploy_file().nil?
35
+ puts "Morpheus Deploy File `morpheus.yml` not detected. Please create one and try again."
36
+ return
37
+ end
38
+
39
+ deploy_args = merged_deploy_args(environment)
40
+ if deploy_args['name'].nil?
41
+ puts "Instance not specified. Please specify the instance name and try again."
42
+ return
43
+ end
44
+
45
+ instance_results = @instances_interface.get(name: deploy_args[:name])
46
+ if instance_results['instances'].empty?
47
+ puts "Instance not found by name #{args[0]}"
48
+ return
49
+ end
50
+ instance = instance_results['instances'][0]
51
+ instance_id = instance['id']
52
+ print "\n" ,cyan, bold, "Morpheus Deployment\n","==================", reset, "\n\n"
53
+
54
+ if !deploy_args['script'].nil?
55
+ print cyan, bold, " - Executing Pre Deploy Script...", reset, "\n"
56
+
57
+ if !system(deploy_args['script'])
58
+ puts "Error executing pre script..."
59
+ return
60
+ end
61
+ end
62
+ # Create a new deployment record
63
+ deploy_result = @deploy_interface.create(instance_id)
64
+ app_deploy = deploy_result['appDeploy']
65
+ deployment_id = app_deploy['id']
66
+
67
+ # Upload Files
68
+ print "\n",cyan, bold, "Uploading Files...", reset, "\n"
69
+ current_working_dir = Dir.pwd
70
+ deploy_args['files'].each do |fmap|
71
+ Dir.chdir(fmap['path'] || current_working_dir)
72
+ files = Dir.glob(fmap['pattern'] || '**/*')
73
+ files.each do |file|
74
+ if File.file?(file)
75
+ print cyan,bold, " - Uploading #{file} ...", reset, "\n"
76
+ destination = file.split("/")[0..-2].join("/")
77
+ @deploy_interface.upload_file(deployment_id,file,destination)
78
+ end
79
+ end
80
+ end
81
+ print cyan, bold, "Upload Complete!", reset, "\n"
82
+ Dir.chdir(current_working_dir)
83
+
84
+ if !deploy_args['post_script'].nil?
85
+ print cyan, bold, "Executing Post Script...", reset, "\n"
86
+ if !system(deploy_args['post_script'])
87
+ puts "Error executing post script..."
88
+ return
89
+ end
90
+ end
91
+
92
+ deploy_payload = {}
93
+
94
+ if deploy_args['options']
95
+ deploy_payload = {
96
+ appDeploy: {
97
+ config: deploy_args['options']
98
+ }
99
+ }
100
+ end
101
+ print cyan, bold, "Deploying to Servers...", reset, "\n"
102
+ @deploy_interface.deploy(deployment_id,deploy_payload)
103
+ print cyan, bold, "Deploy Successful!", reset, "\n"
104
+ end
105
+
106
+ def list(args)
107
+ end
108
+
109
+ def rollback(args)
110
+ end
111
+
112
+ # Loads a morpheus.yml file from within the current working directory.
113
+ # This file contains information necessary in the project to perform a deployment via the cli
114
+ #
115
+ # === Example File Attributes
116
+ # * +script+ - The initial script to run before uploading files
117
+ # * +name+ - The instance name we are deploying to (can be overridden in CLI)
118
+ # * +remote+ - Optional remote appliance name we are connecting to
119
+ # * +files+ - List of file patterns to use for uploading files and their target destination
120
+ # * +options+ - Map of deployment options depending on deployment type
121
+ # * +post_script+ - A post operation script to be run on the local machine
122
+ # * +stage_deploy+ - If set to true the deploy will only be staged and not actually run
123
+ #
124
+ # +NOTE: + It is also possible to nest these properties in an "environments" map to override based on a passed environment deploy name
125
+ #
126
+ def load_deploy_file
127
+ if !File.exist? "morpheus.yml"
128
+ puts "No morheus.yml file detected in the current directory. Nothing to do."
129
+ return nil
130
+ end
131
+
132
+ @deploy_file = YAML.load_file("morpheus.yml")
133
+ return @deploy_file
134
+ end
135
+
136
+ def merged_deploy_args(environment)
137
+ environment = environment || production
138
+
139
+ deploy_args = @deploy_file.reject { |key,value| key == 'environment'}
140
+ if !@deploy_file['environment'].nil? && !@deploy_file['environment'][environment].nil?
141
+ deploy_args = deploy_args.merge(@deploy_file['environment'][environment])
142
+ end
143
+ return deploy_args
144
+ end
145
+ end
@@ -22,6 +22,7 @@ class Morpheus::Cli::Groups
22
22
  end
23
23
  if args.empty?
24
24
  puts "\nUsage: morpheus groups [list,add,remove] [name]\n\n"
25
+ return
25
26
  end
26
27
 
27
28
  case args[0]
@@ -23,6 +23,7 @@ class Morpheus::Cli::InstanceTypes
23
23
  end
24
24
  if args.empty?
25
25
  puts "\nUsage: morpheus instance-types [list,details] [name]\n\n"
26
+ return
26
27
  end
27
28
 
28
29
  case args[0]
@@ -25,6 +25,7 @@ class Morpheus::Cli::Instances
25
25
  end
26
26
  if args.empty?
27
27
  puts "\nUsage: morpheus instances [list,add,remove,stop,start,restart,resize,upgrade,clone,envs,setenv,delenv] [name]\n\n"
28
+ return
28
29
  end
29
30
 
30
31
  case args[0]
@@ -24,6 +24,7 @@ class Morpheus::Cli::Servers
24
24
  end
25
25
  if args.empty?
26
26
  puts "\nUsage: morpheus servers [list,add,remove] [name]\n\n"
27
+ return
27
28
  end
28
29
 
29
30
  case args[0]
@@ -1,5 +1,5 @@
1
1
  module Morpheus
2
2
  module Cli
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
  end
5
5
  end
@@ -22,6 +22,7 @@ class Morpheus::Cli::Zones
22
22
  end
23
23
  if args.empty?
24
24
  puts "\nUsage: morpheus zones [list,add,remove] [name]\n\n"
25
+ return
25
26
  end
26
27
 
27
28
  case args[0]
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: morpheus-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Estes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-17 00:00:00.000000000 Z
11
+ date: 2015-08-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -110,13 +110,17 @@ files:
110
110
  - Rakefile
111
111
  - bin/morpheus
112
112
  - lib/morpheus/api/api_client.rb
113
+ - lib/morpheus/api/apps_interface.rb
114
+ - lib/morpheus/api/deploy_interface.rb
113
115
  - lib/morpheus/api/groups_interface.rb
114
116
  - lib/morpheus/api/instance_types_interface.rb
115
117
  - lib/morpheus/api/instances_interface.rb
116
118
  - lib/morpheus/api/servers_interface.rb
117
119
  - lib/morpheus/api/zones_interface.rb
118
120
  - lib/morpheus/cli.rb
121
+ - lib/morpheus/cli/apps.rb
119
122
  - lib/morpheus/cli/credentials.rb
123
+ - lib/morpheus/cli/deploys.rb
120
124
  - lib/morpheus/cli/error_handler.rb
121
125
  - lib/morpheus/cli/groups.rb
122
126
  - lib/morpheus/cli/instance_types.rb