misty 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +222 -1
- data/lib/misty.rb +8 -0
- data/lib/misty/auth.rb +60 -0
- data/lib/misty/auth/auth_v2.rb +46 -0
- data/lib/misty/auth/auth_v3.rb +58 -0
- data/lib/misty/autoload.rb +82 -0
- data/lib/misty/cloud.rb +133 -0
- data/lib/misty/http/client.rb +115 -0
- data/lib/misty/http/direct.rb +26 -0
- data/lib/misty/http/method_builder.rb +96 -0
- data/lib/misty/http/request.rb +75 -0
- data/lib/misty/misty.rb +51 -0
- data/lib/misty/openstack/aodh/aodh_v2.rb +12 -0
- data/lib/misty/openstack/aodh/v2.rb +20 -0
- data/lib/misty/openstack/ceilometer/ceilometer_v2.rb +13 -0
- data/lib/misty/openstack/ceilometer/v2.rb +20 -0
- data/lib/misty/openstack/cinder/cinder_v1.rb +35 -0
- data/lib/misty/openstack/cinder/cinder_v3.rb +148 -0
- data/lib/misty/openstack/cinder/v1.rb +24 -0
- data/lib/misty/openstack/cinder/v3.rb +24 -0
- data/lib/misty/openstack/designate/designate_v2.rb +69 -0
- data/lib/misty/openstack/designate/v2.rb +20 -0
- data/lib/misty/openstack/glance/glance_v1.rb +16 -0
- data/lib/misty/openstack/glance/glance_v2.rb +29 -0
- data/lib/misty/openstack/glance/v1.rb +20 -0
- data/lib/misty/openstack/glance/v2.rb +20 -0
- data/lib/misty/openstack/heat/heat_v1.rb +85 -0
- data/lib/misty/openstack/heat/v1.rb +24 -0
- data/lib/misty/openstack/ironic/ironic_v1.rb +71 -0
- data/lib/misty/openstack/ironic/v1.rb +26 -0
- data/lib/misty/openstack/karbor/karbor_v1.rb +32 -0
- data/lib/misty/openstack/karbor/v1.rb +20 -0
- data/lib/misty/openstack/keystone/keystone_v2_0.rb +11 -0
- data/lib/misty/openstack/keystone/keystone_v2_0_ext.rb +32 -0
- data/lib/misty/openstack/keystone/keystone_v3.rb +147 -0
- data/lib/misty/openstack/keystone/keystone_v3_ext.rb +124 -0
- data/lib/misty/openstack/keystone/v2_0.rb +23 -0
- data/lib/misty/openstack/keystone/v3.rb +23 -0
- data/lib/misty/openstack/magnum/magnum_v1.rb +41 -0
- data/lib/misty/openstack/magnum/v1.rb +26 -0
- data/lib/misty/openstack/manila/manila_v2.rb +143 -0
- data/lib/misty/openstack/manila/v2.rb +26 -0
- data/lib/misty/openstack/microversion.rb +62 -0
- data/lib/misty/openstack/neutron/neutron_v2_0.rb +205 -0
- data/lib/misty/openstack/neutron/v2_0.rb +20 -0
- data/lib/misty/openstack/nova/nova_v2_1.rb +269 -0
- data/lib/misty/openstack/nova/v2_1.rb +40 -0
- data/lib/misty/openstack/sahara/sahara_v1_1.rb +77 -0
- data/lib/misty/openstack/sahara/v1_1.rb +20 -0
- data/lib/misty/openstack/searchlight/searchlight_v1.rb +15 -0
- data/lib/misty/openstack/searchlight/v1.rb +20 -0
- data/lib/misty/openstack/senlin/senlin_v1.rb +66 -0
- data/lib/misty/openstack/senlin/v1.rb +20 -0
- data/lib/misty/openstack/swift/swift_v1.rb +23 -0
- data/lib/misty/openstack/swift/v1.rb +20 -0
- data/lib/misty/openstack/trove/trove_v1_0.rb +51 -0
- data/lib/misty/openstack/trove/v1_0.rb +20 -0
- data/lib/misty/openstack/zaqar/v2.rb +20 -0
- data/lib/misty/openstack/zaqar/zaqar_v2.rb +46 -0
- data/lib/misty/version.rb +2 -2
- data/test/integration/compute_test.rb +35 -0
- data/test/integration/network_test.rb +34 -0
- data/test/integration/orchestration_test.rb +92 -0
- data/test/integration/test_helper.rb +19 -0
- data/test/integration/vcr/compute_using_nova_v2_1.yml +1107 -0
- data/test/integration/vcr/network_using_neutron_v2_0.yml +1029 -0
- data/test/integration/vcr/orchestration_using_heat_v1.yml +1457 -0
- data/test/unit/auth_helper.rb +52 -0
- data/test/unit/auth_test.rb +99 -0
- data/test/unit/cloud/requests_test.rb +113 -0
- data/test/unit/cloud/services_test.rb +171 -0
- data/test/unit/cloud_test.rb +145 -0
- data/test/unit/http/client_test.rb +74 -0
- data/test/unit/http/direct_test.rb +103 -0
- data/test/unit/http/method_builder_test.rb +133 -0
- data/test/unit/http/request_test.rb +123 -0
- data/test/unit/misty_test.rb +36 -0
- data/test/unit/openstack/APIs_test.rb +40 -0
- data/test/unit/openstack/microversion_test.rb +70 -0
- data/test/unit/service_helper.rb +25 -0
- data/test/unit/test_helper.rb +8 -0
- metadata +170 -5
    
        data/lib/misty/cloud.rb
    ADDED
    
    | @@ -0,0 +1,133 @@ | |
