]> git.donarmstrong.com Git - dsa-puppet.git/blob - 3rdparty/modules/aviator/feature/aviator/core/service.rb
Revert "add stackforge/keystone to 3rdparty"
[dsa-puppet.git] / 3rdparty / modules / aviator / feature / aviator / core / service.rb
1 module Aviator
2
3   class Service
4
5     class AccessDetailsNotDefinedError < StandardError
6       def initialize
7         super ":access_details is not defined."
8       end
9     end
10
11     class ProviderNotDefinedError < StandardError
12       def initialize
13         super ":provider is not defined."
14       end
15     end
16
17     class ServiceNameNotDefinedError < StandardError
18       def initialize
19         super ":service is not defined."
20       end
21     end
22
23     class SessionDataNotProvidedError < StandardError
24       def initialize
25         super "default_session_data is not initialized and no session data was "\
26               "provided in the method call."
27       end
28     end
29
30
31     class UnknownRequestError < StandardError
32       def initialize(request_name)
33         super "Unknown request #{ request_name }."
34       end
35     end
36
37
38     class MissingServiceEndpointError < StandardError
39       def initialize(service_name, request_name)
40         request_name = request_name.to_s.split('::').last.underscore
41         super "The session's service catalog does not have an entry for the #{ service_name } "\
42               "service. Therefore, I don't know to which base URL the request should be sent. "\
43               "This may be because you are using a default or unscoped token. If this is not your "\
44               "intention, please authenticate with a scoped token. If using a default token is your "\
45               "intention, make sure to provide a base url when you call the request. For :example => \n\n"\
46               "session.#{ service_name }_service.request :#{ request_name }, :base_url => 'http://myenv.com:9999/v2.0' do |params|\n"\
47               "  params[:example1] = 'example1'\n"\
48               "  params[:example2] = 'example2'\n"\
49               "end\n\n"
50       end
51     end
52
53     attr_accessor :default_session_data
54
55     attr_reader :service,
56                 :provider
57
58
59     def initialize(opts={})
60       @provider = opts[:provider] || (raise ProviderNotDefinedError.new)
61       @service  = opts[:service]  || (raise ServiceNameNotDefinedError.new)
62       @log_file = opts[:log_file]
63
64       @default_session_data = opts[:default_session_data]
65
66       load_requests
67     end
68
69
70     def request(request_name, options={}, &params)
71       session_data = options[:session_data] || default_session_data
72
73       raise SessionDataNotProvidedError.new unless session_data
74
75       [:base_url].each do |k|
76         session_data[k] = options[k] if options[k]
77       end
78
79       request_class = find_request(request_name, session_data, options[:endpoint_type])
80
81       raise UnknownRequestError.new(request_name) unless request_class
82
83       request  = request_class.new(session_data, &params)
84
85       response = http_connection.send(request.http_method) do |r|
86         r.url        request.url
87         r.headers.merge!(request.headers)        if request.headers?
88         r.query    = request.querystring         if request.querystring?
89         r.body     = JSON.generate(request.body) if request.body?
90       end
91
92       Aviator::Response.send(:new, response, request)
93     end
94
95
96     def request_classes
97       @request_classes
98     end
99
100
101     private
102
103
104     def http_connection
105       @http_connection ||= Faraday.new do |conn|
106         conn.use     Logger.configure(log_file) if log_file
107         conn.adapter Faraday.default_adapter
108
109         conn.headers['Content-Type'] = 'application/json'
110       end
111     end
112
113
114     # Candidate for extraction to aviator/openstack
115     def find_request(name, session_data, endpoint_type=nil)
116       endpoint_types = if endpoint_type
117                          [endpoint_type.to_s.camelize]
118                        else
119                          ['Public', 'Admin']
120                        end
121
122       namespace = Aviator.const_get(provider.camelize) \
123                          .const_get(service.camelize)
124
125       version = infer_version(session_data, name).to_s.camelize
126
127       return nil unless version && namespace.const_defined?(version)
128
129       namespace = namespace.const_get(version, name)
130
131       endpoint_types.each do |endpoint_type|
132         name = name.to_s.camelize
133
134         next unless namespace.const_defined?(endpoint_type)
135         next unless namespace.const_get(endpoint_type).const_defined?(name)
136
137         return namespace.const_get(endpoint_type).const_get(name)
138       end
139
140       nil
141     end
142
143
144     # Candidate for extraction to aviator/openstack
145     def infer_version(session_data, request_name='sample_request')
146       if session_data.has_key?(:auth_service) && session_data[:auth_service][:api_version]
147         session_data[:auth_service][:api_version].to_sym
148
149       elsif session_data.has_key?(:auth_service) && session_data[:auth_service][:host_uri]
150         m = session_data[:auth_service][:host_uri].match(/(v\d+)\.?\d*/)
151         return m[1].to_sym unless m.nil?
152
153       elsif session_data.has_key? :base_url
154         m = session_data[:base_url].match(/(v\d+)\.?\d*/)
155         return m[1].to_sym unless m.nil?
156
157       elsif session_data.has_key? :access
158         service_spec = session_data[:access][:serviceCatalog].find{|s| s[:type] == service }
159         raise MissingServiceEndpointError.new(service.to_s, request_name) unless service_spec
160         version = service_spec[:endpoints][0][:publicURL].match(/(v\d+)\.?\d*/)
161         version ? version[1].to_sym : :v1
162       end
163     end
164
165
166     def load_requests
167       # :TODO => This should be determined by a provider-specific module.
168       # e.g. Aviator::OpenStack::requests_base_dir
169       request_file_paths = Dir.glob(Pathname.new(__FILE__).join(
170                              '..',
171                              '..',
172                              provider.to_s,
173                              service.to_s,
174                              '**',
175                              '*.rb'
176                              ).expand_path
177                            )
178
179       request_file_paths.each{ |path| require path }
180
181       constant_parts = request_file_paths \
182                         .map{|rf| rf.to_s.match(/#{provider}\/#{service}\/([\w\/]+)\.rb$/) } \
183                         .map{|rf| rf[1].split('/').map{|c| c.camelize }.join('::') }
184
185       @request_classes = constant_parts.map do |cp|
186         "Aviator::#{provider.camelize}::#{service.camelize}::#{cp}".constantize
187       end
188     end
189
190
191     def log_file
192       @log_file
193     end
194
195   end
196
197 end