Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Initial commit

  • Loading branch information...
commit ee0bd4afa7df4e06ac28fcce4fb44b7f02beefbc 0 parents
authored August 24, 2010
5  Gemfile
... ...
@@ -0,0 +1,5 @@
  1
+gem "jeweler"
  2
+gem "rspec"
  3
+gem "rake"
  4
+gem "uuid"
  5
+gem "activesupport", "~> 2.3.8"
28  Gemfile.lock
... ...
@@ -0,0 +1,28 @@
  1
+GEM
  2
+  remote: http://rubygems.org/
  3
+  specs:
  4
+    activesupport (2.3.8)
  5
+    gemcutter (0.6.1)
  6
+    git (1.2.5)
  7
+    jeweler (1.4.0)
  8
+      gemcutter (>= 0.1.0)
  9
+      git (>= 1.2.5)
  10
+      rubyforge (>= 2.0.0)
  11
+    json_pure (1.4.6)
  12
+    macaddr (1.0.0)
  13
+    rake (0.8.7)
  14
+    rspec (1.3.0)
  15
+    rubyforge (2.0.4)
  16
+      json_pure (>= 1.1.7)
  17
+    uuid (2.1.0)
  18
+      macaddr (~> 1.0)
  19
+
  20
+PLATFORMS
  21
+  ruby
  22
+
  23
+DEPENDENCIES
  24
+  activesupport (~> 2.3.8)
  25
+  jeweler
  26
+  rake
  27
+  rspec
  28
+  uuid
26  Rakefile
... ...
@@ -0,0 +1,26 @@
  1
+require "rubygems"
  2
+require "bundler"
  3
+Bundler.setup
  4
+
  5
+begin
  6
+  require 'jeweler'
  7
+  Jeweler::Tasks.new do |s|
  8
+    s.name = "e20_ops_middleware"
  9
+    s.summary = "Operations support gem for Efficiency 2.0 projects"
  10
+    s.email = "tech@efficiency20.com"
  11
+    s.homepage = "http://github.com/efficiency20/ops_middleware"
  12
+    s.description = "Operations support gem for Efficiency 2.0 projects"
  13
+    s.authors = ["Efficiency 2.0"]
  14
+  end
  15
+rescue LoadError
  16
+  puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
  17
+end
  18
+
  19
+require "spec/rake/spectask"
  20
+
  21
+desc "Run all specs"
  22
+Spec::Rake::SpecTask.new("spec") do |t|
  23
+  t.spec_files = FileList["spec/**/*_spec.rb"]
  24
+end
  25
+
  26
+task :default => :spec
11  lib/e20/ops/hostname.rb
... ...
@@ -0,0 +1,11 @@
  1
+module E20
  2
+  module Ops
  3
+    class Hostname
  4
+
  5
+      def to_s
  6
+        @hostname ||= `hostname`.strip
  7
+      end
  8
+
  9
+    end
  10
+  end
  11
+end
12  lib/e20/ops/middleware.rb
... ...
@@ -0,0 +1,12 @@
  1
+module E20
  2
+  module Ops
  3
+    autoload :Revision, "e20/ops/revision"
  4
+    autoload :Hostname, "e20/ops/hostname"
  5
+
  6
+    module Middleware
  7
+      autoload :HostnameMiddleware, "e20/ops/middleware/hostname_middleware"
  8
+      autoload :RevisionMiddleware, "e20/ops/middleware/revision_middleware"
  9
+      autoload :TransactionIdMiddleware, "e20/ops/middleware/transaction_id_middleware"
  10
+    end
  11
+  end
  12
+end
24  lib/e20/ops/middleware/hostname_middleware.rb
... ...
@@ -0,0 +1,24 @@
  1
+module E20
  2
+  module Ops
  3
+    module Middleware
  4
+      class HostnameMiddleware
  5
+
  6
+        def initialize(app, options = {})
  7
+          @app = app
  8
+          @hostname = options[:hostname] || Hostname.new
  9
+
  10
+          if (logger = options[:logger])
  11
+            logger.info "[#{self.class.name}] Running on: #{@hostname}"
  12
+          end
  13
+        end
  14
+
  15
+        def call(env)
  16
+          status, headers, body = @app.call(env)
  17
+          headers["X-Served-By"] = @hostname.to_s
  18
+          [status, headers, body]
  19
+        end
  20
+
  21
+      end
  22
+    end
  23
+  end
  24
+end
29  lib/e20/ops/middleware/revision_middleware.rb
... ...
@@ -0,0 +1,29 @@
  1
+module E20
  2
+  module Ops
  3
+    module Middleware
  4
+      class RevisionMiddleware
  5
+
  6
+        def initialize(app, options = {})
  7
+          @app = app
  8
+          @revision = options[:revision] || Revision.new
  9
+
  10
