Permalink
Browse files

Merge branch 'master' into branch side-by-side-poc

Change-Id: I924b96e633a0100f6fe2ce3a29569c33f00fe018
  • Loading branch information...
2 parents 06bff3e + bdfd70b commit eda15e83a46fe19651cef6b9a42ef536769ee599 @bnugmanov bnugmanov committed Aug 14, 2012
View
@@ -6,9 +6,9 @@ gem 'rails', '~> 3.0.14'
gem 'nats', :require => 'nats/client'
# VCAP common components
-gem 'vcap_common', :require => ['vcap/common', 'vcap/component'], :git => 'https://github.com/cloudfoundry/vcap-common.git', :ref => '5334b662'
+gem 'vcap_common', :require => ['vcap/common', 'vcap/component'], :git => 'https://github.com/cloudfoundry/vcap-common.git', :ref => '1dca468ec0'
gem 'vcap_logging', :require => ['vcap/logging'], :git => 'https://github.com/cloudfoundry/common.git', :ref => 'e36886a1'
-gem 'vcap_staging', '~> 0.1.61', :git => 'https://github.com/cloudfoundry/vcap-staging.git', :ref => '910bda9f'
+gem 'vcap_staging', '~> 0.1.62', :git => 'https://github.com/cloudfoundry/vcap-staging.git', :ref => '74d89654'
gem 'cf-uaa-client', '~> 1.0', :git => 'https://github.com/cloudfoundry/uaa.git', :ref => 'b19eb89b'
# For queuing staging tasks
@@ -38,23 +38,27 @@ GIT
GIT
remote: https://github.com/cloudfoundry/vcap-common.git
- revision: 5334b662238f14ed2ddbb80f524dcf8cdd0eaadf
- ref: 5334b662
+ revision: 1dca468ec017ea5d296aeac1aa2fb7a70affba63
+ ref: 1dca468ec0
specs:
- vcap_common (2.0.0)
+ vcap_common (2.0.4)
+ em-http-request (~> 1.0.0.beta3)
eventmachine
- membrane
+ httpclient
+ membrane (~> 0.0.2)
+ mime-types
+ multipart-post
nats (~> 0.4.22.beta.8)
posix-spawn (~> 0.3.6)
thin (~> 1.3.1)
yajl-ruby (~> 0.8.3)
GIT
remote: https://github.com/cloudfoundry/vcap-staging.git
- revision: 910bda9fa69504fbe2202edceb8d0b7d1d253fb7
- ref: 910bda9f
+ revision: 74d896544071fcae8acfb0c6cebae59f62d0a411
+ ref: 74d89654
specs:
- vcap_staging (0.1.61)
+ vcap_staging (0.1.62)
nokogiri (>= 1.4.4)
rake
rspec
@@ -118,6 +122,7 @@ GEM
abstract (>= 1.0.0)
hiredis (0.3.2)
http_parser.rb (0.5.1)
+ httpclient (2.2.5)
i18n (0.5.0)
interact (0.4.3)
json (1.7.3)
@@ -128,13 +133,14 @@ GEM
i18n (>= 0.4.0)
mime-types (~> 1.16)
treetop (~> 1.4.8)
- membrane (0.0.1)
+ membrane (0.0.2)
mime-types (1.18)
mocha (0.9.12)
- nats (0.4.22)
- daemons (>= 1.1.4)
+ multipart-post (1.1.5)
+ nats (0.4.24)
+ daemons (>= 1.1.5)
eventmachine (>= 0.12.10)
- json_pure (>= 1.6.1)
+ json_pure (>= 1.7.3)
thin (>= 1.3.1)
nokogiri (1.4.7)
pg (0.10.1)
@@ -228,5 +234,5 @@ DEPENDENCIES
uuidtools (~> 2.1.2)
vcap_common!
vcap_logging!
- vcap_staging (~> 0.1.61)!
+ vcap_staging (~> 0.1.62)!
yajl-ruby (~> 0.8.3)
View
@@ -254,3 +254,9 @@ vendor
External libraries that the application depends on. Also includes the plugins
subdirectory. If the app has frozen rails, those gems also go here, under
vendor/rails/. This directory is in the load path.
+
+
+== File a bug
+
+To file a bug against Cloud Foundry Open Source and its components, sign up and
+use our bug tracking system: http://cloudfoundry.atlassian.net
@@ -372,6 +372,14 @@ def update_app_env(app)
env = body_params[:env].uniq
env_new = env.delete_if {|e| e =~ /^(vcap|vmc)_/i }
raise CloudError.new(CloudError::FORBIDDEN) if env != env_new
+ # TODO this is a suggested workaround until we have a consistent mechanism
+ # for users to pass in configuration that controls staging behavior
+ if app.environment != env
+ old_bundle_without = app.environment.find {|env| env =~ /\ABUNDLE_WITHOUT=/}
+ new_bundle_without = env.find {|env| env =~ /\ABUNDLE_WITHOUT=/}
+ # Restage the app if user has changed BUNDLE_WITHOUT
+ app.package_state = 'PENDING' if old_bundle_without != new_bundle_without
+ end
app.environment = env
end
@@ -1,12 +1,15 @@
+require 'fileutils'
require 'json_message'
+require 'uri'
+require 'date'
require 'services/api'
# TODO(mjp): Split these into separate controllers (user facing vs gateway facing, along with tests)
class ServicesController < ApplicationController
include ServicesHelper
- before_filter :validate_content_type
+ before_filter :validate_content_type, :except => [:import_from_data]
before_filter :require_service_auth_token, :only => [:create, :get, :delete, :update_handle, :list_handles, :list_brokered_services]
before_filter :require_user, :only => [:provision, :bind, :bind_external, :unbind, :unprovision,
:create_snapshot, :enum_snapshots, :snapshot_details,:rollback_snapshot, :delete_snapshot,
@@ -326,22 +329,58 @@ def import_from_url
render :json => result.extract
end
- # import serialized data to an instance from request data
+ # import serialized data to an instance from uploaded file
#
def import_from_data
- max_upload_size = AppConfig[:service_lifecycle][:max_upload_size] || 1
- max_upload_size = max_upload_size * 1024 * 1024
- raise CloudError.new(CloudError::BAD_REQUEST) unless request.content_length < max_upload_size
-
- req = VCAP::Services::Api::SerializedData.decode(request_body)
-
- cfg = ServiceConfig.find_by_user_id_and_name(user.id, params['id'])
- raise CloudError.new(CloudError::SERVICE_NOT_FOUND) unless cfg
- raise CloudError.new(CloudError::FORBIDDEN) unless cfg.provisioned_by?(user)
+ data_file_path = get_uploaded_data_file_path
+ unless data_file_path
+ CloudController.logger.debug("import_from_data - Bad request: uploaded file is not found")
+ raise CloudError.new(CloudError::BAD_REQUEST)
+ end
- result = cfg.import_from_data req
+ begin
+ # Check the service and user's permission
+ cfg = ServiceConfig.find_by_user_id_and_name(user.id, params['id'])
+ raise CloudError.new(CloudError::SERVICE_NOT_FOUND) unless cfg
+ raise CloudError.new(CloudError::FORBIDDEN) unless cfg.provisioned_by?(user)
+
+ # Check whether has upload_token
+ upload_token = AppConfig[:service_lifecycle][:upload_token]
+ raise CloudError.new(CloudError::SDS_ERROR, "No upload token for registered serialization_data_server") unless upload_token
+
+ # Check the size of the uploaded file
+ max_upload_size = AppConfig[:service_lifecycle][:max_upload_size] || 1
+ max_upload_size = max_upload_size * 1024 * 1024
+ unless File.size(data_file_path) < max_upload_size
+ CloudController.logger.debug("import_from_data -Bad request: uploaded file exceeded the size limitation #{max_upload_size}B")
+ raise CloudError.new(CloudError::BAD_REQUEST)
+ end
- render :json => result.extract
+ # Select a serialization data server
+ active_sds = AppConfig[:service_lifecycle][:serialization_data_server]
+ # Currently, we just use Array.sample method to select one of serialization_data_server(sds) randomly
+ # In the future, sds could provide info like capability/load/score/priority to help load-balance.
+ upload_url = active_sds.sample if active_sds && active_sds.count > 0
+ raise CloudError.new(CloudError::SDS_NOT_FOUND) unless upload_url
+ upload_url = "http://#{upload_url}" unless (upload_url.start_with?('http://') || upload_url.start_with?('https://'))
+
+ req = {
+ :upload_url => upload_url,
+ :upload_token => upload_token,
+ :data_file_path => data_file_path,
+ :upload_timeout => (AppConfig[:service_lifecycle][:upload_timeout] || 60)
+ }
+ CloudController.logger.debug("import_from_data - request is #{req.inspect}")
+
+ serialized_url= cfg.import_from_data req
+ unless serialized_url.is_a? VCAP::Services::Api::SerializedURL
+ raise CloudError.new(CloudError::SDS_ERROR, "Serialization returned invalid response.")
+ end
+ result = cfg.import_from_url(serialized_url)
+ render :json => result.extract
+ ensure
+ FileUtils.rm_rf(data_file_path)
+ end
end
# Get job information
@@ -423,6 +462,22 @@ def unbind
protected
+ # get path of uploaded serialized data file
+ def get_uploaded_data_file_path
+ path = nil
+ CloudController.logger.debug("get_uploaded_data_file #{params.inspect}")
+ if CloudController.use_nginx
+ path = params[:data_file_path]
+ path = nil unless path && File.exist?(path)
+ else
+ file = params[:data_file]
+ if file && file.path && File.exist?(file.path)
+ path = file.path
+ end
+ end
+ path
+ end
+
def require_service_auth_token
hdr = VCAP::Services::Api::GATEWAY_TOKEN_HEADER.upcase.gsub(/-/, '_')
@service_auth_token = request.headers[hdr]
@@ -109,22 +109,6 @@ def as_json(options = nil)
}
end
- # Called by AppManager when staging this app.
- def staging_environment
- Yajl::Encoder.encode(staging_environment_data)
- end
-
- # The data that is passed to the staging plugin for this app.
- def staging_environment_data
- # each ServiceBinding returns a denormalized configuration.
- services = service_bindings(true).map {|sb| sb.for_staging}
- { :services => services,
- :framework => framework,
- :runtime => runtime,
- :resources => resource_requirements,
- :meta => metadata }
- end
-
def staging_task_properties
services = service_bindings(true).map {|sb| sb.for_staging}
{ :services => services,
@@ -315,7 +315,7 @@ def stage
raise CloudError.new(CloudError::APP_INVALID_RUNTIME, app.runtime, app.framework)
end
- env_json = app.staging_environment
+ env_json = Yajl::Encoder.encode(app.staging_task_properties)
app_source_dir = Dir.mktmpdir
app.explode_into(app_source_dir)
@@ -565,7 +565,7 @@ def new_message
svc = cfg.service
{ :name => cfg.alias,
:type => svc.synthesize_service_type,
- :label => svc.label,
+ :label => sb.get_label,
:vendor => svc.name,
:version => svc.version,
:tags => svc.tags,
@@ -173,7 +173,9 @@ def is_builtin?
def verify_auth_token(token)
if is_builtin?
key = (self.provider && self.provider != "core") ? self.name + "-" + self.provider : self.name
- (AppConfig[:builtin_services][key.to_sym][:token] == token)
+ token_a = AppConfig[:builtin_services][key.to_sym][:token]
+ token_b = AppConfig[:builtin_services][key.to_sym][:token_b]
+ (token_a == token || (token_b && token_b == token))
else
(self.token == token)
end
@@ -17,13 +17,25 @@ class ServiceBinding < ActiveRecord::Base
# :label, :name, :credentials, :options
def for_staging
data = {}
- data[:label] = service_config.service.label # what we call the offering
- data[:tags] = service_config.service.tags
- data[:name] = service_config.alias # what the user chose to name it
+ cfg = service_config
+ svc = cfg.service
+ data[:label] = get_label
+ data[:tags] = svc.tags
+ data[:name] = cfg.alias # what the user chose to name it
data[:credentials] = credentials
data[:options] = binding_options # options specified at bind-time
- data[:plan] = service_config.plan
- data[:plan_option] = service_config.plan_option
+ data[:plan] = cfg.plan
+ data[:plan_option] = cfg.plan_option
data
end
+
+ def get_label
+ version = service_config.data["version"]
+ if version
+ "#{service_config.service.name}-#{version}"
+ else
+ # old instance
+ service_config.service.label
+ end
+ end
end
@@ -68,7 +68,7 @@ def self.provision(service, user, cfg_alias, plan, plan_option, version)
raise CloudError.new(CloudError::SERVICE_GATEWAY_ERROR)
end
svc_config.attributes = {
- :data => config.data,
+ :data => config.configuration,
:credentials => config.credentials,
:name => config.service_id
}
@@ -107,6 +107,12 @@ def unprovision
ServiceConfig.unprovision(service, name)
end
+ def handle_sds_error(e)
+ CloudController.logger.error("Error talking to serialization_data_server: #{e}")
+ CloudController.logger.error(e)
+ raise CloudError.new(CloudError::SDS_ERROR, "#{e.message}")
+ end
+
def handle_lifecycle_error(e)
CloudController.logger.error("Error talking to gateway: #{e}")
CloudController.logger.error(e)
@@ -174,10 +180,10 @@ def import_from_url req
end
def import_from_data req
- client = VCAP::Services::Api::ServiceGatewayClient.new(service.url, service.token, service.timeout)
- client.import_from_data(:service_id => name, :msg => req)
+ client = VCAP::Services::Api::SDSClient.new(req[:upload_url], req[:upload_token], req[:upload_timeout])
+ client.import_from_data(:service =>service.name , :service_id => name, :msg => req[:data_file_path])
rescue => e
- handle_lifecycle_error(e)
+ handle_sds_error(e)
end
def job_info job_id
@@ -8,13 +8,11 @@ class UaaToken
@token_issuer ||= CF::UAA::TokenIssuer.new(AppConfig[:uaa][:url],
AppConfig[:uaa][:resource_id],
- AppConfig[:uaa][:client_secret],
- "read write password")
+ AppConfig[:uaa][:client_secret])
@id_token_issuer ||= CF::UAA::TokenIssuer.new(AppConfig[:uaa][:url],
"vmc",
- nil,
- "read")
+ nil)
class << self
@@ -144,7 +144,7 @@ builtin_services:
token: "0xdeadbeef"
filesystem:
token: "0xdeadbeef"
- vblob:
+ blob:
token: "0xdeadbeef"
# Service broker
@@ -154,6 +154,10 @@ service_broker:
# lifecycle
service_lifecycle:
max_upload_size: 1 # in MB
+ upload_token: dlfoosecret
+ upload_timeout: 60
+ serialization_data_server:
+ - 127.0.0.1:8080
# Enable/disable starting apps in debug modes.
allow_debug: true
@@ -56,6 +56,8 @@ def to_json(options = nil)
ACCOUNT_TOO_MANY_SERVICES = [504, HTTP_FORBIDDEN, "Too many Services provisioned: %s, you're allowed: %s"]
EXTENSION_NOT_IMPL = [505, HTTP_NOT_IMPLEMENTED, "Service extension %s is not implemented."]
UNSUPPORTED_VERSION = [506, HTTP_NOT_FOUND, "Unsupported service version %s."]
+ SDS_ERROR = [507, HTTP_INTERNAL_SERVER_ERROR, "Get error from serialization_data_server: '%s'"]
+ SDS_NOT_FOUND = [508, HTTP_INTERNAL_SERVER_ERROR, "No available active serialization data server"]
# Account Capacity
ACCOUNT_NOT_ENOUGH_MEMORY = [600, HTTP_FORBIDDEN, "Not enough memory capacity, you're allowed: %s"]
Oops, something went wrong.

0 comments on commit eda15e8

Please sign in to comment.