mamiya 0.2.1 → 0.2.2

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: 5b090d33b53e168ee13379616652d080bc4bd461
4
- data.tar.gz: 18514e6676da70a2e6fb15cca785e5c974202027
3
+ metadata.gz: 3fff2664bac4156374129f9094fe5fc7459d3b8b
4
+ data.tar.gz: efe0195812cbb482507dae05cacbb05cf8ca57a1
5
5
  SHA512:
6
- metadata.gz: 93457344b41f4febc0e835d9ad70bb8158602579d13edd078d248da359e898bea7464e54bb4abc7b619d4c7c6935de39a93f9cbc4d2772f5833e1daf930ce2c8
7
- data.tar.gz: 99dc4da9eb96dae58a2526fdb36b61aa77dac64a929bb8337f7a1263b6c6f7f2ab048172d1aa9161220975fd88f84bb477f731edd5f32b6679333a5ecc568995
6
+ metadata.gz: ed7ec72684c57cd099a95e2c66bca126637dd8837eb5c66ea2b9b74fc6a289b87acf041359289319ff79684ed3e6e3ebd56266d3facf1d14b21dd80cebb86083
7
+ data.tar.gz: aa23567e2219203fb190e5436398c5ae934baceb0ced7dcb7e4e1c226cfeb83c404c32fbb617d358fa37e9e31657556352e8f89caaf9a4384e02ed9aec1206b1
data/README.md CHANGED
@@ -2,23 +2,17 @@
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 -- using tarballs, some storages (S3, etc), and [Serf](http://www.serfdom.io/).
6
5
 
7
- ## Installation
6
+ ## What's mamiya?
8
7
 
9
- (Detailed documentation coming soon)
8
+ Mamiya allows you to deploy without ssh -- using tarballs, some storages (S3, etc), and [Serf](http://www.serfdom.io/).
9
+ Build application package on CI or somewhere, then distribute earlier (before you say "Deploy!"). You can switch to a new application quickly, when you're saying "deploy."
10
10
 
11
- 1. Install gem (`gem install mamiya`, or bundling by `gem 'mamiya'`)
12
- 2. Prepare master node for `mamiya master` process
13
- - master has HTTP API to allow control the cluster via HTTP
14
- - master watches agents in the cluster
15
- 3. Then install `mamiya agent` in your deployment target hosts
16
- 4. Write deploy script for your own
17
- - how to build package, how to prepare release, how to release, etc.
18
- 5. Build then push package
19
- - `mamiya build`
20
- - `mamiya push path/to/package.tar.gz`
21
- 6. Time to deploy: `mamiya client deploy -a app package`
11
+ Mamiya uses similar directory structure with Capistrano 'deploy_to' -- you can try this easy.
12
+
13
+ ## Quick Start
14
+
15
+ See [./docs/quick_start.md](./docs/quick_start.md).
22
16
 
23
17
  ### Example configuration
24
18
 
@@ -30,7 +24,7 @@ Try Mamiya in your local machine: `foreman start`
30
24
  Existing major deploy tools (capistrano, mina, ...) use SSH to operate servers.
31
25
  But connecting to lot of servers via SSH makes deployment slow.
32
26
 
33
- This solves such problem by using [Serf](http://www.serfdom.io/) and tarball on one storage (Amazon S3).
27
+ Mamiya solves such problem by using [Serf](http://www.serfdom.io/) and tarball on one storage (Amazon S3).
34
28
 
35
29
  Also, I'm planning to allow to distribute files before the deploy command. I guess this can skip or shorten
36
30
  file transferring phase in deploy.
@@ -0,0 +1,212 @@
1
+ # Quick Start
2
+
3
+ ## What's mamiya?
4
+
5
+ Mamiya allows you to deploy using without ssh -- using tarballs, some storages (S3, etc), and [Serf](http://www.serfdom.io/).
6
+ Build application package on CI or somewhere, then distribute earlier (before you say "Deploy!"). You can switch to an new application quickly, when you're saying "deploy."
7
+
8
+ Also, this free you from SSH and RSync problems.
9
+
10
+ ## Concepts
11
+
12
+ - __Package__ is a tarball contains your application.
13
+ - __Storage__ is a place to store package.
14
+ - __Script__ is a Ruby script that defines how to deploy (prepare, restart, etc) your application.
15
+
16
+ - __CI (or, somewhere)__ builds packages and push them on _Storage_
17
+ - __Master__ controls the cluster of _Agents_
18
+ - __Agent__ receives deployment and do it.
19
+
20
+ ## Prepare master and agent
21
+
22
+ Run `sudo gem install mamiya` to install mamiya on your systems.
23
+
24
+ (TODO: write init.d/systemd/upstart script for easier boot up)
25
+
26
+ ### Master
27
+
28
+ On a server for master node; it'll controll the cluster:
29
+
30
+ #### Configure
31
+
32
+ typical configuration for the master here:
33
+
34
+ ``` ruby
35
+ # /etc/mamiya/config.rb
36
+
37
+ set :storage, {
38
+ type: :s3,
39
+ bucket: 'YOUR-S3-BUCKET-NAME',
40
+ region: 'ap-northeast-1', # set it to your region
41
+ access_key_id: '...',
42
+ secret_access_key: '...',
43
+ }
44
+
45
+ set :serf, {
46
+ agent: {
47
+ bind: "0.0.0.0:7760",
48
+ rpc_addr: "127.0.0.1:7762",
49
+ }
50
+ }
51
+
52
+ set :web, {
53
+ port: 7761,
54
+ }
55
+ ```
56
+
57
+ #### Run it
58
+
59
+ ```
60
+ mamiya master -c /etc/mamiya/config.rb
61
+ ```
62
+
63
+ ### Agent
64
+
65
+ On a server for agent node; where the package will be deployed:
66
+
67
+ #### Configure
68
+
69
+ typical configuration for the agents here:
70
+
71
+ ``` ruby
72
+ # /etc/mamiya/config.rb
73
+
74
+ set :storage, {
75
+ type: :s3,
76
+ bucket: 'YOUR-S3-BUCKET-NAME',
77
+ region: 'ap-northeast-1', # set it to your region
78
+ access_key_id: '...',
79
+ secret_access_key: '...',
80
+ }
81
+
82
+ set :serf, {
83
+ agent: {
84
+ bind: "0.0.0.0:7760",
85
+ rpc_addr: "127.0.0.1:7762",
86
+ join: 'YOUR-MASTER-HOST:7760', # set it to your master host
87
+ }
88
+ }
89
+
90
+ set :web, {
91
+ port: 7761,
92
+ }
93
+
94
+ # Where should the application go. :myapp is a Symbol to identify application.
95
+ applications[:myapp] = {deploy_to: '/home/app/myapp'}
96
+
97
+ # Where should Mamiya store packages, pre-releases temporarily.
98
+ set :packages_dir, '/tmp/mamiya/packages'
99
+ set :prereleases_dir, '/tmp/mamiya/prereleases'
100
+
101
+ # And how many you want to keep them?
102
+ set :keep_packages, 3
103
+ set :keep_prereleases, 3
104
+
105
+ # Label your agent. Block will be called every time when referencing labels.
106
+ # (Recommend to implement thread or timeout for periodically fetch...)
107
+ labels do
108
+ %i(app production active)
109
+ end
110
+ ```
111
+
112
+ #### Run it
113
+
114
+ ```
115
+ mamiya master -c /etc/mamiya/config.rb
116
+ ```
117
+
118
+ ### Confirm both working
119
+
120
+ Use `mamiya client` command family to communicate with master process. By default `http://localhost:7761/` is used. You can change by `-m`, `--master` option or `$MAMIYA_MASTER_URL` environment variable.
121
+
122
+ ```
123
+ master $ mamiya client list-agents
124
+ AGENT_NAME alive
125
+ ```
126
+
127
+ ## Prepare deploy script
128
+
129
+ _Script_ should have required operations and configurations for an application being deployed.
130
+
131
+ Script is used for package building and deployments. It'll be copied into a package during package build, then deliver, used on agents.
132
+
133
+ ```
134
+ set :application, 'myapp'
135
+
136
+ # Using for package build
137
+ set :exclude_from_package, ['tmp', 'log', 'spec', '.sass-cache']
138
+ set :dereference_symlinks, true
139
+ set :build_from, "/tmp/build_from"
140
+ set :build_to, "./builds"
141
+ # set :package_under, 'dir'
142
+
143
+ # You may use helpers here
144
+ # set :repository, '...'
145
+ # use :git, exclude_git_clean_targets: true
146
+
147
+ # Procedure for build
148
+ build 'write built at' do
149
+ # build something...
150
+ File.write('built_at', "#{Time.now}\n")
151
+ end
152
+
153
+ # Step `prepare` on agents,
154
+ prepare 'write prepared_at' do
155
+ File.write release_path.join('prepared_at'), Time.now
156
+ end
157
+
158
+ # You can declare multiples. Run by order defined.
159
+ prepare 'bundle stuff' do
160
+ run 'bundle', 'install'
161
+ end
162
+
163
+ # Step `release` run when Release is required. Usually for restarting app process, etc.
164
+ # Also these step declaration accepts labels for `only` and `except` key to limit agents to run on.
165
+ # (Labels can be set by agent's configuration)
166
+ release 'reload unicorn', only [:app] do
167
+ run 'pkill', '-HUP', '-f', 'unicorn'
168
+ end
169
+ ```
170
+
171
+ ## Build your first package and push it
172
+
173
+ Have all agents and master node run? Okay, let's build your first package!
174
+
175
+ ```
176
+ $ mamiya build -S ./deploy.rb
177
+ 11/18 09:37:01 INFO [Build] Running script.before_build
178
+ 11/18 09:37:01 INFO [Build] Running script.prepare_build
179
+ 11/18 09:37:01 INFO [Build] Running script.build
180
+ 11/18 09:37:01 INFO [Build] Copying script files
181
+ 11/18 09:37:01 INFO [Build] Packed.
182
+ 11/18 09:37:01 INFO [Build] Running script.after_build
183
+ 11/18 09:37:01 INFO [Build] DONE: 20141118093701-myapp built at .../builds/20141118093701-myapp.tar.gz
184
+ ```
185
+
186
+ (`-S`,` --script` specifies where the script is. More options available; see `mamiya help build`)
187
+
188
+ Great! You can unpack using `tar xf` to confirm what has packed, if you want.
189
+
190
+ You have to push it onto storage to make available for agents.
191
+
192
+ ```
193
+ $ mamiya push -C ./config.rb
194
+ 11/18 09:42:43 INFO [Push] Pushing builds/20141118093701-myapp.tar.gz to storage(app=myapp)...
195
+ 11/18 09:42:43 INFO [Push] DONE!
196
+ ```
197
+
198
+ (`-C`, `--config` specifies where configuration file is... to find `:storage` configuration.)
199
+
200
+ ## Deploy it
201
+
202
+ `mamiya client deploy <PACKAGE>` prepares the package then release it after all nodes get ready.
203
+
204
+ ```
205
+ $ export MAMIYA_APP=myapp
206
+ $ mamiya client list-packages
207
+ 20141118093701-myapp
208
+ $ mamiya client deploy 20141118093701-myapp
209
+ ```
210
+
211
+ (You can use `-a`, `--application` option instead of `$MAMIYA_APP`)
212
+
@@ -295,19 +295,17 @@ not distributed: #{dist['not_distributed_count']} agents
295
295
 
296
296
  if type == :deploy
297
297
  do_prep = -> do
298
- puts "=> Preparing..."
298
+ puts " * sending prepare request"
299
299
  prepare(package)
300
300
  end
301
301
 
302
- do_prep[]
303
-
304
- puts " * Wait until prepared"
302
+ puts "=> Wait agents to have prepared"
305
303
  puts ""
306
304
 
307
305
  i = 0
308
306
  loop do
309
307
  i += 1
310
- do_prep[] if i % 25 == 0
308
+ do_prep[] if i == 2 || i % 25 == 0
311
309
 
312
310
  s = pkg_status(package, :short)
313
311
  puts ""
@@ -6,6 +6,18 @@ require 'json'
6
6
  module Mamiya
7
7
  module Storages
8
8
  class S3 < Mamiya::Storages::Abstract
9
+ class MultipleObjectsDeletionError < StandardError
10
+ attr_accessor :errors
11
+
12
+ def initialize(errors)
13
+ message = errors.map do |error|
14
+ "#{error.code}: #{error.message} (key=#{error.key})"
15
+ end.join(', ')
16
+ super(message)
17
+ @errors = errors
18
+ end
19
+ end
20
+
9
21
  def self.find(config={})
10
22
  s3 = initiate_s3_with_config(config)
11
23
  Hash[s3.list_objects(bucket: config[:bucket], delimiter: '/').common_prefixes.map { |prefix|
@@ -96,7 +108,10 @@ module Mamiya
96
108
  }.compact
97
109
  raise NotFound if objs_to_delete.empty?
98
110
 
99
- s3.delete_objects(bucket: @config[:bucket], delete: {objects: objs_to_delete})
111
+ result = s3.delete_objects(bucket: @config[:bucket], delete: {objects: objs_to_delete})
112
+ unless result.errors.empty?
113
+ raise MultipleObjectsDeletionError.new(result.errors)
114
+ end
100
115
  end
101
116
 
102
117
  def self.initiate_s3_with_config(config) # :nodoc:
@@ -1,3 +1,3 @@
1
1
  module Mamiya
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
@@ -250,6 +250,7 @@ describe Mamiya::Storages::S3 do
250
250
 
251
251
  describe "#remove(package_name)" do
252
252
  let(:package_name) { 'test' }
253
+ let(:s3_delete_response) { double('response for POST /?delete', errors: []) }
253
254
  subject(:remove) { storage.remove(package_name) }
254
255
 
255
256
  before do
@@ -257,7 +258,7 @@ describe Mamiya::Storages::S3 do
257
258
  end
258
259
 
259
260
  it "removes specified package from S3" do
260
- expect(s3).to receive(:delete_objects).with(bucket: 'testbucket', delete: {objects: [{key: 'myapp/test.tar.gz'}, {key: 'myapp/test.json'}]})
261
+ expect(s3).to receive(:delete_objects).with(bucket: 'testbucket', delete: {objects: [{key: 'myapp/test.tar.gz'}, {key: 'myapp/test.json'}]}).and_return(s3_delete_response)
261
262
  remove
262
263
  end
263
264
 
@@ -265,7 +266,7 @@ describe Mamiya::Storages::S3 do
265
266
  let(:package_name) { 'test.tar.gz' }
266
267
 
267
268
  it "removes specified package from S3" do
268
- expect(s3).to receive(:delete_objects).with(bucket: 'testbucket', delete: {objects: [{key: 'myapp/test.tar.gz'}, {key: 'myapp/test.json'}]})
269
+ expect(s3).to receive(:delete_objects).with(bucket: 'testbucket', delete: {objects: [{key: 'myapp/test.tar.gz'}, {key: 'myapp/test.json'}]}).and_return(s3_delete_response)
269
270
  remove
270
271
  end
271
272
  end
@@ -274,7 +275,7 @@ describe Mamiya::Storages::S3 do
274
275
  let(:package_name) { 'test.json' }
275
276
 
276
277
  it "removes specified package from S3" do
277
- expect(s3).to receive(:delete_objects).with(bucket: 'testbucket', delete: {objects: [{key: 'myapp/test.tar.gz'}, {key: 'myapp/test.json'}]})
278
+ expect(s3).to receive(:delete_objects).with(bucket: 'testbucket', delete: {objects: [{key: 'myapp/test.tar.gz'}, {key: 'myapp/test.json'}]}).and_return(s3_delete_response)
278
279
  remove
279
280
  end
280
281
  end
@@ -288,6 +289,21 @@ describe Mamiya::Storages::S3 do
288
289
  expect { storage.remove('test') }.to raise_error(Mamiya::Storages::Abstract::NotFound)
289
290
  end
290
291
  end
292
+
293
+ context "when delete_objects fails" do
294
+ let(:errors) do
295
+ [
296
+ double('Aws::S3::Errors::InteranlError', code: 'InteranlError', message: 'Internal Error', key: 'myapp/test.tar.gz'),
297
+ double('Aws::S3::Errors::AccessDenied', code: 'AccessDenied', message: 'Access Denied', key: 'myapp/test.json'),
298
+ ]
299
+ end
300
+ let(:s3_delete_response) { double('response for POST /?delete', errors: errors) }
301
+
302
+ it "raises error" do
303
+ expect(s3).to receive(:delete_objects).with(bucket: 'testbucket', delete: {objects: [{key: 'myapp/test.tar.gz'}, {key: 'myapp/test.json'}]}).and_return(s3_delete_response)
304
+ expect { remove }.to raise_error(Mamiya::Storages::S3::MultipleObjectsDeletionError, /Access Denied/)
305
+ end
306
+ end
291
307
  end
292
308
 
293
309
  describe ".find" do
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.2.1
4
+ version: 0.2.2
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-10-20 00:00:00.000000000 Z
11
+ date: 2014-12-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -183,6 +183,7 @@ files:
183
183
  - docs/internal/serf_events.md
184
184
  - docs/internal/serf_queries.md
185
185
  - docs/internal/tasks.md
186
+ - docs/quick_start.md
186
187
  - docs/upgrading.md
187
188
  - example/.gitignore
188
189
  - example/Procfile
@@ -297,7 +298,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
297
298
  version: '0'
298
299
  requirements: []
299
300
  rubyforge_project:
300
- rubygems_version: 2.2.2
301
+ rubygems_version: 2.4.1
301
302
  signing_key:
302
303
  specification_version: 4
303
304
  summary: Fast deploy tool using tarballs and serf