+          if (logger = options[:logger])
  11
+            logger.info "[#{self.class.name}] Running: #{@revision}"
  12
+          end
  13
+        end
  14
+
  15
+        def call(env)
  16
+          if env["PATH_INFO"] == "/system/revision"
  17
+            body = "#{@revision}\n"
  18
+            [200, { "Content-Type" => "text/plain", "Content-Length" => body.size.to_s }, body]
  19
+          else
  20
+            status, headers, body = @app.call(env)
  21
+            headers["X-Revision"] = @revision.to_s
  22
+            [status, headers, body]
  23
+          end
  24
+        end
  25
+
  26
+      end
  27
+    end
  28
+  end
  29
+end
27  lib/e20/ops/middleware/transaction_id_middleware.rb
... ...
@@ -0,0 +1,27 @@
  1
+require "uuid"
  2
+require "logger"
  3
+
  4
+module E20
  5
+  module Ops
  6
+    module Middleware
  7
+      class TransactionIdMiddleware
  8
+
  9
+        def initialize(app, options = {})
  10
+          @app = app
  11
+          @uuid_generator = options[:uuid_generator] || UUID.new
  12
+          @logger = options[:logger] || Logger.new(STDOUT)
  13
+        end
  14
+
  15
+        def call(env)
  16
+          uuid = @uuid_generator.generate
  17
+          @logger.info "[#{self.class.name}] Transaction ID: #{uuid}"
  18
+
  19
+          status, headers, body = @app.call(env)
  20
+          headers["X-Transaction-Id"] = uuid
  21
+          [status, headers, body]
  22
+        end
  23
+
  24
+      end
  25
+    end
  26
+  end
  27
+end
35  lib/e20/ops/revision.rb
... ...
@@ -0,0 +1,35 @@
  1
+require "active_support"
  2
+
  3
+module E20
  4
+  module Ops
  5
+    class Revision
  6
+
  7
+      def initialize(root = Pathname.new(Dir.pwd))
  8
+        @root = root
  9
+      end
  10
+
  11
+      def to_s
  12
+        @revision ||= begin
  13
+          if revision_file.exist?
  14
+            revision_file.read.strip
  15
+          elsif revision_from_git.present?
  16
+            revision_from_git
  17
+          else
  18
+            "unknown"
  19
+          end
  20
+        end
  21
+      end
  22
+
  23
+    private
  24
+
  25
+      def revision_from_git
  26
+        @revision_from_git ||= `git rev-parse HEAD`.strip
  27
+      end
  28
+
  29
+      def revision_file
  30
+        @root.join("REVISION")
  31
+      end
  32
+
  33
+    end
  34
+  end
  35
+end
9  spec/ops/hostname_spec.rb
... ...
@@ -0,0 +1,9 @@
  1
+require "spec_helper"
  2
+
  3
+describe E20::Ops::Hostname do
  4
+  it "returns the hostname" do
  5
+    hostname = E20::Ops::Hostname.new
  6