| 1 | 
            +
            require 'misty/auth/auth_v2'
         | 
| 2 | 
            +
            require 'misty/auth/auth_v3'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Misty
         | 
| 5 | 
            +
              class Cloud
         | 
| 6 | 
            +
                Setup   = Struct.new(:auth, :content_type, :log)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                Options = Struct.new(:alarming, :baremetal, :block_storage, :clustering, :compute, :container, :data_processing,
         | 
| 9 | 
            +
                  :database, :data_protection, :dns, :identity, :image, :messaging, :metering, :network, :object_storage,
         | 
| 10 | 
            +
                  :orchestration, :search, :shared_file_systems)
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                attr_reader :services
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def initialize(options = {:auth => {}})
         | 
| 15 | 
            +
                  @cloud = Setup.new
         | 
| 16 | 
            +
                  @cloud.auth = Misty::Auth.factory(options[:auth])
         | 
| 17 | 
            +
                  @cloud.content_type = options[:content_type] ? options[:content_type] : nil
         | 
| 18 | 
            +
                  @cloud.log = Logger.new(options[:log_file] ? options[:log_file] : Misty::LOG_FILE)
         | 
| 19 | 
            +
                  @cloud.log.level = options[:log_level] ? options[:log_level] : Misty::LOG_LEVEL
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  @options = Options.new
         | 
| 22 | 
            +
                  Misty.services.each do |service|
         | 
| 23 | 
            +
                    @options.send("#{service.name}=".to_sym, options[service.name] ? options[service.name] : {})
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  @services = setup_services(@options)
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def setup_services(options)
         | 
| 30 | 
            +
                  services = {}
         | 
| 31 | 
            +
                  Misty.services.each do |service|
         | 
| 32 | 
            +
                    if options[service.name] && options[service.name][:api_version] \
         | 
| 33 | 
            +
                      && service.versions.include?(options[service.name][:api_version])
         | 
| 34 | 
            +
                      services.merge!(service.name => {service.project => options[service.name][:api_version]})
         | 
| 35 | 
            +
                    else
         | 
| 36 | 
            +
                      # Highest version is used by default!
         | 
