Project

General

Profile

Download (6.82 KB) Statistics
| Branch: | Tag: | Revision:

runcible / lib / runcible / base.rb @ a5858c9b

1 24595c26 Eric D. Helms
require 'rest_client'
2
require 'oauth'
3
require 'json'
4 e702df84 Dmitri Dolguikh
require 'thread'
5 24595c26 Eric D. Helms
6
module Runcible
7
  class Base
8 3e3ad61c Partha Aji
    def initialize(config = {})
9 e702df84 Dmitri Dolguikh
      @mutex = Mutex.new
10 661ca339 Justin Sherrill
      @config = config
11 24595c26 Eric D. Helms
    end
12 a9c0cc12 David Davis
13 aaeb6609 Dmitri Dolguikh
    def lazy_config=(a_block)
14
      @mutex.synchronize { @lazy_config = a_block }
15 e702df84 Dmitri Dolguikh
    end
16
17 661ca339 Justin Sherrill
    def config
18 e702df84 Dmitri Dolguikh
      @mutex.synchronize do
19
        @config = @lazy_config.call if defined?(@lazy_config)
20 3e3ad61c Partha Aji
        fail Runcible::ConfigurationUndefinedError, Runcible::ConfigurationUndefinedError.message unless @config
21 661ca339 Justin Sherrill
        @config
22 a9c0cc12 David Davis
      end
23 24595c26 Eric D. Helms
    end
24
25 661ca339 Justin Sherrill
    def path(*args)
26
      self.class.path(*args)
27
    end
28
29 08315925 Justin Sherrill
    # rubocop:disable Metrics/AbcSize:
30 3e3ad61c Partha Aji
    def call(method, path, options = {})
31 bed41e04 Justin Sherrill
      clone_config = self.config.clone
32 4a1c5153 Justin Sherrill
      #on occation path will already have prefix (sync cancel)
33 3e3ad61c Partha Aji
      path = clone_config[:api_path] + path unless path.start_with?(clone_config[:api_path])
34 24595c26 Eric D. Helms
35 5126dd02 David Davis
      RestClient.log = []
36 bed41e04 Justin Sherrill
      headers = clone_config[:headers].clone
37 0ac76b0c Eric D. Helms
38 bed41e04 Justin Sherrill
      get_params = options[:params] if options[:params]
39
      path = combine_get_params(path, get_params) if get_params
40
41 ec04c979 Justin Sherrill
      client_options = {}
42 5126dd02 David Davis
      client_options[:timeout] = clone_config[:timeout] if clone_config[:timeout]
43
      client_options[:open_timeout] = clone_config[:open_timeout] if clone_config[:open_timeout]
44
      client_options[:verify_ssl] = clone_config[:verify_ssl] unless clone_config[:verify_ssl].nil?
45 ec04c979 Justin Sherrill
46 bed41e04 Justin Sherrill
      if clone_config[:oauth]
47 14da342c Sean O'Keeffe
        self.logger.warn('[DEPRECATION] Pulp oauth is deprecated.  Please use cert_auth instead.')
48 db2196de Christine Fouant
        headers = add_oauth_header(method, path, headers)
49 3e3ad61c Partha Aji
        headers['pulp-user'] = clone_config[:user]
50 db2196de Christine Fouant
      elsif clone_config[:cert_auth]
51
        if !clone_config[:cert_auth][:ssl_client_cert] || !clone_config[:cert_auth][:ssl_client_key]
52
          fail Runcible::ConfigurationUndefinedError, "Missing SSL certificate or key configuration."
53
        end
54
        client_options[:ssl_client_cert] = clone_config[:cert_auth][:ssl_client_cert]
55
        client_options[:ssl_client_key] = clone_config[:cert_auth][:ssl_client_key]
56 4d21ed02 Eric D. Helms
      else
57 5126dd02 David Davis
        client_options[:user] = clone_config[:user]
58 ec04c979 Justin Sherrill
        client_options[:password] = config[:http_auth][:password]
59 4d21ed02 Eric D. Helms
      end
60 24595c26 Eric D. Helms
61 3ba90809 Eric D. Helms
      client_options[:ssl_ca_file] = config[:ca_cert_file] unless config[:ca_cert_file].nil?
62 db2196de Christine Fouant
      client = RestClient::Resource.new(clone_config[:url], client_options)
63
64 24595c26 Eric D. Helms
      args = [method]
65 4d21ed02 Eric D. Helms
      args << generate_payload(options) if [:post, :put].include?(method)
66 ffa120e8 David Davis
      args << headers
67 24595c26 Eric D. Helms
68 414f0ec7 Eric D. Helms
      response = get_response(client, path, *args)
69
      process_response(response)
70
71 9e2380de Christine Fouant
    rescue RestClient::ResourceNotFound => e
72
      log_info
73
      raise e
74 414f0ec7 Eric D. Helms
    rescue => e
75
      log_exception
76
      raise e
77
    end
78
79 661ca339 Justin Sherrill
    def get_response(client, path, *args)
80 e5f2394a Justin Sherrill
      client[path].send(*args) do |response, _request, _result, &_block|
81
        resp = response.return!
82 414f0ec7 Eric D. Helms
        log_debug
83 54c3055b Eric D. Helms
        return resp
84 414f0ec7 Eric D. Helms
      end
85 24595c26 Eric D. Helms
    end
86
87 661ca339 Justin Sherrill
    def combine_get_params(path, params)
88 5126dd02 David Davis
      query_string = params.map do |k, v|
89 bed41e04 Justin Sherrill
        if v.is_a? Array
90 3e3ad61c Partha Aji
          v.map { |y| "#{k}=#{y}" }.join('&')
91 bed41e04 Justin Sherrill
        else
92 3e3ad61c Partha Aji
          "#{k}=#{v}"
93 bed41e04 Justin Sherrill
        end
94 c4c2e79f David Davis
      end
95 3e3ad61c Partha Aji
      query_string = query_string.flatten.join('&')
96 bed41e04 Justin Sherrill
      path + "?#{query_string}"
97
    end
98
99 661ca339 Justin Sherrill
    def generate_payload(options)
100 ffa120e8 David Davis
      if options[:payload].is_a?(String)
101
        return options[:payload]
102
      elsif options[:payload].is_a?(Hash)
103
        format_payload_json(options[:payload])
104
      end
105
    end
106
107
    def format_payload_json(payload_hash)
108
      if payload_hash
109
        if payload_hash[:optional]
110 5126dd02 David Davis
          payload = if payload_hash[:required]
111
                      payload_hash[:required].merge(payload_hash[:optional])
112
                    else
113
                      payload_hash[:optional]
114
                    end
115 ffa120e8 David Davis
        elsif payload_hash[:delta]
116
          payload = payload_hash
117 9b42e5f7 Eric D. Helms
        else
118 ffa120e8 David Davis
          payload = payload_hash[:required]
119 9b42e5f7 Eric D. Helms
        end
120
      else
121 54e29583 Eric D. Helms
        payload = {}
122 9b42e5f7 Eric D. Helms
      end
123 50bf07ad Eric D. Helms
124 4d21ed02 Eric D. Helms
      return payload.to_json
125 9b42e5f7 Eric D. Helms
    end
126
127 661ca339 Justin Sherrill
    def process_response(response)
128 24595c26 Eric D. Helms
      begin
129 f37833e8 Eric D. Helms
        body = response.body == "null" ? nil : JSON.parse(response.body)
130 4288d8bc Justin Sherrill
        if body.respond_to? :with_indifferent_access
131
          body = body.with_indifferent_access
132
        elsif body.is_a? Array
133 5126dd02 David Davis
          body = body.map do |i|
134 4288d8bc Justin Sherrill
            i.respond_to?(:with_indifferent_access) ? i.with_indifferent_access : i
135
          end
136
        end
137 e5f2394a Justin Sherrill
        response = Runcible::Response.new(body, response)
