litmus_paper 1.0.0 → 1.1.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.
data/README.md CHANGED
@@ -23,6 +23,10 @@ Or install it yourself as:
23
23
  Use the sample config to run it under unicorn. Or execute litmus-agent-check to
24
24
  use it as an agent-check for HAProxy.
25
25
 
26
+ ## Releasing
27
+
28
+ $ ./release
29
+
26
30
  ## Contributing
27
31
 
28
32
  1. Fork it
@@ -34,7 +34,12 @@ module LitmusPaper
34
34
  end
35
35
 
36
36
  get "/:service/status" do
37
- health = LitmusPaper.check_service(params[:service])
37
+ health = _cache.get(params[:service])
38
+ _cache.set(
39
+ params[:service],
40
+ health = LitmusPaper.check_service(params[:service])
41
+ ) unless health
42
+
38
43
  if health.nil?
39
44
  _text 404, "NOT FOUND", { "X-Health" => "0" }
40
45
  else
@@ -100,6 +105,14 @@ module LitmusPaper
100
105
  _text 500, "Server Error"
101
106
  end
102
107
 
108
+ def _cache
109
+ @cache ||= LitmusPaper::Cache.new(
110
+ LitmusPaper.cache_location,
111
+ "litmus_cache",
112
+ LitmusPaper.cache_ttl
113
+ )
114
+ end
115
+
103
116
  def _create_status_file(status_file)
104
117
  status_file.create(params[:reason], params[:health])
105
118
  _text 201, "File created"
@@ -0,0 +1,33 @@
1
+ require 'yaml'
2
+
3
+ module LitmusPaper
4
+ class Cache
5
+ def initialize(location, namespace, ttl)
6
+ @path = File.join(location, namespace)
7
+ @ttl = ttl
8
+
9
+ FileUtils.mkdir_p(@path)
10
+ end
11
+
12
+ def set(key, value)
13
+ return unless @ttl > 0
14
+ File.open(File.join(@path, key), "a") do |f|
15
+ f.flock(File::LOCK_EX)
16
+ f.rewind
17
+ f.write("#{Time.now.to_f + @ttl} #{YAML::dump(value)}")
18
+ f.flush
19
+ f.truncate(f.pos)
20
+ end
21
+ end
22
+
23
+ def get(key)
24
+ return unless File.exists?(File.join(@path, key))
25
+ File.open(File.join(@path, key), "r") do |f|
26
+ f.flock(File::LOCK_SH)
27
+ entry = f.read
28
+ expires_at, value = entry.split(" ", 2)
29
+ expires_at.to_f < Time.now.to_f ? nil : YAML::load(value)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,4 +1,11 @@
1
1
  module LitmusPaper
2
- class Configuration < Struct.new(:port, :data_directory, :services)
2
+ fields = [
3
+ :port,
4
+ :data_directory,
5
+ :services,
6
+ :cache_location,
7
+ :cache_ttl
8
+ ]
9
+ class Configuration < Struct.new(*fields)
3
10
  end
4
11
  end
@@ -5,13 +5,21 @@ module LitmusPaper
5
5
  @services = {}
6
6
  @port = 9292
7
7
  @data_directory = "/etc/litmus"
8
+ @cache_location = "/run/shm"
9
+ @cache_ttl = -1
8
10
  end
9
11
 
10
12
  def evaluate(file = @config_file_path)
11
13
  LitmusPaper.logger.info "Loading file #{file}"
12
14
  config_contents = File.read(file)
13
15
  instance_eval(config_contents)
14
- LitmusPaper::Configuration.new(@port, @data_directory, @services)
16
+ LitmusPaper::Configuration.new(
17
+ @port,
18
+ @data_directory,
19
+ @services,
20
+ @cache_location,
21
+ @cache_ttl
22
+ )
15
23
  end
16
24
 
17
25
  def include_files(glob_pattern)
@@ -36,5 +44,13 @@ module LitmusPaper
36
44
  block.call(service)
37
45
  @services[name.to_s] = service
38
46
  end
47
+
48
+ def cache_location(location)
49
+ @cache_location = location
50
+ end
51
+
52
+ def cache_ttl(ttl)
53
+ @cache_ttl = ttl
54
+ end
39
55
  end
40
56
  end
@@ -1,3 +1,3 @@
1
1
  module LitmusPaper
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
data/lib/litmus_paper.rb CHANGED
@@ -14,6 +14,7 @@ require 'forwardable'
14
14
 
15
15
  require 'remote_syslog_logger'
16
16
 
17
+ require 'litmus_paper/cache'
17
18
  require 'litmus_paper/configuration'
