joumae 0.1.0 → 0.2.0

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