Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'vblob' into services-r9

Change-Id: I7a3e7fcfab2457a680483e30013a697b6b92ba5f
  • Loading branch information...
commit 0b2a22a143b0229c2a48a42c2bede8672756ab31 2 parents 5c0cc39 + cf8f153
SonicWang authored
Showing with 1,290 additions and 0 deletions.
  1. +25 −0 vblob/Gemfile
  2. +169 −0 vblob/Gemfile.lock
  3. +39 −0 vblob/Rakefile
  4. +28 −0 vblob/bin/vblob_gateway
  5. +36 −0 vblob/bin/vblob_node
  6. +28 −0 vblob/config/vblob_gateway.yml
  7. +23 −0 vblob/config/vblob_node.yml
  8. +12 −0 vblob/lib/vblob_service/common.rb
  9. +503 −0 vblob/lib/vblob_service/vblob_node.rb
  10. +9 −0 vblob/lib/vblob_service/vblob_provisioner.rb
  11. +29 −0 vblob/resources/vblob.conf.erb
  12. +41 −0 vblob/spec/Rakefile
  13. +97 −0 vblob/spec/spec_helper.rb
  14. +105 −0 vblob/spec/vblob_bind_spec.rb
  15. +42 −0 vblob/spec/vblob_orphan_spec.rb
  16. +104 −0 vblob/spec/vblob_provision_spec.rb
  17. BIN  vblob/vendor/cache/addressable-2.2.6.gem
  18. BIN  vblob/vendor/cache/bcrypt-ruby-2.1.4.gem
  19. BIN  vblob/vendor/cache/builder-3.0.0.gem
  20. BIN  vblob/vendor/cache/ci_reporter-1.6.9.gem
  21. BIN  vblob/vendor/cache/curb-0.7.16.gem
  22. BIN  vblob/vendor/cache/daemons-1.1.5.gem
  23. BIN  vblob/vendor/cache/data_objects-0.10.7.gem
  24. BIN  vblob/vendor/cache/datamapper-1.1.0.gem
  25. BIN  vblob/vendor/cache/diff-lcs-1.1.3.gem
  26. BIN  vblob/vendor/cache/dm-aggregates-1.1.0.gem
  27. BIN  vblob/vendor/cache/dm-constraints-1.1.0.gem
  28. BIN  vblob/vendor/cache/dm-core-1.1.0.gem
  29. BIN  vblob/vendor/cache/dm-do-adapter-1.1.0.gem
  30. BIN  vblob/vendor/cache/dm-migrations-1.1.0.gem
  31. BIN  vblob/vendor/cache/dm-serializer-1.1.0.gem
  32. BIN  vblob/vendor/cache/dm-sqlite-adapter-1.1.0.gem
  33. BIN  vblob/vendor/cache/dm-timestamps-1.1.0.gem
  34. BIN  vblob/vendor/cache/dm-transactions-1.1.0.gem
  35. BIN  vblob/vendor/cache/dm-types-1.1.0.gem
  36. BIN  vblob/vendor/cache/dm-validations-1.1.0.gem
  37. BIN  vblob/vendor/cache/do_sqlite3-0.10.7.gem
  38. BIN  vblob/vendor/cache/em-http-request-0.3.0.gem
  39. BIN  vblob/vendor/cache/escape_utils-0.2.4.gem
  40. BIN  vblob/vendor/cache/eventmachine-0.12.11.cloudfoundry.3.gem
  41. BIN  vblob/vendor/cache/eventmachine_httpserver-0.2.1.gem
  42. BIN  vblob/vendor/cache/fastercsv-1.5.4.gem
  43. BIN  vblob/vendor/cache/json-1.4.6.gem
  44. BIN  vblob/vendor/cache/json_pure-1.6.4.gem
  45. BIN  vblob/vendor/cache/little-plugger-1.1.3.gem
  46. BIN  vblob/vendor/cache/logging-1.6.1.gem
  47. BIN  vblob/vendor/cache/macaddr-1.5.0.gem
  48. BIN  vblob/vendor/cache/multi_json-1.0.4.gem
  49. BIN  vblob/vendor/cache/nats-0.4.22.beta.4.gem
  50. BIN  vblob/vendor/cache/posix-spawn-0.3.6.gem
  51. BIN  vblob/vendor/cache/rack-1.4.0.gem
  52. BIN  vblob/vendor/cache/rake-0.9.2.2.gem
  53. BIN  vblob/vendor/cache/rcov-0.9.11.gem
  54. BIN  vblob/vendor/cache/redis-2.2.2.gem
  55. BIN  vblob/vendor/cache/redis-namespace-1.0.3.gem
  56. BIN  vblob/vendor/cache/redisk-0.2.2.gem
  57. BIN  vblob/vendor/cache/resque-1.19.0.gem
  58. BIN  vblob/vendor/cache/resque-status-0.2.4.gem
  59. BIN  vblob/vendor/cache/rspec-2.7.0.gem
  60. BIN  vblob/vendor/cache/rspec-core-2.7.1.gem
  61. BIN  vblob/vendor/cache/rspec-expectations-2.7.0.gem
  62. BIN  vblob/vendor/cache/rspec-mocks-2.7.0.gem
  63. BIN  vblob/vendor/cache/ruby-hmac-0.4.0.gem
  64. BIN  vblob/vendor/cache/sinatra-1.2.7.gem
  65. BIN  vblob/vendor/cache/stringex-1.2.2.gem
  66. BIN  vblob/vendor/cache/systemu-2.4.2.gem
  67. BIN  vblob/vendor/cache/thin-1.3.1.gem
  68. BIN  vblob/vendor/cache/tilt-1.3.3.gem
  69. BIN  vblob/vendor/cache/uuid-2.3.4.gem
  70. BIN  vblob/vendor/cache/uuidtools-2.1.2.gem
  71. BIN  vblob/vendor/cache/vcap_common-1.0.4.gem
  72. BIN  vblob/vendor/cache/vcap_logging-0.1.3.gem
  73. BIN  vblob/vendor/cache/vcap_services_base-0.1.7.gem
  74. BIN  vblob/vendor/cache/vegas-0.1.8.gem
  75. BIN  vblob/vendor/cache/yajl-ruby-0.8.3.gem
