joumae 0.1.0 → 0.2.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: d5ab0c54854665d91ae1ba7c7638f325fc630dbe
4
- data.tar.gz: 9721b41223c894b49004bd1f84ece6ad982ebbe3
3
+ metadata.gz: 5d1c747df9f623727c13160a5717d41f3aa0393d
4
+ data.tar.gz: 5a5a8885e10c261ff9a0c9bc7cfcedc1a00ae1f4
5
5
  SHA512:
6
- metadata.gz: f3a9d53966637570389ec1812f4965e7c34cd4515dbd3eb1dda93109e0f53acdea497e41a07ed98fd7b5c7a79db83e3d6cd8de062889c6a08328a49eb7c5c3a5
7
- data.tar.gz: 7a092e0fc7531f07d55d3ba81f8498ed3bd1d55735cade8fced13dd35f6e5e2ab41ec89c3778a91f4e7878c1f919248ca1b7725f9917f5a33048ae12bab78956
6
+ metadata.gz: 93c49e86d5d8c965a0092db4cfad1daf54308a4e7c822b5e2abc8a9fe0accdd2549d6f6f9a6a012b280fbe84462e757688d43f001234e95d5bd0efda30059033
7
+ data.tar.gz: 99491532511ca7b8c12e9ba2b9477fdf6fd50ee73b013d66dc8d014418d46acb3050f6a482629a98864fa4f0790209f9662d7e4ca452f7c95ec7ea3d76ed481c
data/.gitignore CHANGED
@@ -1,2 +1,5 @@
1
1
  *~
2
2
  .env
3
+ .envrc
4
+ pkg/
5
+ bin/
data/README.md CHANGED
@@ -22,7 +22,22 @@ Or install it yourself as:
22
22
 
23
23
  ## Usage
24
24
 
25
- TODO: Write usage instructions here
25
+ ### CLI
26
+
27
+ The `joumae` command allows you to run arbitrary commands while locking a named resource:
28
+
29
+ ```
30
+ $ joumae --resource-name your-app-servers run -- bash -c "\"echo Deployment started.; sleep 10; echo Deployment finished.\""
31
+ ```
32
+
33
+ If you consecutively ran the command twice, the latter one fails because the resource is already locked.
34
+
35
+ The `joumae` command requires two environment variables to be present:
36
+
37
+ ```
38
+ export JOUMAE_API_ENDPOINT="https://yourid.execute-api.ap-northeast-1.amazonaws.com/yourstage/"
39
+ export JOUMAE_API_KEY="eyJ0eXAiOiJKV1QiLCJhbGc..."
40
+ ```
26
41
 
27
42
  ## Development
28
43
 
data/exe/joumae ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'joumae/cli'
4
+ Joumae::CLI.run!
data/integration_test.rb CHANGED
@@ -7,14 +7,20 @@ client = Joumae::Client.create
7
7
 
8
8
  uuid = SecureRandom.uuid
9
9
  p client.create(uuid)
10
- p client.acquire(uuid, 'test')
11
- p client.renew(uuid, 'tet')
12
- p client.release(uuid, 'test')
10
+ p client.acquire(uuid)
11
+ p client.renew(uuid)
12
+ p client.release(uuid)
13
13
 
14
- transaction = Joumae::Transaction.new(resource_name: uuid, owner: 'test', client: client)
14
+ #Joumae::Command.new(resource_name: "app-development-deployment", owner: "kuoka", client: Joumae::Client.create)
15
+
16
+ transaction = Joumae::Transaction.new(resource_name: uuid, client: client)
15
17
 
16
18
  transaction.start
17
19
 
18
20
  sleep 10
19
21
 
20
22
  transaction.finish
23
+
24
+ command = Joumae::Command.new("sleep 10", resource_name: uuid, client: client)
25
+
26
+ command.run!
data/lib/joumae/cli.rb ADDED
@@ -0,0 +1,50 @@
1
+ require 'optparse'
2
+
3
+ require 'joumae'
4
+ require "joumae/logging"
5
+
6
+ module Joumae
7
+ class CLI
8
+ include Logging
9
+
10
+ def initialize(argv)
11
+ @argv = argv
12
+ end
13
+
14
+ def parse!
15
+ argv = @argv.dup
16
+
17
+ opt = OptionParser.new
18
+ opt.on('--resource-name VALUE') { |v| @resource_name = v }
19
+ opt.parse!(argv)
20
+ @sub, *@args= argv
21
+ debug [@sub, @args]
22
+ end
23
+
24
+ def run!
25
+ parse!
26
+
27
+ case @sub
28
+ when "run"
29
+ client = Joumae::Client.create
30
+ cmd = @args.join(" ")
31
+ command = Joumae::Command.new(cmd, resource_name: @resource_name, client: client)
32
+ begin
33
+ command.run!
34
+ rescue Joumae::CommandFailedError => e
35
+ $stderr.puts "#{e.message} Aborting."
36
+ exit e.status
37
+ rescue Joumae::Client::ResourceAlreadyLockedError => e
38
+ $stderr.puts "#{e.message} Aborting."
39
+ exit 1
40
+ end
41
+ else
42
+ fail "The sub-command #{@sub} does not exist."
43
+ end
44
+ end
45
+
46
+ def self.run!
47
+ new(ARGV).run!
48
+ end
49
+ end
50
+ end
data/lib/joumae/client.rb CHANGED
@@ -20,21 +20,21 @@ module Joumae
20
20
  post_json(resources_url, {api_key: api_key, name: name})