18
19
  require 'litmus_paper/configuration_file'
19
20
  require 'litmus_paper/dependency/file_contents'
@@ -35,7 +36,7 @@ require 'litmus_paper/version'
35
36
  module LitmusPaper
36
37
  class << self
37
38
  extend Forwardable
38
- def_delegators :@config, :services, :data_directory, :port
39
+ def_delegators :@config, :services, :data_directory, :port, :cache_location, :cache_ttl
39
40
  attr_accessor :logger
40
41
  end
41
42
 
data/release ADDED
@@ -0,0 +1,11 @@
1
+ #!/bin/bash
2
+
3
+ set -o errexit
4
+ set -o pipefail
5
+ set -o nounset
6
+ set -o xtrace
7
+
8
+ chmod -R go+rX .
9
+ rm -f *.gem
10
+ gem build litmus_paper.gemspec
11
+ gem push litmus_paper*.gem
@@ -272,7 +272,7 @@ describe LitmusPaper::App do
272
272
  last_response.header["X-Health-Forced"].should == "health"
273
273
  end
274
274
 
275
- it "returns the actualy health value for an unhealthy service when the measured health is less than the forced value" do
275
+ it "returns the actual health value for an unhealthy service when the measured health is less than the forced value" do
276
276
  test_service = LitmusPaper::Service.new('test', [NeverAvailableDependency.new], [LitmusPaper::Metric::ConstantMetric.new(100)])
277
277
  LitmusPaper.services['test'] = test_service
278
278
  LitmusPaper::StatusFile.service_health_file("test").create("Forcing health", 88)
@@ -418,6 +418,45 @@ describe LitmusPaper::App do
418
418
  last_response.headers["X-Health-Forced"].should == "up"
419
419
  last_response.body.should match(/Up for testing/)
420
420
  end
421
+
422
+ it "retrieves a cached value during the cache_ttl" do
423
+ begin
424
+ cache = LitmusPaper::Cache.new(
425
+ location = "/tmp/litmus_cache",
426
+ namespace = "test_cache",
427
+ ttl = 0.05
428
+ )
429
+ LitmusPaper::App.any_instance.stub(:_cache).and_return(cache)
430
+ test_service = LitmusPaper::Service.new(
431
+ 'test',
432
+ [AlwaysAvailableDependency.new],
433
+ [LitmusPaper::Metric::ConstantMetric.new(100)]
434
+ )
435
+ LitmusPaper.services['test'] = test_service
436
+
437
+ post "/test/health", :reason => "health for testing", :health => 88
438
+ last_response.status.should == 201
439
+
440
+ get "/test/status"
441
+ last_response.status.should == 200
442
+ last_response.body.should match(/health for testing 88/)
443
+
444
+ delete "/test/health"
445
+ last_response.status.should == 200
446
+
447
+ get "/test/status"
448
+ last_response.should be_ok
449
+ last_response.body.should match(/health for testing 88/)
450
+
451
+ sleep ttl
452
+
453
+ get "/test/status"
454
+ last_response.should be_ok
455
+ last_response.body.should_not match(/health for testing 88/)
456
+ ensure
457
+ FileUtils.rm_rf(location)
458
+ end
459
+ end
421
460
  end
422
461
 
423
462
  describe "server errors" do
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+
3
+ describe LitmusPaper::Cache do
4
+ before(:each) do
5
+ @location = "/tmp/litmus_cache"
6
+ @namespace = "test_cache"
7
+ @ttl = -1
8
+ end
9
+
10
+ after(:each) do
11
+ FileUtils.rm_rf(@location)
12
+ end
13
+
14
+ describe "initialize" do
15
+ it "creates the directory structure" do
16
+ File.exists?(@location).should be false
17
+ LitmusPaper::Cache.new(@location, @namespace, @ttl)
18
+ File.exists?(File.join(@location, @namespace)).should be true
19
+ end
20
+ end
21
+
22
+ describe "get" do
23
+ it "returns false if the key was not previously set" do
24
+ cache = LitmusPaper::Cache.new(@location, @namespace, @ttl)
25
+ cache.get("non-existant-key").should be_nil
26
+ end
27
+
28
+ context "when called with fresh entry" do
29
+ it "returns the value set" do
30
+ cache = LitmusPaper::Cache.new(@location, @namespace, 10)
31
+ cache.set("key", "some value")
32
+ cache.get("key").should == "some value"
33
+ end
34
+ end
35
+
36
+ context "when called with expired entry" do
37
+ it "returns nil" do
38
+ cache = LitmusPaper::Cache.new(@location, @namespace, -1)
39
+ cache.set("key", "some value")
40
+ cache.get("key").should be_nil
41
+ end
42
+ end
43
+ end
44
+
45
+ describe "set" do
46
+ context "when called with non-positive ttl" do
47
+ it "does not store the value" do
48
+ key = "key"
49
+ cache = LitmusPaper::Cache.new(@location, @namespace, 0)
50
+ cache.set(key, "some value")
51
+ File.exists?(File.join(@location, @namespace, key)).should be false
52
+ end
53
+ end
54
+
55
+ context "when called with positive ttl" do
56
+ it "stores the value" do
57
+ key = "key"
58
+ cache = LitmusPaper::Cache.new(@location, @namespace, 1)
59
+ cache.set(key, "some value")
60
+ File.exists?(File.join(@location, @namespace, key)).should be true
61
+ end
62
+ end
63
+
64
+ it "expires the entry after the ttl" do
65
+ key = "key"
66
+ ttl = 0.01
67
+ cache = LitmusPaper::Cache.new(@location, @namespace, ttl)
68
+ cache.set(key, "some value")
69
+ cache.get(key).should == "some value"
70
+ sleep ttl
71
+ cache.get(key).should be_nil
72
+ end
73
+ end
74
+ end
@@ -19,6 +19,18 @@ describe LitmusPaper::ConfigurationFile do
19
19
  config = config_file.evaluate
