morpheus-cli 0.0.1 → 0.0.2

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