21
21
  end
22
22
 
23
- def acquire(name, acquired_by)
24
- post_json(acquire_resource_url, {api_key: api_key, name: name, acquiredBy: acquired_by})
23
+ def acquire(name)
24
+ post_json(acquire_resource_url(name), {api_key: api_key})
25
25
  end
26
26
 
27
- def renew(name, acquired_by)
28
- post_json(renew_resource_url, {api_key: api_key, name: name, acquired_by: acquired_by})
27
+ def renew(name)
28
+ post_json(renew_resource_url(name), {api_key: api_key})
29
29
  end
30
30
 
31
- def release(name, acquired_by)
32
- post_json(release_resource_url, {api_key: api_key, name: name, acquired_by: acquired_by})
31
+ def release(name)
32
+ post_json(release_resource_url(name), {api_key: api_key})
33
33
  end
34
34
 
35
35
  def post_json(url, params={})
36
36
  begin
37
- logger.info "POST #{url} #{params.to_json}"
37
+ debug "POST #{url} #{params.to_json}"
38
38
  request = Net::HTTP::Post.new(url.path, {'Content-Type' =>'application/json'})
39
39
  request.body = params.to_json
40
40
  https = Net::HTTP.new(url.hostname, 443)
@@ -45,11 +45,17 @@ module Joumae
45
45
  # response = httpclient.post_content(url, params.to_json, header: {'Content-Type' => 'application/json'})
46
46
 
47
47
  if response.code == '404'
48
- fail "Not found."
48
+ fail ResourceNotFoundError, "Not found."
49
+ elsif response.code == '423'
50
+ response_body_as_json = JSON.parse(response.body)
51
+ raise ResourceAlreadyLockedError, response_body_as_json["message"]
49
52
  elsif response.code != '200'
50
- fail "Unexpected status: #{response.code}"
53
+ fail UnexpectedError, "Unexpected status: #{response.code}"
51
54
  end
52
55
 
56
+ debug "Code: #{response.code}"
57
+ debug "Result: #{response.body}"
58
+
53
59
  response_body = JSON.parse(response.body)
54
60
  response_body
55
61
  rescue => e
@@ -62,24 +68,44 @@ module Joumae
62
68
  URI.parse("#{api_endpoint}/resources")
63
69
  end
64
70
 
65
- def acquire_resource_url
66
- URI.parse("#{api_endpoint}/resources/acquire")
71
+ def acquire_resource_url(name)
72
+ URI.parse("#{api_endpoint}/resources/#{name}/lock/acquire")
73
+ end
74
+
75
+ def renew_resource_url(name)
76
+ URI.parse("#{api_endpoint}/resources/#{name}/lock/renew")
67
77
  end
68
78
 
69
- def renew_resource_url
70
- URI.parse("#{api_endpoint}/resources/renew")
79
+ def release_resource_url(name)
80
+ URI.parse("#{api_endpoint}/resources/#{name}/lock/release")
71
81
  end
72
82
 
73
- def release_resource_url
74
- URI.parse("#{api_endpoint}/resources/release")
83
+ protected
84
+
85
+ def debug(msg)
86
+ logger.debug msg
75
87
  end
76
88
 
89
+ private
90
+
77
91
  def httpclient
78
92
  @httpclient ||= HTTPClient.new
79
93
  end
80
94
 
81
95
  def logger
82
- @logger ||= Logger.new(STDOUT)
96
+ @logger ||= Logger.new(STDOUT).tap do |logger|
97
+ log_level_from_env = ENV['JOUMAE_LOG_LEVEL'] || 'INFO'
98
+ logger.level = Logger.const_get(log_level_from_env)
99
+ end
100
+ end
101
+
102
+ class ResourceAlreadyLockedError < StandardError
103
+ end
104
+
105
+ class ResourceNotFoundError < StandardError
106
+ end
107
+
108
+ class UnexpectedError < StandardError
83
109
  end
84
110
  end
85
111
  end