138 24595c26 Eric D. Helms
      rescue JSON::ParserError
139 3e3ad61c Partha Aji
        log_exception
140 24595c26 Eric D. Helms
      end
141
142 7a20f47b Eric D. Helms
      return response
143 24595c26 Eric D. Helms
    end
144
145 3e3ad61c Partha Aji
    def required_params(local_names, binding, keys_to_remove = [])
146
      local_names = local_names.each_with_object({}) do |v, acc|
147 5afa786f Eric D. Helms
        value = binding.eval(v.to_s) unless v == :_
148
        acc[v] = value unless value.nil?
149 cc7af6f7 Eric D. Helms
        acc
150
      end
151 34e25883 Eric D. Helms
152 50bf07ad Eric D. Helms
      #The double delete is to support 1.8.7 and 1.9.3
153
      local_names.delete(:payload)
154
      local_names.delete(:optional)
155 3e3ad61c Partha Aji
      local_names.delete('payload')
156
      local_names.delete('optional')
157 34e25883 Eric D. Helms
      keys_to_remove.each do |key|
158
        local_names.delete(key)
159 50bf07ad Eric D. Helms
        local_names.delete(key.to_sym)
160 34e25883 Eric D. Helms
      end
161
162 cc7af6f7 Eric D. Helms
      return local_names
163
    end
164
165 661ca339 Justin Sherrill
    def add_http_auth_header
166 4d21ed02 Eric D. Helms
      return {:user => config[:user], :password => config[:http_auth][:password]}
167
    end
168
169 661ca339 Justin Sherrill
    def add_oauth_header(method, path, headers)
170 0ac76b0c Eric D. Helms
      default_options = { :site               => config[:url],
171
                          :http_method        => method,
172 3e3ad61c Partha Aji
                          :request_token_path => '',
173
                          :authorize_path     => '',
174
                          :access_token_path  => '' }
175 0ac76b0c Eric D. Helms
176
      consumer = OAuth::Consumer.new(config[:oauth][:oauth_key], config[:oauth][:oauth_secret], default_options)
177
178
      method_to_http_request = { :get    => Net::HTTP::Get,
179
                                 :post   => Net::HTTP::Post,
180
                                 :put    => Net::HTTP::Put,
181
                                 :delete => Net::HTTP::Delete }
182
183
      http_request = method_to_http_request[method].new(path)
184
      consumer.sign!(http_request)
185
186
      headers['Authorization'] = http_request['Authorization']
187
      return headers
188
    end
189
190 661ca339 Justin Sherrill
    def log_debug
191 414f0ec7 Eric D. Helms
      if self.config[:logging][:debug]
192 3e3ad61c Partha Aji
        log_message = generate_log_message
193 414f0ec7 Eric D. Helms
        self.config[:logging][:logger].debug(log_message)
194
      end
195
    end
196
197 661ca339 Justin Sherrill
    def log_exception
198 414f0ec7 Eric D. Helms
      if self.config[:logging][:exception]
199
        log_message = generate_log_message
200
        self.config[:logging][:logger].error(log_message)
201
      end
202
    end
203
204 9e2380de Christine Fouant
    def log_info
205
      if self.config[:logging][:info]
206
        log_message = generate_log_message
207
        self.config[:logging][:logger].info(log_message)
208
      end
209
    end
210
211 661ca339 Justin Sherrill
    def generate_log_message
212 414f0ec7 Eric D. Helms
      RestClient.log.join('\n')
213
    end
214
215 571d1317 Justin Sherrill
    def logger
216
      self.config[:logging][:logger]
217
    end
218 3e3ad61c Partha Aji
  end
219 a9c0cc12 David Davis
220
  class ConfigurationUndefinedError < StandardError
221
    def self.message
222
      # override me to change the error message
223 3e3ad61c Partha Aji
      'Configuration not set. Runcible::Base.config= must be called before Runcible::Base.config.'
224 a9c0cc12 David Davis
    end
225
  end
226 24595c26 Eric D. Helms
end