| 37 | 
            +
                      services.merge!(service.name => {service.project => service.versions.sort[-1]})
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
                  services
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def build_service(service_name)
         | 
| 44 | 
            +
                  project = @services[service_name].keys[0]
         | 
| 45 | 
            +
                  version = @services[service_name].fetch(project)
         | 
| 46 | 
            +
                  version = self.class.dot_to_underscore(version)
         | 
| 47 | 
            +
                  klass = Object.const_get("Misty::Openstack::#{project.capitalize}::#{version.capitalize}")
         | 
| 48 | 
            +
                  klass.new(@cloud, @options[service_name])
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                def self.dot_to_underscore(val)
         | 
| 52 | 
            +
                  val.gsub(/\./,'_')
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                def alarming
         | 
| 56 | 
            +
                  @alarming ||= build_service(:alarming)
         | 
| 57 | 
            +
                end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                def baremetal
         | 
| 60 | 
            +
                  @baremetal ||= build_service(:baremetal)
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                def block_storage
         | 
| 64 | 
            +
                  @block_storage ||= build_service(:block_storage)
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                alias volume block_storage
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                def clustering
         | 
| 70 | 
            +
                  @clustering ||= build_service(:clustering)
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                def compute
         | 
| 74 | 
            +
                  @compute ||= build_service(:compute)
         | 
| 75 | 
            +
                end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                def container
         | 
| 78 | 
            +
                  @container ||= build_service(:container)
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                def data_processing
         | 
| 82 | 
            +
                  @data_processing ||= build_service(:data_processing)
         | 
| 83 | 
            +
                end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                def data_protection
         | 
| 86 | 
            +
                  @data_protection ||= build_service(:data_protection)
         | 
| 87 | 
            +
                end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                def database
         | 
| 90 | 
            +
                  @database ||= build_service(:database)
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                def dns
         | 
| 94 | 
            +
                  @dns ||= build_service(:dns)
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                def identity
         | 
| 98 | 
            +
                  @identity ||= build_service(:identity)
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                def image
         | 
| 102 | 
            +
                  @image ||= build_service(:image)
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                def messaging
         | 
| 106 | 
            +
                  @messaging ||= build_service(:messaging)
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                def metering
         | 
| 110 | 
            +
                  @metering ||= build_service(:metering)
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                def network
         | 
| 114 | 
            +
                  @network ||= build_service(:network)
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                def object_storage
         | 
| 118 | 
            +
                  @object_storage ||= build_service(:object_storage)
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                def orchestration
         | 
| 122 | 
            +
                  @orchestration ||= build_service(:orchestration)
         | 
| 123 | 
            +
                end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                def search
         | 
| 126 | 
            +
                  @search ||= build_service(:search)
         | 
| 127 | 
            +
                end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                def shared_file_systems
         | 
| 130 | 
            +
                  @shared_file_systems ||= build_service(:shared_file_systems)
         | 
| 131 | 
            +
                end
         | 
| 132 | 
            +
              end
         | 
| 133 | 
            +
            end
         | 
| @@ -0,0 +1,115 @@ | |
| 1 | 
            +
            require 'misty/http/method_builder'
         | 
| 2 | 
            +
            require 'misty/http/request'
         | 
| 3 | 
            +
            require 'misty/http/direct'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Misty
         | 
| 6 | 
            +
              module HTTP
         | 
| 7 | 
            +
                class Client
         | 
| 8 | 
            +
                  class InvalidDataError < StandardError; end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  include Misty::HTTP::MethodBuilder
         | 
| 11 | 
            +
                  include Misty::HTTP::Request
         | 
| 12 | 
            +
                  include Misty::HTTP::Direct
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  INTERFACES = %w{admin public internal}
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  attr_reader :microversion
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  Options = Struct.new(:base_path, :base_url, :interface, :region_id, :service_names, :ssl_verify_mode, :version)
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                  def requests
         | 
