]> git.donarmstrong.com Git - dsa-puppet.git/blob - 3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/provider.rb
add aimonb/aviator to 3rdparty
[dsa-puppet.git] / 3rdparty / modules / aviator / lib / puppet / feature / aviator / openstack / provider.rb
1 module Aviator
2 module Openstack
3
4   #
5   # <b>Request Options</b>
6   #
7   # The following options may be used in combination with each other when calling
8   # an OpenStack request class
9   #
10   # :api_version => :v2::
11   #     Forces Aviator to use the request class for the v2 API. For any other
12   #     version, replace :v2 with the desired one. Note that this may throw an
13   #     error if no such request class for the given api version exists. If you
14   #     want to globally specify the API version to use for a specific service,
15   #     declare it in your config file under the correct environment. For example:
16   #
17   #  production:
18   #    provider: openstack
19   #    ...
20   #    compute_service:
21   #       api_version: v2
22   #
23   # Note that the <tt>:api_version</tt> option overrides whatever is declared in the
24   # configuration.
25   #
26   # :endpoint_type => (:public|:admin)::
27   #    This allows you to be specific about the endpoint type in cases where two
28   #    request classes under admin and public endpoints of the same service share
29   #    the same name. This is true, for example, for the :list_tenants request of
30   #    the identity service's v2 API. Its public endpoint will return only the tenants
31   #    the user is a member of whereas the admin endpoint will return all tenants
32   #    in the system.
33   #
34   # :session_data => Hash::
35   #    Under normal situations, you wouldn't need to use this as it is automatically populated
36   #    by the Session object provided it is authenticated. The specific use case when you'd
37   #    need to set thsi optin is when you want to use Aviator to seed your OpenStack installation.
38   #    In such a scenario, you would need to use a service token since no usernames and tenants
39   #    would exist yet in the environment. To use a service token with Aviator, you will need to
40   #    write something similar to the following example:
41   #
42   #  openstack = Aviator::Session.new(:config => { :provider => 'openstack'})
43   #
44   #  session_data = {:base_url      => 'http://example.com',
45   #                  :service_token => 'service-token-created-at-openstack-install-time'}
46   #
47   #  openstack.request :identity, :create_tenant, :api_version => :v2, :session_data => session_data) do |params|
48   #    params.name        = 'Tenant A'
49   #    params.description = 'First Tenant!'
50   #    params.enabled     = true
51   #  end
52   #
53   # Notice how the above code skips authentication. This is because the service token is
54   # pre-validated and ready for use with any request. Also note how we're providing a <tt>:base_url</tt>
55   # member in our session data. This is necessary since we normally get the service endpoints from
56   # Keystone when we authenticate. Now since we are not authenticating against Keystone, we don't have
57   # that catalogue to begin with. Thus the need to hardcode it in the request.
58   #
59   module Provider
60
61     class MultipleServiceApisError < StandardError
62       def initialize(service, entries, request_name)
63         types = entries.map{|e| e[:type] }.join("\n - ")
64         msg = <<EOF
65 Multiple entries for the #{ service } service were found in the api catalog:
66
67  - #{ types }
68
69 I'm unable to guess which one it is you want to use. To fix this problem, you'll need to
70 do one of two things:
71
72   1) Indicate in the config file the api version you want to use:
73
74       production:
75         provider: openstack
76         ...
77         #{ service }_service:
78           api_version: v2
79
80   2) Indicate the api version when you call the request:
81
82       session.#{ service }_service.request :#{ request_name }, :api_version => :v2 { ... }
83
84 If you combine the two methods, method #2 will override method #1
85
86 EOF
87         super(msg)
88       end
89     end
90
91     class << self
92
93       #:nodoc:
94       def find_request(service, name, session_data, options)
95         service = service.to_s
96         endpoint_type = options[:endpoint_type]
97         endpoint_types = if endpoint_type
98                            [endpoint_type.to_s.camelize]
99                          else
100                            ['Public', 'Admin']
101                          end
102
103         namespace = Aviator.const_get('Openstack') \
104                            .const_get(service.camelize) \
105                            .const_get('Requests')
106
107         if options[:api_version]
108           m = options[:api_version].to_s.match(/(v\d+)\.?\d*/)
109           version = m[1].to_s.camelize unless m.nil?
110         end
111
112         version ||= infer_version(session_data, name, service)
113
114         unless version.nil?
115           version = version.to_s.camelize
116         end
117
118         return nil unless version && namespace.const_defined?(version)
119
120         namespace = namespace.const_get(version, name)
121
122         endpoint_types.each do |endpoint_type|
123           name = name.to_s.camelize
124
125           next unless namespace.const_defined?(endpoint_type)
126           next unless namespace.const_get(endpoint_type).const_defined?(name)
127
128           return namespace.const_get(endpoint_type).const_get(name)
129         end
130
131         nil
132       end
133
134
135       def root_dir
136         Pathname.new(__FILE__).join('..').expand_path
137       end
138
139
140       def request_file_paths(service)
141           Dir.glob(Pathname.new(__FILE__).join(
142             '..',
143              service.to_s,
144             'requests',
145             '**',
146             '*.rb'
147             ).expand_path
148           )
149       end
150
151
152       private
153
154       def infer_version(session_data, request_name, service)
155         if session_data.has_key?(:auth_service) && session_data[:auth_service][:api_version]
156         session_data[:auth_service][:api_version].to_sym
157
158         elsif session_data.has_key?(:auth_service) && session_data[:auth_service][:host_uri]
159           m = session_data[:auth_service][:host_uri].match(/(v\d+)\.?\d*/)
160           return m[1].to_sym unless m.nil?
161
162         elsif session_data.has_key? :base_url
163           m = session_data[:base_url].match(/(v\d+)\.?\d*/)
164           return m[1].to_sym unless m.nil?
165
166         elsif session_data.has_key?(:body) && session_data[:body].has_key?(:access)
167           service_specs = session_data[:body][:access][:serviceCatalog].select{|s| s[:type].match("#{ service }(v\d+)?") }
168           raise MultipleServiceApisError.new(service, service_specs, request_name) unless service_specs.length <= 1
169           raise Aviator::Service::MissingServiceEndpointError.new(service.to_s, request_name) unless service_specs.length > 0
170           version = service_specs[0][:endpoints][0][:publicURL].match(/(v\d+)\.?\d*/)
171           version ? version[1].to_sym : :v1
172
173         elsif session_data.has_key?(:headers) && session_data[:headers].has_key?("x-subject-token")
174           service_specs = session_data[:body][:token][:catalog].select{|s| s[:type].match("#{ service }(v\d+)?") }
175           raise MultipleServiceApisError.new(service, service_specs, request_name) unless service_specs.length <= 1
176           raise Aviator::Service::MissingServiceEndpointError.new(service.to_s, request_name) unless service_specs.length > 0
177           version = service_specs[0][:endpoints][0][:url].match(/(v\d+)\.?\d*/)
178           version ? version[1].to_sym : :v1
179         end
180       end
181
182     end # class << self
183
184   end # module Provider
185
186 end # module Openstack
187 end # module Aviator