diff --git a/atmos/Gemfile b/atmos/Gemfile
new file mode 100644
index 00000000..eda7689a
--- /dev/null
+++ b/atmos/Gemfile
@@ -0,0 +1,22 @@
+source :rubygems
+
+gem "eventmachine"
+gem "em-http-request"
+gem "ruby-hmac"
+gem "uuidtools"
+gem "datamapper", ">= 0.10.2"
+gem "do_sqlite3"
+gem "dm-sqlite-adapter"
+gem "sinatra"
+gem "thin"
+gem "xml-simple"
+
+gem 'vcap_common', :path => '../../common'
+gem 'vcap_logging', '>=0.1.3', :require => ['vcap/logging']
+
+group :test do
+ gem "rake"
+ gem "rspec"
+ gem "rcov"
+ gem "ci_reporter"
+end
diff --git a/atmos/Gemfile.lock b/atmos/Gemfile.lock
new file mode 100644
index 00000000..e0006161
--- /dev/null
+++ b/atmos/Gemfile.lock
@@ -0,0 +1,129 @@
+PATH
+ remote: ../../common
+ specs:
+ vcap_common (0.99)
+ eventmachine (~> 0.12.10)
+ logging (>= 1.5.0)
+ nats
+ posix-spawn
+ thin
+ yajl-ruby
+
+GEM
+ remote: http://rubygems.org/
+ specs:
+ addressable (2.2.4)
+ bcrypt-ruby (2.1.4)
+ builder (3.0.0)
+ ci_reporter (1.6.4)
+ builder (>= 2.1.2)
+ daemons (1.1.2)
+ data_objects (0.10.3)
+ addressable (~> 2.1)
+ datamapper (1.1.0)
+ dm-aggregates (= 1.1.0)
+ dm-constraints (= 1.1.0)
+ dm-core (= 1.1.0)
+ dm-migrations (= 1.1.0)
+ dm-serializer (= 1.1.0)
+ dm-timestamps (= 1.1.0)
+ dm-transactions (= 1.1.0)
+ dm-types (= 1.1.0)
+ dm-validations (= 1.1.0)
+ diff-lcs (1.1.2)
+ dm-aggregates (1.1.0)
+ dm-core (~> 1.1.0)
+ dm-constraints (1.1.0)
+ dm-core (~> 1.1.0)
+ dm-core (1.1.0)
+ addressable (~> 2.2.4)
+ dm-do-adapter (1.1.0)
+ data_objects (~> 0.10.2)
+ dm-core (~> 1.1.0)
+ dm-migrations (1.1.0)
+ dm-core (~> 1.1.0)
+ dm-serializer (1.1.0)
+ dm-core (~> 1.1.0)
+ fastercsv (~> 1.5.4)
+ json (~> 1.4.6)
+ dm-sqlite-adapter (1.1.0)
+ dm-do-adapter (~> 1.1.0)
+ do_sqlite3 (~> 0.10.2)
+ dm-timestamps (1.1.0)
+ dm-core (~> 1.1.0)
+ dm-transactions (1.1.0)
+ dm-core (~> 1.1.0)
+ dm-types (1.1.0)
+ bcrypt-ruby (~> 2.1.4)
+ dm-core (~> 1.1.0)
+ fastercsv (~> 1.5.4)
+ json (~> 1.4.6)
+ stringex (~> 1.2.0)
+ uuidtools (~> 2.1.2)
+ dm-validations (1.1.0)
+ dm-core (~> 1.1.0)
+ do_sqlite3 (0.10.3)
+ data_objects (= 0.10.3)
+ em-http-request (0.3.0)
+ addressable (>= 2.0.0)
+ escape_utils
+ eventmachine (>= 0.12.9)
+ escape_utils (0.2.3)
+ eventmachine (0.12.10)
+ fastercsv (1.5.4)
+ json (1.4.6)
+ json_pure (1.5.1)
+ little-plugger (1.1.2)
+ logging (1.5.0)
+ little-plugger (>= 1.1.2)
+ nats (0.4.10)
+ daemons (>= 1.1.0)
+ eventmachine (>= 0.12.10)
+ json_pure (>= 1.5.1)
+ posix-spawn (0.3.6)
+ rack (1.2.2)
+ rake (0.8.7)
+ rcov (0.9.9)
+ rspec (2.5.0)
+ rspec-core (~> 2.5.0)
+ rspec-expectations (~> 2.5.0)
+ rspec-mocks (~> 2.5.0)
+ rspec-core (2.5.1)
+ rspec-expectations (2.5.0)
+ diff-lcs (~> 1.1.2)
+ rspec-mocks (2.5.0)
+ ruby-hmac (0.4.0)
+ sinatra (1.2.1)
+ rack (~> 1.1)
+ tilt (< 2.0, >= 1.2.2)
+ stringex (1.2.1)
+ thin (1.2.11)
+ daemons (>= 1.0.9)
+ eventmachine (>= 0.12.6)
+ rack (>= 1.0.0)
+ tilt (1.2.2)
+ uuidtools (2.1.2)
+ vcap_logging (0.1.3)
+ xml-simple (1.0.15)
+ yajl-ruby (0.8.3)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ ci_reporter
+ datamapper (>= 0.10.2)
+ dm-sqlite-adapter
+ do_sqlite3
+ em-http-request
+ eventmachine
+ rake
+ rcov
+ rspec
+ ruby-hmac
+ sinatra
+ thin
+ uuidtools
+ vcap_common!
+ vcap_logging (>= 0.1.3)
+ xml-simple
diff --git a/atmos/Rakefile b/atmos/Rakefile
new file mode 100644
index 00000000..07ac2e80
--- /dev/null
+++ b/atmos/Rakefile
@@ -0,0 +1,39 @@
+require 'rake'
+
+desc "Run specs"
+task "spec" => ["bundler:install:test", "test:spec"]
+
+desc "Run specs using RCov"
+task "spec:rcov" => ["bundler:install:test", "test:spec:rcov"]
+
+namespace "bundler" do
+ desc "Install gems"
+ task "install" do
+ sh("bundle install")
+ end
+
+ desc "Install gems for test"
+ task "install:test" do
+ sh("bundle install --without development production")
+ end
+
+ desc "Install gems for production"
+ task "install:production" do
+ sh("bundle install --without development test")
+ end
+
+ desc "Install gems for development"
+ task "install:development" do
+ sh("bundle install --without test production")
+ end
+end
+
+namespace "test" do
+ task "spec" do |t|
+ sh("cd spec && ../../base/bin/nats-util start && rake spec && ../../base/bin/nats-util stop")
+ end
+
+ task "spec:rcov" do |t|
+ sh("cd spec && rake spec:rcov")
+ end
+end
diff --git a/atmos/bin/atmos_gateway b/atmos/bin/atmos_gateway
new file mode 100755
index 00000000..fe0dc5d8
--- /dev/null
+++ b/atmos/bin/atmos_gateway
@@ -0,0 +1,32 @@
+#!/usr/bin/env ruby
+# -*- mode: ruby -*-
+#
+# Copyright (c) 2009-2011 VMware, Inc.
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
+
+$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', '..', 'base', 'lib')
+require 'base/gateway'
+
+$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
+require 'atmos_service/provisioner'
+require 'atmos_service/atmos_helper'
+
+class VCAP::Services::Atmos::Gateway < VCAP::Services::Base::Gateway
+
+ def provisioner_class
+ VCAP::Services::Atmos::Provisioner
+ end
+
+ def default_config_file
+ File.join(File.dirname(__FILE__), '..', 'config', 'atmos_gateway.yml')
+ end
+
+ def additional_options
+ {:atmos => @config[:atmos]}
+ end
+end
+
+VCAP::Services::Atmos::Gateway.new.start
+
+
diff --git a/atmos/config/atmos_gateway.yml b/atmos/config/atmos_gateway.yml
new file mode 100644
index 00000000..32b97225
--- /dev/null
+++ b/atmos/config/atmos_gateway.yml
@@ -0,0 +1,29 @@
+---
+#cloud_controller_uri: api.vcap.me
+service:
+ name: atmos
+ version: "1.4"
+ description: 'Atmos object store'
+ plans: ['free']
+ tags: ['atmos', 'atmos-1.4', 'object store']
+ip_route: localhost
+#proxy:
+# host: proxy
+# port: 8080
+# keepalive: true
+index: 0
+token: "0xdeadbeef"
+mbus: nats://localhost:4222
+logging:
+ level: debug
+pid: /var/vcap/sys/run/atmos_service.pid
+
+# atmos configuration
+# Not configured by default as it would require revealing
+# credentials to a non-local resource.
+atmos:
+ host: "127.0.0.1"
+ port: "443"
+ tenant: "tenant"
+ tenantadmin: "admin"
+ tenantpasswd: "password"
diff --git a/atmos/lib/atmos_service/atmos_error.rb b/atmos/lib/atmos_service/atmos_error.rb
new file mode 100644
index 00000000..bf9efeab
--- /dev/null
+++ b/atmos/lib/atmos_service/atmos_error.rb
@@ -0,0 +1,17 @@
+# Copyright (c) 2009-2011 VMware, Inc.
+$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', '..', '..', 'base', 'lib')
+
+require "base/service_error"
+
+module VCAP
+ module Services
+ module Atmos
+ class AtmosError < VCAP::Services::Base::Error::ServiceError
+ ATMOS_BACKEND_ERROR_CREATE_SUBTENAT = [31801, HTTP_INTERNAL, 'Atmos create subtenant error. Atmos error code: %s.']
+ ATMOS_BACKEND_ERROR_DELETE_SUBTENAT = [31802, HTTP_INTERNAL, 'Atmos delete subtenant error. Atmos error code: %s.']
+ ATMOS_BACKEND_ERROR_CREATE_USER = [31803, HTTP_INTERNAL, 'Atmos create user error. Atmos error code: %s.']
+ ATMOS_BACKEND_ERROR_DELETE_USER = [31804, HTTP_INTERNAL, 'Atmos delete user error. Atmos error code: %s.']
+ end
+ end
+ end
+end
diff --git a/atmos/lib/atmos_service/atmos_helper.rb b/atmos/lib/atmos_service/atmos_helper.rb
new file mode 100644
index 00000000..2f03495b
--- /dev/null
+++ b/atmos/lib/atmos_service/atmos_helper.rb
@@ -0,0 +1,143 @@
+# Copyright (c) 2009-2011 VMware, Inc.
+require 'xmlsimple'
+require 'net/http'
+require 'atmos_error'
+
+class VCAP::Services::Atmos::Helper
+
+ include VCAP::Services::Atmos
+
+ def initialize(atmos_config, logger)
+ @logger = logger
+
+ @host = atmos_config[:host]
+ @tenant = atmos_config[:tenant]
+ @tenantadmin = atmos_config[:tenantadmin]
+ @tenantpasswd = atmos_config[:tenantpasswd]
+ @port = atmos_config[:port]
+ end
+
+
+ def create_subtenant(name)
+ uri = URI.parse("http://#{@host}/sysmgmt/tenants/#{@tenant}/subtenants")
+
+ headers = { 'x-atmos-authsource' => 'local',
+ 'x-atmos-tenantadmin' => @tenantadmin,
+ 'x-atmos-tenantadminpassword' => @tenantpasswd,
+ 'x-atmos-authtype' => 'password',
+ 'x-atmos-subtenantname' => name
+ }
+ req = Net::HTTP::Post.new(uri.request_uri)
+
+ req["accept"] = '*/*'
+ headers.keys.each {|f| req.add_field(f, headers[f])}
+
+ @logger.debug "create subtenant #{name} uri: #{uri.inspect} req: #{req.inspect} hdrs: #{headers.inspect}"
+
+ http = Net::HTTP.new(uri.host, @port.to_i)
+ http.use_ssl = true
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
+
+ res = http.request(req)
+
+ # Response Body is like:
+ #
+ # 2e705c1a08e5412fb7231055d56733e0
+
+ if res.code == "201"
+ id = XmlSimple.xml_in(res.body, { 'KeyAttr' => 'subtenantId' })
+ return id
+ end
+ raise AtmosError.new(AtmosError::ATMOS_BACKEND_ERROR_CREATE_SUBTENAT, res.code)
+ end
+
+ def delete_subtenant(name)
+ uri = URI.parse("http://#{@host}/sysmgmt/tenants/#{@tenant}/subtenants/#{name}")
+
+ headers = { 'x-atmos-tenantadmin' => @tenantadmin,
+ 'x-atmos-tenantadminpassword' => @tenantpasswd,
+ 'x-atmos-authtype' => 'password'
+ }
+ req = Net::HTTP::Delete.new(uri.request_uri)
+
+ req["accept"] = '*/*'
+ headers.keys.each {|f| req.add_field(f, headers[f])}
+
+ @logger.debug "delete subtenant #{name}"
+
+ http = Net::HTTP.new(uri.host, @port.to_i)
+ http.use_ssl = true
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
+
+ res = http.request(req)
+
+ # Response Body is like:
+ #
+ # true
+
+ raise AtmosError.new(AtmosError::ATMOS_BACKEND_ERROR_DELETE_SUBTENAT, res.code) unless res.code == "200"
+ true
+ end
+
+ def create_user(username, subtenant_name)
+ uri = URI.parse("http://#{@host}/sysmgmt/tenants/#{@tenant}/subtenants/#{subtenant_name}/uids")
+
+ headers = { 'x-atmos-tenantadmin' => @tenantadmin,
+ 'x-atmos-tenantadminpassword' => @tenantpasswd,
+ 'x-atmos-authtype' => 'password',
+ 'x-atmos-uid' => username
+ }
+
+ req = Net::HTTP::Post.new(uri.request_uri)
+ req["accept"] = '*/*'
+ headers.keys.each {|f| req.add_field(f, headers[f])}
+
+ @logger.debug "create user #{username} under subtenant #{subtenant_name} in tenant #{@tenant}"
+ @logger.debug uri
+
+ http = Net::HTTP.new(uri.host, @port.to_i)
+ http.use_ssl = true
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
+
+ res = http.request(req)
+
+ # Response Body is like:
+ #
+ # jzpKHy5ee28jMpTiiqkmTa5vdu8=
+
+ if res.code == "200"
+ shared_secret = XmlSimple.xml_in(res.body, { 'KeyAttr' => 'sharedSecret' })
+ return shared_secret
+ end
+ raise AtmosError.new(AtmosError::ATMOS_BACKEND_ERROR_CREATE_USER, res.code)
+ end
+
+ def delete_user(username, subtenant_name)
+ uri = URI.parse("http://#{@host}/sysmgmt/tenants/#{@tenant}/subtenants/#{subtenant_name}/uids/#{username}")
+
+ headers = { 'x-atmos-tenantadmin' => @tenantadmin,
+ 'x-atmos-tenantadminpassword' => @tenantpasswd,
+ 'x-atmos-authtype' => 'password'
+ }
+
+ req = Net::HTTP::Delete.new(uri.request_uri)
+ req["accept"] = '*/*'
+ headers.keys.each {|f| req.add_field(f, headers[f])}
+
+ @logger.debug "delete user #{username} under subtenant #{subtenant_name} in tenant #{@tenant}"
+ @logger.debug uri
+
+ http = Net::HTTP.new(uri.host, @port.to_i)
+ http.use_ssl = true
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
+
+ res = http.request(req)
+
+ # Response Body:
+ #
+ # true
+
+ raise AtmosError.new(AtmosError::ATMOS_BACKEND_ERROR_DELETE_USER, res.code) unless res.code == "200"
+ true
+ end
+end
diff --git a/atmos/lib/atmos_service/common.rb b/atmos/lib/atmos_service/common.rb
new file mode 100644
index 00000000..7728d65c
--- /dev/null
+++ b/atmos/lib/atmos_service/common.rb
@@ -0,0 +1,12 @@
+# Copyright (c) 2009-2011 VMware, Inc.
+module VCAP
+ module Services
+ module Atmos
+ module Common
+ def service_name
+ "AtmosaaS"
+ end
+ end
+ end
+ end
+end
diff --git a/atmos/lib/atmos_service/provisioner.rb b/atmos/lib/atmos_service/provisioner.rb
new file mode 100644
index 00000000..29b6a61f
--- /dev/null
+++ b/atmos/lib/atmos_service/provisioner.rb
@@ -0,0 +1,154 @@
+# Copyright (c) 2009-2011 VMware, Inc.
+$:.unshift File.join(File.dirname(__FILE__), '.')
+
+require "base/provisioner"
+require "atmos_service/common"
+require "uuidtools"
+require "atmos_helper"
+require "atmos_error"
+
+class VCAP::Services::Atmos::Provisioner < VCAP::Services::Base::Provisioner
+
+ include VCAP::Services::Atmos::Common
+ include VCAP::Services::Atmos
+
+ ATMOS_CONFIG_FILE = File.expand_path("../../../config/atmos_gateway.yml", __FILE__)
+
+ def to_s
+ "VCAP::Services::Atmos::Provisioner instance: #{@atmos_config.inspect}"
+ end
+
+ def get_atmos_config
+ config_file = YAML.load_file(ATMOS_CONFIG_FILE)
+ config = VCAP.symbolize_keys(config_file)
+ config[:atmos]
+ end
+
+ def initialize(options)
+ super(options)
+ @atmos_config = options[:additional_options][:atmos] || get_atmos_config
+ @logger.debug "atmos_config: #{@atmos_config.inspect}"
+
+ @host = @atmos_config[:host]
+ @port = @atmos_config[:port]
+
+ @atmos_helper = VCAP::Services::Atmos::Helper.new(@atmos_config, @logger)
+ end
+
+ def provision_service(request, prov_handle=nil, &blk)
+ @logger.debug("[#{service_description}] Attempting to provision instance (request=#{request.extract})")
+ begin
+ st_name = UUIDTools::UUID.random_create.to_s
+ st_id = @atmos_helper.create_subtenant(st_name)
+
+ # should we create subtenant admin rather than uid here?
+ token = UUIDTools::UUID.random_create.to_s
+ shared_secret = @atmos_helper.create_user(token, st_name)
+
+ svc = {
+ :data => {:subtenant_name => st_name, :subtenant_id => st_id, :host => @host},
+ :service_id => st_name,
+ :credentials => {:host => @host, :port => @port, :token => token,
+ :shared_secret => shared_secret, :subtenant_id => st_id}
+ }
+ @logger.debug("Service provisioned: #{svc.inspect}")
+ @prov_svcs[svc[:service_id]] = svc
+ blk.call(success(svc))
+ rescue => e
+ # roll back work
+ @logger.warn 'provision error, trying to roll back if necessary'
+ begin
+ @atmos_helper.delete_subtenant(st_name) if st_id
+ rescue => e1
+ @logger.info 'roll back error'
+ end
+ if e.instance_of? AtmosError
+ blk.call(failure(e))
+ else
+ @logger.warn(e)
+ blk.call(internal_fail)
+ end
+ end
+ end
+
+ def unprovision_service(instance_id, &blk)
+ @logger.debug("[#{service_description}] Attempting to unprovision instance (instance id=#{instance_id}")
+ begin
+ success = @atmos_helper.delete_subtenant(instance_id)
+ if success
+ bindings = find_all_bindings(instance_id)
+ @logger.debug("unprovision service: #{instance_id} ")
+ @prov_svcs.delete(instance_id)
+ bindings.each do |b|
+ @logger.debug("delete binded user: #{b[:service_id]} ")
+ @prov_svcs.delete(b[:service_id])
+ end
+ end
+ blk.call(success())
+ rescue => e
+ if e.instance_of? AtmosError
+ blk.call(failure(e))
+ else
+ @logger.warn(e)
+ blk.call(internal_fail)
+ end
+ end
+ end
+
+ def bind_instance(instance_id, binding_options, bind_handle=nil, &blk)
+ @logger.debug("attempting to bind service: #{instance_id}")
+ if instance_id.nil?
+ @logger.warn("#{instance_id} is null!")
+ blk.call(internal_fail)
+ end
+
+ begin
+ svc = @prov_svcs[instance_id]
+ raise "#{instance_id} not found!" if svc.nil?
+ @logger.debug("svc[data]: #{svc[:data]}")
+
+ token = UUIDTools::UUID.random_create.to_s
+ shared_secret = @atmos_helper.create_user(token, instance_id)
+
+ res = {
+ :service_id => token,
+ :configuration => svc[:data],
+ :credentials => {:host => @host, :port => @port, :token => token,
+ :shared_secret => shared_secret, :subtenant_id => svc[:data][:subtenant_id]}
+ }
+ @logger.debug("binded: #{res.inspect}")
+ @prov_svcs[res[:service_id]] = res
+ blk.call(success(res))
+ rescue => e
+ if e.instance_of? AtmosError
+ blk.call(failure(e))
+ else
+ @logger.warn(e)
+ blk.call(internal_fail)
+ end
+ end
+ end
+
+ def unbind_instance(instance_id, handle_id, binding_options, &blk)
+ @logger.debug("attempting to unbind service: #{instance_id}")
+ begin
+ raise "instance_id cannot be nil" if instance_id.nil?
+ svc = @prov_svcs[handle_id]
+ raise "#{handle_id} not found!" if svc.nil?
+
+ configuration = (svc[:configuration].nil?) ? svc[:data] : svc[:configuration]
+ @logger.debug("svc[configuration]: #{configuration}")
+ success = @atmos_helper.delete_user(handle_id, instance_id)
+ @prov_svcs.delete(handle_id) if success
+ blk.call(success())
+ rescue => e
+ if e.instance_of? AtmosError
+ blk.call(failure(e))
+ else
+ @logger.warn(e)
+ blk.call(internal_fail)
+ end
+ end
+ end
+
+end
diff --git a/atmos/spec/Rakefile b/atmos/spec/Rakefile
new file mode 100644
index 00000000..79753f79
--- /dev/null
+++ b/atmos/spec/Rakefile
@@ -0,0 +1,41 @@
+require 'rake'
+require 'tempfile'
+
+require 'rubygems'
+require 'bundler/setup'
+Bundler.require(:default, :test)
+
+require 'rspec'
+require 'rspec/core/rake_task'
+require 'ci/reporter/rake/rspec'
+
+coverage_dir = File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_coverage"))
+reports_dir = File.expand_path(File.join(File.dirname(__FILE__), "..", "spec_reports"))
+dump_file = File.join(Dir.tmpdir, "atmos.rcov")
+ignore_pattern = 'spec,[.]bundle,[/]gems[/]'
+
+ENV['CI_REPORTS'] = reports_dir
+
+desc "Run specs using RCov"
+task "spec:rcov" => ["ci:setup:rspec", "spec:rcov_internal", "convert_rcov_to_clover"]
+
+RSpec::Core::RakeTask.new do |t|
+ t.pattern = "**/*_spec.rb"
+ t.rspec_opts = ["--format", "documentation", "--colour"]
+end
+
+desc "Run specs using RCov (internal, use spec:rcov instead)"
+RSpec::Core::RakeTask.new("spec:rcov_internal") do |t|
+ sh("rm -f #{dump_file}")
+ t.pattern = "**/*_spec.rb"
+ t.rspec_opts = ["--format", "progress", "--colour"]
+ t.rcov = true
+ t.rcov_opts = ['--aggregate', dump_file, '--exclude', ignore_pattern, '--output', coverage_dir]
+end
+
+task "convert_rcov_to_clover" do |t|
+ analyzer = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "..", "tests", "common", "rcov_analyzer.rb"))
+ clover_output = File.join(coverage_dir, "clover.xml")
+ sh("ruby #{analyzer} #{dump_file} #{ignore_pattern} > #{clover_output}")
+ sh("rm -f #{dump_file}")
+end
diff --git a/atmos/spec/atmos_gateway_spec.rb b/atmos/spec/atmos_gateway_spec.rb
new file mode 100644
index 00000000..4962a511
--- /dev/null
+++ b/atmos/spec/atmos_gateway_spec.rb
@@ -0,0 +1,194 @@
+# Copyright (c) 2009-2011 VMware, Inc.
+$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
+$LOAD_PATH.unshift(File.expand_path("../../../base/lib", __FILE__))
+
+require File.dirname(__FILE__) + '/spec_helper'
+require "atmos_service/provisioner"
+require "atmos_service/atmos_helper"
+require "uuidtools"
+
+require "atmos_rest_client"
+
+include VCAP::Services::Atmos
+
+describe VCAP::Services::Atmos::Provisioner do
+
+ before :all do
+ @run_tests = check_provisioner_config
+ @config = get_provisioner_config
+ @logger = @config[:logger]
+ @logger.debug @config
+
+ @atmos_helper = Helper.new(@config[:additional_options][:atmos], @logger)
+ end
+
+ it "should successfully new VCAP::Services::Atmos::Provisioner instance" do
+ EM.run do
+ @sg = Provisioner.new(@config)
+ @logger.debug @sg
+ @sg.should_not be_nil
+ EM.stop
+ end
+ end
+
+ describe "provision_bind_unbind" do
+ before :all do
+ @subtenant_name_p = UUIDTools::UUID.random_create.to_s
+ @subtenant_name_p1 = UUIDTools::UUID.random_create.to_s
+ @token = UUIDTools::UUID.random_create.to_s
+ end
+
+ it "should successfully create atmos subtenant" do
+ subtenant_id = @atmos_helper.create_subtenant(@subtenant_name_p)
+ subtenant_id.should_not be_nil
+ end
+
+ it "should successfully create token under a subtenant" do
+ shared_secret = @atmos_helper.create_user(@token, @subtenant_name_p)
+ @logger.debug "token: " + @token + ", shared_secret: " + shared_secret
+ shared_secret.should_not be_nil
+ end
+
+ it "should successfully delete token under a subtenant" do
+ success = @atmos_helper.delete_user(@token, @subtenant_name_p)
+ success.should == true
+ end
+
+ it "should successfully create object after bind" do
+ subtenant_id = @atmos_helper.create_subtenant(@subtenant_name_p1)
+ subtenant_id.should_not be_nil
+ shared_secret = @atmos_helper.create_user(@token, @subtenant_name_p1)
+ @logger.debug "token: " + @token + ", shared_secret: " + shared_secret
+ shared_secret.should_not be_nil
+ host = @config[:additional_options][:atmos][:host]
+ port = @config[:additional_options][:atmos][:port]
+
+ opts = {
+ :url => "http://" + host + ":" + port,
+ :sid => subtenant_id,
+ :uid => @token,
+ :key => shared_secret,
+ }
+ client = AtmosClient.new(opts)
+ obj = UUIDTools::UUID.random_create.to_s
+ res = client.create_obj(obj)
+ res.should_not == Net::HTTPForbidden
+
+ id = res['location']
+ @logger.debug "object: " + obj + " created at: #{id}"
+ res = client.get_obj(id)
+ res.should_not == Net::HTTPForbidden
+
+ @logger.debug "response of reading object: #{res.body}"
+ obj_same = obj == res.body
+ obj_same.should == true
+
+ res = client.delete_obj(id)
+ res.should_not == Net::HTTPForbidden
+ @logger.debug "response of deleting file: #{res}"
+ end
+
+ after :all do
+ if @run_tests
+ @atmos_helper.delete_subtenant(@subtenant_name_p)
+ @atmos_helper.delete_subtenant(@subtenant_name_p1)
+ end
+ end
+ end
+
+ describe "multi-tenancy" do
+ before :all do
+ @subtenant_name1 = UUIDTools::UUID.random_create.to_s
+ @subtenant_name2 = UUIDTools::UUID.random_create.to_s
+ @token = UUIDTools::UUID.random_create.to_s
+ end
+
+ it "should isolate between different subtenants" do
+ subtenant_id1 = @atmos_helper.create_subtenant(@subtenant_name1)
+ subtenant_id2 = @atmos_helper.create_subtenant(@subtenant_name2)
+ subtenant_id1.should_not be_nil
+ subtenant_id2.should_not be_nil
+
+ shared_secret1 = @atmos_helper.create_user(@token, @subtenant_name1)
+ shared_secret2 = @atmos_helper.create_user(@token, @subtenant_name2)
+ shared_secret1.should_not be_nil
+ shared_secret2.should_not be_nil
+
+ host = @config[:additional_options][:atmos][:host]
+ port = @config[:additional_options][:atmos][:port]
+
+ opts = {
+ :url => "http://" + host + ":" + port,
+ :sid => subtenant_id1,
+ :uid => @token,
+ :key => shared_secret2,
+ }
+ client = AtmosClient.new(opts)
+ res = client.create_obj("obj")
+ @logger.debug res.to_s
+ same_class = res == Net::HTTPForbidden || res['location'].nil?
+ same_class.should == true
+
+ opts = {
+ :url => "http://" + host + ":" + port,
+ :sid => subtenant_id2,
+ :uid => @token,
+ :key => shared_secret1,
+ }
+ client = AtmosClient.new(opts)
+ res = client.create_obj("obj")
+ @logger.debug res.to_s
+ same_class = res == Net::HTTPForbidden || res['location'].nil?
+ same_class.should == true
+ end
+
+ after :all do
+ if @run_tests
+ @atmos_helper.delete_subtenant(@subtenant_name1)
+ @atmos_helper.delete_subtenant(@subtenant_name2)
+ end
+ end
+ end
+
+ describe "null credential" do
+ before :all do
+ @subtenant_name = UUIDTools::UUID.random_create.to_s
+ end
+
+ it "should prevent null credential from login" do
+ subtenant_id = @atmos_helper.create_subtenant(@subtenant_name)
+ subtenant_id.should_not be_nil
+ host = @config[:additional_options][:atmos][:host]
+ port = @config[:additional_options][:atmos][:port]
+
+ opts = {
+ :url => "http://" + host + ":" + port,
+ :sid => subtenant_id,
+ :uid => "",
+ :key => "",
+ }
+ client = AtmosClient.new(opts)
+ res = client.create_obj("obj")
+ @logger.debug res.to_s
+ same_class = res == Net::HTTPForbidden || res['location'].nil?
+ same_class.should == true
+ end
+
+ after :all do
+ @atmos_helper.delete_subtenant(@subtenant_name) if @run_tests
+ end
+ end
+
+ describe "unprovision" do
+ before :all do
+ @subtenant_name_up = UUIDTools::UUID.random_create.to_s
+ @atmos_helper.create_subtenant(@subtenant_name_up) if @run_tests
+ end
+
+ it "should successfully delete atmos subtenant" do
+ @logger.debug "subtenant_name: " + @subtenant_name_up
+ success = @atmos_helper.delete_subtenant(@subtenant_name_up)
+ success.should == true
+ end
+ end
+end
diff --git a/atmos/spec/atmos_rest_client.rb b/atmos/spec/atmos_rest_client.rb
new file mode 100644
index 00000000..d419fbc6
--- /dev/null
+++ b/atmos/spec/atmos_rest_client.rb
@@ -0,0 +1,115 @@
+# Copyright (c) 2009-2011 VMware, Inc.
+require 'net/http'
+require 'net/https'
+require 'uri'
+require 'time'
+require 'openssl'
+require 'base64'
+
+# A very simple Atmos client which focus on basic file operations
+# using namespace method.
+class AtmosClient
+ include Digest
+ include OpenSSL
+
+ REQUIRED_OPTS = %w(url sid uid key)
+ HEADERS = {
+ :date => 'date',
+ :emc_date => 'x-emc-date',
+ :sign => 'x-emc-signature',
+ :uid => 'x-emc-uid',
+ :type => 'content-type',
+ :extent => 'Extent',
+ }
+ def initialize(opts)
+ @opts = opts
+ # http server
+ url = URI.parse(@opts[:url])
+ @http = Net::HTTP.new(url.host, url.port)
+ @http.use_ssl = true if (url.port == 443 || url.port == 10080)
+ @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ end
+
+ def get_obj_ns(path='')
+ path = '/rest/namespace/'+ path
+ req = Net::HTTP::Get.new(path)
+ send_request(req)
+ end
+
+ def get_obj(id)
+ return unless id
+ req = Net::HTTP::Get.new(id)
+ send_request(req)
+ end
+
+ def create_obj_ns(path='', content=nil)
+ path = '/rest/namespace/'+ path
+ req = Net::HTTP::Post.new(path)
+ req.body = content
+ send_request(req)
+ end
+
+ def create_obj(content=nil)
+ req = Net::HTTP::Post.new('/rest/objects')
+ req.body = content
+ send_request(req)
+ end
+
+ def delete_obj_ns(path='')
+ path = '/rest/namespace/'+ path
+ req = Net::HTTP::Delete.new(path)
+ send_request(req)
+ end
+
+ def delete_obj(id)
+ return unless id
+ req = Net::HTTP::Delete.new(id)
+ send_request(req)
+ end
+
+protected
+
+ def send_request(req)
+ prepare_request(req)
+ res = @http.start do |http|
+ http.request(req)
+ end
+ return res
+ end
+
+ def prepare_request(request)
+ t = Time.now.httpdate
+ request[HEADERS[:emc_date]] = t
+ request[HEADERS[:date]] = t
+ request[HEADERS[:type]] = 'application/octet-stream'
+ request[HEADERS[:uid]] = "#{@opts[:sid]}/#{@opts[:uid]}"
+ request[HEADERS[:sign]] = gen_auth_header(request)
+ end
+
+ def gen_auth_header(request)
+ hash_string = "#{request.method}\n"+
+ "#{request[HEADERS[:type]]}\n" +
+ "#{request[HEADERS[:extent]]}\n"+
+ "#{request[HEADERS[:date]]}\n"+
+ "#{request.path.downcase}\n"
+
+ custom_args = {}
+ request.each_header do |key, value|
+ if key =~ /^x-emc-/
+ custom_args[key] = value
+ end
+ end
+ custom_args = custom_args.sort()
+ custom_headers = ""
+ custom_args.each do |key, value|
+ custom_headers += key + ":" + value.lstrip.rstrip + "\n"
+ end
+
+ custom_headers = custom_headers.chomp()
+ hash_string += custom_headers
+ digest = HMAC.digest(OpenSSL::Digest.new('sha1'),
+ Base64.decode64(@opts[:key]), hash_string)
+ Base64.encode64(digest.to_s).chomp
+ end
+end
+
diff --git a/atmos/spec/spec_helper.rb b/atmos/spec/spec_helper.rb
new file mode 100644
index 00000000..e859c7b1
--- /dev/null
+++ b/atmos/spec/spec_helper.rb
@@ -0,0 +1,88 @@
+# Copyright (c) 2009-2011 VMware, Inc.
+$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
+$LOAD_PATH.unshift(File.expand_path("../../../", __FILE__))
+
+require "rubygems"
+require "rspec"
+
+HTTP_PORT = 9865
+
+def symbolize_keys(hash)
+ if hash.is_a? Hash
+ new_hash = {}
+ hash.each do |k, v|
+ new_hash[k.to_sym] = symbolize_keys(v)
+ end
+ new_hash
+ else
+ hash
+ end
+end
+
+def parse_property(hash, key, type, options = {})
+ obj = hash[key]
+ if obj.nil?
+ raise "Missing required option: #{key}" unless options[:optional]
+ nil
+ elsif type == Range
+ raise "Invalid Range object: #{obj}" unless obj.kind_of?(Hash)
+ first, last = obj["first"], obj["last"]
+ raise "Invalid Range object: #{obj}" unless first.kind_of?(Integer) and last.kind_of?(Integer)
+ Range.new(first, last)
+ else
+ raise "Invalid #{type} object: #{obj}" unless obj.kind_of?(type)
+ obj
+ end
+end
+
+# Atmos configuration. The atmos service we test against is a shared,
+# off-box instace, so we don't want to bake the credentials into the
+# config file. To avoid having to update the config file manually
+# prior to testing, we load the atmos config from the environment.
+def check_provisioner_config
+ vars = ["VCAP_ATMOS_HOST", "VCAP_ATMOS_TENANT", "VCAP_ATMOS_TENANT_ADMIN", "VCAP_ATMOS_TENANT_PASSWD"]
+ vars.each do |e|
+ if ENV[e].nil?
+ pending "Disabling atmos tests. Set the following environment variables to run them: #{vars.inspect}"
+ return false
+ end
+ end
+ true
+end
+
+def get_provisioner_config()
+ config_file = File.join(File.dirname(__FILE__), "../config/atmos_gateway.yml")
+ config = YAML.load_file(config_file)
+ config = symbolize_keys(config)
+ options = {
+ :logger => Logger.new(parse_property(config, "log_file", String, :optional => true) || STDOUT, "daily"),
+ # Following options are for Provisioner
+ :version => config[:service][:version],
+ :local_ip => 'localhost',
+ # Following options are for AsynchronousServiceGateway
+ :service => config[:service],
+ :token => config[:token],
+ :cloud_controller => config[:cloud_controller],
+ # Following options are for Thin
+ :host => 'localhost',
+ :port => HTTP_PORT,
+ :additional_options => {:atmos => {
+ :host => ENV['VCAP_ATMOS_HOST'],
+ :port => ENV['VCAP_ATMOS_PORT'] || "443",
+ :tenant => ENV['VCAP_ATMOS_TENANT'],
+ :tenantadmin => ENV['VCAP_ATMOS_TENANT_ADMIN'],
+ :tenantpasswd => ENV['VCAP_ATMOS_TENANT_PASSWD']
+ }}
+ }
+
+ options[:logger].level = Logger::DEBUG
+ options
+end
+
+def start_server(opts)
+ sp = Provisioner.new(@opts).start()
+ opts = opts.merge({:provisioner => sp})
+ sg = VCAP::Services::AsynchronousServiceGateway.new(opts)
+ Thin::Server.start(opts[:host], opts[:port], sg)
+end
+
diff --git a/atmos/vendor/cache/addressable-2.2.4.gem b/atmos/vendor/cache/addressable-2.2.4.gem
new file mode 100644
index 00000000..9a6215d5
Binary files /dev/null and b/atmos/vendor/cache/addressable-2.2.4.gem differ
diff --git a/atmos/vendor/cache/bcrypt-ruby-2.1.4.gem b/atmos/vendor/cache/bcrypt-ruby-2.1.4.gem
new file mode 100644
index 00000000..cba34df3
Binary files /dev/null and b/atmos/vendor/cache/bcrypt-ruby-2.1.4.gem differ
diff --git a/atmos/vendor/cache/builder-3.0.0.gem b/atmos/vendor/cache/builder-3.0.0.gem
new file mode 100644
index 00000000..a2c6d160
Binary files /dev/null and b/atmos/vendor/cache/builder-3.0.0.gem differ
diff --git a/atmos/vendor/cache/ci_reporter-1.6.4.gem b/atmos/vendor/cache/ci_reporter-1.6.4.gem
new file mode 100644
index 00000000..d8a1cac0
Binary files /dev/null and b/atmos/vendor/cache/ci_reporter-1.6.4.gem differ
diff --git a/atmos/vendor/cache/daemons-1.1.2.gem b/atmos/vendor/cache/daemons-1.1.2.gem
new file mode 100644
index 00000000..9fd917df
Binary files /dev/null and b/atmos/vendor/cache/daemons-1.1.2.gem differ
diff --git a/atmos/vendor/cache/data_objects-0.10.3.gem b/atmos/vendor/cache/data_objects-0.10.3.gem
new file mode 100644
index 00000000..fb0b4b92
Binary files /dev/null and b/atmos/vendor/cache/data_objects-0.10.3.gem differ
diff --git a/atmos/vendor/cache/datamapper-1.1.0.gem b/atmos/vendor/cache/datamapper-1.1.0.gem
new file mode 100644
index 00000000..2f83dea1
Binary files /dev/null and b/atmos/vendor/cache/datamapper-1.1.0.gem differ
diff --git a/atmos/vendor/cache/diff-lcs-1.1.2.gem b/atmos/vendor/cache/diff-lcs-1.1.2.gem
new file mode 100644
index 00000000..aa0be73b
Binary files /dev/null and b/atmos/vendor/cache/diff-lcs-1.1.2.gem differ
diff --git a/atmos/vendor/cache/dm-aggregates-1.1.0.gem b/atmos/vendor/cache/dm-aggregates-1.1.0.gem
new file mode 100644
index 00000000..bdec7df0
Binary files /dev/null and b/atmos/vendor/cache/dm-aggregates-1.1.0.gem differ
diff --git a/atmos/vendor/cache/dm-constraints-1.1.0.gem b/atmos/vendor/cache/dm-constraints-1.1.0.gem
new file mode 100644
index 00000000..be01d0ff
Binary files /dev/null and b/atmos/vendor/cache/dm-constraints-1.1.0.gem differ
diff --git a/atmos/vendor/cache/dm-core-1.1.0.gem b/atmos/vendor/cache/dm-core-1.1.0.gem
new file mode 100644
index 00000000..33f27852
Binary files /dev/null and b/atmos/vendor/cache/dm-core-1.1.0.gem differ
diff --git a/atmos/vendor/cache/dm-do-adapter-1.1.0.gem b/atmos/vendor/cache/dm-do-adapter-1.1.0.gem
new file mode 100644
index 00000000..f0b2f2dc
Binary files /dev/null and b/atmos/vendor/cache/dm-do-adapter-1.1.0.gem differ
diff --git a/atmos/vendor/cache/dm-migrations-1.1.0.gem b/atmos/vendor/cache/dm-migrations-1.1.0.gem
new file mode 100644
index 00000000..04ac505d
Binary files /dev/null and b/atmos/vendor/cache/dm-migrations-1.1.0.gem differ
diff --git a/atmos/vendor/cache/dm-serializer-1.1.0.gem b/atmos/vendor/cache/dm-serializer-1.1.0.gem
new file mode 100644
index 00000000..4a861974
Binary files /dev/null and b/atmos/vendor/cache/dm-serializer-1.1.0.gem differ
diff --git a/atmos/vendor/cache/dm-sqlite-adapter-1.1.0.gem b/atmos/vendor/cache/dm-sqlite-adapter-1.1.0.gem
new file mode 100644
index 00000000..da919e4c
Binary files /dev/null and b/atmos/vendor/cache/dm-sqlite-adapter-1.1.0.gem differ
diff --git a/atmos/vendor/cache/dm-timestamps-1.1.0.gem b/atmos/vendor/cache/dm-timestamps-1.1.0.gem
new file mode 100644
index 00000000..48c51cca
Binary files /dev/null and b/atmos/vendor/cache/dm-timestamps-1.1.0.gem differ
diff --git a/atmos/vendor/cache/dm-transactions-1.1.0.gem b/atmos/vendor/cache/dm-transactions-1.1.0.gem
new file mode 100644
index 00000000..538f2a30
Binary files /dev/null and b/atmos/vendor/cache/dm-transactions-1.1.0.gem differ
diff --git a/atmos/vendor/cache/dm-types-1.1.0.gem b/atmos/vendor/cache/dm-types-1.1.0.gem
new file mode 100644
index 00000000..713e5cad
Binary files /dev/null and b/atmos/vendor/cache/dm-types-1.1.0.gem differ
diff --git a/atmos/vendor/cache/dm-validations-1.1.0.gem b/atmos/vendor/cache/dm-validations-1.1.0.gem
new file mode 100644
index 00000000..d50113ff
Binary files /dev/null and b/atmos/vendor/cache/dm-validations-1.1.0.gem differ
diff --git a/atmos/vendor/cache/do_sqlite3-0.10.3.gem b/atmos/vendor/cache/do_sqlite3-0.10.3.gem
new file mode 100644
index 00000000..482ed131
Binary files /dev/null and b/atmos/vendor/cache/do_sqlite3-0.10.3.gem differ
diff --git a/atmos/vendor/cache/em-http-request-0.3.0.gem b/atmos/vendor/cache/em-http-request-0.3.0.gem
new file mode 100644
index 00000000..e1e30403
Binary files /dev/null and b/atmos/vendor/cache/em-http-request-0.3.0.gem differ
diff --git a/atmos/vendor/cache/escape_utils-0.2.3.gem b/atmos/vendor/cache/escape_utils-0.2.3.gem
new file mode 100644
index 00000000..586014cb
Binary files /dev/null and b/atmos/vendor/cache/escape_utils-0.2.3.gem differ
diff --git a/atmos/vendor/cache/eventmachine-0.12.10.gem b/atmos/vendor/cache/eventmachine-0.12.10.gem
new file mode 100644
index 00000000..aa54c34a
Binary files /dev/null and b/atmos/vendor/cache/eventmachine-0.12.10.gem differ
diff --git a/atmos/vendor/cache/fastercsv-1.5.4.gem b/atmos/vendor/cache/fastercsv-1.5.4.gem
new file mode 100644
index 00000000..ff247ecd
Binary files /dev/null and b/atmos/vendor/cache/fastercsv-1.5.4.gem differ
diff --git a/atmos/vendor/cache/json-1.4.6.gem b/atmos/vendor/cache/json-1.4.6.gem
new file mode 100644
index 00000000..53e04e6e
Binary files /dev/null and b/atmos/vendor/cache/json-1.4.6.gem differ
diff --git a/atmos/vendor/cache/json_pure-1.5.1.gem b/atmos/vendor/cache/json_pure-1.5.1.gem
new file mode 100644
index 00000000..04ac32bd
Binary files /dev/null and b/atmos/vendor/cache/json_pure-1.5.1.gem differ
diff --git a/atmos/vendor/cache/little-plugger-1.1.2.gem b/atmos/vendor/cache/little-plugger-1.1.2.gem
new file mode 100644
index 00000000..ec25ec0b
Binary files /dev/null and b/atmos/vendor/cache/little-plugger-1.1.2.gem differ
diff --git a/atmos/vendor/cache/logging-1.5.0.gem b/atmos/vendor/cache/logging-1.5.0.gem
new file mode 100644
index 00000000..9d434f53
Binary files /dev/null and b/atmos/vendor/cache/logging-1.5.0.gem differ
diff --git a/atmos/vendor/cache/nats-0.4.10.gem b/atmos/vendor/cache/nats-0.4.10.gem
new file mode 100644
index 00000000..7bc1af7e
Binary files /dev/null and b/atmos/vendor/cache/nats-0.4.10.gem differ
diff --git a/atmos/vendor/cache/posix-spawn-0.3.6.gem b/atmos/vendor/cache/posix-spawn-0.3.6.gem
new file mode 100644
index 00000000..1156f3a3
Binary files /dev/null and b/atmos/vendor/cache/posix-spawn-0.3.6.gem differ
diff --git a/atmos/vendor/cache/rack-1.2.2.gem b/atmos/vendor/cache/rack-1.2.2.gem
new file mode 100644
index 00000000..4158b135
Binary files /dev/null and b/atmos/vendor/cache/rack-1.2.2.gem differ
diff --git a/atmos/vendor/cache/rake-0.8.7.gem b/atmos/vendor/cache/rake-0.8.7.gem
new file mode 100644
index 00000000..0740cec7
Binary files /dev/null and b/atmos/vendor/cache/rake-0.8.7.gem differ
diff --git a/atmos/vendor/cache/rcov-0.9.9.gem b/atmos/vendor/cache/rcov-0.9.9.gem
new file mode 100644
index 00000000..acb0cbc1
Binary files /dev/null and b/atmos/vendor/cache/rcov-0.9.9.gem differ
diff --git a/atmos/vendor/cache/rspec-2.5.0.gem b/atmos/vendor/cache/rspec-2.5.0.gem
new file mode 100644
index 00000000..89e4b6c7
Binary files /dev/null and b/atmos/vendor/cache/rspec-2.5.0.gem differ
diff --git a/atmos/vendor/cache/rspec-core-2.5.1.gem b/atmos/vendor/cache/rspec-core-2.5.1.gem
new file mode 100644
index 00000000..0751c798
Binary files /dev/null and b/atmos/vendor/cache/rspec-core-2.5.1.gem differ
diff --git a/atmos/vendor/cache/rspec-expectations-2.5.0.gem b/atmos/vendor/cache/rspec-expectations-2.5.0.gem
new file mode 100644
index 00000000..dada52d5
Binary files /dev/null and b/atmos/vendor/cache/rspec-expectations-2.5.0.gem differ
diff --git a/atmos/vendor/cache/rspec-mocks-2.5.0.gem b/atmos/vendor/cache/rspec-mocks-2.5.0.gem
new file mode 100644
index 00000000..1f71c1a2
Binary files /dev/null and b/atmos/vendor/cache/rspec-mocks-2.5.0.gem differ
diff --git a/atmos/vendor/cache/ruby-hmac-0.4.0.gem b/atmos/vendor/cache/ruby-hmac-0.4.0.gem
new file mode 100644
index 00000000..5d070197
Binary files /dev/null and b/atmos/vendor/cache/ruby-hmac-0.4.0.gem differ
diff --git a/atmos/vendor/cache/sinatra-1.2.1.gem b/atmos/vendor/cache/sinatra-1.2.1.gem
new file mode 100644
index 00000000..9f6ff27d
Binary files /dev/null and b/atmos/vendor/cache/sinatra-1.2.1.gem differ
diff --git a/atmos/vendor/cache/stringex-1.2.1.gem b/atmos/vendor/cache/stringex-1.2.1.gem
new file mode 100644
index 00000000..c7f98051
Binary files /dev/null and b/atmos/vendor/cache/stringex-1.2.1.gem differ
diff --git a/atmos/vendor/cache/thin-1.2.11.gem b/atmos/vendor/cache/thin-1.2.11.gem
new file mode 100644
index 00000000..d4950899
Binary files /dev/null and b/atmos/vendor/cache/thin-1.2.11.gem differ
diff --git a/atmos/vendor/cache/tilt-1.2.2.gem b/atmos/vendor/cache/tilt-1.2.2.gem
new file mode 100644
index 00000000..a931fb8c
Binary files /dev/null and b/atmos/vendor/cache/tilt-1.2.2.gem differ
diff --git a/atmos/vendor/cache/uuidtools-2.1.2.gem b/atmos/vendor/cache/uuidtools-2.1.2.gem
new file mode 100644
index 00000000..5f302bcb
Binary files /dev/null and b/atmos/vendor/cache/uuidtools-2.1.2.gem differ
diff --git a/atmos/vendor/cache/vcap_logging-0.1.3.gem b/atmos/vendor/cache/vcap_logging-0.1.3.gem
new file mode 100644
index 00000000..9d7b4eda
Binary files /dev/null and b/atmos/vendor/cache/vcap_logging-0.1.3.gem differ
diff --git a/atmos/vendor/cache/xml-simple-1.0.15.gem b/atmos/vendor/cache/xml-simple-1.0.15.gem
new file mode 100644
index 00000000..dee4cf53
Binary files /dev/null and b/atmos/vendor/cache/xml-simple-1.0.15.gem differ
diff --git a/atmos/vendor/cache/yajl-ruby-0.8.3.gem b/atmos/vendor/cache/yajl-ruby-0.8.3.gem
new file mode 100644
index 00000000..e3bdf3eb
Binary files /dev/null and b/atmos/vendor/cache/yajl-ruby-0.8.3.gem differ
diff --git a/base/lib/base/gateway.rb b/base/lib/base/gateway.rb
index 2652b5bf..cde9168c 100644
--- a/base/lib/base/gateway.rb
+++ b/base/lib/base/gateway.rb
@@ -93,7 +93,8 @@ def start
:node_timeout => node_timeout,
:z_interval => @config[:z_interval],
:allow_over_provisioning => @config[:allow_over_provisioning],
- :max_nats_payload => @config[:max_nats_payload]
+ :max_nats_payload => @config[:max_nats_payload],
+ :additional_options => additional_options
)
sg = async_gateway_class.new(
:proxy => @config[:proxy],
@@ -130,4 +131,8 @@ def parse_gateway_config(config_file)
config
end
+
+ def additional_options
+ {}
+ end
end