On 05/23/12, [email protected] wrote: I did some mistake when rebasing this patch. To make it work please add:
require_relative './helpers/result' to 'helpers.rb' ;-) -- Michal > From: Michal Fojtik <[email protected]> > > > Signed-off-by: Michal fojtik <[email protected]> > --- > server/bin/deltacloudd | 4 +- > server/config.ru | 8 ++ > server/lib/ec2/helpers.rb | 22 ++++++ > server/lib/ec2/helpers/converter.rb | 140 > +++++++++++++++++++++++++++++++++++ > server/lib/ec2/helpers/errors.rb | 46 ++++++++++++ > server/lib/ec2/query_parser.rb | 129 ++++++++++++++++++++++++++++++++ > server/lib/ec2/server.rb | 60 +++++++++++++++ > 7 files changed, 407 insertions(+), 2 deletions(-) > create mode 100644 server/lib/ec2/helpers.rb > create mode 100644 server/lib/ec2/helpers/converter.rb > create mode 100644 server/lib/ec2/helpers/errors.rb > create mode 100644 server/lib/ec2/query_parser.rb > create mode 100644 server/lib/ec2/server.rb > > diff --git a/server/bin/deltacloudd b/server/bin/deltacloudd > index 57b6c49..8eb448d 100755 > --- a/server/bin/deltacloudd > +++ b/server/bin/deltacloudd > @@ -61,8 +61,8 @@ BANNER > opts.on( '-P', '--provider PROVIDER', 'Use PROVIDER (default is set in the > driver)') do |provider| > ENV['API_PROVIDER'] = provider > end > - opts.on('--cimi', 'USe the DMTF CIMI frontend, not the Deltacloud > frontend') do > - ENV['API_FRONTEND'] = 'cimi' > + opts.on('-f', '--frontend FRONTEND', 'Use the different frontend, not the > Deltacloud (cimi or ec2)') do |frontend| > + ENV['API_FRONTEND'] = frontend > end > opts.on( '-c', '--config [FILE]', 'Read provider and other config from > FILE (default: ~/.deltacloud/config)') do |config| > options[:config] = File::expand_path(config || DEFAULT_CONFIG) > diff --git a/server/config.ru b/server/config.ru > index 87d9506..d3c6ce6 100644 > --- a/server/config.ru > +++ b/server/config.ru > @@ -35,6 +35,14 @@ if ENV['API_FRONTEND'] == 'cimi' > end > end > > +if ENV['API_FRONTEND'] == 'ec2' > + Deltacloud::configure do |server| > + server.root_url '/' > + server.version '2012-04-01' > + server.klass 'Deltacloud::EC2::API' > + end > +end > + > Deltacloud.require_frontend! > > class IndexEntrypoint < Sinatra::Base > diff --git a/server/lib/ec2/helpers.rb b/server/lib/ec2/helpers.rb > new file mode 100644 > index 0000000..7517f36 > --- /dev/null > +++ b/server/lib/ec2/helpers.rb > @@ -0,0 +1,22 @@ > +# Licensed to the Apache Software Foundation (ASF) under one or more > +# contributor license agreements. See the NOTICE file distributed with > +# this work for additional information regarding copyright ownership. The > +# ASF licenses this file to you under the Apache License, Version 2.0 (the > +# "License"); you may not use this file except in compliance with the > +# License. You may obtain a copy of the License at > +# > +# http://www.apache.org/licenses/LICENSE-2.0 > +# > +# Unless required by applicable law or agreed to in writing, software > +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT > +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the > +# License for the specific language governing permissions and limitations > +# under the License. > + > +module Deltacloud > + module EC2; end > +end > + > +require_relative './helpers/errors' > +require_relative '../deltacloud/helpers/driver_helper' > +require_relative '../deltacloud/helpers/auth_helper' > diff --git a/server/lib/ec2/helpers/converter.rb > b/server/lib/ec2/helpers/converter.rb > new file mode 100644 > index 0000000..8a70fe1 > --- /dev/null > +++ b/server/lib/ec2/helpers/converter.rb > @@ -0,0 +1,140 @@ > +# Licensed to the Apache Software Foundation (ASF) under one or more > +# contributor license agreements. See the NOTICE file distributed with > +# this work for additional information regarding copyright ownership. The > +# ASF licenses this file to you under the Apache License, Version 2.0 (the > +# "License"); you may not use this file except in compliance with the > +# License. You may obtain a copy of the License at > +# > +# http://www.apache.org/licenses/LICENSE-2.0 > +# > +# Unless required by applicable law or agreed to in writing, software > +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT > +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the > +# License for the specific language governing permissions and limitations > +# under the License. > + > +module Deltacloud::EC2 > + > + class Converter > + > + def self.convert(builder, action, result) > + klass_name = ActionHandler::MAPPINGS[action][:method].to_s.camelize > + klass = Converter.const_get(klass_name) > + klass.new(builder, result).to_xml > + end > + > + class Base > + > + attr_reader :xml > + attr_reader :obj > + > + def initialize(builder, object) > + @xml = builder > + @obj = object > + end > + > + end > + > + class Realms < Base > + > + def to_xml > + xml.availabilityZoneInfo { > + obj.each do |item| > + xml.item { > + xml.zoneName item.id > + xml.zoneState item.state > + xml.regionName item.name > + } > + end > + } > + end > + > + end > + > + class Images < Base > + > + def to_xml > + xml.imagesSet { > + obj.each do |item| > + xml.item { > + xml.imageId item.id > + xml.imageState item.state.downcase > + xml.imageOwnerId item.owner_id > + xml.architecture item.architecture > + xml.imageType 'machine' > + xml.name item.name > + xml.description item.description > + } > + end > + } > + end > + > + end > + > + class CreateInstance < Base > + > + def to_xml > + xml.reservationId 'r-11111111' > + xml.ownerId @obj.owner_id > + xml.groupSet { > + xml.item { > + xml.groupId 'sg-11111111' > + xml.groupName 'default' > + } > + } > + Instances.new(@xml, [@obj]).instance_set > + end > + > + end > + > + class Instances < Base > + > + def instance_set > + xml.instancesSet { > + obj.each do |item| > + xml.item { > + xml.instanceId item.id > + xml.imageId item.image_id > + xml.instanceType item.instance_profile.name > + xml.launchTime item.launch_time > + xml.ipAddress item.public_addresses.first.address > + xml.privateIpAddress item.public_addresses.first.address > + xml.dnsName item.public_addresses.first.address > + xml.privateDnsName item.private_addresses.first.address > + xml.architecture item.instance_profile.architecture > + xml.keyName item.keyname > + xml.instanceState { > + xml.code '16' > + xml.name item.state.downcase > + } > + xml.placement { > + xml.availabilityZone item.realm_id > + xml.groupName > + xml.tenancy 'default' > + } > + } > + end > + } > + end > + > + def to_xml > + xml.reservationSet { > + xml.item { > + xml.reservationId 'r-11111111' > + xml.ownerId 'deltacloud' > + xml.groupSet { > + xml.item { > + xml.groupId 'sg-11111111' > + xml.groupName 'default' > + } > + } > + self.instance_set > + } > + } > + end > + > + end > + > + end > + > +end > diff --git a/server/lib/ec2/helpers/errors.rb > b/server/lib/ec2/helpers/errors.rb > new file mode 100644 > index 0000000..7f8d610 > --- /dev/null > +++ b/server/lib/ec2/helpers/errors.rb > @@ -0,0 +1,46 @@ > +# Licensed to the Apache Software Foundation (ASF) under one or more > +# contributor license agreements. See the NOTICE file distributed with > +# this work for additional information regarding copyright ownership. The > +# ASF licenses this file to you under the Apache License, Version 2.0 (the > +# "License"); you may not use this file except in compliance with the > +# License. You may obtain a copy of the License at > +# > +# http://www.apache.org/licenses/LICENSE-2.0 > +# > +# Unless required by applicable law or agreed to in writing, software > +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT > +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the > +# License for the specific language governing permissions and limitations > +# under the License. > + > +module Deltacloud::EC2 > + module Errors > + > + def report_error(code) > + error = (request.env['sinatra.error'] || @exception) > + code = 500 if not code and not error.class.method_defined? :code > + Nokogiri::XML::Builder.new do |xml| > + xml.send(:Response) { > + xml.send(:Errors) { > + xml.send(:Code, error_for_code(code)) > + xml.send(:Message, error.respond_to?(:message) ? error.message : > '') > + } > + xml.send(:RequestID, request_id) > + } > + end.to_xml > + end > + > + def request_id > + > Digest::MD5.hexdigest("#{request.env['REMOTE_ADDR']}#{request.env['HTTP_USER_AGENT']}#{Time.now.to_i}#{rand(250)}") > + end > + > + def error_for_code(code) > + case code > + when 401 then 'AuthFailure' > + when 500 then 'InternalError' > + else "Unavailable (#{code})" > + end > + end > + > + end > +end > diff --git a/server/lib/ec2/query_parser.rb b/server/lib/ec2/query_parser.rb > new file mode 100644 > index 0000000..7eebc9a > --- /dev/null > +++ b/server/lib/ec2/query_parser.rb > @@ -0,0 +1,129 @@ > +# Licensed to the Apache Software Foundation (ASF) under one or more > +# contributor license agreements. See the NOTICE file distributed with > +# this work for additional information regarding copyright ownership. The > +# ASF licenses this file to you under the Apache License, Version 2.0 (the > +# "License"); you may not use this file except in compliance with the > +# License. You may obtain a copy of the License at > +# > +# http://www.apache.org/licenses/LICENSE-2.0 > +# > +# Unless required by applicable law or agreed to in writing, software > +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT > +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the > +# License for the specific language governing permissions and limitations > +# under the License. > + > +module Deltacloud::EC2 > + > + class ActionHandler > + > + MAPPINGS = { > + :describe_availability_zones => { :method => :realms, :params => { > 'ZoneName.1' => :id } }, > + :describe_images => { :method => :images, :params => { 'ImageId.1' => > :id }}, > + :describe_instances => { :method => :instances, :params => {} }, > + :run_instances => { :method => :create_instance, :params => { > 'ImageId' => :image_id, 'InstanceType' => :hwp_id, > 'Placement.AvailabilityZone' => :realm_id }} > + } > + > + attr_reader :action > + > + def initialize(action) > + @action = action > + end > + > + def deltacloud_method > + MAPPINGS[action.action][:method] > + end > + > + def deltacloud_method_params > + MAPPINGS[action.action][:params].inject({}) do |result, p| > + result[p.last] = action.parameters.delete(p.first) > + result.delete_if { |k,v| v.nil? } > + end > + end > + > + def perform!(credentials, driver) > + @result = case deltacloud_method > + when :create_instance then driver.send(deltacloud_method, > credentials, deltacloud_method_params.delete(:image_id), > deltacloud_method_params) > + else driver.send(deltacloud_method, credentials, > deltacloud_method_params) > + end > + end > + > + def to_xml > + ResultParser.parse(action, @result).to_xml > + end > + > + end > + > + class ResultParser > + > + def self.parse(parser, result) > + Nokogiri::XML::Builder.new do |xml| > + xml.send(:"#{parser.action.to_s.camelize}Response", :xmlns => > 'http://ec2.amazonaws.com/doc/2012-04-01/') { > + xml.requestId parser.request_id > + new(xml, parser, result).build_xml > + } > + end > + end > + > + def initialize(xml, parser, result) > + @builder = xml > + @parser = parser > + @result = result > + end > + > + def build_xml > + Converter.convert(@builder, @parser.action, @result) > + end > + > + end > + > + class QueryParser > + > + def self.parse(params, request_id) > + parser = new(request_id, params) > + unless parser.valid_action? > + raise 'Invalid action (%s)' % parser.action > + else > + ActionHandler.new(parser) > + end > + end > + > + attr_reader :action > + attr_reader :parameters > + attr_reader :version > + attr_reader :expiration > + attr_reader :authentication > + attr_reader :request_id > + > + def initialize(request_id, params={}) > + @request_id = request_id > + @action = (params.delete('Action') || 'Unknown').underscore.intern > + @version = params.delete('Version') > + @authentication = { > + :security_token => params.delete('SecurityToken'), > + :access_key_id => params.delete('AWSAccessKeyId'), > + :signature => { > + :version => params.delete('SignatureVersion'), > + :value => params.delete('Signature'), > + :method => params.delete('SignatureMethod'), > + :timestamp => params.delete('Timestamp') > + } > + } > + @expiration = params.delete('Expires') > + @parameters = params > + end > + > + def valid_actions > + ActionHandler::MAPPINGS.keys > + end > + > + def valid_action? > + return false if @action == :unknown > + return false unless valid_actions.include?(@action) > + true > + end > + > + > + end > + > +end > diff --git a/server/lib/ec2/server.rb b/server/lib/ec2/server.rb > new file mode 100644 > index 0000000..29fc545 > --- /dev/null > +++ b/server/lib/ec2/server.rb > @@ -0,0 +1,60 @@ > +# Licensed to the Apache Software Foundation (ASF) under one or more > +# contributor license agreements. See the NOTICE file distributed with > +# this work for additional information regarding copyright ownership. The > +# ASF licenses this file to you under the Apache License, Version 2.0 (the > +# "License"); you may not use this file except in compliance with the > +# License. You may obtain a copy of the License at > +# > +# http://www.apache.org/licenses/LICENSE-2.0 > +# > +# Unless required by applicable law or agreed to in writing, software > +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT > +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the > +# License for the specific language governing permissions and limitations > +# under the License. > + > +require 'rubygems' > +require 'nokogiri' > +require 'sinatra/base' > + > +require_relative '../sinatra' > +require_relative './helpers' > +require_relative './query_parser' > +require_relative '../deltacloud/models' > +require_relative '../deltacloud/drivers' > + > +module Deltacloud::EC2 > + class API < Sinatra::Base > + > + extend Deltacloud::Helpers::Drivers > + > + use Rack::ETag > + use Rack::CommonLogger > + > + helpers Sinatra::AuthHelper > + helpers Deltacloud::Helpers::Drivers > + helpers Deltacloud::EC2::Errors > + > + enable :xhtml > + enable :dump_errors > + enable :show_errors > + enable :method_override > + disable :show_exceptions > + > + set :version, Deltacloud[:version] > + set :root_url, Deltacloud[:root_url] > + set :root, File.join(File.dirname(__FILE__), '..', '..') > + > + after do > + headers 'Server' => 'Apache-Deltacloud-EC2/' + settings.version > + end > + > + get '/' do > + content_type :xml > + ec2_action = QueryParser.parse(params, request_id) > + ec2_action.perform!(credentials, driver) > + ec2_action.to_xml > + end > + > + end > +end > -- > 1.7.10.2 > -- Michal Fojtik Sr. Software Engineer, Deltacloud API (http://deltacloud.org)
