Permalink
Browse files

Move plugin registry to vcap/common

vcap/common is a more natural home for the plugin registry, and will
allow us to reuse it across components.

Test plan:
- Unit tests pass

Change-Id: Ifcc36837179029ce7db3ac40e1eaa3596f4723c3
  • Loading branch information...
1 parent 9b70622 commit 466d8adfc4c12cbd94635377d666ae624f8a0f0c mpage committed Nov 10, 2011
View
2 cloud_controller/Gemfile
@@ -8,7 +8,7 @@ gem 'nats', '>= 0.4.10', :require => 'nats/client'
gem 'logging', '>= 1.5.0'
# VCAP common components
-gem 'vcap_common', :require => ['vcap/common', 'vcap/component'], :path => '../common'
+gem 'vcap_common', :require => ['vcap/common', 'vcap/component']
gem 'vcap_logging', :require => ['vcap/logging']
gem 'vcap_staging', '= 0.1.22'
View
20 cloud_controller/Gemfile.lock
@@ -1,14 +1,3 @@
-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:
@@ -136,6 +125,13 @@ GEM
polyglot (>= 0.3.1)
tzinfo (0.3.26)
uuidtools (2.1.2)
+ vcap_common (1.0)
+ eventmachine (~> 0.12.10)
+ logging (>= 1.5.0)
+ nats
+ posix-spawn
+ thin
+ yajl-ruby
vcap_logging (0.1.0)
vcap_stager_ipc (0.0.2)
eventmachine
@@ -179,7 +175,7 @@ DEPENDENCIES
sqlite3
thin (> 1.2)
uuidtools
- vcap_common!
+ vcap_common
vcap_logging
vcap_stager_ipc (= 0.0.2)
vcap_staging (= 0.1.22)
View
2 cloud_controller/config/cloud_controller.yml
@@ -96,7 +96,7 @@ staging:
max_staging_runtime: 120 # secs
# Create a secure environment for staging
secure: false
- new_stager_percent: 100
+ new_stager_percent: 0
allow_debug: false
View
BIN cloud_controller/vendor/cache/vcap_common-0.99.gem
Binary file not shown.
View
BIN cloud_controller/vendor/cache/vcap_common-1.0.0.gem
Binary file not shown.
View
BIN cloud_controller/vendor/cache/vcap_common-1.0.gem
Binary file not shown.
View
14 common/Gemfile.lock
@@ -1,12 +1,14 @@
PATH
remote: .
specs:
- vcap_common (0.99)
+ vcap_common (1.0.0)
eventmachine (~> 0.12.10)
logging (>= 1.5.0)
nats
posix-spawn
+ rake
thin
+ vcap_logging
yajl-ruby
GEM
@@ -24,16 +26,17 @@ GEM
eventmachine
eventmachine (0.12.10)
http_parser.rb (0.5.1)
- json_pure (1.5.3)
+ json_pure (1.6.1)
little-plugger (1.1.2)
- logging (1.6.0)
+ logging (1.6.1)
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.3.2)
+ rack (1.3.4)
+ rake (0.9.2.2)
rspec (2.5.0)
rspec-core (~> 2.5.0)
rspec-expectations (~> 2.5.0)
@@ -46,7 +49,8 @@ GEM
daemons (>= 1.0.9)
eventmachine (>= 0.12.6)
rack (>= 1.0.0)
- yajl-ruby (0.8.3)
+ vcap_logging (0.1.3)
+ yajl-ruby (1.0.0)
PLATFORMS
ruby
View
51 common/lib/vcap/plugin_registry.rb
@@ -0,0 +1,51 @@
+require 'vcap/logging'
+
+module VCAP
+ class PluginRegistry
+ class << self
+ attr_accessor :plugin_config_dir
+ attr_accessor :plugins
+
+ def plugins
+ @plugins ||= {}
+ @plugins
+ end
+
+ # Registers a set of plugins with the system. Plugins should call this method
+ # when their export file is required.
+ def register_plugins(*plugins)
+ @plugins ||= {}
+ logger = VCAP::Logging.logger('vcap.plugins.registry')
+ plugins.each do |plugin|
+ logger.debug("Registering plugin '#{plugin.name}'")
+ @plugins[plugin.name] = plugin
+ end
+ end
+
+ # Configures registered plugins
+ #
+ # NB: The contract exposed here is that a plugin's config filename
+ # is of the form '<plugin_name>.yml'.
+ def configure_plugins
+ return unless @plugin_config_dir
+ logger = VCAP::Logging.logger('vcap.plugins.registry')
+
+ config_glob = File.join(@plugin_config_dir, "*.yml")
+ logger.debug("Looking for plugin configs using the glob '#{config_glob}'")
+ config_paths = Dir.glob(config_glob)
+
+ logger.debug("Found #{config_paths.length} configs")
+ for config_path in config_paths
+ plugin_name = File.basename(config_path, '.yml')
+ plugin = @plugins[plugin_name]
+ if plugin
+ plugin.configure(config_path)
+ else
+ logger.warn("No plugin found for config at '#{config_path}'")
+ end
+ end
+ end
+
+ end # << self
+ end # VCAP::PluginRegistry
+end # VCAP
View
1 common/spec/spec_helper.rb
@@ -10,6 +10,7 @@
require "vcap/subprocess"
require "vcap/process_utils"
require "vcap/config"
+require 'vcap/plugin_registry'
def fixture_path(*args)
base = File.expand_path("../", __FILE__)
View
55 common/spec/unit/plugin_registry_spec.rb
@@ -0,0 +1,55 @@
+require File.expand_path('../../spec_helper', __FILE__)
+
+require 'fileutils'
+require 'tmpdir'
+
+describe VCAP::PluginRegistry do
+ describe '.register_plugins' do
+ before :each do
+ VCAP::PluginRegistry.plugins = {}
+ end
+
+ it 'should allow registration of multiple plugins' do
+ plugins = [stub_plugin('a'), stub_plugin('b')]
+ VCAP::PluginRegistry.register_plugins(*plugins)
+ for plugin in plugins
+ VCAP::PluginRegistry.plugins[plugin.name].should == plugin
+ end
+ end
+
+ it 'should only allow one plugin per name' do
+ VCAP::PluginRegistry.register_plugins(stub_plugin('a'))
+ plugin = stub_plugin('a')
+ VCAP::PluginRegistry.register_plugins(plugin)
+ VCAP::PluginRegistry.plugins['a'].should == plugin
+ end
+ end
+
+ describe '.configured_plugins' do
+ before :each do
+ @tmpdir = Dir.mktmpdir
+ end
+
+ after :each do
+ FileUtils.rm_rf(@tmpdir)
+ end
+
+ it 'should call configure() on the appropriate plugin with the correct path' do
+ for name in ['a', 'b']
+ plugin = stub_plugin(name)
+ config_file = File.join(@tmpdir, "#{name}.yml")
+ FileUtils.touch(config_file)
+ plugin.should_receive(:configure).with(config_file)
+ VCAP::PluginRegistry.register_plugins(plugin)
+ end
+ VCAP::PluginRegistry.plugin_config_dir = @tmpdir
+ VCAP::PluginRegistry.configure_plugins()
+ end
+ end
+
+ def stub_plugin(name)
+ plugin = mock(name)
+ plugin.stub!(:name).and_return(name)
+ plugin
+ end
+end
View
BIN common/vcap_common-0.99.gem
Binary file not shown.
View
BIN common/vcap_common-1.0.0.gem
Binary file not shown.
View
4 common/vcap_common.gemspec
@@ -1,6 +1,6 @@
spec = Gem::Specification.new do |s|
s.name = 'vcap_common'
- s.version = 0.99
+ s.version = '1.0.0'
s.date = '2011-02-09'
s.summary = 'vcap common'
s.homepage = "http://github.com/vmware-ac/core"
@@ -15,6 +15,8 @@ spec = Gem::Specification.new do |s|
s.add_dependency('nats')
s.add_dependency('logging', '>= 1.5.0')
s.add_dependency('posix-spawn')
+ s.add_dependency('rake')
+ s.add_dependency('vcap_logging')
s.require_paths = ['lib']
View
2 dea/Gemfile
@@ -11,7 +11,7 @@ gem 'thin'
gem 'yajl-ruby', :require => ['yajl', 'yajl/json_gem']
gem 'logging', '>= 1.5.0'
-gem 'vcap_common', :path => '../common'
+gem 'vcap_common'
gem 'vcap_logging', :require => ['vcap/logging']
group :test do
View
20 dea/Gemfile.lock
@@ -1,14 +1,3 @@
-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:
@@ -51,6 +40,13 @@ GEM
daemons (>= 1.0.9)
eventmachine (>= 0.12.6)
rack (>= 1.0.0)
+ vcap_common (1.0)
+ eventmachine (~> 0.12.10)
+ logging (>= 1.5.0)
+ nats
+ posix-spawn
+ thin
+ yajl-ruby
vcap_logging (0.1.0)
yajl-ruby (0.8.2)
@@ -69,6 +65,6 @@ DEPENDENCIES
rcov
rspec
thin
- vcap_common!
+ vcap_common
vcap_logging
yajl-ruby
View
BIN dea/vendor/cache/vcap_common-1.0.0.gem
Binary file not shown.
View
2 router/Gemfile
@@ -7,7 +7,7 @@ gem 'eventmachine', '~> 0.12.10'
gem "http_parser.rb", :require => "http/parser"
gem "yajl-ruby", :require => ["yajl", "yajl/json_gem"]
-gem 'vcap_common', :path => '../common'
+gem 'vcap_common'
gem 'vcap_logging', :require => ['vcap/logging']
group :test do
View
24 router/Gemfile.lock
@@ -1,14 +1,3 @@
-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:
@@ -21,14 +10,14 @@ GEM
http_parser.rb (0.5.1)
json_pure (1.5.1)
little-plugger (1.1.2)
- logging (1.5.2)
+ logging (1.6.1)
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.3.2)
+ rack (1.3.4)
rake (0.8.7)
rcov (0.9.9)
rspec (2.5.0)
@@ -43,6 +32,13 @@ GEM
daemons (>= 1.0.9)
eventmachine (>= 0.12.6)
rack (>= 1.0.0)
+ vcap_common (1.0)
+ eventmachine (~> 0.12.10)
+ logging (>= 1.5.0)
+ nats
+ posix-spawn
+ thin
+ yajl-ruby
vcap_logging (0.1.0)
yajl-ruby (0.8.2)
@@ -58,6 +54,6 @@ DEPENDENCIES
rake
rcov
rspec
- vcap_common!
+ vcap_common
vcap_logging
yajl-ruby
View
BIN router/vendor/cache/logging-1.5.2.gem
Binary file not shown.
View
BIN router/vendor/cache/logging-1.6.1.gem
Binary file not shown.
View
BIN router/vendor/cache/rack-1.3.2.gem
Binary file not shown.
View
BIN router/vendor/cache/rack-1.3.4.gem
Binary file not shown.
View
BIN router/vendor/cache/vcap_common-1.0.0.gem
Binary file not shown.
View
BIN router/vendor/cache/vcap_common-1.0.gem
Binary file not shown.
View
2 stager/Gemfile
@@ -7,7 +7,7 @@ gem 'logging', '= 1.5.2'
gem 'rest-client', '= 1.6.7'
gem 'yajl-ruby', '>= 0.7.9'
-gem 'vcap_common'
+gem 'vcap_common', '>= 1.0.0'
gem 'vcap_logging', '>= 0.1.1'
gem 'vcap_staging', '>= 0.1.11'
gem 'vcap_stager_ipc', '= 0.0.2'
View
4 stager/Gemfile.lock
@@ -40,7 +40,7 @@ GEM
vcap_cloud_controller_ipc (0.0.1)
rake
yajl-ruby
- vcap_common (0.99)
+ vcap_common (1.0.0)
eventmachine (~> 0.12.10)
logging (>= 1.5.0)
nats
@@ -77,7 +77,7 @@ DEPENDENCIES
rspec
sinatra
vcap_cloud_controller_ipc
- vcap_common
+ vcap_common (>= 1.0.0)
vcap_logging (>= 0.1.1)
vcap_stager_ipc (= 0.0.2)
vcap_staging (>= 0.1.11)
View
5 stager/bin/plugin_runner
@@ -1,8 +1,9 @@
+ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
+$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
+
require 'bundler/setup'
require 'yaml'
-$LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
-
if ARGV.length != 2
$stderr.puts "Usage: plugin_runner [serialized plugin runner path] [error path]"
exit 1
View
1 stager/lib/vcap/stager/errors.rb
@@ -40,5 +40,6 @@ class MissingFrameworkPluginError < PluginRunnerError; set_desc "Missing frame
class DuplicateFrameworkPluginError < PluginRunnerError; set_desc "Duplicate framework plugins specified"; end
class UnknownPluginTypeError < PluginRunnerError; set_desc "Unknown plugin type"; end
class StagingAbortedError < PluginRunnerError; set_desc "Staging aborted"; end
+ class UnsupportedPluginError < PluginRunnerError; set_desc "Unsupported plugin"; end
end
end
View
53 stager/lib/vcap/stager/plugin_runner.rb
@@ -4,6 +4,7 @@
require 'vcap/cloud_controller/ipc'
require 'vcap/logging'
+require 'vcap/plugin_registry'
require 'vcap/stager/constants'
require 'vcap/stager/errors'
@@ -18,22 +19,9 @@ module Stager
# Responsible for orchestrating the execution of all staging plugins selected
# by the user.
class VCAP::Stager::PluginRunner
- GEMFILE_TEMPLATE_PATH = File.join(VCAP::Stager::ASSET_DIR, 'plugin_runner_gemfile.erb')
- RUNNER_BIN_PATH = File.join(VCAP::Stager::BIN_DIR, 'plugin_runner')
+ RUNNER_BIN_PATH = File.join(VCAP::Stager::BIN_DIR, 'plugin_runner')
class << self
- attr_reader :registered_plugins
-
- def register_plugins(*plugins)
- @registered_plugins ||= []
- plugins.each {|plugin| @registered_plugins << plugin }
- end
-
- # Testing only
- def reset_registered_plugins
- @registered_plugins = []
- end
-
def from_file(src_path)
YAML.load_file(src_path)
end
@@ -51,17 +39,14 @@ def initialize(source_dir, dest_dir, app_properties, cc_info)
@dest_dir = dest_dir
@droplet = VCAP::Stager::Droplet.new(dest_dir)
@app_properties = app_properties
- @logger = VCAP::Logging.logger('vcap.stager.plugin_runner')
@services_client = VCAP::CloudController::Ipc::ServiceConsumerV1Client.new(cc_info['host'],
cc_info['port'],
:staging_task_id => cc_info['task_id'])
@environment = {}
end
def run_plugins
- for plugin_info in @app_properties['plugins']['staging']
- require(plugin_info['gem']['name'])
- end
+ @logger = VCAP::Logging.logger('vcap.stager.plugin_runner')
framework_plugin, feature_plugins = collect_plugins
@@ -90,22 +75,6 @@ def run_plugins
@droplet.generate_vcap_start_script(@environment)
end
- # Generates a Gemfile that should be used in conjuction with running the
- # standalone script using 'bundle exec'. We assume that every plugin has
- # already been installed locally on the system (therefore its individual
- # dependencies have been satisfied) and rely on Bundler to resolve possible
- # conflicts in plugin dependencies.
- #
- # @param dest_path String Where to place the generated Gemfile
- def generate_gemfile(dest_path)
- plugin_gems = @app_properties['plugins']['staging'].map {|p| p['gem'] }
- template = File.read(GEMFILE_TEMPLATE_PATH)
- renderer = ERB.new(template)
- gemfile_contents = renderer.result(binding())
- File.open(dest_path, 'w+') {|f| f.write(gemfile_contents) }
- dest_path
- end
-
# Serializes *self* to the supplied path
#
# @param dest_path String Where to serialize ourselves
@@ -120,20 +89,26 @@ def to_file(dest_path)
def collect_plugins
framework_plugin = nil
feature_plugins = []
- for plugin in self.class.registered_plugins
- ptype = plugin.plugin_type
+
+ for name in @app_properties['plugins'].keys
+ plugin = VCAP::PluginRegistry.plugins[name]
+ unless plugin
+ raise VCAP::Stager::UnsupportedPluginError, name
+ end
+
+ ptype = plugin.staging_plugin_type
case ptype
when :framework
- @logger.debug("Found framework plugin: #{plugin.name}")
+ @logger.debug("Found framework plugin: #{name}")
if framework_plugin
- errstr = [framework_plugin.name, plugin.name].join(', ')
+ errstr = [framework_plugin.name, name].join(', ')
raise VCAP::Stager::DuplicateFrameworkPluginError, errstr
else
framework_plugin = plugin
end
when :feature
- @logger.debug("Found feature plugin: #{plugin.name}")
+ @logger.debug("Found feature plugin: #{name}")
feature_plugins << plugin
else
View
24 stager/lib/vcap/stager/task.rb
@@ -254,26 +254,10 @@ def run_plugins(src_dir, dst_dir, base_dir)
runner_path = File.join(base_dir, 'plugin_runner')
gemfile_path = File.join(base_dir, 'Gemfile')
error_path = File.join(base_dir, 'plugin_runner_error')
- stager_uid = get_uid()
-
- unless stager_uid != nil
- @vcap_logger.error("Failed to get our uid!")
- raise VCAP::Stager::InternalError
- end
runner = VCAP::Stager::PluginRunner.new(src_dir, dst_dir, @app_props, @cc_info)
runner.to_file(runner_path)
- runner.generate_gemfile(gemfile_path)
- runner_cmd = "GEMFILE_PATH='%s' bundle exec %s %s" % [gemfile_path,
- VCAP::Stager::PluginRunner::RUNNER_BIN_PATH,
- error_path]
- # Can't wait until containers!
- if @user
- runner_cmd = "sudo -u '##{@user[:uid]}' #{runner_cmd}"
- @vcap_logger.debug("Chowning #{base_dir} to #{@user}")
- res = run_logged("sudo chown -R #{@user[:user]} #{base_dir}")
- raise VCAP::Stager::StagingPluginError, "Failed chowning base directory" unless res[:success]
- end
+ runner_cmd = "#{@ruby_path} %s %s" % [VCAP::Stager::PluginRunner::RUNNER_BIN_PATH, error_path]
@vcap_logger.debug("Executing plugin runner with command #{runner_cmd}")
res = run_logged(runner_cmd, 0, @max_staging_duration)
@@ -303,12 +287,6 @@ def run_plugins(src_dir, dst_dir, base_dir)
raise VCAP::Stager::PluginRunnerError
end
end
-
- ensure
- if @user
- @vcap_logger.debug("Chowning #{base_dir} back to #{stager_uid}")
- run_logged("sudo chown -R #{@stager_uid} #{base_dir}")
- end
end
# Packages and uploads the droplet in staged_dir
View
36 stager/spec/unit/plugin_runner_spec.rb
@@ -4,21 +4,6 @@
require 'tmpdir'
describe VCAP::Stager::PluginRunner do
- describe '#generate_gemfile' do
- it 'should write out a Gemfile containing all plugins to be run' do
- tmpdir = Dir.mktmpdir
- gemfile_path = File.join(tmpdir, 'Gemfile')
- plugins = [{'gem' => {'name' => 'test1'}},
- {'gem' => {'name' => 'test2', 'version' => '0.0.1'}}]
- runner = VCAP::Stager::PluginRunner.new(tmpdir, tmpdir, {'plugins' => {'staging' => plugins}}, {})
- runner.generate_gemfile(gemfile_path)
- File.exist?(gemfile_path).should be_true
- gemfile_contents = File.read(gemfile_path)
- gemfile_contents.match(/^gem 'test1'$/).should be_true
- gemfile_contents.match(/^gem 'test2', '= 0.0.1'$/).should be_true
- end
- end
-
describe '#run_plugins' do
before :each do
@src_dir = Dir.mktmpdir
@@ -33,7 +18,7 @@
'name' => 'testapp',
'framework' => 'sinatra',
'runtime' => 'ruby18',
- 'plugins' => {'staging' => []},
+ 'plugins' => {},
'service_configs' => [],
'service_bindings' => [],
'resource_limits' => {
@@ -42,7 +27,7 @@
'fds' => 1024,
}
}
- VCAP::Stager::PluginRunner.reset_registered_plugins()
+ VCAP::PluginRegistry.plugins = {}
end
after :each do
@@ -51,11 +36,11 @@
end
it 'should raise an error for unknown plugins' do
- @app_props['plugins']['staging'] = [{'gem' => {'name' => 'invalid_gem'}}]
+ @app_props['plugins']['unknown'] = {}
orch = VCAP::Stager::PluginRunner.new(@src_dir, @dst_dir, @app_props, @cc_info)
expect do
orch.run_plugins
- end.to raise_error(LoadError)
+ end.to raise_error(VCAP::Stager::UnsupportedPluginError)
end
it 'should raise an error if no framework plugin is supplied' do
@@ -69,8 +54,9 @@
plugins = []
2.times do |i|
name = "plugin_#{i}"
+ @app_props['plugins'][name] = {}
p = create_mock_plugin(name, :framework)
- VCAP::Stager::PluginRunner.register_plugins(p)
+ VCAP::PluginRegistry.register_plugins(p)
end
orch = VCAP::Stager::PluginRunner.new(@src_dir, @dst_dir, @app_props, @cc_info)
expect do
@@ -79,8 +65,9 @@
end
it 'should raise an error if a plugin of unknown type is supplied' do
- p = create_mock_plugin(:plugin0, :invalid_plugin_type)
- VCAP::Stager::PluginRunner.register_plugins(p)
+ p = create_mock_plugin('plugin0', :invalid_plugin_type)
+ VCAP::PluginRegistry.register_plugins(p)
+ @app_props['plugins']['plugin0'] = {}
orch = VCAP::Stager::PluginRunner.new(@src_dir, @dst_dir, @app_props, @cc_info)
expect do
orch.run_plugins
@@ -91,9 +78,10 @@
plugin_types = [:framework, :feature, :feature]
plugin_types.each_with_index do |ptype, ii|
name = "plugin_#{ii}"
+ @app_props['plugins'][name] = {}
p = create_mock_plugin(name, ptype)
p.should_receive(:stage).with(any_args())
- VCAP::Stager::PluginRunner.register_plugins(p)
+ VCAP::PluginRegistry.register_plugins(p)
end
orch = VCAP::Stager::PluginRunner.new(@src_dir, @dst_dir, @app_props, @cc_info)
orch.run_plugins
@@ -102,7 +90,7 @@
def create_mock_plugin(name, type)
ret = mock(name)
- ret.stub(:plugin_type).and_return(type)
+ ret.stub(:staging_plugin_type).and_return(type)
ret.stub(:name).and_return(name)
ret
end
View
1 stager/spec/unit/task_spec.rb
@@ -102,7 +102,6 @@
'task_id' => 'test',
}
@task = VCAP::Stager::Task.new(1, @props, nil, nil, @cc_info, nil)
- @task.stub(:get_uid).and_return(0)
end
after :each do
View
BIN stager/vendor/cache/vcap_common-0.99.gem
Binary file not shown.
View
BIN stager/vendor/cache/vcap_common-1.0.0.gem
Binary file not shown.

0 comments on commit 466d8ad

Please sign in to comment.