+    hostname.stub(:` => "Computer.local\n")
  7
+    hostname.to_s.should == "Computer.local"
  8
+  end
  9
+end
27  spec/ops/middleware/hostname_middleware_spec.rb
... ...
@@ -0,0 +1,27 @@
  1
+require "spec_helper"
  2
+
  3
+describe E20::Ops::Middleware::HostnameMiddleware do
  4
+  let(:app) { Proc.new { |env| [200, {}, "OK!"] } }
  5
+
  6
+  it "is initialized with an app" do
  7
+    E20::Ops::Middleware::HostnameMiddleware.new(app)
  8
+  end
  9
+
  10
+  it "delegates to the app" do
  11
+    middleware = E20::Ops::Middleware::HostnameMiddleware.new(app)
  12
+    status, headers, body = middleware.call({})
  13
+    body.should == "OK!"
  14
+  end
  15
+
  16
+  it "logs the hostname when initialized" do
  17
+    log_io = StringIO.new
  18
+    E20::Ops::Middleware::HostnameMiddleware.new(app, :logger => Logger.new(log_io))
  19
+    log_io.string.should include("[E20::Ops::Middleware::HostnameMiddleware] Running on: ")
  20
+  end
  21
+
  22
+  it "sets an X-Served-By header" do
  23
+    middleware = E20::Ops::Middleware::HostnameMiddleware.new(app, :hostname => "Computer.local")
  24
+    status, headers, body = middleware.call({})
  25
+    headers["X-Served-By"].should == "Computer.local"
  26
+  end
  27
+end
37  spec/ops/middleware/revision_middleware_spec.rb
... ...
@@ -0,0 +1,37 @@
  1
+require "spec_helper"
  2
+
  3
+describe E20::Ops::Middleware::RevisionMiddleware do
  4
+  let(:app) { Proc.new { |env| [200, {}, "OK!"] } }
  5
+
  6
+  it "is initialized with an app" do
  7
+    E20::Ops::Middleware::RevisionMiddleware.new(app)
  8
+  end
  9
+
  10
+  context "/system/revision" do
  11
+    it "returns the current running revision" do
  12
+      middleware = E20::Ops::Middleware::RevisionMiddleware.new(app, :revision => "rev")
  13
+      status, headers, body = middleware.call({"PATH_INFO" => "/system/revision"})
  14
+      body.should == "rev\n"
  15
+    end
  16
+  end
  17
+
  18
+  context "any other endpoint" do
  19
+    it "delegates to the app" do
  20
+      middleware = E20::Ops::Middleware::RevisionMiddleware.new(app)
  21
+      status, headers, body = middleware.call({})
  22
+      body.should == "OK!"
  23
+    end
  24
+
  25
+    it "logs the running revision when initialized" do
  26
+      log_io = StringIO.new
  27
+      E20::Ops::Middleware::RevisionMiddleware.new(app, :revision => "rev", :logger => Logger.new(log_io))
  28
+      log_io.string.should include("[E20::Ops::Middleware::RevisionMiddleware] Running: rev")
  29
+    end
  30
+
  31
+    it "sets an X-Revision header" do
  32
+      middleware = E20::Ops::Middleware::RevisionMiddleware.new(app, :revision => "the_revision", :logger => nil)
  33
+      status, headers, body = middleware.call({})
  34
+      headers["X-Revision"].should == "the_revision"
  35
+    end
  36
+  end
  37
+end
30  spec/ops/middleware/transaction_id_middleware_spec.rb
... ...
@@ -0,0 +1,30 @@
  1
+require "spec_helper"
  2
+
  3
+describe E20::Ops::Middleware::TransactionIdMiddleware do
  4
+  let(:app)    { Proc.new { |env| [200, {}, "OK!"] } }
  5
+  let(:uuid)   { stub(:generate => "abc123") }
  6
+  let(:logger) { Logger.new(StringIO.new) }
  7
+
  8
+  it "is initialized with an app" do
  9
+    E20::Ops::Middleware::TransactionIdMiddleware.new(app)
  10
+  end
  11
+
  12
+  it "delegates to the app" do
  13
+    middleware = E20::Ops::Middleware::TransactionIdMiddleware.new(app, :logger => logger)
  14
+    status, headers, body = middleware.call({})
  15
+    body.should == "OK!"
  16
+  end
  17
+
  18
+  it "sets an X-Transaction-Id header" do
  19
+    middleware = E20::Ops::Middleware::TransactionIdMiddleware.new(app, :uuid_generator => uuid, :logger => logger)
  20
+    status, headers, body = middleware.call({})
  21
+    headers["X-Transaction-Id"].should == "abc123"
  22
+  end
  23
+
  24
+  it "logs a line for each request" do
  25
+    log_io = StringIO.new
  26
+    middleware = E20::Ops::Middleware::TransactionIdMiddleware.new(app, :uuid_generator => uuid, :logger => Logger.new(log_io))
  27
+    middleware.call({})
  28
+    log_io.string.should include("[E20::Ops::Middleware::TransactionIdMiddleware] Transaction ID: abc123")
  29
+  end
  30
+end
25  spec/ops/revision_spec.rb
... ...
@@ -0,0 +1,25 @@
  1
+require "spec_helper"
  2
+
  3
+describe E20::Ops::Revision do
  4
+  context "when a REVISION file is present" do
  5
+    it "adds a X-Revision header with the REVISION" do
  6
+      tmp_path = Pathname.new(Dir.tmpdir)
  7
+      tmp_path.join("REVISION").open("w") { |f| f.write "hello\n" }
  8
+      E20::Ops::Revision.new(tmp_path).to_s.should == "hello"
  9
+    end
  10
+  end
  11
+
  12
+  context "when a REVISION file is not present" do
  13
+    it "adds a X-Revision header with the git rev-parse HEAD" do
  14
+      E20::Ops::Revision.new.to_s.should == `git rev-parse HEAD`.strip
  15
+    end
  16
+  end
  17
+
  18
+  context "when neither a REVISION file or a git revision are available" do
  19
+    it "adds a X-Revision header of 'unknown'" do
  20
+      revision = E20::Ops::Revision.new
  21
+      revision.stub(:` => "")
  22
+      revision.to_s.should == "unknown"
  23
+    end
  24
+  end
  25
+end
1  spec/spec.opts
... ...
@@ -0,0 +1 @@
  1
+--color
2  spec/spec_helper.rb
... ...
@@ -0,0 +1,2 @@
  1
+require "spec"
  2
+require "e20/ops/middleware"

0 notes on commit ee0bd4a

Please sign in to comment.
Something went wrong with that request. Please try again.