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