| 21 | 
            +
                    list = []
         | 
| 22 | 
            +
                    self.class.api.each do |_path, verbs|
         | 
| 23 | 
            +
                      verbs.each do |_verb, requests|
         | 
| 24 | 
            +
                        list << requests
         | 
| 25 | 
            +
                      end
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
                    list.flatten.sort
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  # Options - Values shown are the default
         | 
| 31 | 
            +
                  #   Base path can be forced (Not recommended, mainly used for test purposes)
         | 
| 32 | 
            +
                  #    :base_path => nil
         | 
| 33 | 
            +
                  #   URL can be forced (Helps when setup is broken)
         | 
| 34 | 
            +
                  #    :base_url => nil
         | 
| 35 | 
            +
                  #   Endpoint type (admin, public or internal)
         | 
| 36 | 
            +
                  #     :interface => "public"
         | 
| 37 | 
            +
                  #   Region ID
         | 
| 38 | 
            +
                  #    :region_id => "regionOne"
         | 
| 39 | 
            +
                  #   Service name
         | 
| 40 | 
            +
                  #    The Service names are pre defined but more can be added using this option.
         | 
| 41 | 
            +
                  #    :service_name
         | 
| 42 | 
            +
                  #   SSL Verify Mode
         | 
| 43 | 
            +
                  #     :ssl_verify_mode => true
         | 
| 44 | 
            +
                  #   (micro)version: Can be numbered (3.1) or by state (CURRENT, LATEST or SUPPORTED)
         | 
| 45 | 
            +
                  #     :version => "CURRENT"
         | 
| 46 | 
            +
                  def initialize(cloud, options)
         | 
| 47 | 
            +
                    @cloud = cloud
         | 
| 48 | 
            +
                    @options = setup(options)
         | 
| 49 | 
            +
                    @uri = URI.parse(@cloud.auth.get_endpoint(@options.service_names, @options.region_id, @options.interface))
         | 
| 50 | 
            +
                    @base_path = @options.base_path ? @options.base_path : @uri.path
         | 
| 51 | 
            +
                    @base_path = @base_path.chomp("/")
         | 
| 52 | 
            +
                    @http = net_http(@uri)
         | 
| 53 | 
            +
                    @version = nil
         | 
| 54 | 
            +
                    @microversion = false
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  # Sub classes to override
         | 
| 58 | 
            +
                  # When a catalog provides a base path and the Service API definition containts the generic equivalent as prefix
         | 
| 59 | 
            +
                  # then the preifx is redundant and must be removed from the path.
         | 
| 60 | 
            +
                  # For example:
         | 
| 61 | 
            +
                  # Catalog provides "http://192.0.2.21:8004/v1/48985e6b8da145699d411f12a3459fca"
         | 
| 62 | 
            +
                  # and Service API has "/v1/{tenant_id}/stacks"
         | 
| 63 | 
            +
                  # then the path prefix is ignored and path is only "/stacks"
         | 
| 64 | 
            +
                  def self.prefix_path_to_ignore
         | 
| 65 | 
            +
                    ""
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  def headers_default
         | 
| 69 | 
            +
                    Misty::HEADER_JSON
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  def headers
         | 
| 73 | 
            +
                    h = headers_default.merge("X-Auth-Token" => "#{@cloud.auth.get_token}")
         | 
| 74 | 
            +
                    h.merge!(microversion_header) if microversion
         | 
| 75 | 
            +
                    h
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  private
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                  def baseclass
         | 
| 81 | 
            +
                    self.class.to_s.split('::')[-1]
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                  def net_http(uri)
         | 
| 85 | 
            +
                    http = Net::HTTP.new(uri.host, uri.port)
         | 
| 86 | 
            +
                    http.set_debug_output($stdout) if @cloud.log.level == Logger::DEBUG
         | 
| 87 | 
            +
                    if uri.scheme == "https"
         | 