View
25 vblob/Gemfile
@@ -0,0 +1,25 @@
+source :rubygems
+
+gem 'eventmachine'
+gem "em-http-request"
+gem "nats"
+gem "ruby-hmac"
+gem "uuidtools"
+gem "datamapper", ">= 0.10.2"
+gem "do_sqlite3"
+gem "dm-sqlite-adapter"
+gem "sinatra"
+gem "thin"
+gem "json"
+gem "yajl-ruby"
+
+gem 'vcap_common', '~> 1.0.4', :require => ['vcap/common', 'vcap/component']
+gem 'vcap_logging', '>=0.1.3', :require => ['vcap/logging']
+gem 'vcap_services_base'
+
+group :test do
+ gem "rake"
+ gem "rspec"
+ gem "rcov"
+ gem "ci_reporter"
+end
View
169 vblob/Gemfile.lock
@@ -0,0 +1,169 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ addressable (2.2.6)
+ bcrypt-ruby (2.1.4)
+ builder (3.0.0)
+ ci_reporter (1.6.9)
+ builder (>= 2.1.2)
+ curb (0.7.16)
+ daemons (1.1.5)
+ data_objects (0.10.7)
+ 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.3)
+ 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.7)
+ data_objects (= 0.10.7)
+ em-http-request (0.3.0)
+ addressable (>= 2.0.0)
+ escape_utils
+ eventmachine (>= 0.12.9)
+ escape_utils (0.2.4)
+ eventmachine (0.12.11.cloudfoundry.3)
+ eventmachine_httpserver (0.2.1)
+ fastercsv (1.5.4)
+ json (1.4.6)
+ json_pure (1.6.4)
+ little-plugger (1.1.3)
+ logging (1.6.1)
+ little-plugger (>= 1.1.2)
+ macaddr (1.5.0)
+ systemu (>= 2.4.0)
+ multi_json (1.0.4)
+ nats (0.4.22.beta.4)
+ daemons (>= 1.1.4)
+ eventmachine (>= 0.12.10)
+ json_pure (>= 1.6.1)
+ thin (>= 1.3.1)
+ posix-spawn (0.3.6)
+ rack (1.4.0)
+ rake (0.9.2.2)
+ rcov (0.9.11)
+ redis (2.2.2)
+ redis-namespace (1.0.3)
+ redis (< 3.0.0)
+ redisk (0.2.2)
+ redis (>= 0.1.1)
+ redis-namespace (>= 0.1.0)
+ resque (1.19.0)
+ multi_json (~> 1.0)
+ redis-namespace (~> 1.0.2)
+ sinatra (>= 0.9.2)
+ vegas (~> 0.1.2)
+ resque-status (0.2.4)
+ redisk (>= 0.2.1)
+ resque (>= 1.3.1)
+ uuid (>= 2.0.2)
+ rspec (2.7.0)
+ rspec-core (~> 2.7.0)
+ rspec-expectations (~> 2.7.0)
+ rspec-mocks (~> 2.7.0)
+ rspec-core (2.7.1)
+ rspec-expectations (2.7.0)
+ diff-lcs (~> 1.1.2)
+ rspec-mocks (2.7.0)
+ ruby-hmac (0.4.0)
+ sinatra (1.2.7)
+ rack (~> 1.1)
+ tilt (>= 1.2.2, < 2.0)
+ stringex (1.2.2)
+ systemu (2.4.2)
+ thin (1.3.1)
+ daemons (>= 1.0.9)
+ eventmachine (>= 0.12.6)
+ rack (>= 1.0.0)
+ tilt (1.3.3)
+ uuid (2.3.4)
+ macaddr (~> 1.0)
+ uuidtools (2.1.2)
+ vcap_common (1.0.4)
+ eventmachine (~> 0.12.11.cloudfoundry.3)
+ logging (>= 1.5.0)
+ nats (~> 0.4.22.beta.4)
+ posix-spawn (~> 0.3.6)
+ thin (~> 1.3.1)
+ yajl-ruby (~> 0.8.3)
+ vcap_logging (0.1.3)
+ vcap_services_base (0.1.7)
+ curb (~> 0.7.16)
+ datamapper (~> 1.1.0)
+ do_sqlite3 (~> 0.10.3)
+ em-http-request (~> 0.3.0)
+ eventmachine (~> 0.12.11.cloudfoundry.3)
+ eventmachine_httpserver (~> 0.2.1)
+ json (~> 1.4.6)
+ nats (~> 0.4.22.beta.4)
+ resque-status (~> 0.2.4)
+ ruby-hmac (~> 0.4.0)
+ sinatra (~> 1.2.3)
+ thin (~> 1.3.1)
+ uuidtools (~> 2.1.2)
+ vcap_common (>= 1.0.4)
+ vcap_logging (>= 0.1.3)
+ vegas (0.1.8)
+ rack (>= 1.0.0)
+ yajl-ruby (0.8.3)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ ci_reporter
+ datamapper (>= 0.10.2)
+ dm-sqlite-adapter
+ do_sqlite3
+ em-http-request
+ eventmachine
+ json
+ nats
+ rake
+ rcov
+ rspec
+ ruby-hmac
+ sinatra
+ thin
+ uuidtools
+ vcap_common (~> 1.0.4)
+ vcap_logging (>= 0.1.3)
+ vcap_services_base
+ yajl-ruby
View
39 vblob/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
View
28 vblob/bin/vblob_gateway
@@ -0,0 +1,28 @@
+#!/usr/bin/env ruby
+# -*- mode: ruby -*-
+# Copyright (c) 2009-2011 VMware, Inc.
+#
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
+require 'bundler/setup'
+require 'vcap_services_base'
+
+$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
+require 'vblob_service/vblob_provisioner'
+
+class VCAP::Services::VBlob::Gateway < VCAP::Services::Base::Gateway
+
+ def provisioner_class
+ VCAP::Services::VBlob::Provisioner
+ end
+
+ def default_config_file
+ config_base_dir = ENV["CLOUD_FOUNDRY_CONFIG_PATH"] || File.join(File.dirname(__FILE__), '..', 'config')
+ File.join(config_base_dir, 'vblob_gateway.yml')
+ end
+
+end
+
+VCAP::Services::VBlob::Gateway.new.start
+
+
View
36 vblob/bin/vblob_node
@@ -0,0 +1,36 @@
+#!/usr/bin/env ruby
+# -*- mode: ruby -*-
+# Copyright (c) 2009-2011 VMware, Inc.
+
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
+require 'bundler/setup'
+require 'vcap_services_base'
+
+$LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__))
+require "vblob_service/vblob_node"
+
+class VCAP::Services::VBlob::NodeBin < VCAP::Services::Base::NodeBin
+
+ def node_class
+ VCAP::Services::VBlob::Node
+ end
+
+ def default_config_file
+ config_base_dir = ENV["CLOUD_FOUNDRY_CONFIG_PATH"] || File.join(File.dirname(__FILE__), '..', 'config')
+ File.join(config_base_dir, 'vblob_node.yml')
+ end
+
+ def additional_config(options, config)
+ options[:config_template] = File.expand_path("../../resources/vblob.conf.erb", __FILE__)
+ options[:port_range] = parse_property(config, "port_range", Range)
+ options[:nodejs_path] = parse_property(config, "nodejs_path", String)
+ options[:vblobd_log_dir] = parse_property(config, "vblobd_log_dir", String)
+ options[:vblobd_path] = parse_property(config, "vblobd_path", String)
+ options[:vblobd_auth] = parse_property(config, "vblobd_auth", String)
+ options[:max_memory] = parse_property(config, "max_memory", Integer)
+ options
+ end
+
+end
+
+VCAP::Services::VBlob::NodeBin.new.start
View
28 vblob/config/vblob_gateway.yml
@@ -0,0 +1,28 @@
+---
+# cloud_controller_uri: api.vcap.me
+service:
+ name: vblob
+ version: "1.0"
+ description: 'vBlob service'
+ plans: ['free']
+ tags: ['vblob', 'vblob-1.0', 'nosql']
+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/vblob_service.pid
+# z_interval: 30
+# check_orphan_interval: 3600
+# double_check_orphan_interval: 300
+plan_management:
+ plans:
+ free:
+ low_water: 10
+ high_water: 180
+ #allow_over_provisioning: false
View
23 vblob/config/vblob_node.yml
@@ -0,0 +1,23 @@
+---
+capacity: 200
+plan: free
+local_db: sqlite3:/var/vcap/services/vblob/vblob_node.db
+mbus: nats://localhost:4222
+index: 0
+base_dir: /var/vcap/services/vblob/instances
+ip_route: 127.0.0.1
+logging:
+ level: debug
+vblobd_log_dir: /var/vcap/sys/service-log/vblob
+pid: /var/vcap/sys/run/vblob_node.pid
+max_memory: 128
+node_id: vblob_node_free_1
+nodejs_path: node
+vblobd_path: /var/vcap/packages/vblob
+vblobd_auth: disabled
+port_range:
+ first: 45001
+ last: 65000
+# z_interval: 30
+# max_nats_payload: 1048576
+# fqdn_hosts: false
View
12 vblob/lib/vblob_service/common.rb
@@ -0,0 +1,12 @@
+# Copyright (c) 2009-2011 VMware, Inc.
+module VCAP
+ module Services
+ module VBlob
+ module Common
+ def service_name
+ "VBlobaaS"
+ end
+ end
+ end
+ end
+end
View
503 vblob/lib/vblob_service/vblob_node.rb
@@ -0,0 +1,503 @@
+# Copyright (c) 2009-2011 VMware, Inc.
+require "erb"
+require "fileutils"
+require "logger"
+require "pp"
+require "set"
+require "timeout"
+require "net/http"
+require "openssl"
+require "digest/sha2"
+require "base64"
+require "yajl"
+require "json"
+
+require "nats/client"
+require "uuidtools"
+
+require 'vcap/common'
+require 'vcap/component'
+require "vblob_service/common"
+
+module VCAP
+ module Services
+ module VBlob
+ class Node < VCAP::Services::Base::Node
+ end
+ end
+ end
+end
+
+class VCAP::Services::VBlob::Node
+
+ VBLOB_TIMEOUT = 3
+
+ include VCAP::Services::VBlob::Common
+
+ class ProvisionedService
+ include DataMapper::Resource
+ property :name, String, :key => true
+ property :port, Integer, :unique => true
+ property :pid, Integer
+ property :memory, Integer
+ property :keyid, String, :required => true
+ property :secretid, String, :required => true
+
+ def listening?
+ begin
+ TCPSocket.open('localhost', port).close
+ return true
+ rescue => e
+ return false
+ end
+ end
+
+ def running?
+ return false unless !pid.nil?
+ VCAP.process_running? pid
+ end
+
+ def kill(sig=:SIGTERM)
+ if !pid.nil?
+ @wait_thread = Process.detach(pid)
+ Process.kill(sig, pid) if running?
+ end
+ end
+
+ def wait_killed(timeout=5, interval=0.2)
+ begin
+ Timeout::timeout(timeout) do
+ @wait_thread.join if @wait_thread
+ while running? do
+ sleep interval
+ end
+ end
+ rescue Timeout::Error
+ return false
+ end
+ true
+ end
+ end
+
+ def initialize(options)
+ super(options)
+ @base_dir = options[:base_dir]
+ FileUtils.mkdir_p(@base_dir)
+ @nodejs_path = options[:nodejs_path]
+ @vblobd_path = options[:vblobd_path]
+ @vblobd_log_dir = options[:vblobd_log_dir]
+ @vblobd_auth = options[:vblobd_auth] || "basic" #default is basic auth
+
+ @max_memory = options[:max_memory]
+
+ @config_template = ERB.new(File.read(options[:config_template]))
+
+ DataMapper.setup(:default, options[:local_db])
+ DataMapper::auto_upgrade!
+
+ @free_ports = Set.new
+ options[:port_range].each {|port| @free_ports << port}
+ @mutex = Mutex.new
+ end
+
+ def fetch_port(port=nil)
+ @mutex.synchronize do
+ port ||= @free_ports.first
+ raise "port #{port} is already taken!" unless @free_ports.include?(port)
+ @free_ports.delete(port)
+ port
+ end
+ end
+
+ def return_port(port)
+ @mutex.synchronize do
+ @free_ports << port
+ end
+ end
+
+ def delete_port(port)
+ @mutex.synchronize do
+ @free_ports.delete(port)
+ end
+ end
+
+ def pre_send_announcement
+ @capacity_lock.synchronize do
+ ProvisionedService.all.each do |provisioned_service|
+ @capacity -= capacity_unit
+ delete_port(provisioned_service.port)
+ if provisioned_service.listening?
+ @logger.warn("Service #{provisioned_service.name} already listening on port #{provisioned_service.port}")
+ next
+ end
+
+ unless service_exist?(provisioned_service)
+ @logger.warn("Service #{provisioned_service.name} in local DB, but not in file system")
+ next
+ end
+
+ begin
+ pid = start_instance(provisioned_service)
+ provisioned_service.pid = pid
+ raise "Cannot save provision_service" unless provisioned_service.save
+ rescue => e
+ provisioned_service.kill
+ @logger.error("Error starting service #{provisioned_service.name}: #{e}")
+ end
+ end
+ end
+ end
+
+ def shutdown
+ super
+ @logger.info("Shutting down instances..")
+ ProvisionedService.all.each { |provisioned_service|
+ @logger.debug("Trying to terminate vblobd pid:#{provisioned_service.pid}")
+ provisioned_service.kill(:SIGTERM)
+ provisioned_service.wait_killed ?
+ @logger.debug("VBlobd pid:#{provisioned_service.pid} terminated") :
+ @logger.error("Timeout to terminate vblobd pid:#{provisioned_service.pid}")
+ }
+ end
+
+ def announcement
+ @capacity_lock.synchronize do
+ { :available_capacity => @capacity }
+ end
+ end
+
+ def all_instances_list
+ ProvisionedService.all.map{|ps| ps["name"]}
+ end
+
+ def all_bindings_list
+ list = []
+ ProvisionedService.all.each do |instance|
+ begin
+ req = Net::HTTP::Get.new("/~bind", auth_header(instance.keyid, instance.secretid))
+ res = Net::HTTP.start(@local_ip, instance.port) {|http|
+ http.request(req)
+ }
+ raise "Couldn't get binding list" if (!res || res.code != "200")
+ bindings = Yajl::Parser.parse(res.body)
+ bindings.each_key {|key|
+ credential = {
+ 'name' => instance.name,
+ 'port' => instance.port,
+ 'username' => key
+ }
+ list << credential if credential['username'] != instance.keyid
+ }
+ rescue => e
+ @logger.warn("Failed to fetch user list: #{e.message}")
+ end
+ end
+ list
+ end
+
+ # will be re-used by restore codes; thus credential could be none null
+ def provision(plan, credential = nil)
+ @logger.debug("Provision a service instance")
+ port = credential && credential['port'] ? fetch_port(credential['port']) : fetch_port
+ name = credential && credential['name'] ? credential['name'] : UUIDTools::UUID.random_create.to_s
+
+ username = credential && credential['username'] ? credential['username'] : UUIDTools::UUID.random_create.to_s
+ password = credential && credential['password'] ? credential['password'] : UUIDTools::UUID.random_create.to_s
+ # Cleanup instance dir if it exists
+ FileUtils.rm_rf(service_dir(name))
+
+ provisioned_service = ProvisionedService.new
+ provisioned_service.name = name
+ provisioned_service.port = port
+ provisioned_service.memory = @max_memory
+ provisioned_service.keyid = username
+ provisioned_service.secretid = password
+ provisioned_service.pid = start_instance(provisioned_service)
+
+ raise "Cannot save provision_service" unless provisioned_service.save
+
+ sleep 1 # allows some time for the instance to ramp up
+
+ host = get_host
+ response = {
+ "hostname" => host,
+ "host" => host,
+ "port" => provisioned_service.port,
+ "name" => provisioned_service.name,
+ "username" => username,
+ "password" => password
+ }
+ @logger.debug("Provision response: #{response}")
+ return response
+ rescue => e
+ @logger.error("Error provision instance: #{e}")
+ record_service_log(provisioned_service.name)
+ cleanup_service(provisioned_service)
+ raise e
+ end
+
+ def unprovision(name, bindings)
+ provisioned_service = ProvisionedService.get(name)
+ raise ServiceError.new(ServiceError::NOT_FOUND, name) if provisioned_service.nil?
+ cleanup_service(provisioned_service)
+ @logger.info("Successfully fulfilled unprovision request: #{name}.")
+ true
+ end
+
+ def cleanup_service(provisioned_service)
+ @logger.info("Killing #{provisioned_service.name} started with pid #{provisioned_service.pid}")
+ provisioned_service.kill(:SIGKILL) if provisioned_service.running?
+ dir = service_dir(provisioned_service.name)
+ log_dir = log_dir(provisioned_service.name)
+ EM.defer do
+ FileUtils.rm_rf(dir)
+ FileUtils.rm_rf(log_dir)
+ end
+ return_port(provisioned_service.port)
+ raise "Could not cleanup service: #{provisioned_service.errors.pretty_inspect}" unless provisioned_service.destroy
+ true
+ end
+
+ # provide the key/secret to vblob gw
+ def bind(name, bind_opts, credential = nil)
+ @logger.debug("Bind request: name=#{name}, bind_opts=#{bind_opts}")
+ provisioned_service = ProvisionedService.get(name)
+ raise "Could not find service: #{name}" if provisioned_service.nil?
+ username = credential && credential['username'] ? credential['username'] : UUIDTools::UUID.random_create.to_s
+ password = credential && credential['password'] ? credential['password'] : UUIDTools::UUID.random_create.to_s
+
+ vblobgw_add_user({
+ :port => provisioned_service.port,
+ :admin => provisioned_service.keyid,
+ :adminpass => provisioned_service.secretid,
+ :username => username,
+ :password => password,
+ :bindopt => bind_opts
+ })
+
+ host = get_host
+ response = {
+ "hostname" => host,
+ "host" => host,
+ "port" => provisioned_service.port,
+ "username" => username,
+ "password" => password,
+ "name" => provisioned_service.name,
+ }
+ @logger.debug("response: #{response}")
+ response
+ end
+
+ def unbind(credential)
+ @logger.debug("Unbind request: credential=#{credential}")
+ name = credential['name']
+ provisioned_service = ProvisionedService.get(name)
+ raise ServiceError.new(ServiceError::NOT_FOUND, name) if provisioned_service.nil?
+
+ if provisioned_service.port != credential['port']
+ raise ServiceError.new(ServiceError::HTTP_BAD_REQUEST)
+ end
+
+ vblobgw_remove_user({
+ :port => credential['port'],
+ :admin => provisioned_service.keyid,
+ :adminpass => provisioned_service.secretid,
+ :username => credential['username'],
+ :password => credential['password']
+ })
+ @logger.debug("Successfully unbind #{credential}")
+ true
+ end
+
+ def varz_details
+ # Do disk summary
+ du_hash = {}
+ du_all_out = `cd #{@base_dir}; du -sk * 2> /dev/null`
+ du_entries = du_all_out.split("\n")
+ du_entries.each do |du_entry|
+ size, dir = du_entry.split("\t")
+ size = size.to_i * 1024 # Convert to bytes
+ du_hash[dir] = size
+ end
+
+ # Get meta db.stats
+ stats = []
+ ProvisionedService.all.each do |provisioned_service|
+ stat = {}
+ # TODO: get stat from vblob services
+ stat['name'] = provisioned_service.name
+ stats << stat
+ end
+ {
+ :running_services => stats,
+ :disk => du_hash,
+ :max_capacity => @max_capacity,
+ :available_capacity => @capacity
+ }
+ end
+
+ def healthz_details
+ healthz = {}
+ healthz[:self] = "ok"
+ ProvisionedService.all.each do |instance|
+ healthz[instance.name.to_sym] = get_healthz(instance)
+ end
+ healthz
+ rescue => e
+ @logger.warn("Error get healthz details: #{e}")
+ {:self => "fail"}
+ end
+
+ def get_healthz(instance)
+ # ping vblob gw
+ req = Net::HTTP::Get.new("/")
+ res = nil
+ Timeout::timeout(VBLOB_TIMEOUT) do
+ res = Net::HTTP.start(@local_ip, instance.port) {|http|
+ http.request(req)
+ }
+ end
+ res ? "ok" : "fail"
+ rescue => e
+ @logger.warn("Getting healthz for #{instance.inspect} failed with error #{e}")
+ "fail"
+ end
+
+ def start_instance(provisioned_service)
+ @logger.debug("Starting instance: #{provisioned_service.pretty_inspect}")
+ memory = @max_memory
+ pid = fork
+ if pid
+ @logger.debug("Service #{provisioned_service.name} started with pid #{pid}")
+ # In parent, detach the child.
+ Process.detach(pid)
+ pid
+ else
+ $0 = "Starting VBlob service: #{provisioned_service.name}"
+ close_fds
+ vblob_port = provisioned_service.port
+ dir = service_dir(provisioned_service.name)
+ logdir = log_dir(provisioned_service.name);
+ vblob_dir = vblob_dir(dir)
+ log_file = log_file_vblob(provisioned_service.name)
+ account_file = File.join(dir,"account.json")
+ keyid = provisioned_service.keyid
+ secretid = provisioned_service.secretid
+ config = @config_template.result(binding)
+ config_path = File.join(dir, "config.json")
+ if !(File.exist?(dir))
+ FileUtils.mkdir_p(dir) rescue @logger.warn("Creating service folder for #{provisioned_service.name} failed")
+ end
+ if !(File.exist?(vblob_dir))
+ FileUtils.mkdir_p(vblob_dir) rescue @logger.warn("Creating vblob data folder for #{provisioned_service.name} failed")
+ end
+ if !(File.exist?(logdir))
+ FileUtils.mkdir_p(logdir) rescue @logger.warn("Creating log folder for #{provisioned_service.name} failed")
+ end
+ if File.exist?(config_path)
+ FileUtils.rm_f(config_path) rescue @logger.warn("Deleting old config file for #{provisioned_service.name} failed")
+ end
+ File.open(config_path, "w") {|f| f.write(config)}
+ cmd = "#{@nodejs_path} #{@vblobd_path}/server.js -f #{config_path}"
+ exec(cmd) rescue @logger.warn("exec(#{cmd}) failed!")
+ end
+ end
+
+ def close_fds
+ 3.upto(get_max_open_fd) do |fd|
+ begin
+ IO.for_fd(fd, "r").close
+ rescue
+ end
+ end
+ end
+
+ def get_max_open_fd
+ max = 0
+
+ dir = nil
+ if File.directory?("/proc/self/fd/") # Linux
+ dir = "/proc/self/fd/"
+ elsif File.directory?("/dev/fd/") # Mac
+ dir = "/dev/fd/"
+ end
+
+ if dir
+ Dir.foreach(dir) do |entry|
+ begin
+ pid = Integer(entry)
+ max = pid if pid > max
+ rescue
+ end
+ end
+ else
+ max = 65535
+ end
+
+ max
+ end
+
+ def vblobgw_add_user(options)
+ @logger.debug("add user #{options[:username]} in port: #{options[:port]}")
+ creds = "{\"#{options[:username]}\":\"#{options[:password]}\"}";
+ res = nil
+ Timeout::timeout(VBLOB_TIMEOUT) do
+ res = Net::HTTP.start(@local_ip, options[:port]) {|http|
+ http.send_request('PUT','/~bind',creds, auth_header(options[:admin], options[:adminpass]))
+ }
+ end
+ raise "Add vblob user #{options[:username]} failed" if (res.nil? || res.code != "200")
+ @logger.debug("user #{options[:username]} added")
+ end
+
+ def vblobgw_remove_user(options)
+ @logger.debug("remove user #{options[:username]} in port: #{options[:port]}")
+ creds = "{\"#{options[:username]}\":\"#{options[:password]}\"}";
+ res = nil
+ Timeout::timeout(VBLOB_TIMEOUT) do
+ res = Net::HTTP.start(@local_ip, options[:port]) {|http|
+ http.send_request('PUT','/~unbind',creds, auth_header(options[:admin], options[:adminpass]))
+ }
+ end
+ raise "Delete vblob user #{options[:username]} failed" if (res.nil? || res.code != "200")
+ @logger.debug("user #{options[:username]} removed")
+ end
+
+ def service_dir(service_id)
+ File.join(@base_dir, service_id)
+ end
+
+ def log_dir(instance_id)
+ File.join(@vblobd_log_dir,instance_id)
+ end
+
+ def log_file_vblob(instance_id)
+ File.join(log_dir(instance_id), 'vblob.log')
+ end
+
+ def service_exist?(provisioned_service)
+ Dir.exists?(service_dir(provisioned_service.name))
+ end
+
+ def vblob_dir(base_dir)
+ File.join(base_dir,'vblob_data')
+ end
+
+ def auth_header(user,passwd)
+ {"Authorization" => "Basic " + Base64.strict_encode64("#{user}:#{passwd}").strip}
+ end
+
+ def record_service_log(service_id)
+ @logger.warn(" *** BEGIN vblob log - instance: #{service_id}")
+ @logger.warn("")
+ file = File.new(log_file_vblob(service_id), 'r')
+ while (line = file.gets)
+ @logger.warn(line.chomp!)
+ end
+ rescue => e
+ @logger.warn(e)
+ ensure
+ @logger.warn(" *** END vblob log - instance: #{service_id}")
+ @logger.warn("")
+ end
+end
View
9 vblob/lib/vblob_service/vblob_provisioner.rb
@@ -0,0 +1,9 @@
+# Copyright (c) 2009-2011 VMware, Inc.
+require "vblob_service/common"
+
+class VCAP::Services::VBlob::Provisioner < VCAP::Services::Base::Provisioner
+
+ include VCAP::Services::VBlob::Common
+
+end
+
View
29 vblob/resources/vblob.conf.erb
@@ -0,0 +1,29 @@
+{
+ "drivers" : [
+ {
+ "fs-<%= provisioned_service.name %>": {
+ "type": "fs",
+ "option": {
+ "root": "<%= vblob_dir %>",
+ "node_exepath": "<%= @nodejs_path %>",
+ "gc_exepath": "<%= @vblobd_path %>/drivers/fs/fs_gc.js",
+ "gcfc_exepath": "<%= @vblobd_path %>/drivers/fs/fs_gcfc.js",
+ "gctmp_exepath": "<%= @vblobd_path %>/drivers/fs/fs_gctmp.js",
+ "ec_exepath": "<%= @vblobd_path %>/drivers/fs/fs_ec.js",
+ "quota": 2147483648,
+ "obj_limit": 32768
+ }
+ }
+ }
+ ],
+ "port" : <%= vblob_port %> ,
+ "current_driver" : "fs-<%= provisioned_service.name %>",
+ "logtype" : "winston",
+ "logfile" : "<%= log_file %>",
+ "keyID" : "<%= keyid %>",
+ "secretID" : "<%= secretid %>",
+ "auth" : "<%= @vblobd_auth %>",
+ "debug" : false,
+ "account_file" : "<%= account_file %>",
+ "account_api" : true
+}
View
41 vblob/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, "vblob.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|
+ FileUtils.rm_rf(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.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}")
+ FileUtils.rm_rf(dump_file)
+end
View
97 vblob/spec/spec_helper.rb
@@ -0,0 +1,97 @@
+# Copyright (c) 2009-2011 VMware, Inc.
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
+PWD = File.dirname(__FILE__)
+TMP = '/tmp/vblob'
+
+$:.unshift File.join(PWD, '..')
+$:.unshift File.join(PWD, '..', 'lib')
+
+require "rubygems"
+require "bundler/setup"
+require "vcap_services_base"
+require "rspec"
+require "socket"
+require "timeout"
+require "erb"
+require "vblob_service/vblob_node"
+require "fileutils"
+require 'vcap/common'
+require 'vcap/logging'
+
+# Define constants
+HTTP_PORT = 9865
+
+TEST_COLL = 'testColl'
+TEST_KEY = 'test_key'
+TEST_VAL = 1234
+TEST_VAL_2 = 4321
+
+include VCAP::Services::VBlob
+
+module VCAP
+ module Services
+ module VBlob
+ class Node
+ attr_reader :available_memory
+ end
+ end
+ end
+end
+
+def is_port_open?(host, port)
+ begin
+ Timeout::timeout(1) do
+ begin
+ s = TCPSocket.new(host, port)
+ s.close
+ return true
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
+ return false
+ end
+ end
+ rescue Timeout::Error
+ end
+ false
+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
+
+def get_node_config()
+ config_file = File.join(PWD, "../config/vblob_node.yml")
+ config = YAML.load_file(config_file)
+ vblob_conf_template = File.join(PWD, "../resources/vblob.conf.erb")
+ options = {
+ # :logger => Logger.new(parse_property(config, "log_file", String, :optional => true) || STDOUT, "daily"),
+ :nodejs_path => parse_property(config, "nodejs_path", String),
+ :plan => parse_property(config, "plan", String),
+ :capacity => parse_property(config, "capacity", Integer),
+ :vblobd_path => parse_property(config, "vblobd_path", String),
+ :vblobd_log_dir => parse_property(config, "vblobd_log_dir", String),
+ :ip_route => parse_property(config, "ip_route", String, :optional => true),
+ :node_id => parse_property(config, "node_id", String),
+ :mbus => parse_property(config, "mbus", String),
+ :config_template => vblob_conf_template,
+ :port_range => parse_property(config, "port_range", Range),
+ :max_memory => parse_property(config, "max_memory", Integer),
+ :base_dir => '/tmp/vblob/instances',
+ :local_db => 'sqlite3:/tmp/vblob/vblob_node.db'
+ }
+ VCAP::Logging.setup_from_config(config["logging"])
+ # Use the node id for logger identity name.
+ options[:logger] = VCAP::Logging.logger(options[:node_id])
+ options
+end
View
105 vblob/spec/vblob_bind_spec.rb
@@ -0,0 +1,105 @@
+# Copyright (c) 2009-2011 VMware, Inc.
+require "spec_helper"
+
+describe "vblob_node bind" do
+
+ before :all do
+ EM.run do
+ @app_id = "myapp"
+ @opts = get_node_config()
+ @logger = @opts[:logger]
+ @node = Node.new(@opts)
+ EM.add_timer(2) do #must! wait for a while before provisioning
+ @resp = @node.provision("free")
+ end
+ EM.add_timer(4) do
+ @bind_resp = @node.bind(@resp['name'], 'rw')
+ EM.stop
+ end
+ end
+ end
+
+ it "should have valid response" do
+ @resp.should_not be_nil
+ @resp['host'].should_not be_nil
+ @resp['port'].should_not be_nil
+ @resp['username'].should_not be_nil
+ @resp['password'].should_not be_nil
+ @bind_resp.should_not be_nil
+ @bind_resp['host'].should_not be_nil
+ @bind_resp['port'].should_not be_nil
+ @bind_resp['username'].should_not be_nil
+ @bind_resp['password'].should_not be_nil
+ end
+
+ it "should be able to connect to vblob" do
+ is_port_open?('127.0.0.1', @resp['port']).should be_true
+ end
+
+ it "should return error when tring to bind on non-existent instance" do
+ e = nil
+ begin
+ @node.bind('non-existent', 'rw')
+ rescue => e
+ end
+ e.should_not be_nil
+ end
+
+ it "should allow binded user to access" do
+ response = nil
+ EM.run do
+ begin
+ response = `curl http://#{@resp['host']}:#{@resp['port']}/bucket1 -X PUT -s`
+ response = `curl http://#{@resp['host']}:#{@resp['port']}/bucket1 -X DELETE -s`
+ rescue => e
+ end
+ e.should be_nil
+ EM.stop
+ end
+ response.should_not be_nil
+ end
+
+ it "should return error when trying to unbind a non-existent service" do
+ EM.run do
+ begin
+ resp = @node.unbind('not existed')
+ rescue => e
+ end
+ e.should be_true
+ EM.add_timer(1) do
+ EM.stop
+ end
+ end
+ end
+
+ # unbind here
+ it "should be able to unbind it" do
+ EM.run do
+ resp = @node.unbind(@bind_resp)
+ resp.should be_true
+ EM.add_timer(1) do
+ EM.stop
+ end
+ end
+ end
+
+ # unprovision here
+ it "should be able to unprovision an existing instance" do
+ EM.run do
+ @node.unprovision(@resp['name'], [])
+
+ e = nil
+ begin
+ is_port_open?('127.0.0.1',@resp['port']).should_not be_true
+ rescue => e
+ end
+ EM.stop
+ end
+ end
+
+ after:all do
+ FileUtils.rm_rf Dir.glob('/tmp/vblob')
+ end
+end
+
+
View
42 vblob/spec/vblob_orphan_spec.rb
@@ -0,0 +1,42 @@
+# Copyright (c) 2009-2011 VMware, Inc.
+$:.unshift(File.dirname(__FILE__))
+require "spec_helper"
+
+describe "vblob_node check & purge orphan" do
+ before :all do
+ EM.run do
+ @opts = get_node_config
+ @logger = @opts[:logger]
+ @node = Node.new(@opts)
+ EM.stop
+ end
+ end
+
+ it "should return proper instances & bindings list" do
+ EM.run do
+ before_instances = @node.all_instances_list
+ before_bindings = @node.all_bindings_list
+ oi = @node.provision("free")
+ sleep 0.5
+ ob = @node.bind(oi["name"],'rw')
+ after_instances = @node.all_instances_list
+ after_bindings = @node.all_bindings_list
+ @node.unprovision(oi["name"],[])
+ (after_instances - before_instances).include?(oi["name"]).should be_true
+ (after_bindings - before_bindings).index { |credential| credential["username"] == ob["username"] }.should_not be_nil
+ EM.stop
+ end
+ end
+
+ it "should be able to purge the orphan" do
+ EM.run do
+ oi = @node.provision("free")
+ sleep 0.5
+ ob = @node.bind(oi["name"],'rw')
+ @node.purge_orphan([oi["name"]],[ob])
+ @node.all_instances_list.include?(oi["name"]).should be_false
+ @node.all_bindings_list.index { |credential| credential["username"] == ob["username"] }.should be_nil
+ EM.stop
+ end
+ end
+end
View
104 vblob/spec/vblob_provision_spec.rb
@@ -0,0 +1,104 @@
+# Copyright (c) 2009-2011 VMware, Inc.
+$:.unshift(File.dirname(__FILE__))
+require "spec_helper"
+
+describe "vblob_node provision" do
+
+ before :all do
+ EM.run do
+ @opts = get_node_config()
+ @logger = @opts[:logger]
+ @node = Node.new(@opts)
+
+ EM.add_timer(2) { @resp = @node.provision("free") }
+ EM.add_timer(4) { EM.stop }
+ end
+ end
+
+ it "should have valid response" do
+ @resp.should_not be_nil
+ puts @resp
+ inst_name = @resp['name']
+ inst_name.should_not be_nil
+ inst_name.should_not == ""
+ end
+
+ it "should be able to connect to vblob gateway" do
+ is_port_open?('127.0.0.1',@resp['port']).should be_true
+ end
+
+ it "should return varz" do
+ EM.run do
+ stats = nil
+ 10.times do
+ stats = @node.varz_details
+ @node.healthz_details
+ end
+ stats.should_not be_nil
+ stats[:running_services].length.should > 0
+ stats[:running_services][0]['name'].should_not be_nil
+ stats[:disk].should_not be_nil
+ stats[:max_capacity].should > 0
+ stats[:available_capacity].should > 0
+ EM.stop
+ end
+ end
+
+ it "should return healthz" do
+ EM.run do
+ stats = @node.healthz_details
+ stats.should_not be_nil
+ stats[:self].should == "ok"
+ stats[@resp['name'].to_sym].should == "ok"
+ EM.stop
+ end
+ end
+
+ it "should keep the result after node restart" do
+ port_open_1 = nil
+ port_open_2 = nil
+ EM.run do
+ EM.add_timer(0) { @node.shutdown }
+ EM.add_timer(1) { port_open_1 = is_port_open?('127.0.0.1', @resp['port'])
+ }
+ EM.add_timer(2) { @node = Node.new(@opts) }
+ EM.add_timer(3) { port_open_2 = is_port_open?('127.0.0.1', @resp['port'])
+ }
+ EM.add_timer(4) { EM.stop }
+ end
+
+ port_open_1.should be_false
+ port_open_2.should be_true
+ end
+
+ it "should return error when unprovisioning a non-existent instance" do
+ EM.run do
+ e = nil
+ begin
+ @node.unprovision('not existent', [])
+ rescue => e
+ end
+ e.should_not be_nil
+ EM.stop
+ end
+ end
+
+ # unprovision here
+ it "should be able to unprovision an existent instance" do
+ EM.run do
+ e = nil
+ begin
+ @node.unprovision(@resp['name'], [])
+ rescue => e
+ end
+ e.should be_nil
+ EM.stop
+ end
+ end
+
+ after:all do
+ FileUtils.rm_rf Dir.glob('/tmp/vblob')
+ end
+end
+
+
View
BIN  vblob/vendor/cache/addressable-2.2.6.gem
Binary file not shown
View
BIN  vblob/vendor/cache/bcrypt-ruby-2.1.4.gem
Binary file not shown
View
BIN  vblob/vendor/cache/builder-3.0.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/ci_reporter-1.6.9.gem
Binary file not shown
View
BIN  vblob/vendor/cache/curb-0.7.16.gem
Binary file not shown
View
BIN  vblob/vendor/cache/daemons-1.1.5.gem
Binary file not shown
View
BIN  vblob/vendor/cache/data_objects-0.10.7.gem
Binary file not shown
View
BIN  vblob/vendor/cache/datamapper-1.1.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/diff-lcs-1.1.3.gem
Binary file not shown
View
BIN  vblob/vendor/cache/dm-aggregates-1.1.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/dm-constraints-1.1.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/dm-core-1.1.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/dm-do-adapter-1.1.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/dm-migrations-1.1.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/dm-serializer-1.1.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/dm-sqlite-adapter-1.1.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/dm-timestamps-1.1.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/dm-transactions-1.1.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/dm-types-1.1.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/dm-validations-1.1.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/do_sqlite3-0.10.7.gem
Binary file not shown
View
BIN  vblob/vendor/cache/em-http-request-0.3.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/escape_utils-0.2.4.gem
Binary file not shown
View
BIN  vblob/vendor/cache/eventmachine-0.12.11.cloudfoundry.3.gem
Binary file not shown
View
BIN  vblob/vendor/cache/eventmachine_httpserver-0.2.1.gem
Binary file not shown
View
BIN  vblob/vendor/cache/fastercsv-1.5.4.gem
Binary file not shown
View
BIN  vblob/vendor/cache/json-1.4.6.gem
Binary file not shown
View
BIN  vblob/vendor/cache/json_pure-1.6.4.gem
Binary file not shown
View
BIN  vblob/vendor/cache/little-plugger-1.1.3.gem
Binary file not shown
View
BIN  vblob/vendor/cache/logging-1.6.1.gem
Binary file not shown
View
BIN  vblob/vendor/cache/macaddr-1.5.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/multi_json-1.0.4.gem
Binary file not shown
View
BIN  vblob/vendor/cache/nats-0.4.22.beta.4.gem
Binary file not shown
View
BIN  vblob/vendor/cache/posix-spawn-0.3.6.gem
Binary file not shown
View
BIN  vblob/vendor/cache/rack-1.4.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/rake-0.9.2.2.gem
Binary file not shown
View
BIN  vblob/vendor/cache/rcov-0.9.11.gem
Binary file not shown
View
BIN  vblob/vendor/cache/redis-2.2.2.gem
Binary file not shown
View
BIN  vblob/vendor/cache/redis-namespace-1.0.3.gem
Binary file not shown
View
BIN  vblob/vendor/cache/redisk-0.2.2.gem
Binary file not shown
View
BIN  vblob/vendor/cache/resque-1.19.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/resque-status-0.2.4.gem
Binary file not shown
View
BIN  vblob/vendor/cache/rspec-2.7.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/rspec-core-2.7.1.gem
Binary file not shown
View
BIN  vblob/vendor/cache/rspec-expectations-2.7.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/rspec-mocks-2.7.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/ruby-hmac-0.4.0.gem
Binary file not shown
View
BIN  vblob/vendor/cache/sinatra-1.2.7.gem
Binary file not shown
View
BIN  vblob/vendor/cache/stringex-1.2.2.gem
Binary file not shown
View
BIN  vblob/vendor/cache/systemu-2.4.2.gem
Binary file not shown
View
BIN  vblob/vendor/cache/thin-1.3.1.gem
Binary file not shown
View
BIN  vblob/vendor/cache/tilt-1.3.3.gem
Binary file not shown
View
BIN  vblob/vendor/cache/uuid-2.3.4.gem
Binary file not shown
View
BIN  vblob/vendor/cache/uuidtools-2.1.2.gem
Binary file not shown
View
BIN  vblob/vendor/cache/vcap_common-1.0.4.gem
Binary file not shown
View
BIN  vblob/vendor/cache/vcap_logging-0.1.3.gem
Binary file not shown
View
BIN  vblob/vendor/cache/vcap_services_base-0.1.7.gem
Binary file not shown
View
BIN  vblob/vendor/cache/vegas-0.1.8.gem
Binary file not shown
View
BIN  vblob/vendor/cache/yajl-ruby-0.8.3.gem
Binary file not shown
Please sign in to comment.
Something went wrong with that request. Please try again.