mamiya 0.0.1.beta3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: feb2301bfc6bf520112e3606038d9c5387a3bd94
4
- data.tar.gz: b4f96200bd9d5d2495cfd62076f4a9e804f6ef61
3
+ metadata.gz: 8fa28dadde7c00c1165fb66de3fceee10b564577
4
+ data.tar.gz: 614971d0864612144dab18e4db4aee2c3c7a1126
5
5
  SHA512:
6
- metadata.gz: d18e32e3a5ee9ec3a46560337b810c254f1f51008eb1e3ec0be4ab8a3df3b774d73397e21bb6b341b317602b14ec47db5b3ef1281f9300c09f2b40faf81ba47f
7
- data.tar.gz: 2004514ee647cec743bcce5a0230f0ceb012157bcae4662a32ba82efda376e8307c0cbdd142c03334e836969ef5fc1feb3217a0f298370b315972a4a0c9ab8c8
6
+ metadata.gz: 494a8f6d5d1e171ec5f2a154a81c534780eb464e6bc30adff4df5e9393788a43eb57a6f2ffaea7e11ce0208c34b9f5a64547fed531149da478a083380ec18a96
7
+ data.tar.gz: 3cc97e2941f5a10f5ce67552ec1066431f08c1b6ffe4748a2563fa1f085229bc68074e702649529fa3492a682f36f516795b6b963c4f2dbebcf81136be52fd86
data/.travis.yml CHANGED
@@ -1,7 +1,8 @@
1
1
  language: ruby
2
2
  cache: bundler
3
3
  rvm:
4
- - "2.1.1"
4
+ - "2.2"
5
+ - "2.1"
5
6
  - "2.0.0"
6
7
  - "ruby-head"
7
8
 
