mamiya 0.0.1.alpha24 → 0.0.1.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +24 -18
- data/example/config.agent.rb +3 -0
- data/example/config.rb +27 -0
- data/example/deploy.rb +19 -11
- data/lib/mamiya/agent.rb +38 -2
- data/lib/mamiya/agent/actions.rb +4 -0
- data/lib/mamiya/agent/tasks/clean.rb +35 -0
- data/lib/mamiya/agent/tasks/notifyable.rb +4 -1
- data/lib/mamiya/agent/tasks/prepare.rb +2 -0
- data/lib/mamiya/agent/tasks/switch.rb +123 -0
- data/lib/mamiya/cli.rb +1 -20
- data/lib/mamiya/cli/client.rb +225 -3
- data/lib/mamiya/configuration.rb +18 -0
- data/lib/mamiya/master/agent_monitor.rb +19 -4
- data/lib/mamiya/master/agent_monitor_handlers.rb +10 -0
- data/lib/mamiya/master/application_status.rb +72 -0
- data/lib/mamiya/master/package_status.rb +178 -0
- data/lib/mamiya/master/web.rb +48 -44
- data/lib/mamiya/steps/build.rb +1 -1
- data/lib/mamiya/steps/prepare.rb +1 -1
- data/lib/mamiya/steps/switch.rb +2 -1
- data/lib/mamiya/storages/filesystem.rb +1 -1
- data/lib/mamiya/storages/mock.rb +1 -1
- data/lib/mamiya/storages/s3.rb +1 -1
- data/lib/mamiya/storages/s3_proxy.rb +1 -1
- data/lib/mamiya/version.rb +1 -1
- data/spec/agent/actions_spec.rb +26 -1
- data/spec/agent/tasks/clean_spec.rb +88 -2
- data/spec/agent/tasks/notifyable_spec.rb +3 -3
- data/spec/agent/tasks/switch_spec.rb +176 -0
- data/spec/agent_spec.rb +142 -1
- data/spec/configuration_spec.rb +23 -0
- data/spec/master/agent_monitor_spec.rb +128 -38
- data/spec/master/application_status_spec.rb +171 -0
- data/spec/master/package_status_spec.rb +560 -0
- data/spec/master/web_spec.rb +116 -1
- data/spec/steps/build_spec.rb +1 -1
- data/spec/steps/prepare_spec.rb +6 -1
- data/spec/steps/switch_spec.rb +6 -2
- data/spec/storages/filesystem_spec.rb +2 -21
- data/spec/storages/s3_proxy_spec.rb +2 -22
- data/spec/storages/s3_spec.rb +2 -20
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 782cb5f0d2988afede38796bf84f3b37f3343684
|
4
|
+
data.tar.gz: 2d4f5b6102d93c5e05cbc3779364466ca171bece
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74749204a5f0f8071a55889fd1e418f3e4c9c2a721f643f1ece3dca210539b33a50627e5cd6e1d1bf3d7b04c2baf758cc6c886738feb2fc9d4547939fbee6cc7
|
7
|
+
data.tar.gz: 6d46ddc42aa6b206640edcf7d96588b56f11271d7cf606b8522d261bfe9ab64a878d4b774f70bb5485379339cb22cc0f62c3f1db27077689027dcaa65f82c8b7
|
data/README.md
CHANGED
@@ -2,37 +2,43 @@
|
|
2
2
|
|
3
3
|
[![Build Status](https://travis-ci.org/sorah/mamiya.png?branch=master)](https://travis-ci.org/sorah/mamiya)
|
4
4
|
|
5
|
-
Mamiya allows you to deploy using without ssh -- tarballs
|
5
|
+
Mamiya allows you to deploy using without ssh -- using tarballs, some storages (S3, etc), and [Serf](http://www.serfdom.io/).
|
6
6
|
|
7
|
-
|
7
|
+
## Installation
|
8
8
|
|
9
|
-
|
9
|
+
$ gem install mamiya
|
10
10
|
|
11
|
-
|
12
|
-
But connecting to lot of servers via SSH makes deployment slow.
|
11
|
+
or bundle it:
|
13
12
|
|
14
|
-
|
13
|
+
``` ruby
|
14
|
+
gem 'mamiya'
|
15
|
+
```
|
15
16
|
|
16
|
-
|
17
|
-
file transferring phase in deploy.
|
18
|
-
|
19
|
-
## Installation
|
17
|
+
## Usage
|
20
18
|
|
21
|
-
|
19
|
+
(Detailed documentation coming soon)
|
22
20
|
|
23
|
-
|
21
|
+
1. Prepare master node for `mamiya master` process
|
22
|
+
- master has HTTP API to allow control the cluster via HTTP
|
23
|
+
- master watches agents in the cluster
|
24
|
+
2. Then install `mamiya agent` in your deployment target hosts
|
25
|
+
3. Write deploy script for your own
|
26
|
+
- how to build package, how to prepare release, how to release, etc.
|
27
|
+
4. Build then push package
|
28
|
+
5. Time to deploy
|
24
29
|
|
25
|
-
|
30
|
+
[example](./example) directory contains configuration files that work out-of-the-box. Try Mamiya in your local machine: `foreman start`
|
26
31
|
|
27
|
-
|
32
|
+
## Problems in existing deploy tool
|
28
33
|
|
29
|
-
|
34
|
+
Existing major deploy tools (capistrano, mina, ...) use SSH to operate servers.
|
35
|
+
But connecting to lot of servers via SSH makes deployment slow.
|
30
36
|
|
31
|
-
|
37
|
+
This solves such problem by using [Serf](http://www.serfdom.io/) and tarball on one storage (Amazon S3).
|
32
38
|
|
33
|
-
|
39
|
+
Also, I'm planning to allow to distribute files before the deploy command. I guess this can skip or shorten
|
40
|
+
file transferring phase in deploy.
|
34
41
|
|
35
|
-
TODO: Write usage instructions here
|
36
42
|
|
37
43
|
## Upgrade Notes
|
38
44
|
|
data/example/config.agent.rb
CHANGED
@@ -31,9 +31,12 @@ target = targets.join(agent_name).tap(&:mkpath)
|
|
31
31
|
set :packages_dir, target.join('packages')
|
32
32
|
set :prereleases_dir, target.join('prereleases')
|
33
33
|
|
34
|
+
applications[:myapp] = {deploy_to: target}
|
35
|
+
|
34
36
|
# To test
|
35
37
|
Dir.mkdir packages_dir unless File.exist?(packages_dir)
|
36
38
|
Dir.mkdir prereleases_dir unless File.exist?(prereleases_dir)
|
39
|
+
deploy_to_for(:myapp).mkpath unless deploy_to_for(:myapp).exist?
|
37
40
|
|
38
41
|
set :keep_packages, 3
|
39
42
|
set :keep_prereleases, 3
|
data/example/config.rb
CHANGED
@@ -14,10 +14,37 @@ end
|
|
14
14
|
set :packages_dir, "#{File.dirname(__FILE__)}/packages"
|
15
15
|
set :prereleases_dir, "#{File.dirname(__FILE__)}/target/prereleases"
|
16
16
|
|
17
|
+
applications[:myapp] = {deploy_to: File.join(File.dirname(__FILE__), 'targets', 'default')}
|
18
|
+
|
17
19
|
# To test
|
18
20
|
Dir.mkdir packages_dir unless File.exist?(packages_dir)
|
19
21
|
prereleases_dir.mkpath unless File.exist?(prereleases_dir)
|
22
|
+
deploy_to_for(:myapp).mkpath unless deploy_to_for(:myapp).exist?
|
20
23
|
|
21
24
|
set :keep_packages, 3
|
22
25
|
set :keep_prereleases, 3
|
23
26
|
set :fetch_sleep, 2
|
27
|
+
|
28
|
+
before_deploy do
|
29
|
+
p :before_deploy
|
30
|
+
end
|
31
|
+
|
32
|
+
after_deploy do |e|
|
33
|
+
p [:after_deploy, e]
|
34
|
+
end
|
35
|
+
|
36
|
+
before_rollback do
|
37
|
+
p :before_rollback
|
38
|
+
end
|
39
|
+
|
40
|
+
after_rollback do |e|
|
41
|
+
p [:after_rollback, e]
|
42
|
+
end
|
43
|
+
|
44
|
+
before_deploy_or_rollback do
|
45
|
+
p :before_deploy_or_rollback
|
46
|
+
end
|
47
|
+
|
48
|
+
after_deploy_or_rollback do |e|
|
49
|
+
p [:after_deploy_or_rollback, e]
|
50
|
+
end
|
data/example/deploy.rb
CHANGED
@@ -13,20 +13,11 @@ set :dereference_symlinks, true
|
|
13
13
|
set :build_from, "#{File.dirname(__FILE__)}/source"
|
14
14
|
set :build_to, "#{File.dirname(__FILE__)}/builds"
|
15
15
|
|
16
|
-
dir = File.dirname(__FILE__)
|
17
|
-
if File.basename(dir) == 'example'
|
18
|
-
set :deploy_to, File.join(dir, 'targets', 'default')
|
19
|
-
else
|
20
|
-
# target/{releases,prereleases}/<name>/.mamiya.script/../../..
|
21
|
-
set :deploy_to, File.expand_path(File.join(dir, '..', '..', '..'))
|
22
|
-
end
|
23
|
-
|
24
16
|
# to test it
|
25
17
|
Dir.mkdir build_to unless File.exist?(build_to)
|
26
|
-
deploy_to.mkpath unless deploy_to.exist?
|
27
18
|
|
28
|
-
set :bundle_without, [:development, :test]
|
29
|
-
set :bundle_dir, "#{deploy_to}/shared/bundle"
|
19
|
+
#set :bundle_without, [:development, :test]
|
20
|
+
#set :bundle_dir, "#{deploy_to}/shared/bundle"
|
30
21
|
|
31
22
|
#use :git, exclude_git_clean_targets: true
|
32
23
|
|
@@ -47,4 +38,21 @@ end
|
|
47
38
|
# run "bundle", "exec", "rake", "assets:precompile"
|
48
39
|
#end
|
49
40
|
|
41
|
+
prepare 'test' do
|
42
|
+
# run 'bundle', 'install'
|
43
|
+
logger.info "- prep/deploy_to: #{deploy_to}"
|
44
|
+
logger.info "- prep/release_path: #{release_path}"
|
45
|
+
sleep 5
|
46
|
+
File.write release_path.join('prepared_at'), Time.now
|
47
|
+
end
|
48
|
+
|
49
|
+
release 'test' do
|
50
|
+
logger.info "- prep/deploy_to: #{deploy_to}"
|
51
|
+
logger.info "- prep/release_path: #{release_path}"
|
52
|
+
sl = rand(80)
|
53
|
+
logger.info "!!!!!!!!!!!!!!! sleep #{sl} sec"
|
54
|
+
sleep sl
|
55
|
+
File.write release_path.join('released_at'), Time.now
|
56
|
+
end
|
57
|
+
|
50
58
|
|
data/lib/mamiya/agent.rb
CHANGED
@@ -14,6 +14,7 @@ require 'mamiya/agent/task_queue'
|
|
14
14
|
require 'mamiya/agent/tasks/fetch'
|
15
15
|
require 'mamiya/agent/tasks/prepare'
|
16
16
|
require 'mamiya/agent/tasks/clean'
|
17
|
+
require 'mamiya/agent/tasks/switch'
|
17
18
|
|
18
19
|
require 'mamiya/agent/handlers/task'
|
19
20
|
require 'mamiya/agent/actions'
|
@@ -42,6 +43,7 @@ module Mamiya
|
|
42
43
|
Mamiya::Agent::Tasks::Fetch,
|
43
44
|
Mamiya::Agent::Tasks::Prepare,
|
44
45
|
Mamiya::Agent::Tasks::Clean,
|
46
|
+
Mamiya::Agent::Tasks::Switch,
|
45
47
|
])
|
46
48
|
end
|
47
49
|
|
@@ -89,6 +91,8 @@ module Mamiya
|
|
89
91
|
if packages
|
90
92
|
s[:packages] = self.existing_packages
|
91
93
|
s[:prereleases] = self.existing_prereleases
|
94
|
+
s[:releases] = self.releases
|
95
|
+
s[:currents] = self.currents
|
92
96
|
end
|
93
97
|
end
|
94
98
|
end
|
@@ -147,6 +151,35 @@ module Mamiya
|
|
147
151
|
]
|
148
152
|
end
|
149
153
|
|
154
|
+
def releases
|
155
|
+
Hash[config.applications.map do |name, app|
|
156
|
+
deploy_to = Pathname.new(app[:deploy_to])
|
157
|
+
releases = deploy_to.join('releases')
|
158
|
+
next [name, []] unless releases.exist?
|
159
|
+
|
160
|
+
[
|
161
|
+
name,
|
162
|
+
releases.children.map do |release|
|
163
|
+
release.basename.to_s
|
164
|
+
end.sort
|
165
|
+
]
|
166
|
+
end.compact]
|
167
|
+
end
|
168
|
+
|
169
|
+
def currents
|
170
|
+
# TODO: when the target is in outside?
|
171
|
+
Hash[config.applications.map do |name, app|
|
172
|
+
deploy_to = Pathname.new(app[:deploy_to])
|
173
|
+
current = deploy_to.join('current')
|
174
|
+
next unless current.exist?
|
175
|
+
|
176
|
+
[
|
177
|
+
name,
|
178
|
+
current.realpath.basename.to_s
|
179
|
+
]
|
180
|
+
end.compact]
|
181
|
+
end
|
182
|
+
|
150
183
|
def trigger(type, action: nil, coalesce: true, **payload)
|
151
184
|
name = "mamiya:#{type}"
|
152
185
|
name << ":#{action}" if action
|
@@ -173,8 +206,11 @@ module Mamiya
|
|
173
206
|
end
|
174
207
|
|
175
208
|
serf.respond('mamiya:packages') do |event|
|
176
|
-
{
|
177
|
-
|
209
|
+
{
|
210
|
+
'packages' => self.existing_packages,
|
211
|
+
'prereleases' => self.existing_prereleases,
|
212
|
+
'releases' => self.releases,
|
213
|
+
'currents' => self.currents,
|
178
214
|
}.to_json
|
179
215
|
end
|
180
216
|
end
|
data/lib/mamiya/agent/actions.rb
CHANGED
@@ -17,6 +17,10 @@ module Mamiya
|
|
17
17
|
def prepare(application, package, labels: nil)
|
18
18
|
order_task('prepare', app: application, pkg: package, labels: labels)
|
19
19
|
end
|
20
|
+
|
21
|
+
def switch(application, package, labels: nil, no_release: false)
|
22
|
+
order_task('switch', app: application, pkg: package, labels: labels, no_release: no_release)
|
23
|
+
end
|
20
24
|
end
|
21
25
|
end
|
22
26
|
end
|
@@ -9,8 +9,11 @@ module Mamiya
|
|
9
9
|
# XXX:
|
10
10
|
clean_packages
|
11
11
|
clean_prereleases
|
12
|
+
clean_releases
|
12
13
|
end
|
13
14
|
|
15
|
+
###
|
16
|
+
|
14
17
|
def clean_packages
|
15
18
|
package_victims.each do |app, victim|
|
16
19
|
@logger.info "Cleaning package: remove #{victim}"
|
@@ -45,6 +48,8 @@ module Mamiya
|
|
45
48
|
end
|
46
49
|
end
|
47
50
|
|
51
|
+
###
|
52
|
+
|
48
53
|
def clean_prereleases
|
49
54
|
prerelease_victims.each do |app, victim|
|
50
55
|
@logger.info "Cleaning prerelease: remove #{victim}"
|
@@ -70,6 +75,36 @@ module Mamiya
|
|
70
75
|
end
|
71
76
|
end
|
72
77
|
|
78
|
+
###
|
79
|
+
|
80
|
+
def clean_releases
|
81
|
+
release_victims.each do |app, victim|
|
82
|
+
@logger.info "Cleaning release: remove #{victim}"
|
83
|
+
package_name = File.basename(victim)
|
84
|
+
FileUtils.remove_entry_secure victim
|
85
|
+
|
86
|
+
agent.trigger('release', action: 'remove',
|
87
|
+
app: app,
|
88
|
+
pkg: package_name,
|
89
|
+
coalesce: false,
|
90
|
+
)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def release_victims
|
95
|
+
config.applications.flat_map do |name, app|
|
96
|
+
next unless app[:deploy_to]
|
97
|
+
releases = Dir[File.join(app[:deploy_to], 'releases', '*')].sort_by { |_| [File.mtime(_), _] }
|
98
|
+
current = File.join(app[:deploy_to], 'current')
|
99
|
+
current_realpath = File.exist?(current) ? File.realpath(current) : nil
|
100
|
+
|
101
|
+
releases.reject!{ |rel| File.realpath(rel) == current_realpath }
|
102
|
+
|
103
|
+
releases[0...-(config[:keep_releases])].map do |victim|
|
104
|
+
[name, victim]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
73
108
|
end
|
74
109
|
end
|
75
110
|
end
|
@@ -6,7 +6,8 @@ module Mamiya
|
|
6
6
|
class Notifyable < Abstract
|
7
7
|
def execute
|
8
8
|
agent.trigger('task', action: 'start',
|
9
|
-
task: task
|
9
|
+
task: task,
|
10
|
+
coalesce: false,
|
10
11
|
)
|
11
12
|
|
12
13
|
super
|
@@ -16,10 +17,12 @@ module Mamiya
|
|
16
17
|
agent.trigger('task', action: 'error',
|
17
18
|
error: error.class.name,
|
18
19
|
task: task,
|
20
|
+
coalesce: false,
|
19
21
|
)
|
20
22
|
else
|
21
23
|
agent.trigger('task', action: 'finish',
|
22
24
|
task: task,
|
25
|
+
coalesce: false,
|
23
26
|
)
|
24
27
|
end
|
25
28
|
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
require 'mamiya/agent/tasks/notifyable'
|
4
|
+
require 'mamiya/steps/switch'
|
5
|
+
|
6
|
+
module Mamiya
|
7
|
+
class Agent
|
8
|
+
module Tasks
|
9
|
+
class Switch < Notifyable
|
10
|
+
class PrereleaseMissing < Exception; end
|
11
|
+
|
12
|
+
def execute
|
13
|
+
return unless check
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def check
|
18
|
+
return true if prerelease_path.exist?
|
19
|
+
return true if release_prepared?
|
20
|
+
|
21
|
+
unless package_path.exist?
|
22
|
+
new_chain = ['prepare', 'switch'] + (task['_chain'] || [])
|
23
|
+
logger.info "Package not fetched, enqueueing fetch task with #{new_chain.inspect}"
|
24
|
+
task_queue.enqueue(
|
25
|
+
:fetch,
|
26
|
+
task.merge('_chain' => new_chain)
|
27
|
+
)
|
28
|
+
return false
|
29
|
+
end
|
30
|
+
|
31
|
+
unless prerelease_path.exist?
|
32
|
+
new_chain = ['switch'] + (task['_chain'] || [])
|
33
|
+
logger.info "Package not prepared, enqueueing prepare task with #{new_chain.inspect}"
|
34
|
+
task_queue.enqueue(
|
35
|
+
:prepare,
|
36
|
+
task.merge('_chain' => new_chain)
|
37
|
+
)
|
38
|
+
return false
|
39
|
+
end
|
40
|
+
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
def run
|
45
|
+
case
|
46
|
+
when prerelease_path.exist? && release_path.exist? && !release_path.join('.mamiya.prepared').exist?
|
47
|
+
logger.info "Removing existing release (not prepared)"
|
48
|
+
FileUtils.remove_entry_secure release_path
|
49
|
+
when !prerelease_path.exist? && prelease_path.exist? && !release_path.join('.mamiya.prepared').exist?
|
50
|
+
# this condition may be a bug
|
51
|
+
logger.error "Existing release is not prepared but prerelease doesn't exist"
|
52
|
+
raise PrereleaseMissing, "Existing release is not prepared but prerelease doesn't exist"
|
53
|
+
end
|
54
|
+
|
55
|
+
logger.info "Copying #{prerelease_path} -> #{release_path}"
|
56
|
+
FileUtils.cp_r prerelease_path, release_path
|
57
|
+
|
58
|
+
logger.info "Switching"
|
59
|
+
switch_step.run!
|
60
|
+
|
61
|
+
task_queue.enqueue(:clean, {})
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def application
|
67
|
+
task['app']
|
68
|
+
end
|
69
|
+
|
70
|
+
def package
|
71
|
+
task['pkg']
|
72
|
+
end
|
73
|
+
|
74
|
+
def release_name
|
75
|
+
task['release'] || package
|
76
|
+
end
|
77
|
+
|
78
|
+
def packages_dir
|
79
|
+
@packages_dir ||= config.packages_dir
|
80
|
+
end
|
81
|
+
|
82
|
+
def prereleases_dir
|
83
|
+
@prereleases_dir ||= config.prereleases_dir
|
84
|
+
end
|
85
|
+
|
86
|
+
def package_path
|
87
|
+
packages_dir.join(application, "#{package}.tar.gz")
|
88
|
+
end
|
89
|
+
|
90
|
+
def prerelease_path
|
91
|
+
prereleases_dir.join(application, release_name)
|
92
|
+
end
|
93
|
+
|
94
|
+
def releases_dir
|
95
|
+
config.deploy_to_for(application).join('releases').tap(&:mkpath)
|
96
|
+
end
|
97
|
+
|
98
|
+
def release_path
|
99
|
+
releases_dir.join(release_name)
|
100
|
+
end
|
101
|
+
|
102
|
+
def release_prepared?
|
103
|
+
release_path.exist? && release_path.join('.mamiya.prepared').exist?
|
104
|
+
end
|
105
|
+
|
106
|
+
def labels
|
107
|
+
@labels ||= agent.labels
|
108
|
+
end
|
109
|
+
|
110
|
+
def switch_step
|
111
|
+
@switch_step ||= Mamiya::Steps::Switch.new(
|
112
|
+
target: release_path,
|
113
|
+
config: config,
|
114
|
+
logger: logger,
|
115
|
+
config: config,
|
116
|
+
labels: agent.labels,
|
117
|
+
no_release: !!task['no_release']
|
118
|
+
)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|