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)

Reply via email to