@@ -0,0 +1,57 @@
1
+ require 'joumae/transaction'
2
+ require 'joumae/client'
3
+ require "joumae/command_failed_error"
4
+ require 'open3'
5
+
6
+ module Joumae
7
+ class Command
8
+ attr_reader :cmd
9
+
10
+ def initialize(cmd, resource_name:, client:)
11
+ @cmd = cmd
12
+ @resource_name = resource_name
13
+ @client = client
14
+ end
15
+
16
+ def logger
17
+ @logger ||= Logger.new(STDOUT).tap do |logger|
18
+ log_level_from_env = ENV['JOUMAE_LOG_LEVEL'] || 'INFO'
19
+ logger.level = Logger.const_get(log_level_from_env)
20
+ logger.formatter = proc do |severity, datetime, progname, msg|
21
+ date_format = datetime.strftime("%Y-%m-%d %H:%M:%S")
22
+ "#{cmd} (#{severity}): #{msg}\n"
23
+ end
24
+ end
25
+ end
26
+
27
+ def run!
28
+ status = Joumae::Transaction.run!(resource_name: @resource_name, client: @client) do
29
+ Open3.popen3("bash") do |i, o, e, w|
30
+ i.write cmd
31
+ i.close
32
+ o.each do |line| puts line end
33
+ e.each do |line| $stderr.puts line end
34
+
35
+ debug w.value
36
+
37
+ w.value.exitstatus
38
+ end
39
+ end
40
+ raise Joumae::CommandFailedError.new("Exit status(=#{status}) is non-zero.", status) if status != 0
41
+ end
42
+
43
+ private
44
+
45
+ def info(msg)
46
+ logger.info msg
47
+ end
48
+
49
+ def warn(msg)
50
+ logger.warn msg
51
+ end
52
+
53
+ def debug(msg)
54
+ logger.debug msg
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,10 @@
1
+ module Joumae
2
+ class CommandFailedError < StandardError
3
+ attr_reader :status
4
+
5
+ def initialize(msg, status)
6
+ super(msg)
7
+ @status = status
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,24 @@
1
+ module Joumae
2
+ module Logging
3
+ protected
4
+
5
+ def info(msg)
6
+ logger.info msg
7
+ end
8
+
9
+ def warn(msg)
10
+ logger.warn msg
11
+ end
12
+
13
+ def debug(msg)
14
+ logger.debug msg
15
+ end
16
+
17
+ def logger
18
+ @logger ||= Logger.new(STDOUT).tap do |logger|
19
+ log_level_from_env = ENV['JOUMAE_LOG_LEVEL'] || 'INFO'
20
+ logger.level = Logger.const_get(log_level_from_env)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,15 +1,14 @@
1
1
  module Joumae
2
2
  class Transaction
3
- def initialize(resource_name:, owner:, client:, renew_interval: 1)
3
+ def initialize(resource_name:, client:, renew_interval: 1)
4
4
  @resource_name = resource_name
5
- @owner = owner
6
5
  @client = client
7
6
  @renew_interval = renew_interval
8
7
  @finished = false
9
8
  end
10
9
 
11
10
  def start
12
- @client.acquire(@resource_name, @owner)
11
+ @client.acquire(@resource_name)
13
12
 
14
13
  start_thread
15
14
  end
@@ -20,8 +19,8 @@ module Joumae
20
19
  @thread = Thread.start {
21
20
  loop do
22
21
  sleep @renew_interval
23
- exit if finished?
24
- @client.renew(@resource_name, @owner)
22
+ @thread.exit if finished?
23
+ @client.renew(@resource_name)
25
24
  end
26
25
  }
27
26
  end
@@ -34,11 +33,21 @@ module Joumae
34
33
 
35
34
  def finish
36
35
  stop_thread
37
- @client.release(@resource_name, @owner)
36
+ @client.release(@resource_name)
38
37
  end
39
38
 
40
39
  def finished?
41
40
  @finished
42
41
  end
42
+
43
+ def self.run!(resource_name:, client:, &block)
44
+ t = new(resource_name: resource_name, client: client)
45
+ t.start
46
+ begin
47
+ block.call
48
+ ensure
49
+ t.finish
50
+ end
51
+ end
43
52
  end
44
53
  end
@@ -1,3 +1,3 @@
1
1
  module Joumae
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/joumae.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "joumae/version"
2
2
  require "joumae/client"
3
3
  require "joumae/transaction"
4
+ require "joumae/command"
4
5
 
5
6
  module Joumae
6
7
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: joumae
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yusuke KUOKA
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-11-05 00:00:00.000000000 Z
11
+ date: 2015-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -55,7 +55,8 @@ dependencies:
55
55
  description: A Ruby client library for the Joumae lock service.
56
56
  email:
57
57
  - yusuke.kuoka@crowdworks.co.jp
58
- executables: []
58
+ executables:
59
+ - joumae
59
60
  extensions: []
60
61
  extra_rdoc_files: []
61
62
  files:
@@ -68,10 +69,15 @@ files:
68
69
  - Rakefile
69
70
  - bin/console
70
71
  - bin/setup
72
+ - exe/joumae
71
73
  - integration_test.rb
72
74
  - joumae.gemspec
73
75
  - lib/joumae.rb
76
+ - lib/joumae/cli.rb
74
77
  - lib/joumae/client.rb
78
+ - lib/joumae/command.rb
79
+ - lib/joumae/command_failed_error.rb
80
+ - lib/joumae/logging.rb
75
81
  - lib/joumae/transaction.rb
76
82
  - lib/joumae/version.rb
77
83
  homepage: https://github.com/crowdworks/joumae-ruby