Permalink
Browse files

Add client gem for communicating with stagers

This provides a gem that provides a small rpc interface to stagers.
Although this is a bit of yak shaving, it does clean up the interaction
between the CC and Stagers and paves the way for adding support for allowing
staging plugins to perform actions on behalf of users.

Test plan:
- All existing unit tests pass
- New stager_ipc unit tests pass
- BVTs pass

Change-Id: I18d059cbc044fd628680dbb1bfd8428b4ced0c16
  • Loading branch information...
mpage
mpage committed Oct 17, 2011
1 parent 668146d commit 40cb32729fc108687239334cf159def8d125f382
Showing with 478 additions and 369 deletions.
  1. +1 −1 cloud_controller/Gemfile
  2. +10 −5 cloud_controller/Gemfile.lock
  3. +17 −9 cloud_controller/app/controllers/apps_controller.rb
  4. +0 −2 cloud_controller/app/models/app_manager.rb
  5. +1 −1 cloud_controller/config/cloud_controller.yml
  6. +0 −58 cloud_controller/lib/staging_task_manager.rb
  7. +1 −0 cloud_controller/spec/models/service_spec.rb
  8. +0 −46 cloud_controller/spec/staging/staging_task_manager_spec.rb
  9. BIN cloud_controller/vendor/cache/vcap_stager-0.1.3.gem
  10. BIN cloud_controller/vendor/cache/vcap_stager_ipc-0.0.1.gem
  11. +2 −1 stager/Gemfile
  12. +9 −2 stager/Gemfile.lock
  13. +2 −35 stager/Rakefile
  14. +1 −1 stager/config/dev.yml
  15. +0 −1 stager/lib/vcap/stager.rb
  16. +31 −31 stager/lib/vcap/stager/server.rb
  17. +13 −36 stager/lib/vcap/stager/task.rb
  18. +0 −19 stager/lib/vcap/stager/task_error.rb
  19. +2 −1 stager/lib/vcap/stager/task_manager.rb
  20. +0 −48 stager/lib/vcap/stager/task_result.rb
  21. +2 −0 stager/lib/vcap/stager/util.rb
  22. +1 −1 stager/spec/fixtures/stager_config.yml.erb
  23. +11 −18 stager/spec/functional/stager_spec.rb
  24. +0 −24 stager/spec/unit/task_error_spec.rb
  25. +0 −29 stager/spec/unit/task_result_spec.rb
  26. BIN stager/vendor/cache/vcap_stager_ipc-0.0.1.gem
  27. +4 −0 stager_ipc/.gitignore
  28. +3 −0 stager_ipc/Gemfile
  29. +7 −0 stager_ipc/Rakefile
  30. +5 −0 stager_ipc/lib/vcap/stager/ipc.rb
  31. +7 −0 stager_ipc/lib/vcap/stager/ipc/constants.rb
  32. +12 −0 stager_ipc/lib/vcap/stager/ipc/errors.rb
  33. +89 −0 stager_ipc/lib/vcap/stager/ipc/fibered_nats_client.rb
  34. +64 −0 stager_ipc/lib/vcap/stager/ipc/request.rb
  35. +51 −0 stager_ipc/lib/vcap/stager/ipc/response.rb
  36. +7 −0 stager_ipc/lib/vcap/stager/ipc/version.rb
  37. +16 −0 stager_ipc/spec/Rakefile
  38. +21 −0 stager_ipc/spec/fibered_nats_client_spec.rb
  39. +30 −0 stager_ipc/spec/request_spec.rb
  40. +29 −0 stager_ipc/spec/response_spec.rb
  41. +3 −0 stager_ipc/spec/spec_helper.rb
  42. +26 −0 stager_ipc/vcap_stager_ipc.gemspec