| 88 | 
            +
                      http.use_ssl = true
         | 
| 89 | 
            +
                      http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @options[:ssl_verify_mode]
         | 
| 90 | 
            +
                    end
         | 
| 91 | 
            +
                    http
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  def setup(params)
         | 
| 95 | 
            +
                    options = Options.new()
         | 
| 96 | 
            +
                    options.base_path       = params[:base_path]       ? params[:base_path] : nil
         | 
| 97 | 
            +
                    options.base_url        = params[:base_url]        ? params[:base_url] : nil
         | 
| 98 | 
            +
                    options.interface       = params[:interface]       ? params[:interface] : "public"
         | 
| 99 | 
            +
                    options.region_id       = params[:region_id]       ? params[:region_id] : "regionOne"
         | 
| 100 | 
            +
                    options.service_names   = params[:service_name]    ? self.class.service_names << params[:service_name] : self.class.service_names
         | 
| 101 | 
            +
                    options.ssl_verify_mode = params[:ssl_verify_mode] ? params[:ssl_verify_mode] : true
         | 
| 102 | 
            +
                    options.version         = params[:version]         ? params[:version] : "CURRENT"
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                    unless INTERFACES.include?(options.interface)
         | 
| 105 | 
            +
                      raise InvalidDataError, "Options ':interface'must be one of #{INTERFACES}"
         | 
| 106 | 
            +
                    end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                    unless options.ssl_verify_mode == !!options.ssl_verify_mode
         | 
| 109 | 
            +
                      raise InvalidDataError, "Options ':ssl_verify_mode' must be a boolean"
         | 
| 110 | 
            +
                    end
         | 
| 111 | 
            +
                    options
         | 
| 112 | 
            +
                  end
         | 
| 113 | 
            +
                end
         | 
| 114 | 
            +
              end
         | 
| 115 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            module Misty
         | 
| 2 | 
            +
              module HTTP
         | 
| 3 | 
            +
                # Provides methods to submit the current service with a path and override @base_path if needed
         | 
| 4 | 
            +
                module Direct
         | 
| 5 | 
            +
                  def base_set(base_path)
         | 
| 6 | 
            +
                    base = base_path ? base_path : @base_path
         | 
| 7 | 
            +
                  end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def delete(path, base_path = nil)
         | 
| 10 | 
            +
                    http_delete(base_set(base_path) + path, headers)
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def get(path, base_path = nil)
         | 
| 14 | 
            +
                    http_get(base_set(base_path) + path, headers)
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def post(path, data, base_path = nil)
         | 
| 18 | 
            +
                    http_post(base_set(base_path) + path, headers, data)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def put(path, data, base_path = nil)
         | 
| 22 | 
            +
                    http_put(base_set(base_path) + path, headers, data)
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,96 @@ | |
| 1 | 
            +
            module Misty
         | 
| 2 | 
            +
              module HTTP
         | 
| 3 | 
            +
                module MethodBuilder
         | 
| 4 | 
            +
                  def method_missing(method_name, *args)
         | 
| 5 | 
            +
                    if method = get_method(method_name)
         | 
| 6 | 
            +
                      method_call(method, *args)
         | 
| 7 | 
            +
                    else
         | 
| 8 | 
            +
                      raise NoMethodError, "API #{baseclass.downcase}: method #{method_name} not implemented!"
         | 
| 9 | 
            +
                    end
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  private
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                  def method_call(method, *args)
         | 
| 15 | 
            +
                    base, path = prefixed_path(method[:path])
         | 
| 16 | 
            +
                    size_path_parameters = count_path_params(path)
         | 
| 17 | 
            +
                    path_params = args[0, size_path_parameters]
         | 
| 18 | 
            +
                    args_left = args - path_params
         | 
| 19 | 
            +
                    path = inject_elements(path, path_params)
         | 
| 20 | 
            +
                    final_path = base_filter(base, path)
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    case method[:request]
         | 
