trinidad_sandbox_extension 0.4.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. data/Gemfile +4 -0
  2. data/Gemfile.lock +56 -0
  3. data/History.txt +6 -0
  4. data/README +27 -0
  5. data/git-hooks/post-commit +7 -0
  6. data/lib/trinidad_sandbox_extension.rb +24 -3
  7. data/lib/trinidad_sandbox_extension/app/helpers/{sandbox.rb → auth.rb} +20 -19
  8. data/lib/trinidad_sandbox_extension/app/helpers/context.rb +72 -0
  9. data/lib/trinidad_sandbox_extension/app/helpers/deploy.rb +106 -0
  10. data/lib/trinidad_sandbox_extension/app/helpers/view.rb +39 -0
  11. data/lib/trinidad_sandbox_extension/app/model/application_context.rb +48 -4
  12. data/lib/trinidad_sandbox_extension/app/public/css/sandbox.css +187 -0
  13. data/lib/trinidad_sandbox_extension/app/sandbox.rb +56 -39
  14. data/lib/trinidad_sandbox_extension/app/views/actions.html.haml +2 -2
  15. data/lib/trinidad_sandbox_extension/app/views/applications.html.haml +17 -0
  16. data/lib/trinidad_sandbox_extension/app/views/applications.xml.haml +13 -0
  17. data/lib/trinidad_sandbox_extension/app/views/deploy.html.haml +16 -0
  18. data/lib/trinidad_sandbox_extension/app/views/layout.html.haml +10 -6
  19. data/lib/trinidad_sandbox_extension/app/views/navigation.html.haml +10 -0
  20. data/spec/trinidad_sandbox_extension_spec.rb +12 -2
  21. data/trinidad-libs/trinidad-sandbox-extension.jar +0 -0
  22. data/trinidad_sandbox_extension.gemspec +16 -9
  23. metadata +52 -41
  24. data/lib/trinidad_sandbox_extension/app/public/css/main.css +0 -137
  25. data/lib/trinidad_sandbox_extension/app/views/app.html.haml +0 -8
  26. data/lib/trinidad_sandbox_extension/app/views/app.xml.haml +0 -11
  27. data/lib/trinidad_sandbox_extension/app/views/index.html.haml +0 -6
  28. data/lib/trinidad_sandbox_extension/app/views/index.xml.haml +0 -3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :gemcutter
2
+
3
+ # Specify your gem's dependencies in test_gem.gemspec
4
+ gemspec
@@ -0,0 +1,56 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ trinidad_sandbox_extension (0.4.2)
5
+ grit
6
+ haml
7
+ json
8
+ sinatra
9
+ sinatra-authorization
10
+ sinatra-flash
11
+ sinatra-respond_to
12
+ trinidad (>= 1.0.1)
13
+
14
+ GEM
15
+ remote: http://rubygems.org/
16
+ specs:
17
+ diff-lcs (1.1.2)
18
+ grit (2.4.1)
19
+ diff-lcs (~> 1.1)
20
+ mime-types (~> 1.15)
21
+ haml (3.0.25)
22
+ jruby-rack (1.0.7)
23
+ json (1.5.1-java)
24
+ mime-types (1.16)
25
+ mocha (0.9.12)
26
+ rack (1.2.1)
27
+ rspec (2.5.0)
28
+ rspec-core (~> 2.5.0)
29
+ rspec-expectations (~> 2.5.0)
30
+ rspec-mocks (~> 2.5.0)
31
+ rspec-core (2.5.1)
32
+ rspec-expectations (2.5.0)
33
+ diff-lcs (~> 1.1.2)
34
+ rspec-mocks (2.5.0)
35
+ sinatra (1.2.0)
36
+ rack (~> 1.1)
37
+ tilt (>= 1.2.2, < 2.0)
38
+ sinatra-authorization (1.0.0)
39
+ sinatra (>= 0.9.1.1)
40
+ sinatra-flash (0.3.0)
41
+ sinatra (>= 1.0.0)
42
+ sinatra-respond_to (0.6.0)
43
+ sinatra (~> 1.1)
44
+ tilt (1.2.2)
45
+ trinidad (1.0.5)
46
+ jruby-rack (>= 1.0.2)
47
+ trinidad_jars (>= 0.3.0)
48
+ trinidad_jars (1.0.0)
49
+
50
+ PLATFORMS
51
+ java
52
+
53
+ DEPENDENCIES
54
+ mocha
55
+ rspec (>= 2.2)
56
+ trinidad_sandbox_extension!
@@ -1,3 +1,9 @@
1
+ == 1.0.0 (2011-03-17)
2
+
3
+ * New design
4
+ * Git based deployment
5
+ * Readonly mode
6
+
1
7
  == 0.4.2 (2010-12-21)
2
8
 
3
9
  * Fix application name when the context path is an empty string
data/README CHANGED
@@ -36,11 +36,38 @@ It also supports basic authentication, we'll have to specify the username and pa
36
36
  username: manager
37
37
  password: XXXXXXX
38
38
 
39
+ We can also use the console in readonly mode, so users can see the applications deployed but they cannot deploy new ones or modify them:
40
+
41
+ ---
42
+ extensions:
43
+ sandbox:
44
+ readonly: true
45
+
39
46
  # FEATURES
40
47
 
41
48
  The console as well as the REST api allow to list all the applications managed by that Trinidad's instance and start/stop them.
42
49
  By security reasons the sandbox application is not listed nor can be stopped.
43
50
 
51
+ # GIT DEPLOYMENT
52
+
53
+ The sandbox console also allows to deploy new applications into Trinidad via Git. By default it uses ssh keys to access to the repository with the user `git`.
54
+
55
+ We can also use git hooks to deploy applications via a POST-Receive callback.
56
+ In this case we use a token for authentication that must be set in the configuration, then we'll use an url like we show bellow in our hook:
57
+
58
+ ---
59
+ extensions:
60
+ sandbox:
61
+ deploy_token: ULTRA_SECRET_TOKEN
62
+
63
+ POST-Receive url: http://host/sandbox/deploy?deploy_token=ULTRA_SECRET_TOKEN
64
+
65
+ If we want to let users to deploy applications in public git repositories we can also disable the ssh authentication with the option `git_ssh`:
66
+
67
+ ---
68
+ extensions:
69
+ sandbox:
70
+ git_ssh: false
44
71
 
45
72
  # TODO
