capistrano-stretcher 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6eb32df62c7426e64ac97effd685d1f3ccc7e796
4
+ data.tar.gz: aac0d3cf7eaba2572aebdbc812f8e4e01215dbef
5
+ SHA512:
6
+ metadata.gz: 3293cd4abe640a2a1987a00557b17f003cc679096d4c896be0809106b2d41d3281dcf13ff693cc1a255d8180e720b399d0d8ac152f84ac1b6e27b08ee6d25f5f
7
+ data.tar.gz: 9e47a94761e8ef7f1124bc56c29c1df2c40b8bef9cad9a435a183630df2fa52972b7eebfb147919183b6f429ed4468cfd20edd091dd18c08cefa72971e6bfbf0
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in capistrano-stretcher.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2015- GMO Pepabo, Inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # Capistrano::Stretcher
2
+
3
+ capistrano task for stretcher.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'capistrano-stretcher'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install capistrano-stretcher
20
+
21
+ ## Requirements
22
+
23
+ capistrano-stretcher requires target server for building to application assets. this server should be installed folloing packages:
24
+
25
+ * git
26
+ * rsync
27
+ * tar
28
+ * gzip
29
+ * awk
30
+ * openssl
31
+ * aws-cli
32
+ * consul
33
+
34
+ target server build assets, upload assets to AWS S3 and invoke `consul event` automatically. so target server can access AWS s3 via aws-cli and join your deployment consul cluster.
35
+
36
+ ## Usage
37
+
38
+ You need to add `require "capistrano/stretcher" to Capfile` and add `config/deploy.rb` following variables:
39
+
40
+ ```
41
+ role :build, ['your-target-server.lan'], :no_release => true
42
+ set :application, 'your-application'
43
+ set :deploy_to, '/var/www'
44
+ set :deploy_roles, 'www,batch'
45
+ set :stretcher_hooks, 'config/stretcher.yml.erb'
46
+ set :local_tarball_name, 'rails-applicaiton.tar.gz'
47
+ set :stretcher_src, "s3://your-deployment-bucket/assets/rails-application-#{env.now}.tgz"
48
+ set :manifest_path, "s3://your-deployment-bucket/manifests/"
49
+ ```
50
+
51
+ and write hooks for stretcher to `config/stretcher.yml.erb`
52
+
53
+ ```yaml
54
+ default: &default
55
+ pre:
56
+ -
57
+ success:
58
+ -
59
+ failure:
60
+ - cat >> /tmp/failure
61
+ www:
62
+ <<: *default
63
+ post:
64
+ - ln -nfs <%= fetch(:deploy_to) %>/shared/data <%= fetch(:deploy_to) %>/current/data
65
+ - sudo systemctl reload unicorn
66
+ batch:
67
+ <<: *default
68
+ post:
69
+ - ln -nfs <%= fetch(:deploy_to) %>/shared/data <%= fetch(:deploy_to) %>/current/data
70
+ ```
71
+
72
+ above hooks is extracted to manifest.yml for stretcher. If you have "www,batch" roles and stages named staging and production, capistrano-stretcher extract to following yaml from configuration.
73
+
74
+ * `manifest_www_staging.yml`
75
+ * `manifest_batch_staging.yml`
76
+
77
+ and invoke
78
+
79
+ * `consul event -name deploy_www_staging s3://.../manifest_www.yml`
80
+ * `consul event -name deploy_batch_staging s3://.../manifest_batch.yml`
81
+
82
+ with `cap staging stretcher:deploy` command on target server. When it's invoked with `cap production stretcher:deploy`, capistrano-strecher replace suffix `staging` to `production`.
83
+
84
+ ## Development
85
+
86
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
87
+
88
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
89
+
90
+ ## Contributing
91
+
92
+ Bug reports and pull requests are welcome on GitHub at https://github.com/pepabo/capistrano-stretcher.
93
+
94
+ ## LICENSE
95
+
96
+ The MIT License (MIT)
97
+
98
+ Copyright (c) 2015- GMO Pepabo, Inc.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "capistrano/stretcher"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "capistrano-stretcher"
7
+ spec.version = "0.1.0"
8
+ spec.authors = ["SHIBATA Hiroshi", "Uchio Kondo"]
9
+ spec.email = ["hsbt@ruby-lang.org", "udzura@udzura.jp"]
10
+
11
+ spec.summary = %q{capistrano task for stretcher.}
12
+ spec.description = %q{capistrano task for stretcher.}
13
+ spec.homepage = "https://github.com/pepabo/capistrano-stretcher"
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ spec.bindir = "exe"
17
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency 'capistrano', '>= 3'
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.10"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+ spec.add_development_dependency "minitest"
25
+ end
@@ -0,0 +1 @@
1
+ # this file is dummy file for Bundler.setup
@@ -0,0 +1 @@
1
+ load File.expand_path("../tasks/stretcher.rake", __FILE__)
@@ -0,0 +1,153 @@
1
+ # -*- coding: utf-8; mode: ruby -*-
2
+ require 'erb'
3
+ require 'yaml'
4
+
5
+ namespace :stretcher do
6
+ set :exclude_dirs, ['tmp']
7
+
8
+ def local_working_path_base
9
+ @_local_working_path_base ||= fetch(:local_working_path_base, "/var/tmp/#{fetch :application}")
10
+ end
11
+
12
+ def local_repo_path
13
+ "#{local_working_path_base}/repo"
14
+ end
15
+
16
+ def local_checkout_path
17
+ "#{local_working_path_base}/checkout"
18
+ end
19
+
20
+ def local_build_path
21
+ "#{local_working_path_base}/build"
22
+ end
23
+
24
+ def local_tarball_path
25
+ "#{local_working_path_base}/tarballs"
26
+ end
27
+
28
+ def application_builder_roles
29
+ roles(fetch(:application_builder_roles, [:build]))
30
+ end
31
+
32
+ task :mark_deploying do
33
+ set :deploying, true
34
+ end
35
+
36
+ desc "Create a tarball that is set up for deploy"
37
+ task :archive_project =>
38
+ [:ensure_directories, :checkout_local,
39
+ :create_tarball, :upload_tarball,
40
+ :create_and_upload_manifest, :cleanup_dirs]
41
+
42
+ task :ensure_directories do
43
+ on application_builder_roles do
44
+ execute :mkdir, '-p', local_repo_path, local_checkout_path, local_build_path, local_tarball_path
45
+ end
46
+ end
47
+
48
+ task :checkout_local do
49
+ on application_builder_roles do
50
+ if test("[ -f #{local_repo_path}/HEAD ]")
51
+ within local_repo_path do
52
+ execute :git, :remote, :update
53
+ end
54
+ else
55
+ execute :git, :clone, '--mirror', repo_url, local_repo_path
56
+ end
57
+
58
+ within local_repo_path do
59
+ execute :mkdir, '-p', "#{local_checkout_path}/#{env.now}"
60
+ execute :git, :archive, fetch(:branch), "| tar -x -C", "#{local_checkout_path}/#{env.now}"
61
+ set :current_revision, capture(:git, 'rev-parse', fetch(:branch)).chomp
62
+
63
+ execute :echo, fetch(:current_revision), "> #{local_checkout_path}/#{env.now}/REVISION"
64
+
65
+ execute :rsync, "-av", "--delete",
66
+ *fetch(:exclude_dirs).map{|d| ['--exclude', d].join(' ')},
67
+ "#{local_checkout_path}/#{env.now}/", "#{local_build_path}/",
68
+ "| pv -l -s $( find #{local_checkout_path}/#{env.now}/ -type f | wc -l ) >/dev/null"
69
+ end
70
+ end
71
+ end
72
+
73
+ task :create_tarball do
74
+ on application_builder_roles do
75
+ within local_build_path do
76
+ execute :mkdir, '-p', "#{local_tarball_path}/#{env.now}"
77
+ execute :tar, '-cf', '-',
78
+ "--exclude tmp", "--exclude spec", "./",
79
+ "| pv -s $( du -sb ./ | awk '{print $1}' )",
80
+ "| gzip -9 > #{local_tarball_path}/#{env.now}/#{fetch(:local_tarball_name)}"
81
+ end
82
+ within local_tarball_path do
83
+ execute :rm, '-f', 'current'
84
+ execute :ln, '-sf', env.now, 'current'
85
+ end
86
+ end
87
+ end
88
+
89
+ task :upload_tarball do
90
+ on application_builder_roles do
91
+ as 'root' do
92
+ execute :aws, :s3, :cp, "#{local_tarball_path}/current/#{fetch(:local_tarball_name)}", fetch(:stretcher_src)
93
+ end
94
+ end
95
+ end
96
+
97
+ task :create_and_upload_manifest do
98
+ on application_builder_roles do
99
+ as 'root' do
100
+ failure_message = "Deploy failed at *$(hostname)* :fire:"
101
+ checksum = capture("openssl sha256 #{local_tarball_path}/current/#{fetch(:local_tarball_name)} | gawk -F' ' '{print $2}'").chomp
102
+ src = fetch(:stretcher_src)
103
+ template = File.read(File.expand_path('../../templates/manifest.yml.erb', __FILE__))
104
+ yaml = YAML.load(ERB.new(capture(:cat, "#{local_build_path}/#{fetch(:stretcher_hooks)}")).result(binding))
105
+ fetch(:deploy_roles).split(',').each do |role|
106
+ hooks = yaml[role]
107
+ yml = ERB.new(template).result(binding)
108
+ tempfile_path = Tempfile.open("manifest_#{role}") do |t|
109
+ t.write yml
110
+ t.path
111
+ end
112
+ upload! tempfile_path, "#{local_tarball_path}/current/manifest_#{role}_#{fetch(:stage)}.yml"
113
+ execute :aws, :s3, :cp, "#{local_tarball_path}/current/manifest_#{role}_#{fetch(:stage)}.yml", "#{fetch(:manifest_path)}/manifest_#{role}_#{fetch(:stage)}.yml"
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ # refs https://github.com/capistrano/capistrano/blob/master/lib/capistrano/tasks/deploy.rake#L138
120
+ task :cleanup_dirs do
121
+ on application_builder_roles do
122
+ releases = capture(:ls, '-tr', "#{local_tarball_path}", "| grep -v current").split
123
+
124
+ if releases.count >= fetch(:keep_releases)
125
+ info t(:keeping_releases, host: host.to_s, keep_releases: fetch(:keep_releases), releases: releases.count)
126
+ directories = (releases - releases.last(fetch(:keep_releases)))
127
+ unless directories.empty?
128
+ directories_str = directories.map do |release|
129
+ "#{local_tarball_path}/#{release} #{local_checkout_path}/#{release}"
130
+ end.join(" ")
131
+ execute :rm, '-rf', directories_str
132
+ else
133
+ info t(:no_old_releases, host: host.to_s, keep_releases: fetch(:keep_releases))
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ desc "Kick the stretcher's deploy event via Consul"
140
+ task :kick_stretcher do
141
+ fetch(:deploy_roles).split(',').each do |target_role|
142
+ on application_builder_roles do
143
+ opts = ["-name deploy_#{target_role}_#{fetch(:stage)}"]
144
+ opts << "-node #{ENV['TARGET_HOSTS']}" if ENV['TARGET_HOSTS']
145
+ opts << "#{fetch(:manifest_path)}/manifest_#{target_role}_#{fetch(:stage)}.yml"
146
+ execute :consul, :event, *opts
147
+ end
148
+ end
149
+ end
150
+
151
+ desc 'Deploy via Stretcher'
152
+ task :deploy => ["stretcher:mark_deploying", "stretcher:archive_project", "stretcher:kick_stretcher"]
153
+ end
@@ -0,0 +1,28 @@
1
+ src: <%= src %>
2
+ checksum: <%= checksum %>
3
+ dest: <%= fetch(:deploy_to) %>/releases/<%= env.now %>
4
+ commands:
5
+ pre:
6
+ <% hooks["pre"].each do |c| %>
7
+ - <%= c %>
8
+ <% end %>
9
+ post:
10
+ - ln -nfs <%= fetch(:deploy_to) %>/releases/<%= env.now %> <%= fetch(:deploy_to) %>/current
11
+ - rm -rf <%= fetch(:deploy_to) %>/current/log
12
+ - ln -nfs <%= fetch(:deploy_to) %>/shared/log <%= fetch(:deploy_to) %>/current/log
13
+ - mkdir -p <%= fetch(:deploy_to) %>/current/tmp
14
+ - ln -nfs <%= fetch(:deploy_to) %>/shared/pids <%= fetch(:deploy_to) %>/current/tmp/pids
15
+ <% hooks["post"].each do |c| %>
16
+ - <%= c %>
17
+ <% end %>
18
+ success:
19
+ <% hooks["success"].each do |c| %>
20
+ - <%= c %>
21
+ <% end %>
22
+ failure:
23
+ <% hooks["failure"].each do |c| %>
24
+ - <%= c %>
25
+ <% end %>
26
+ excludes:
27
+ - "*.pid"
28
+ - "*.socket"
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano-stretcher
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - SHIBATA Hiroshi
8
+ - Uchio Kondo
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2015-12-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: capistrano
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '3'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '3'
28
+ - !ruby/object:Gem::Dependency
29
+ name: bundler
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.10'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.10'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '10.0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '10.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: minitest
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ description: capistrano task for stretcher.
71
+ email:
72
+ - hsbt@ruby-lang.org
73
+ - udzura@udzura.jp
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - ".gitignore"
79
+ - ".travis.yml"
80
+ - Gemfile
81
+ - LICENSE
82
+ - README.md
83
+ - Rakefile
84
+ - bin/console
85
+ - bin/setup
86
+ - capistrano-stretcher.gemspec
87
+ - lib/capistrano-stretcher.rb
88
+ - lib/capistrano/stretcher.rb
89
+ - lib/capistrano/tasks/stretcher.rake
90
+ - lib/capistrano/templates/manifest.yml.erb
91
+ homepage: https://github.com/pepabo/capistrano-stretcher
92
+ licenses: []
93
+ metadata: {}
94
+ post_install_message:
95
+ rdoc_options: []
96
+ require_paths:
97
+ - lib
98
+ required_ruby_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ requirements: []
109
+ rubyforge_project:
110
+ rubygems_version: 2.5.0
111
+ signing_key:
112
+ specification_version: 4
113
+ summary: capistrano task for stretcher.
114
+ test_files: []
115
+ has_rdoc: