mamiya 0.2.1 → 0.2.2

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 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