| 23 | 
            +
                    when :COPY
         | 
| 24 | 
            +
                      http_copy(final_path, headers)
         | 
| 25 | 
            +
                    when :DELETE
         | 
| 26 | 
            +
                      http_delete(final_path, headers)
         | 
| 27 | 
            +
                    when :GET
         | 
| 28 | 
            +
                      final_path << query_param(args_left[0]) if args_left && args_left.size == 1
         | 
| 29 | 
            +
                      http_get(final_path, headers)
         | 
| 30 | 
            +
                    when :HEAD
         | 
| 31 | 
            +
                      http_head(final_path, headers, data)
         | 
| 32 | 
            +
                    when :POST
         | 
| 33 | 
            +
                      data = args_left[0] if args_left && args_left.size == 1
         | 
| 34 | 
            +
                      http_post(final_path, headers, data)
         | 
| 35 | 
            +
                    when :PUT
         | 
| 36 | 
            +
                      data = args_left[0] if args_left && args_left.size == 1
         | 
| 37 | 
            +
                      http_put(final_path, headers, data)
         | 
| 38 | 
            +
                    when :PATCH
         | 
| 39 | 
            +
                      data = args_left[0] if args_left && args_left.size == 1
         | 
| 40 | 
            +
                      http_patch(final_path, headers, data)
         | 
| 41 | 
            +
                    else
         | 
| 42 | 
            +
                      raise SyntaxError, "Invalid HTTP request: #{method[:request]}"
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  def base_filter(base, path)
         | 
| 47 | 
            +
                    return (@base_path + path) if base
         | 
| 48 | 
            +
                    return path
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  def count_path_params(str)
         | 
| 52 | 
            +
                    subpath = /(.*)(\{.*\})(.*)/.match(str)
         | 
| 53 | 
            +
                    return 0 unless subpath
         | 
| 54 | 
            +
                    return count_path_params(subpath[1]) + 1
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  def get_method(name)
         | 
| 58 | 
            +
                    self.class.api.each do |path, requests|
         | 
| 59 | 
            +
                      requests.each do |request, methods_list|
         | 
| 60 | 
            +
                        if methods_list.include?(name)
         | 
| 61 | 
            +
                          return {:path => path, :request => request, :name => name}
         | 
| 62 | 
            +
                        end
         | 
| 63 | 
            +
                      end
         | 
| 64 | 
            +
                    end
         | 
| 65 | 
            +
                    nil
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  def inject_elements(str, args)
         | 
| 69 | 
            +
                    subpath = /(.*)(\{.*\})(.*)/.match(str)
         | 
| 70 | 
            +
                    return str unless subpath
         | 
| 71 | 
            +
                    arg = args.pop
         | 
| 72 | 
            +
                    raise ArgumentError, "Not enough arguments" unless arg
         | 
| 73 | 
            +
                    return inject_elements(subpath[1], args) + arg + subpath[3]
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  def prefixed_path(path)
         | 
| 77 | 
            +
                    unless self.class.prefix_path_to_ignore.empty?
         | 
