mamiya 0.0.1.alpha24 → 0.0.1.beta1
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 +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
|
[](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
|