View
@@ -14,7 +14,7 @@ gem 'vcap_staging', '= 0.1.22'
# For queuing staging tasks
gem 'em-hiredis'
-gem 'vcap_stager', '= 0.1.3'
+gem 'vcap_stager_ipc'
# Databases
gem 'sqlite3'
@@ -124,7 +124,7 @@ GEM
ruby-hmac (0.4.0)
sinatra (1.2.1)
rack (~> 1.1)
- tilt (< 2.0, >= 1.2.2)
+ tilt (>= 1.2.2, < 2.0)
sqlite3 (1.3.3)
thin (1.2.11)
daemons (>= 1.0.9)
@@ -137,8 +137,13 @@ GEM
tzinfo (0.3.26)
uuidtools (2.1.2)
vcap_logging (0.1.0)
- vcap_stager (0.1.3)
- vcap_staging (0.1.22)
+ vcap_stager_ipc (0.0.1)
+ eventmachine
+ rake
+ vcap_common
+ vcap_logging
+ yajl-ruby
+ vcap_staging (0.1.11)
nokogiri (>= 1.4.4)
rake
rspec
@@ -176,6 +181,6 @@ DEPENDENCIES
uuidtools
vcap_common!
vcap_logging
- vcap_stager (= 0.1.3)
- vcap_staging (= 0.1.22)
+ vcap_stager_ipc
+ vcap_staging (= 0.1.11)
yajl-ruby (>= 0.7.9)
@@ -1,4 +1,4 @@
-require 'staging_task_manager'
+require 'vcap/stager/ipc'
class AppsController < ApplicationController
before_filter :require_user, :except => [:download_staged]
@@ -212,25 +212,33 @@ def files
private
def stage_app(app)
- task_mgr = StagingTaskManager.new(:logger => CloudController.logger,
- :timeout => AppConfig[:staging][:max_staging_runtime])
dl_uri = StagingController.download_app_uri(app)
ul_hdl = StagingController.create_upload(app)
+ stager_client = VCAP::Stager::Ipc::FiberedNatsClient.new(NATS.client)
- result = task_mgr.run_staging_task(app, dl_uri, ul_hdl.upload_uri)
+ begin
+ result = stager_client.add_task(app.id,
+ app.staging_task_properties,
+ dl_uri,
+ ul_hdl.upload_uri,
+ AppConfig[:staging][:max_staging_runtime])
+ StagingTaskLog.new(app.id, result['task_log']).save
+ rescue VCAP::Stager::Ipc::RequestTimeoutError
+ raise CloudError.new(CloudError::APP_STAGING_ERROR, "Timed out waiting for reply from stager")
+ end
# Update run count to be consistent with previous staging code
- if result.was_success?
+ unless result['error']
CloudController.logger.debug("Staging task for app_id=#{app.id} succeded.", :tags => [:staging])
- CloudController.logger.debug1("Details: #{result.task_log}", :tags => [:staging])
+ CloudController.logger.debug1("Details: #{result['task_log']}", :tags => [:staging])
app.update_staged_package(ul_hdl.upload_path)
app.package_state = 'STAGED'
app.update_run_count()
else
- CloudController.logger.warn("Staging task for app_id=#{app.id} failed: #{result.error}",
+ CloudController.logger.warn("Staging task for app_id=#{app.id} failed: #{result['error']}",
:tags => [:staging])
- CloudController.logger.debug1("Details: #{result.task_log}", :tags => [:staging])
- raise CloudError.new(CloudError::APP_STAGING_ERROR, result.error.to_s)
+ CloudController.logger.debug1("Details: #{result['task_log']}", :tags => [:staging])
+ raise CloudError.new(CloudError::APP_STAGING_ERROR, result['error'])
end
rescue => e
@@ -1,5 +1,3 @@
-require 'vcap/stager'
-
class AppManager
attr_reader :app
@@ -96,7 +96,7 @@ staging:
max_staging_runtime: 120 # secs
# Create a secure environment for staging
secure: false
- new_stager_percent: 0
+ new_stager_percent: 100
auth:
user: zxsfhgjg
password: ZNVfdase9
@@ -1,58 +0,0 @@
-require 'nats/client'
-
-require 'vcap/stager/task'
-require 'vcap/stager/task_result'
-
-class StagingTaskManager
- DEFAULT_TASK_TIMEOUT = 120
-
- def initialize(opts={})
- @logger = opts[:logger] || VCAP::Logging.logger('vcap.cc.staging_manager')
- @nats_conn = opts[:nats_conn] || NATS.client
- @timeout = opts[:timeout] || DEFAULT_TASK_TIMEOUT
- end
-
- # Enqueues a staging task in redis, blocks until task completes or a timeout occurs.
- #
- # @param app App The app to be staged
- # @param dl_uri String URI that the stager can download the app from
- # @param ul_uri String URI that the stager should upload the staged droplet to
- #
- # @return VCAP::Stager::TaskResult
- def run_staging_task(app, dl_uri, ul_uri)
- inbox = "cc.staging." + VCAP.secure_uuid
- nonce = VCAP.secure_uuid
- f = Fiber.current
-
- # Wait for notification from the stager
- exp_timer = nil
- sid = @nats_conn.subscribe(inbox) do |msg|
- @logger.debug("Received result from stager on '#{inbox}' : '#{msg}'")
- @nats_conn.unsubscribe(sid)
- EM.cancel_timer(exp_timer)
- f.resume(msg)
- end
-
- # Setup timer to expire our request if we don't hear a response from the stager in time
- exp_timer = EM.add_timer(@timeout) do
- @logger.warn("Staging timed out for app_id=#{app.id} (timeout=#{@timeout}, unsubscribing from '#{inbox}'",
- :tags => [:staging])
- @nats_conn.unsubscribe(sid)
- f.resume(nil)
- end
-
- task = VCAP::Stager::Task.new(app.id, app.staging_task_properties, dl_uri, ul_uri, inbox)
- task.enqueue('staging')
- @logger.debug("Enqeued staging task for app_id=#{app.id}.", :tags => [:staging])
-
- reply = Fiber.yield
- if reply
- result = VCAP::Stager::TaskResult.decode(reply)
- StagingTaskLog.new(app.id, result.task_log).save
- else
- result = VCAP::Stager::TaskResult.new(nil, nil, "Timed out waiting for stager's reply.")
- end
-
- result
- end
-end
@@ -116,6 +116,7 @@
describe "#is_builtin?" do
it "should correctly check against AppConfig" do
svc = Service.new(:label => "foo-bar", :url => "http://www.google.com", :token => "foo")
+ AppConfig[:builtin_services].delete(:foo)
svc.is_builtin?.should be_false
AppConfig[:builtin_services][:foo] = true
svc.is_builtin?.should be_true
@@ -1,46 +0,0 @@
-require 'spec_helper'
-
-describe StagingTaskManager do
- before :all do
- # Prevent EM/NATS related initializers from running
- EM.instance_variable_set(:@next_tick_queue, [])
- end
-
- describe '#run_staging_task' do
- it 'should expire long running tasks' do
- nats_conn = mock()
- logger = stub_everything(:logger)
-
- nats_conn.expects(:subscribe).with(any_parameters())
- nats_conn.expects(:unsubscribe).with(any_parameters())
-
- task = stub_everything(:task)
- VCAP::Stager::Task.expects(:new).with(any_parameters()).returns(task)
-
- app = create_stub_app(12345)
- stm = StagingTaskManager.new(
- :logger => logger,
- :nats_conn => nats_conn,
- :timeout => 1
- )
-
- res = nil
- EM.run do
- Fiber.new do
- EM.add_timer(2) { EM.stop }
- res = stm.run_staging_task(app, nil, nil)
- end.resume
- end
-
- res.should be_instance_of(VCAP::Stager::TaskResult)
- res.was_success?.should be_false
- end
- end
-
- def create_stub_app(id, props={})
- ret = mock("app_#{id}")
- ret.stubs(:id).returns(id)
- ret.stubs(:staging_task_properties).returns(props)
- ret
- end
-end
Binary file not shown.
Binary file not shown.
View
@@ -9,7 +9,8 @@ gem 'yajl-ruby', '>= 0.7.9'
gem 'vcap_common'
gem 'vcap_logging', '>= 0.1.1'
-gem 'vcap_staging', '>= 0.1.22'
+gem 'vcap_staging', '>= 0.1.11'
+gem 'vcap_stager_ipc'
group :test do
gem 'rspec'
View
@@ -45,7 +45,13 @@ GEM
thin
yajl-ruby
vcap_logging (0.1.1)
- vcap_staging (0.1.22)
+ vcap_stager_ipc (0.0.1)
+ eventmachine
+ rake
+ vcap_common
+ vcap_logging
+ yajl-ruby
+ vcap_staging (0.1.11)
nokogiri (>= 1.4.4)
rake
rspec
@@ -69,6 +75,7 @@ DEPENDENCIES
sinatra
vcap_common
vcap_logging (>= 0.1.1)
- vcap_staging (>= 0.1.22)
+ vcap_stager_ipc
+ vcap_staging (>= 0.1.11)
webmock
yajl-ruby (>= 0.7.9)
View
@@ -1,36 +1,7 @@
require 'rubygems'
require 'rake'
-require 'rake/gempackagetask'
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
-require 'vcap/stager/version'
-
-GEM_NAME = 'vcap_stager'
-GEM_VERSION = VCAP::Stager::VERSION
-
-gemspec = Gem::Specification.new do |s|
- s.name = GEM_NAME
- s.version = GEM_VERSION
- s.platform = Gem::Platform::RUBY
- s.summary = 'Component responsible for staging apps'
- s.description = 'Takes an app package, environment, and services' \
- + ' and produces a droplet that is executable by the DEA'
- s.authors = ['Matt Page']
- s.email = 'mpage@vmware.com'
- s.homepage = 'http://www.cloudfoundry.com'
- s.executables = []
- s.bindir = 'bin'
- s.require_path = 'lib'
- s.files = %w(Rakefile Gemfile) + Dir.glob("{lib,spec,vendor}/**/*")
-end
-
-Rake::GemPackageTask.new(gemspec) do |pkg|
- pkg.gem_spec = gemspec
-end
-
-task :install => [:package] do
- sh "gem install --no-ri --no-rdoc pkg/#{GEM_NAME}-#{GEM_VERSION}"
-end
task :spec => ['bundler:install:test'] do
desc 'Run tests'
@@ -42,11 +13,7 @@ namespace 'bundler' do
sh('bundle install')
end
- environments = %w(test development production)
- environments.each do |env|
- desc "Install gems for #{env}"
- task "install:#{env}" do
- sh("bundle install --local --without #{(environments - [env]).join(' ')}")
- end
+ task 'install:test' do
+ sh('bundle install --local --without development production')
end
end
View
@@ -5,5 +5,5 @@ pid_filename: /var/vcap/sys/run/stager.pid
nats_uri: nats://127.0.0.1:4222
max_staging_duration: 120
max_active_tasks: 10
-queues: ['staging']
+queues: ['vcap.staging.linux']
secure: false
@@ -9,7 +9,6 @@
require 'vcap/stager/task_error'
require 'vcap/stager/task_logger'
require 'vcap/stager/task_manager'
-require 'vcap/stager/task_result'
require 'vcap/stager/server'
require 'vcap/stager/util'
require 'vcap/stager/version'
Oops, something went wrong.

0 comments on commit 40cb327

Please sign in to comment.