capistrano-stretcher 0.1.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.
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: