trinidad_sandbox_extension 0.4.2 → 1.0.0

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