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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +24 -18
  3. data/example/config.agent.rb +3 -0
  4. data/example/config.rb +27 -0
  5. data/example/deploy.rb +19 -11
  6. data/lib/mamiya/agent.rb +38 -2
  7. data/lib/mamiya/agent/actions.rb +4 -0
  8. data/lib/mamiya/agent/tasks/clean.rb +35 -0
  9. data/lib/mamiya/agent/tasks/notifyable.rb +4 -1
  10. data/lib/mamiya/agent/tasks/prepare.rb +2 -0
  11. data/lib/mamiya/agent/tasks/switch.rb +123 -0
  12. data/lib/mamiya/cli.rb +1 -20
  13. data/lib/mamiya/cli/client.rb +225 -3
  14. data/lib/mamiya/configuration.rb +18 -0
  15. data/lib/mamiya/master/agent_monitor.rb +19 -4
  16. data/lib/mamiya/master/agent_monitor_handlers.rb +10 -0
  17. data/lib/mamiya/master/application_status.rb +72 -0
  18. data/lib/mamiya/master/package_status.rb +178 -0
  19. data/lib/mamiya/master/web.rb +48 -44
  20. data/lib/mamiya/steps/build.rb +1 -1
  21. data/lib/mamiya/steps/prepare.rb +1 -1
  22. data/lib/mamiya/steps/switch.rb +2 -1
  23. data/lib/mamiya/storages/filesystem.rb +1 -1
  24. data/lib/mamiya/storages/mock.rb +1 -1
  25. data/lib/mamiya/storages/s3.rb +1 -1
  26. data/lib/mamiya/storages/s3_proxy.rb +1 -1
  27. data/lib/mamiya/version.rb +1 -1
  28. data/spec/agent/actions_spec.rb +26 -1
  29. data/spec/agent/tasks/clean_spec.rb +88 -2
  30. data/spec/agent/tasks/notifyable_spec.rb +3 -3
  31. data/spec/agent/tasks/switch_spec.rb +176 -0
  32. data/spec/agent_spec.rb +142 -1
  33. data/spec/configuration_spec.rb +23 -0
  34. data/spec/master/agent_monitor_spec.rb +128 -38
  35. data/spec/master/application_status_spec.rb +171 -0
  36. data/spec/master/package_status_spec.rb +560 -0
  37. data/spec/master/web_spec.rb +116 -1
  38. data/spec/steps/build_spec.rb +1 -1
  39. data/spec/steps/prepare_spec.rb +6 -1
  40. data/spec/steps/switch_spec.rb +6 -2
  41. data/spec/storages/filesystem_spec.rb +2 -21
  42. data/spec/storages/s3_proxy_spec.rb +2 -22
  43. data/spec/storages/s3_spec.rb +2 -20
  44. metadata +11 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5cff88034ce82da05b6bbef3f14e01c3d64a0106
4
- data.tar.gz: 955b085f2d2ad3911608daf3356569b072c37af1
3
+ metadata.gz: 782cb5f0d2988afede38796bf84f3b37f3343684
4
+ data.tar.gz: 2d4f5b6102d93c5e05cbc3779364466ca171bece
5
5
  SHA512:
6
- metadata.gz: 09ac1bd2fa42fe80d9c7c0c253b387987f1bd65d73036447c1ebe76b3a7b0a35a442652dea295d6c210d8ad8a5ee8311c004822db6adb2315a1824fc1da6551c
7
- data.tar.gz: 231d431e2a6ab44a47843712edff9b9389aa0594b87915ef308ee08b7ffe914ba3abb4007cbe772c85ae9f4ceecdde43ec9f4a129bb7020ff82a3c02e51538f5
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 in such storage (Amazon S3), and [serf](http://www.serfdom.io/).
5
+ Mamiya allows you to deploy using without ssh -- using tarballs, some storages (S3, etc), and [Serf](http://www.serfdom.io/).
6
6
 
7
- _Still developing_
7
+ ## Installation
8
8
 
9
- ## Problem for other deploy tool
9
+ $ gem install mamiya
10
10
 
11
- Existing major deploy tools (capistrano, mina, ...) use SSH to operate servers.
12
- But connecting to lot of servers via SSH makes deployment slow.
11
+ or bundle it:
13
12
 
14
- This solves such problem by using [Serf](http://www.serfdom.io/) and tarball on one storage (Amazon S3).
13
+ ``` ruby
14
+ gem 'mamiya'
15
+ ```
15
16
 
16
- Also, I'm planning to allow to distribute files before the deploy command. I guess this can skip or shorten
17
- file transferring phase in deploy.
18
-
19
- ## Installation
17
+ ## Usage
20
18
 
21
- Add this line to your application's Gemfile:
19
+ (Detailed documentation coming soon)
22
20
 
23
- gem 'mamiya'
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
- And then execute:
30
+ [example](./example) directory contains configuration files that work out-of-the-box. Try Mamiya in your local machine: `foreman start`
26
31
 
27
- $ bundle
32
+ ## Problems in existing deploy tool
28
33
 
29
- Or install it yourself as:
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
- $ gem install mamiya
37
+ This solves such problem by using [Serf](http://www.serfdom.io/) and tarball on one storage (Amazon S3).
32
38
 
33
- ## Usage
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
 
@@ -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
- {'packages' => self.existing_packages,
177
- 'prereleases' => self.existing_prereleases,
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
@@ -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
@@ -41,6 +41,8 @@ module Mamiya
41
41
 
42
42
  extract_step.run!
43
43
  prepare_step.run!
44
+
45
+ task_queue.enqueue(:clean, {})
44
46
  end
45
47
 
46
48
  private
@@ -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