46
73
 
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+
3
+ git log --name-only -n1 | grep 'src/main/java' > /dev/null
4
+
5
+ if [ $? = 0 ]; then
6
+ rake "ant:build" && git add trinidad-libs/trinidad-sandbox-extension.jar && git ci -m "update extension jar with the latest source code"
7
+ fi
@@ -6,7 +6,7 @@ require File.expand_path('../../trinidad-libs/trinidad-sandbox-extension', __FIL
6
6
  module Trinidad
7
7
  module Extensions
8
8
  class SandboxServerExtension < ServerExtension
9
- VERSION = '0.4.2'
9
+ VERSION = '1.0.0'
10
10
 
11
11
  def configure(tomcat)
12
12
  opts = prepare_options
@@ -42,12 +42,33 @@ module Trinidad
42
42
  app_ctx.privileged = true
43
43
 
44
44
  if opts[:username] && opts[:password]
45
- app_ctx.servlet_context.setAttribute("sandbox_username", opts[:username].to_s);
46
- app_ctx.servlet_context.setAttribute("sandbox_password", opts[:password].to_s);
45
+ app_ctx.servlet_context.set_attribute("sandbox_username", opts[:username].to_s);
46
+ app_ctx.servlet_context.set_attribute("sandbox_password", opts[:password].to_s);
47
47
  end
48
48
 
49
+ app_ctx.servlet_context.set_attribute('deploy_token', opts[:deploy_token]) if opts[:deploy_token]
50
+ app_ctx.servlet_context.set_attribute('host_name', opts[:host_name]) if opts[:host_name]
51
+
52
+ app_ctx.servlet_context.set_attribute('enable_default', boolean_option(opts[:enable_default]))
53
+
54
+ app_ctx.servlet_context.set_attribute('git_ssh', boolean_option(opts[:git_ssh]))
55
+
56
+ app_ctx.servlet_context.set_attribute('readonly', boolean_option(opts[:readonly], false))
57
+
49
58
  app_ctx
50
59
  end
60
+
61
+ private
62
+ def boolean_option(option, default = true)
63
+ option.nil? ? default : option
64
+ end
65
+ end
66
+
67
+ class SandboxOptionsExtension < OptionsExtension
68
+ def configure(parser, default_options)
69
+ default_options[:extensions] ||= {}
70
+ default_options[:extensions][:sandbox] = {}
71
+ end
51
72
  end
52
73
  end
53
74
  end
@@ -1,8 +1,6 @@
1
-
2
1
  module Trinidad
3
2
  module Sandbox
4
3
  module Helpers
5
-
6
4
  module Auth
7
5
  require 'sinatra/authorization'
8
6
  include Sinatra::Authorization
@@ -17,6 +15,24 @@ module Trinidad
17
15
 
18
16
  def authorization_realm; "Trinidad's sandbox"; end
19
17
 
18
+ def basic_auth_required?(request)
19
+ !token_required?(request)
20
+ end
21
+
22
+ def token_required?(request)
23
+ request.path == '/deploy'
24
+ end
25
+
26
+ def token_required(params, realm = authorization_realm)
27
+ return if authorized_by_token?(params)
28
+ response["WWW-Authenticate"] = %(Basic realm="#{realm}")
29
+ throw :halt, [401, "Deploy Token Required"]
30
+ end
31
+
32
+ def authorized_by_token?(params)
33
+ deploy_token.nil? || params[:deploy_token] == deploy_token
34
+ end
35
+
20
36
  private
21
37
  def sandbox_username
22
38
  @sandbox_username ||= $servlet_context.getAttribute('sandbox_username')
@@ -25,24 +41,9 @@ module Trinidad
25
41
  def sandbox_password
26
42
  @sandbox_password ||= $servlet_context.getAttribute('sandbox_password')
27
43
  end
28
- end
29
-
30
- module Context
31
- def sandbox_context
32
- @sandbox_context ||= $servlet_context.getAttribute('sandbox_context')
33
- end
34
-
35
- def context_not_found(name)
36
- flash[:warning] = "application not found: #{name}"
37
- $servlet_context.log "application not found: #{name}"
38
- respond_to do |wants|
39
- wants.html { redirect sandbox_context.path }
40
- wants.xml { status 404 }
41
- end
42
- end
43
44
 
44
- def host
45
- $servlet_context.getAttribute('tomcat_host')
45
+ def deploy_token
46
+ @deploy_token ||= $servlet_context.get_attribute('deploy_token')
46
47
  end
47
48
  end
48
49
  end
@@ -0,0 +1,72 @@
1
+ module Trinidad
2
+ module Sandbox
3
+ module Helpers
4
+ module Context
5
+ def sandbox_context
6
+ @sandbox_context ||= $servlet_context.getAttribute('sandbox_context')
7
+ end
8
+
9
+ def enable_default?
10
+ !!$servlet_context.getAttribute('enable_default')
11
+ end
12
+
13
+ def git_ssh?
14
+ !!$servlet_context.getAttribute('git_ssh')
15
+ end
16
+
17
+ def readonly?
18
+ !!$servlet_context.get_attribute('readonly')
19
+ end
20
+
21
+ def render_readonly
22
+ warning "The console has been started as READONLY, you can access to that resource"
23
+ redirect_to_home 401
24
+ end
25
+
26
+ def context_not_found(name)
27
+ warning "It seems the application #{name} is not running on Trinidad"
28
+ redirect_to_home 404
29
+ end
30
+
31
+ def repo_not_found
32
+ warning "The repository url is required to clone the application", :now
33
+ respond_to_invalid_deploy
34
+ end
35
+
36
+ def invalid_app_path(path)
37
+ warning "The path #{path} is not valid, please remove the slashes", :now
38
+ respond_to_invalid_deploy
39
+ end
40
+
41
+ def host
42
+ $servlet_context.getAttribute('tomcat_host')
43
+ end
44
+
45
+ def redirect_to_home(status_code)
46
+ respond_to do |wants|
47
+ wants.html { redirect sandbox_context.path }
48
+ wants.xml { status status_code }
49
+ end
50
+ end
51
+
52
+ def respond_to_invalid_deploy
53
+ @page_id = 'deploy'
54
+ respond_to do |wants|
55
+ wants.html { haml :deploy }
56
+ wants.xml { status 400 }
57
+ end
58
+ end
59
+
60
+ def warning(message, req = :next)
61
+ flash.send(req)[:warning] = message
62
+ $servlet_context.log message
63
+ end
64
+
65
+ def available_context?(context)
66
+ context.name != sandbox_context.name || enable_default? ||
67
+ (!enable_default? && context.name == 'default')
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,106 @@
1
+ module Trinidad
2
+ module Sandbox
3
+ module Helpers
4
+ module Deploy
5
+ require 'grit'
6
+ require 'json'
7
+ require 'uri'
8
+ require 'fileutils'
9
+
10
+ def deploy_from_form(params)
11
+ repo_url = params["repo"]
12
+ if repo_url.empty?
13
+ repo_not_found
14
+ else
15
+ branch = params["branch"]
16
+ branch = 'master' if branch.empty?
17
+
18
+ ssh = normalize_uri repo_url
19
+ path = params["path"]
20
+ path = path_from_repo(ssh) if path.empty? && !enable_default?
21
+
22
+ unless valid_path? path
23
+ invalid_app_path(path)
24
+ else
25
+ status = find_and_deploy(ssh, branch, path)
26
+ redirect_to_home status
27
+ end
28
+ end
29
+ end
30
+
31
+ def deploy_from_web_hook(params)
32
+ payload = JSON.parse(params['payload'])
33
+ url = payload['repository']['url']
34
+ branch = File.basename payload['ref']
35
+
36
+ ssh = normalize_uri url
37
+ path = path_from_repo(ssh)
38
+
39
+ status = find_and_deploy(ssh, branch, path)
40
+ end
41
+
42
+ def find_and_deploy(repo, branch, path)
43
+ dest = File.join(host.app_base, path)
44
+
45
+ deployed_app = ApplicationContext.find_by_doc_base(dest)
46
+ status = if deployed_app
47
+ redeploy_application(deployed_app, repo, branch, dest)
48
+ 204
49
+ else
50
+ deploy_new_application(path, repo, branch, dest)
51
+ 201
52
+ end
53
+ end
54
+
55
+ def deploy_new_application(path, repo, branch, dest)
56
+ clone(repo, branch, dest)
57
+ bundle(dest)
58
+ ApplicationContext.create(path, dest)
59
+ end
60
+
61
+ def redeploy_application(context, repo, branch, dest)
62
+ context.send(:setPaused, true)
63
+ FileUtils.rm_rf File.expand_path(dest)
64
+
65
+ clone(repo, branch, dest)
66
+
67
+ context.reload
68
+ end
69
+
70
+ private
71
+ def clone(repo, branch, dest)
72
+ Grit.debug = true
73
+ Grit::Git.with_timeout(1000) do
74
+ Grit::Git.new(dest).clone({:branch => branch}, repo, dest)
75
+ end
76
+ end
77
+
78
+ def bundle(dest)
79
+ Dir.chdir(dest) do
80
+ `jruby -S bundle install` if File.exist? 'Gemfile'
81
+ end
82
+ end
83
+
84
+ def normalize_uri(url)
85
+ normalized = if git_ssh?
86
+ return url if url =~ /^git@/
87
+ uri = URI.parse(url)
88
+
89
+ "git@#{uri.host}#{uri.path.sub('/', ':')}"
90
+ end || url
91
+
92
+ normalized << '.git' unless normalized =~ /\.git$/
93
+ normalized
94
+ end
95
+
96
+ def path_from_repo(repo)
97
+ repo.split('/').last.sub('.git', '')
98
+ end
99
+
100
+ def valid_path?(path)
101
+ path.split('/').length == 1
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,39 @@
1
+ module Trinidad
2
+ module Sandbox
3
+ module Helpers
4
+ module View
5
+ def link_to_deploy
6
+ %q{<a href="deploy">deploy</a>}
7
+ end
8
+
9
+ def render_parameters(parameters)
10
+ render = ''
11
+
12
+ parameters.keys.sort.each_with_index do |key, index|
13
+ column = find_column(parameters, index)
14
+
15
+ klass = "column#{column}"
16
+ klass << " reset" if column == 2 && find_column(parameters, index - 1) == 1
17
+
18
+ render << %Q{<li class="#{klass}">#{key} => #{parameters[key]}</li>}
19
+ end
20
+
21
+ render
22
+ end
23
+
24
+ def render_host_name
25
+ $servlet_context.get_attribute('host_name') || 'HOST_NAME'
26
+ end
27
+
28
+ def render_deploy_token
29
+ $servlet_context.get_attribute('deploy_token') || 'SECRET_DEPLOY_TOKEN'
30
+ end
31
+
32
+ private
33
+ def find_column(parameters, index)
34
+ (parameters.length / 2) > index ? 1 : 2
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end