20
20
  config.data_directory.should == "/tmp/litmus_paper"
21
21
  end
22
+
23
+ it "configures the cache_location" do
24
+ config_file = LitmusPaper::ConfigurationFile.new(TEST_CONFIG)
25
+ config = config_file.evaluate
26
+ config.cache_location.should == "/tmp/litmus_paper_cache"
27
+ end
28
+
29
+ it "configures the cache_ttl" do
30
+ config_file = LitmusPaper::ConfigurationFile.new(TEST_CONFIG)
31
+ config = config_file.evaluate
32
+ config.cache_ttl.should == -1
33
+ end
22
34
  end
23
35
 
24
36
  describe "include_files" do
@@ -4,6 +4,9 @@ port 9293
4
4
 
5
5
  data_directory "/tmp/litmus_paper"
6
6
 
7
+ cache_location "/tmp/litmus_paper_cache"
8
+ cache_ttl -1
9
+
7
10
  service :test do |s|
8
11
  s.depends Dependency::HTTP, "http://localhost/heartbeat"
9
12
 
@@ -4,6 +4,9 @@ port 9293
4
4
 
5
5
  data_directory "/tmp/litmus_paper"
6
6
 
7
+ cache_location "/tmp/litmus_paper_cache"
8
+ cache_ttl -1
9
+
7
10
  service :foo do |s|
8
11
  s.depends Dependency::HTTP, "http://localhost/heartbeat"
9
12
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: litmus_paper
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-10-05 00:00:00.000000000 Z
12
+ date: 2017-12-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sinatra
@@ -165,6 +165,7 @@ files:
165
165
  - lib/litmus_paper/agent_check_handler.rb
166
166
  - lib/litmus_paper/agent_check_server.rb
167
167
  - lib/litmus_paper/app.rb
168
+ - lib/litmus_paper/cache.rb
168
169
  - lib/litmus_paper/cli/admin.rb
169
170
  - lib/litmus_paper/cli/admin/command.rb
170
171
  - lib/litmus_paper/cli/admin/force.rb
@@ -192,9 +193,11 @@ files:
192
193
  - lib/litmus_paper/version.rb
193
194
  - litmus-agent-check.init.sh
194
195
  - litmus_paper.gemspec
196
+ - release
195
197
  - spec/litmus_paper/agent_check_handler_spec.rb
196
198
  - spec/litmus_paper/agent_check_server_spec.rb
197
199
  - spec/litmus_paper/app_spec.rb
200
+ - spec/litmus_paper/cache_spec.rb
198
201
  - spec/litmus_paper/cli/admin_spec.rb
199
202
  - spec/litmus_paper/configuration_file_spec.rb
200
203
  - spec/litmus_paper/dependency/file_contents_spec.rb
@@ -255,6 +258,7 @@ test_files:
255
258
  - spec/litmus_paper/agent_check_handler_spec.rb
256
259
  - spec/litmus_paper/agent_check_server_spec.rb
257
260
  - spec/litmus_paper/app_spec.rb
261
+ - spec/litmus_paper/cache_spec.rb
258
262
  - spec/litmus_paper/cli/admin_spec.rb
259
263
  - spec/litmus_paper/configuration_file_spec.rb
260
264
  - spec/litmus_paper/dependency/file_contents_spec.rb