data/README.md CHANGED
@@ -6,28 +6,22 @@ Mamiya allows you to deploy using without ssh -- using tarballs, some storages (
6
6
 
7
7
  ## Installation
8
8
 
9
- $ gem install mamiya
10
-
11
- or bundle it:
12
-
13
- ``` ruby
14
- gem 'mamiya'
15
- ```
16
-
17
- ## Usage
18
-
19
9
  (Detailed documentation coming soon)
20
10
 
21
- 1. Prepare master node for `mamiya master` process
11
+ 1. Install gem (`gem install mamiya`, or bundling by `gem 'mamiya'`)
12
+ 2. Prepare master node for `mamiya master` process
22
13
  - master has HTTP API to allow control the cluster via HTTP
23
14
  - 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
15
+ 3. Then install `mamiya agent` in your deployment target hosts
16
+ 4. Write deploy script for your own
26
17
  - how to build package, how to prepare release, how to release, etc.
27
- 4. Build then push package
28
- 5. Time to deploy
18
+ 5. Build then push package
19
+ 6. Time to deploy
29
20
 
30
- [example](./example) directory contains configuration files that work out-of-the-box. Try Mamiya in your local machine: `foreman start`
21
+ ### Example configuration
22
+
23
+ [example](./example) directory contains configuration files that work out-of-the-box.
24
+ Try Mamiya in your local machine: `foreman start`
31
25
 
32
26
  ## Problems in existing deploy tool
33
27
 
@@ -39,30 +33,13 @@ This solves such problem by using [Serf](http://www.serfdom.io/) and tarball on
39
33
  Also, I'm planning to allow to distribute files before the deploy command. I guess this can skip or shorten
40
34
  file transferring phase in deploy.
41
35
 
36
+ ## Misc.
42
37
 
43
- ## Upgrade Notes
44
-
45
- ### 0.0.1.alpha21
46
-
47
- #### Configuration now written in Ruby
38
+ - [Scalable Deployments - How we deploy Rails app to 150+ hosts in a minute // Speaker Deck](https://speakerdeck.com/sorah/scalable-deployments-how-we-deploy-rails-app-to-150-plus-hosts-in-a-minute)
48
39
 
49
- You should rewrite your configuration yaml in Ruby. See examples/config.rb for example.
50
-
51
- ### 0.0.1.alpha20
52
-
53
- _tl;dr_ Don't mix alpha19 and alpha20.
54
-
55
- #### Internal component for distribution has been replaced completely
56
-
57
- alpha20 introduces new class `TaskQueue` and removes `Fetcher`. This changes way to distribute packages -- including internal serf events, job tracking that Distribution API does, etc.
58
- So basically there's no compatibility for distribution, between alpha19 and alpha20 and later. Distribute task from alpha20 doesn't effect to alpha19, and vice versa.
59
-
60
- Good new: There's no change in Distribution API.
61
-
62
- #### Agent status has changed
40
+ ## Upgrade Notes
63
41
 
64
- - Due to removal of `Fetcher`, alpha20 removes `.fetcher` object from agent status.
65
- - Added `.queues`, represents task queues that managed by `TaskQueue` class.
42
+ See [docs/upgrading.md](./docs/upgrading.md).
66
43
 
67
44
  ## Contributing
68
45
 
data/docs/upgrading.md ADDED
@@ -0,0 +1,25 @@
1
+ # Upgrade Notes
2
+
3
+ ## 0.0.1.alpha21
4
+
5
+ ### Configuration now written in Ruby
6
+
7
+ You should rewrite your configuration yaml in Ruby. See examples/config.rb for example.
8
+
9
+ ## 0.0.1.alpha20
10
+
11
+ _tl;dr_ Don't mix alpha19 and alpha20.
12
+
13
+ ### Internal component for distribution has been replaced completely
14
+
15
+ alpha20 introduces new class `TaskQueue` and removes `Fetcher`. This changes way to distribute packages -- including internal serf events, job tracking that Distribution API does, etc.
16
+ So basically there's no compatibility for distribution, between alpha19 and alpha20 and later. Distribute task from alpha20 doesn't effect to alpha19, and vice versa.
17
+
18
+ Good new: There's no change in Distribution API.
19
+
20
+ ### Agent status has changed
21
+
22
+ - Due to removal of `Fetcher`, alpha20 removes `.fetcher` object from agent status.
23
+ - Added `.queues`, represents task queues that managed by `TaskQueue` class.
24
+
25
+
@@ -42,6 +42,7 @@ set :keep_packages, 3
42
42
  set :keep_prereleases, 3
43
43
  set :fetch_sleep, 2
44
44
 
45
+ _labels = [rand(2) == 0 ? :a : :b]
45
46
  labels do
46
- [:"p#{ENV['PORT']}"]
47
+ [:"p#{ENV['PORT']}", *_labels]
47
48
  end
data/example/deploy.rb CHANGED
@@ -16,6 +16,28 @@ set :build_to, "#{File.dirname(__FILE__)}/builds"
16
16
  # to test it
17
17
  Dir.mkdir build_to unless File.exist?(build_to)
18
18
 
19
+ build("test") do
20
+ # build something...
21
+ File.write('built_at', "#{Time.now}\n")
22
+ end
23
+
24
+ prepare 'test' do
25
+ # run 'bundle', 'install'
26
+ sleep 5
27
+ File.write release_path.join('prepared_at'), Time.now
28
+ end
29
+
30
+ release 'test' do
31
+ # run '/etc/init.d/app', 'reload'
32
+ i = rand(10)
33
+ logger.info "SLEEP #{i} sec"
34
+ sleep i
35
+ File.write release_path.join('released_at'), Time.now
36
+ end
37
+
38
+
39
+
40
+
19
41
  #set :bundle_without, [:development, :test]
20
42
  #set :bundle_dir, "#{deploy_to}/shared/bundle"
21
43
 
@@ -25,10 +47,6 @@ Dir.mkdir build_to unless File.exist?(build_to)
25
47
  # run "bundle", "install"
26
48
  #end
27
49
 
28
- build("test") do
29
- File.write('built_at', "#{Time.now}\n")
30
- end
31
-
32
50
  #build("include assets and .bundle") do
33
51
  # exclude_from_package.reject! { |_| _ == 'public/assets/' }
34
52
  # exclude_from_package.reject! { |_| _ == '.bundle/' }
@@ -38,21 +56,4 @@ end
38
56
  # run "bundle", "exec", "rake", "assets:precompile"
39
57
  #end
40
58
 
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
-
58
59
 
@@ -117,6 +117,8 @@ module Mamiya
117
117
  begin
118
118
  status[:lock].synchronize do
119
119
  status[:pending].delete task
120
+
121
+ task['start'] = Time.now.to_i
120
122
  status[:working] = task
121
123
  end
122
124
  task_logger = @logger.with_clean_progname
@@ -52,8 +52,10 @@ module Mamiya
52
52
  raise PrereleaseMissing, "Existing release is not prepared but prerelease doesn't exist"
53
53
  end
54
54
 
55
- logger.info "Copying #{prerelease_path} -> #{release_path}"
56
- FileUtils.cp_r prerelease_path, release_path
55
+ unless release_path.exist?
56
+ logger.info "Copying #{prerelease_path} -> #{release_path}"
57
+ FileUtils.cp_r prerelease_path, release_path
58
+ end
57
59
 
58
60
  logger.info "Switching"
59
61
  switch_step.run!
@@ -5,28 +5,18 @@ module Mamiya
5
5
  class Switch < Abstract
6
6
  def run!
7
7
  @exception = nil
8
- logger.info "Switching to #{target}"
9
-
10
- script.before_switch(labels)[]
11
-
12
- # TODO: link with relative if available?
13
- # TODO: Restore this if FAILED
14
- File.unlink script.current_path if script.current_path.symlink?
15
- script.current_path.make_symlink(target.realpath)
8
+ @switched = false
16
9
 
17
- if do_release?
18
- begin
19
- old_pwd = Dir.pwd
20
- Dir.chdir(target)
21
-
22
- logger.info "Releasing..."
10
+ if current_targets_release?
11
+ logger.info "Already switched"
12
+ else
13
+ switch
14
+ end
23
15
 
24
- script.release(labels)[@exception]
25
- ensure
26
- Dir.chdir old_pwd if old_pwd
27
- end
16
+ if @switched ? do_release? : force_release?
17
+ release
28
18
  else
29
- logger.warn "Skipping release (:no_release is set)"
19
+ logger.warn "Skipping release"
30
20
  end
31
21
 
32
22
  rescue Exception => e
@@ -35,11 +25,34 @@ module Mamiya
35
25
  ensure
36
26
  logger.warn "Exception occured, cleaning up..." if @exception
37
27
 
38
- script.after_switch(labels)[@exception]
28
+ script.after_switch(labels)[@exception] if @switched
39
29
 
40
30
  logger.info "DONE!" unless @exception
41
31
  end
42
32
 
33
+ def switch
34
+ logger.info "Switching to #{target}"
35
+ @switched = true
36
+ script.before_switch(labels)[]
37
+
38
+ File.unlink script.current_path if script.current_path.symlink?
39
+ script.current_path.make_symlink(target.realpath)
40
+ end
41
+
42
+ def release
43
+ # TODO: link with relative if available?
44
+ # TODO: Restore this if FAILED
45
+
46
+ old_pwd = Dir.pwd
47
+ Dir.chdir(target)
48
+
49
+ logger.info "Releasing..."
50
+
51
+ script.release(labels)[@exception]
52
+ ensure
53
+ Dir.chdir old_pwd if old_pwd
54
+ end
55
+
43
56
  # XXX: dupe with prepare step. modulize?
44
57
 
45
58
  # This class see target_dir's script
@@ -57,8 +70,20 @@ module Mamiya
57
70
 
58
71
  private
59
72
 
73
+ def current_targets_release?
74
+ script.current_path.exist? && script.current_path.realpath == target.realpath
75
+ end
76
+
60
77
  def do_release?
61
- !options[:no_release]
78
+ force_release? ? true : !no_release?
79
+ end
80
+
81
+ def force_release?
82
+ !!options[:do_release]
83
+ end
84
+
85
+ def no_release?
86
+ !!options[:no_release]
62
87
  end
63
88
 
64
89
  def target
@@ -1,3 +1,3 @@
1
1
  module Mamiya
2
- VERSION = "0.0.1.beta3"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -41,7 +41,6 @@ describe Mamiya::Agent::TaskQueue do
41
41
  end
42
42
  end
43
43
 
44
-
45
44
  let(:task_class_a) do
46
45
  Class.new(task_class_root) do
47
46
  def self.identifier
@@ -62,6 +61,10 @@ describe Mamiya::Agent::TaskQueue do
62
61
  described_class.new(agent, task_classes: [task_class_a, task_class_b])
63
62
  end
64
63
 
64
+ before do
65
+ allow(Time).to receive(:now).and_return(Time.now)
66
+ end
67
+
65
68
  describe "lifecycle (#start!, #stop!)" do
66
69
  it "can start and stop" do
67
70
  expect(queue).not_to be_running
@@ -170,7 +173,7 @@ describe Mamiya::Agent::TaskQueue do
170
173
 
171
174
  100.times { break unless task_class_a.locks.empty?; sleep 0.01 }
172
175
  expect(task_class_a.locks).not_to be_empty
173
- expect(queue.status[:a][:working]).to eq('wait' => true, 'id' => 1, 'task' => :a)
176
+ expect(queue.status[:a][:working]).to eq('wait' => true, 'id' => 1, 'task' => :a, 'start' => Time.now.to_i)
174
177
 
175
178
  queue.enqueue(:a, 'id' => 2)
176
179
  100.times { break unless queue.status[:a][:queue].empty?; sleep 0.01 }
@@ -236,8 +239,8 @@ describe Mamiya::Agent::TaskQueue do
236
239
  expect(task_class_a.locks).not_to be_empty
237
240
  expect(task_class_b.locks).not_to be_empty
238
241
 
239
- expect(queue.status[:a][:working]).to eq('wait' => true, 'id' => 1, 'task' => :a)
240
- expect(queue.status[:b][:working]).to eq('wait' => true, 'id' => 2, 'task' => :b)
242
+ expect(queue.status[:a][:working]).to eq('wait' => true, 'id' => 1, 'task' => :a, 'start' => Time.now.to_i)
243
+ expect(queue.status[:b][:working]).to eq('wait' => true, 'id' => 2, 'task' => :b, 'start' => Time.now.to_i)
241
244
 
242
245
  queue.enqueue(:a, 'id' => 3)
243
246
  queue.enqueue(:b, 'id' => 4)
@@ -119,6 +119,42 @@ describe Mamiya::Steps::Switch do
119
119
  }.from(nil).to(release_path.realpath)
120
120
  end
121
121
 
122
+ context "when current targets the target" do
123
+ before do
124
+ current_path.make_symlink(release_path.realpath)
125
+ end
126
+
127
+ it "doesn't call hooks" do
128
+ called = false
129
+ allow(script).to receive(:release).and_return(proc { called = true })
130
+ allow(script).to receive(:before_switch).and_return(proc { called = true })
131
+ allow(script).to receive(:after_switch).and_return(proc { called = true })
132
+ step.run!
133
+
134
+ expect(called).to be_false
135
+ end
136
+
137
+ context "with do_release" do
138
+ let(:options) do
139
+ {target: release_path, do_release: true}
140
+ end
141
+
142
+ it "calls hooks" do
143
+ hooks = %i(release)
144
+
145
+ flags = []
146
+ hooks.each do |sym|
147
+ allow(script).to receive(sym).and_return(proc { flags << sym })
148
+ end
149
+
150
+ expect { step.run! }.
151
+ to change { flags }.
152
+ from([]).
153
+ to(hooks)
154
+ end
155
+ end
156
+ end
157
+
122
158
  context "when current already exists" do
123
159
  before do
124
160
  current_path.make_symlink('releases/20140515000707')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mamiya
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.beta3
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shota Fukumori (sora_h)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-09-17 00:00:00.000000000 Z
11
+ date: 2014-09-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -180,9 +180,7 @@ files:
180
180
  - README.md
181
181
  - Rakefile
182
182
  - bin/mamiya
183
- - docs/cli.md
184
- - docs/sequences/deploy.png
185
- - docs/sequences/deploy.uml
183
+ - docs/upgrading.md
186
184
  - example/.gitignore
187
185
  - example/Procfile
188
186
  - example/README.md
@@ -289,9 +287,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
289
287
  version: '0'
290
288
  required_rubygems_version: !ruby/object:Gem::Requirement
291
289
  requirements:
292
- - - ">"
290
+ - - ">="
293
291
  - !ruby/object:Gem::Version
294
- version: 1.3.1
292
+ version: '0'
295
293
  requirements: []
296
294
  rubyforge_project:
297
295
  rubygems_version: 2.2.2
data/docs/cli.md DELETED
@@ -1,78 +0,0 @@
1
- # Commands
2
-
3
- ## Global options
4
-
5
- - `-C`, `--config`: path to configuration file (default: `./config.yml`)
6
- - config file won't be required if a command don't need it.
7
- - `-S`, `--script`: path to script file (default: `./deploy.rb`)
8
- - script file won't be required if a command don't need it.
9
- - `-a`, `--app`: Specify application name to operate
10
- - `-d`, `--debug`: Enable debug mode
11
- - `--color`, `--no-color`: Enable or disable colored output. When the stdout is a terminal, it'll be enabled by default.
12
-
13
- ## Storage related commands
14
-
15
- ### `list-applications` - list application in storage
16
-
17
- ```
18
- $ mamiya list-applications -C ./config.yml
19
- ```
20
-
21
- ### `list-packages` - list packages for specified app in storage
22
-
23
- ```
24
- $ mamiya list-packages -C ./config.yml -a myapp
25
- ```
26
-
27
- - __Requires:__ configuration file, application name
28
- - application name will be retrieved from deploy script when not specified.
29
- - __Options:__
30
- - `-n`, `--name-only`: Show only names (without heading text)
31
-
32
- ### `show` - show package information
33
-
34
- ```
35
- $ mamiya list-packages -C ./config.yml -a myapp PACKAGE_NAME
36
- ```
37
-
38
- - __Requires:__ configuration file, application name, package name
39
- - application name will be retrieved from deploy script when not specified.
40
- - __Options:__
41
- - `-f`, `--format`: Choose output format from `pp`, `json`, or `yaml`. Default: `pp`.
42
-
43
- ## Build, pushing and fetching packages
44
-
45
- ### `build` - build package using script
46
-
47
- ```
48
- $ mamiya build --script ./deploy.rb --source source_dir --destination dest_dir
49
- ```
50
-
51
- - __Requires:__ application name, source, destination, deploy script
52
- - source, description, and app name will be taken from deploy script, if omitted
53
- - __Options:__
54
- - `-f`, `--source`, `--build-from`: directory for package source.
55
- - `-t`, `--destination`, `--build-to`: directory to save built packages.
56
- - `-P`, `--skip-prepare-build`: Skip prepare build phase of deploy script.
57
-
58
- ### `push` - push built package to the storage
59
-
60
- ### `fetch`
61
-
62
- ## Package related commands
63
-
64
- ### `extract`
65
-
66
- ## `client` - API client for `mamiya master`
67
-
68
- ### `list-applications`
69
-
70
- ### `list-packages`
71
-
72
- ### `show-package`
73
-
74
- ### `list-agents`
75
-
76
- ### `show-agent`
77
-
78
- ### `show-distribution`
Binary file
@@ -1,58 +0,0 @@
1
- @startuml
2
- == Building ==
3
- Master --> Master: Build package
4
- note right of Master: e.g. assets precompile
5
- Master --> Storage: Upload package
6
-
7
- == Distributing ==
8
- Master --> Client: Download request
9
- activate Master
10
- Master --> Master: Wait all clients to have package to deploy
11
-
12
- alt if doesn't have package
13
- activate Client
14
- Client --> Client: Set status serf tag
15
- Client --> Storage: HTTP request
16
- Storage --> Client: Response package
17
- Client --> Client: Set packages serf tag
18
- Client --> Master: Report download finish
19
- deactivate Client
20
- end
21
-
22
- deactivate Master
23
-
24
- == Preparing ==
25
-
26
- Master --> Client: Request to prepare package
27
- activate Master
28
- Master --> Master: Wait all clients to have package to deploy
29
- activate Client
30
- Client --> Client: Set status serf tag
31
- Client --> Client: Unpack package
32
- Client --> Client: Run prepare phase
33
- note left of Client: e.g. bundle install, config files
34
- Client --> Client: Set prepared serf tag
35
- Client --> Client: Set status serf tag
36
- Client --> Master: Report preparation finish
37
- deactivate Client
38
- deactivate Master
39
-
40
- == Finalize ==
41
-
42
- Master --> Client: Request finalize
43
- activate Master
44
- Master --> Master: Wait all clients restarted
45
- activate Client
46
- Client --> Client: Set status serf tag
47
- Client --> Client: Run finalize phase
48
- note left of Client: e.g. restart web server
49
- Client --> Master: Report finalize complete
50
- Client --> Client: Set status serf tag
51
- Client --> Client: Wait to be reloaded
52
- Client --> Client: Set status serf tag
53
- Client --> Client: Set deployed serf tag
54
- Client --> Master: Report deploy complete
55
- deactivate Client
56
- deactivate Master
57
-
58
- @enduml