| 78 | 
            +
                      if path =~ %r{#{self.class.prefix_path_to_ignore}}
         | 
| 79 | 
            +
                        return true, path.gsub(self.class.prefix_path_to_ignore, '')
         | 
| 80 | 
            +
                      else
         | 
| 81 | 
            +
                        return false, path
         | 
| 82 | 
            +
                      end
         | 
| 83 | 
            +
                    end
         | 
| 84 | 
            +
                    return true, path
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  def query_param(data)
         | 
| 88 | 
            +
                    if data.is_a? String
         | 
| 89 | 
            +
                      str = '?'
         | 
| 90 | 
            +
                      str.force_encoding('ASCII-8BIT')
         | 
| 91 | 
            +
                      str << data unless data.empty?
         | 
| 92 | 
            +
                    end
         | 
| 93 | 
            +
                  end
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
              end
         | 
| 96 | 
            +
            end
         | 
| @@ -0,0 +1,75 @@ | |
| 1 | 
            +
            module Misty
         | 
| 2 | 
            +
              module HTTP
         | 
| 3 | 
            +
                module Request
         | 
| 4 | 
            +
                  def decode?(response)
         | 
| 5 | 
            +
                    if @cloud.content_type != :json && response.code =~ /2??/  && !response.is_a?(Net::HTTPNoContent) \
         | 
| 6 | 
            +
                      && !response.is_a?(Net::HTTPResetContent) && response.header["content-type"] \
         | 
| 7 | 
            +
                      && response.header["content-type"].include?("application/json")
         | 
| 8 | 
            +
                      true
         | 
| 9 | 
            +
                    end
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  def http(request)
         | 
| 13 | 
            +
                    response = @http.request(request)
         | 
| 14 | 
            +
                    response.body = JSON.load(response.body) if decode?(response)
         | 
| 15 | 
            +
                    response
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def http_delete(path, headers)
         | 
| 19 | 
            +
                    @cloud.log.info(http_to_s(path, headers))
         | 
| 20 | 
            +
                    request = Net::HTTP::Delete.new(path, headers)
         | 
| 21 | 
            +
                    http(request)
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def http_copy(path, headers)
         | 
| 25 | 
            +
                    @cloud.log.info(http_to_s(path, headers))
         | 
| 26 | 
            +
                    request = Net::HTTP::Copy.new(path, headers)
         | 
| 27 | 
            +
                    http(request)
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def http_get(path, headers)
         | 
| 31 | 
            +
                    @cloud.log.info(http_to_s(path, headers))
         | 
| 32 | 
            +
                    request = Net::HTTP::Get.new(path, headers)
         | 
| 33 | 
            +
                    http(request)
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  def http_head(path, headers)
         | 
| 37 | 
            +
                    @cloud.log.info(http_to_s(path, headers))
         | 
| 38 | 
            +
                    request = Net::HTTP::Head.new(path, headers)
         | 
| 39 | 
            +
                    http(request)
         | 
| 40 | 
            +
                  end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                  def http_options(path, headers)
         | 
| 43 | 
            +
                    @cloud.log.info(http_to_s(path, headers))
         | 
| 44 | 
            +
                    request = Net::HTTP::Options.new(path, headers)
         | 
| 45 | 
            +
                    http(request)
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  def http_patch(path, headers, data)
         | 
| 49 | 
            +
                    @cloud.log.info(http_to_s(path, headers, data))
         | 
| 50 | 
            +
                    request = Net::HTTP::Patch.new(path, headers)
         | 
| 51 | 
            +
                    request.body = Misty.to_json(data)
         | 
| 52 | 
            +
                    http(request)
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  def http_post(path, headers, data)
         | 
| 56 | 
            +
                    @cloud.log.info(http_to_s(path, headers, data))
         | 
| 57 | 
            +
                    request = Net::HTTP::Post.new(path, headers)
         | 
| 58 | 
            +
                    request.body = Misty.to_json(data)
         | 
| 59 | 
            +
                    http(request)
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  def http_put(path, headers, data)
         | 
| 63 | 
            +
                    @cloud.log.info(http_to_s(path, headers, data))
         | 
| 64 | 
            +
                    request = Net::HTTP::Put.new(path, headers)
         | 
| 65 | 
            +
                    request.body = Misty.to_json(data)
         | 
| 66 | 
            +
                    http(request)
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  def http_to_s(path, headers, data = nil)
         | 
| 70 | 
            +
                    log = "base_url='#{@uri.host}:#{@uri.port}', path='#{path}', header=#{headers}"
         | 
| 71 | 
            +
                    log << ", data='#{data}'" if data
         | 
| 72 | 
            +
                  end
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
              end
         | 
| 75 | 
            +
            end
         |