debox 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/.gitignore +20 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +15 -0
  4. data/LICENSE +22 -0
  5. data/README.md +29 -0
  6. data/Rakefile +2 -0
  7. data/bin/debox +15 -0
  8. data/debox.gemspec +23 -0
  9. data/lib/debox.rb +9 -0
  10. data/lib/debox/api.rb +261 -0
  11. data/lib/debox/cli.rb +111 -0
  12. data/lib/debox/command.rb +48 -0
  13. data/lib/debox/command/apps.rb +14 -0
  14. data/lib/debox/command/auth.rb +29 -0
  15. data/lib/debox/command/base.rb +57 -0
  16. data/lib/debox/command/cap.rb +16 -0
  17. data/lib/debox/command/deploy.rb +18 -0
  18. data/lib/debox/command/key.rb +20 -0
  19. data/lib/debox/command/live.rb +14 -0
  20. data/lib/debox/command/log.rb +17 -0
  21. data/lib/debox/command/login.rb +18 -0
  22. data/lib/debox/command/logs.rb +27 -0
  23. data/lib/debox/command/recipes.rb +65 -0
  24. data/lib/debox/config.rb +59 -0
  25. data/lib/debox/utils.rb +77 -0
  26. data/lib/debox/version.rb +3 -0
  27. data/spec/integration/api/api_key_spec.rb +20 -0
  28. data/spec/integration/api/apps_spec.rb +9 -0
  29. data/spec/integration/api/cap/cap_spec.rb +58 -0
  30. data/spec/integration/api/live/log_spec.rb +12 -0
  31. data/spec/integration/api/logs/index_spec.rb +54 -0
  32. data/spec/integration/api/logs/show_spec.rb +27 -0
  33. data/spec/integration/api/public_key_spec.rb +15 -0
  34. data/spec/integration/api/recipes/create_spec.rb +10 -0
  35. data/spec/integration/api/recipes/destroy_spec.rb +14 -0
  36. data/spec/integration/api/recipes/index_spec.rb +17 -0
  37. data/spec/integration/api/recipes/new_spec.rb +10 -0
  38. data/spec/integration/api/recipes/show_spec.rb +10 -0
  39. data/spec/integration/api/recipes/update_spec.rb +11 -0
  40. data/spec/integration/api/users/create_spec.rb +8 -0
  41. data/spec/integration/api/users/delete_spec.rb +11 -0
  42. data/spec/integration/api/users/index_spec.rb +10 -0
  43. data/spec/integration/commands/apps_spec.rb +8 -0
  44. data/spec/integration/commands/cap_spec.rb +17 -0
  45. data/spec/integration/commands/key_spec.rb +24 -0
  46. data/spec/integration/commands/login_spec.rb +11 -0
  47. data/spec/integration/commands/logs/index_spec.rb +14 -0
  48. data/spec/integration/commands/logs/show_spec.rb +14 -0
  49. data/spec/integration/commands/recipes/delete_spec.rb +8 -0
  50. data/spec/integration/commands/recipes/edit_spec.rb +23 -0
  51. data/spec/integration/commands/recipes/index_spec.rb +8 -0
  52. data/spec/integration/commands/recipes/show_spec.rb +8 -0
  53. data/spec/spec_helper.rb +35 -0
  54. data/spec/support/herlpers.rb +43 -0
  55. metadata +209 -0
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *~
19
+ #*
20
+ .#*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source 'https://rubygems.org'
2
+ gem 'json'
3
+ gem 'netrc'
4
+ gem 'highline'
5
+ gem 'eventmachine'
6
+ gem 'em-eventsource'
7
+
8
+ # Specify your gem's dependencies in debox.gemspec
9
+ gemspec
10
+
11
+ group :test do
12
+ gem 'debox_server'
13
+ gem 'rspec'
14
+ gem 'thin'
15
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Eloy Gomez
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # Debox
2
+
3
+ Command line tool for Debox
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'debox'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install debox
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+
5
+ require "pathname"
6
+ bin_file = Pathname.new(__FILE__).realpath
7
+
8
+ # add self to libpath
9
+ $:.unshift File.expand_path("../../lib", bin_file)
10
+
11
+ # start up the CLI
12
+ require "debox"
13
+ require "debox/cli"
14
+
15
+ Debox::CLI.new(*ARGV).start
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/debox/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Eloy Gomez"]
6
+ gem.email = ["eloy@indeos.es"]
7
+ gem.description = "CLI for debox"
8
+ gem.summary = "Debox is a deploy manager"
9
+ gem.homepage = "https://github.com/harlock/debox"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "debox"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = Debox::VERSION
17
+
18
+ gem.add_runtime_dependency 'json'
19
+ gem.add_runtime_dependency 'netrc'
20
+ gem.add_runtime_dependency 'highline'
21
+ gem.add_runtime_dependency 'eventmachine'
22
+ gem.add_runtime_dependency 'em-eventsource'
23
+ end
@@ -0,0 +1,9 @@
1
+ require 'json'
2
+ require 'tempfile'
3
+ require 'digest/md5'
4
+ require "debox/version"
5
+ require "debox/config"
6
+ require "debox/command"
7
+
8
+ module Debox
9
+ end
@@ -0,0 +1,261 @@
1
+ require "net/http"
2
+ require 'base64'
3
+ require 'eventmachine'
4
+ require 'em-eventsource'
5
+
6
+ module Debox
7
+ module API
8
+
9
+ # Return the api_key for the user
10
+ # @params:
11
+ # :host
12
+ # :user
13
+ # :password
14
+ def self.api_key(opt)
15
+ get_raw '/v1/api_key', opt, skip_basic_auth: true
16
+ end
17
+
18
+ # apps
19
+ #----------------------------------------------------------------------
20
+ def self.apps
21
+ get '/v1/apps'
22
+ end
23
+
24
+ # users
25
+ #----------------------------------------------------------------------
26
+
27
+ # Create a new user
28
+ # @params:
29
+ # :host
30
+ # :user
31
+ # :password
32
+ def self.users_create(opt)
33
+ post_raw '/v1/users/create', user: opt[:user], password: opt[:password]
34
+ end
35
+
36
+ def self.users_delete(opt)
37
+ delete_raw '/v1/users/destroy', user: opt[:user]
38
+ end
39
+
40
+ # Return existing users
41
+ def self.users
42
+ get '/v1/users'
43
+ end
44
+
45
+ # recipes
46
+ #----------------------------------------------------------------------
47
+
48
+ def self.recipes(opt)
49
+ get("/v1/recipes/#{opt[:app]}")
50
+ end
51
+
52
+ def self.recipes_new(opt)
53
+ get_raw("/v1/recipes/#{opt[:app]}/#{opt[:env]}/new").body
54
+ end
55
+
56
+ def self.recipes_show(opt)
57
+ get_raw("/v1/recipes/#{opt[:app]}/#{opt[:env]}").body
58
+ end
59
+
60
+ def self.recipes_create(opt)
61
+ post_raw "/v1/recipes/#{opt[:app]}/#{opt[:env]}", content: opt[:content]
62
+ end
63
+
64
+ def self.recipes_update(opt)
65
+ put_raw "/v1/recipes/#{opt[:app]}/#{opt[:env]}", content: opt[:content]
66
+ end
67
+
68
+ def self.recipes_destroy(opt)
69
+ delete_raw("/v1/recipes/#{opt[:app]}/#{opt[:env]}")
70
+ end
71
+
72
+ # Cap
73
+ #----------------------------------------------------------------------
74
+
75
+ def self.cap(opt, &block)
76
+ path = "/v1/cap/#{opt[:app]}"
77
+ path += "/#{opt[:env]}" if opt[:env]
78
+ path += "?task=#{opt[:task]}" if opt[:task]
79
+ get(path)
80
+ end
81
+
82
+ # Public key
83
+ #----------------------------------------------------------------------
84
+
85
+ def self.public_key
86
+ get_raw('/v1/public_key').body
87
+ end
88
+
89
+ # logs
90
+ #----------------------------------------------------------------------
91
+
92
+ def self.live(opt, &block)
93
+ path = "/v1/live/log/#{opt[:app]}"
94
+ path += "/#{opt[:env]}" if opt[:env]
95
+
96
+ # stream path, nil, { }, block
97
+ eventSource path, { }, block
98
+ end
99
+
100
+ def self.logs(opt)
101
+ path = "/v1/logs/#{opt[:app]}"
102
+ path += "/#{opt[:env]}" if opt[:env]
103
+ get path
104
+ end
105
+
106
+ def self.log(opt)
107
+ path = "/v1/log/#{opt[:app]}"
108
+ path += "/#{opt[:env]}" if opt[:env]
109
+ path += "?index=#{opt[:index]}" if opt[:index]
110
+ get_raw(path).body
111
+ end
112
+
113
+ private
114
+
115
+ # HTTP helpers
116
+ #----------------------------------------------------------------------
117
+
118
+ def self.post_raw(path, request_params=nil, options={})
119
+ run_request :post, path, request_params, options
120
+ end
121
+
122
+ def self.post(path, request_params=nil, options={})
123
+ JSON.parse post_raw(path, request_params, options).body, symbolize_names: true
124
+ end
125
+
126
+ def self.get_raw(path, request_params=nil, options={})
127
+ run_request :get, path, request_params, options
128
+ end
129
+
130
+ def self.get(path, request_params=nil, options={})
131
+ JSON.parse get_raw(path, request_params, options).body, symbolize_names: true
132
+ end
133
+
134
+ def self.put_raw(path, request_params=nil, options={})
135
+ run_request :put, path, request_params, options
136
+ end
137
+
138
+ def self.put(path, request_params=nil, options={})
139
+ JSON.parse put_raw(path, request_params, options).body, symbolize_names: true
140
+ end
141
+
142
+ def self.delete_raw(path, request_params=nil, options={})
143
+ run_request :delete, path, request_params, options
144
+ end
145
+
146
+ def self.delete(path, request_params=nil, options={})
147
+ JSON.parse delete_raw(path, request_params, options).body, symbolize_names: true
148
+ end
149
+
150
+
151
+ # Create a new Net::HTTP request
152
+ def self.new_request(type, path, request_params=nil, options={})
153
+ if type == :post
154
+ request = Net::HTTP::Post.new(path)
155
+ elsif type == :put
156
+ request = Net::HTTP::Put.new(path)
157
+ elsif type == :get
158
+ request = Net::HTTP::Get.new(path)
159
+ elsif type == :delete
160
+ request = Net::HTTP::Delete.new(path)
161
+ else
162
+ error_and_exit "Invalid request type: #{type}"
163
+ end
164
+
165
+ request.set_form_data(request_params) if request_params
166
+
167
+ if !options[:skip_basic_auth] && Debox::Config.logged_in?
168
+ request.basic_auth Debox.config[:user], Debox.config[:api_key]
169
+ end
170
+ return request
171
+ end
172
+
173
+ def self.is_valid_response?(response)
174
+ !response.code.match(/^20/).nil?
175
+ end
176
+
177
+ def self.check_errors(response)
178
+ unauthorized_error if response.code == "401"
179
+ server_error if response.code == "500"
180
+ not_found_error if response.code == "404"
181
+ error_and_exit("#{response.code}: #{response.body}") unless is_valid_response? response
182
+ end
183
+
184
+ # Run request
185
+ def self.run_request(type, path, request_params=nil, options={})
186
+ request = new_request type, path, request_params, options
187
+ http = Net::HTTP.new Debox.config[:host], Debox.config[:port]
188
+ response = http.request(request)
189
+ # Process errors
190
+ check_errors response
191
+ return response
192
+ end
193
+
194
+ # Run request and read run block with the chunk
195
+ def self.stream(path, request_params=nil, options={ }, block)
196
+ request = new_request :get, path, request_params, options
197
+ http = http_connection
198
+ http.request(request) do | response|
199
+ check_errors response
200
+ response.read_body do |chunk|
201
+ block.call chunk
202
+ end
203
+ end
204
+ end
205
+
206
+
207
+ def self.eventSource(path, query={ }, block)
208
+ host = "http://#{Debox.config[:host]}:#{Debox.config[:port]}"
209
+ auth = [Debox.config[:user], Debox.config[:api_key]].join(':')
210
+ headers = { 'Authorization' => "Basic #{Base64.strict_encode64 auth}" }
211
+
212
+ EM.run do
213
+ source = EventMachine::EventSource.new("#{host}#{path}", query, headers )
214
+ source.message do |m|
215
+ block.call m
216
+ end
217
+
218
+ source.error do |error|
219
+ puts "ERROR: #{error}"
220
+ EM.stop
221
+ end
222
+
223
+ source.on 'finish' do
224
+ puts "Job finished"
225
+ source.close
226
+ EM.stop
227
+ end
228
+
229
+ source.start
230
+ end
231
+
232
+ end
233
+
234
+
235
+ def self.http_connection
236
+ http = Net::HTTP.start(Debox.config[:host], Debox.config[:port])
237
+ # Set timeout to 30 min
238
+ http.read_timeout = 180000
239
+ return http
240
+ end
241
+
242
+ def self.unauthorized_error
243
+ error_and_exit "Access denied. Please login first."
244
+ end
245
+
246
+ def self.server_error
247
+ error_and_exit "Ups, something went wrong. Please, try later."
248
+ end
249
+
250
+ def self.not_found_error
251
+ error_and_exit "Ups, something went wrong (not found). Please, try to update your client."
252
+ end
253
+
254
+ def self.error_and_exit(msg)
255
+ raise DeboxServerException.new msg
256
+ end
257
+ end
258
+
259
+ class DeboxServerException < Exception
260
+ end
261
+ end
@@ -0,0 +1,111 @@
1
+ class Debox::CLI
2
+ include Debox::Utils
3
+
4
+ def initialize(*args)
5
+ @args = args
6
+ option_parser.parse! args
7
+ end
8
+
9
+ # Run the command requested in the command line
10
+ def run_command(args)
11
+ Debox::Command.load
12
+ given_command = args.shift.strip rescue "help"
13
+ if given_command == 'help' || options[:show_help]
14
+ help_and_exit
15
+ end
16
+ command = Debox::Command.get_command given_command
17
+ unless command
18
+ puts "Invalid command #{given_command}"
19
+ help_and_error
20
+ end
21
+
22
+ Debox::Config.merge_command_line_options! options
23
+ Debox::Command.run(command, options, args)
24
+ end
25
+
26
+ # Prepare the console and run the command
27
+ def start
28
+ begin
29
+ $stdin.sync = true if $stdin.isatty
30
+ $stdout.sync = true if $stdout.isatty
31
+
32
+ # Run the commands
33
+ run_command @args
34
+
35
+ rescue Interrupt => error
36
+ puts 'stty icanon echo, Command cancelled.'
37
+ puts error.backtrace
38
+ rescue => error
39
+ puts error
40
+ puts "--------------------------------------------------------------------------------"
41
+ puts error.backtrace
42
+ exit(1)
43
+ end
44
+ end
45
+
46
+ def option_parser
47
+ @option_parser ||= new_option_parser
48
+ end
49
+
50
+ private
51
+
52
+ def help_show
53
+ puts "Usage: debox command [options]"
54
+ puts "Commands:"
55
+ Debox::Command.commands.values.each do |cmd|
56
+ puts help_content cmd
57
+ end
58
+ puts option_parser.help
59
+ end
60
+
61
+ def help_content(cmd)
62
+ help = cmd[:help]
63
+ command = cmd[:command]
64
+ params_str = help[:params].join ' '
65
+ opt_params_str = help[:opt_params].map { |p| "[#{p}]"}.join ' '
66
+ help_text = help[:text]
67
+ command_str = " #{command} #{params_str} #{opt_params_str}".ljust(50)
68
+ "#{command_str} # #{help_text}"
69
+ end
70
+
71
+ def help_and_exit
72
+ help_show
73
+ exit 0
74
+ end
75
+
76
+
77
+ def help_and_error
78
+ help_show
79
+ exit 1
80
+ end
81
+
82
+ def options
83
+ @options ||= {}
84
+ end
85
+
86
+
87
+ def new_option_parser
88
+ OptionParser.new do |opts|
89
+ opts.banner = "Options:"
90
+ opts.on("-h", "--host SERVER_HOST", "Debox server url") do |host|
91
+ options[:host] = host
92
+ # If host option, set default port unless defined
93
+ options[:port] = 80 unless options[:port]
94
+ end
95
+
96
+ opts.on("-p", "--port PORT", "Debox server port") do |port|
97
+ options[:port] = port
98
+ end
99
+
100
+ opts.on("-u", "--user EMAIL", "User name") do |u|
101
+ options[:user] = u
102
+ end
103
+
104
+ opts.on("-?", "--help", "Show this help") do |v|
105
+ options[:show_help] = true
106
+ end
107
+
108
+ end
109
+ end
110
+
111
+ end