redhat_access_lib 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 28ee4071dfdcde44888e21d564c2671f9f7bdbdb
4
+ data.tar.gz: 69c2bb2e6c5edd63b7fb74ce6a6cf0ed83e8acb7
5
+ SHA512:
6
+ metadata.gz: f0c37cd7508267505894f68fad37445640b95ba8e0d1d4882a953d849255a02135aad1d236c50c1f6adf32ca2ca3d0eb3310e7d85bfa500365c51996afb2c745
7
+ data.tar.gz: 22ab3cc62253c9645e5133787b47f7a2d41762c17232fadeb08abc9cafe80a2676f7d0727d1334def3aa1abf93ee378596e5a3a41bcfafaf0c27e34599b76565
@@ -0,0 +1,9 @@
1
+ require 'rake/testtask'
2
+
3
+
4
+ task :default => [:test]
5
+
6
+ Rake::TestTask.new do |t|
7
+ t.libs << "spec"
8
+ t.test_files = FileList['spec/**/*_spec.rb']
9
+ end
@@ -0,0 +1,43 @@
1
+ require_relative '../brokers/broker'
2
+ require_relative '../brokers/article'
3
+ require_relative '../brokers/case'
4
+ require_relative '../brokers/solution'
5
+ require_relative '../brokers/symptom'
6
+ require_relative '../brokers/problem'
7
+ require_relative '../brokers/attachment'
8
+ require_relative '../brokers/product'
9
+ require_relative '../brokers/entitlement'
10
+ require_relative '../brokers/comment'
11
+ require_relative '../brokers/group'
12
+
13
+ require_relative '../network/http_connection'
14
+
15
+ module RedHatSupportLib
16
+ module Api
17
+ class API
18
+ attr_reader :article_broker, :case_broker, :solution_broker
19
+ attr_reader :symptom_broker, :problem_broker, :attachment_broker
20
+ attr_reader :product_broker, :group_broker, :entitlement_broker, :comment_broker
21
+
22
+ def initialize(network_config, attachments_config)
23
+ @connection = Network::HttpConnection.new(network_config)
24
+ @article_broker = Brokers::Article.new(@connection)
25
+ @case_broker = Brokers::Case.new(@connection)
26
+ @solution_broker = Brokers::Solution.new(@connection)
27
+ @symptom_broker = Brokers::Symptom.new(@connection)
28
+ @problem_broker = Brokers::Problem.new(@connection)
29
+ @comment_broker = Brokers::Comment.new(@connection)
30
+ @attachment_broker = Brokers::Attachment.new(@connection, @comment_broker, attachments_config)
31
+ @product_broker = Brokers::Product.new(@connection)
32
+ @group_broker = Brokers::Group.new(@connection)
33
+ @entitlement_broker = Brokers::Entitlement.new(@connection)
34
+
35
+ end
36
+
37
+ def self.log_location(path)
38
+
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,230 @@
1
+ require_relative '../network/http_request'
2
+
3
+ module RedHatSupportLib::TelemetryApi
4
+
5
+ SUBSET_LIST_TYPE_KEY = :subset_list_type
6
+ SUBSET_LIST_TYPE_MACHINE_ID = :machine_ids
7
+ SUBSET_LIST_TYPE_LEAF_ID = :leaf_ids
8
+ SUBSET_ROUTE_REGEX = [/^(v[0-9]|latest)\/systems\/status$/,
9
+ /^systems\/status$/,
10
+ /^(v[0-9]|latest)\/systems$/,
11
+ /^systems$/,
12
+ /^(v[0-9]|latest)\/rules$/,
13
+ /^rules$/,
14
+ /^(v[0-9]|latest)\/reports$/,
15
+ /^reports$/,
16
+ /^(v[0-9]|latest)\/messaging\/data\/weeklyinfo$/].freeze
17
+
18
+
19
+ class Client
20
+ RestClient.log =Object.new.tap do |proxy|
21
+ def proxy.<<(message)
22
+ Rails.logger.debug message
23
+ end
24
+ end
25
+
26
+ #
27
+ # Creates and returns the subset route corresponding to 'path' if 'path' is a subset resource, otherwise
28
+ # returns 'nil'
29
+ #
30
+ def create_subset_route(path)
31
+ SUBSET_ROUTE_REGEX.each do |regex|
32
+ if regex.match(path)
33
+ subset_id = get_hash(get_machines)
34
+ path.gsub(regex) do |s|
35
+ api_version = Regexp.last_match[1]
36
+ if api_version
37
+ path = s.sub(api_version, "#{api_version}/subsets/#{subset_id}")
38
+ else
39
+ path = "subsets/#{subset_id}/#{s}"
40
+ end
41
+ end
42
+ return path
43
+ end
44
+ end
45
+ nil
46
+ end
47
+
48
+
49
+ def initialize(upload_url,
50
+ api_url,
51
+ creds,
52
+ optional)
53
+
54
+ @creds = creds
55
+ @upload_url = upload_url
56
+ @api_url = api_url
57
+ @subset_url = "#{@api_url}/subsets"
58
+ @subset_list_type = SUBSET_LIST_TYPE_LEAF_ID
59
+
60
+ if optional
61
+ @logger = optional[:logger]
62
+ @http_proxy = optional[:http_proxy] if optional[:http_proxy]
63
+ @user_agent = optional[:user_agent] if optional[:user_agent]
64
+ @http_headers = optional[:headers] if optional[:headers]
65
+ @subset_list_type = optional[SUBSET_LIST_TYPE_KEY] if optional[SUBSET_LIST_TYPE_KEY]
66
+ end
67
+ ldebug ("HTTP proxy is set to #{@http_proxy}")
68
+ end
69
+
70
+ def post_upload(original_params,
71
+ original_payload)
72
+
73
+ call_tapi('POST',
74
+ '/',
75
+ original_params,
76
+ original_payload,
77
+ do_upload: true)
78
+ end
79
+
80
+ def call_tapi_no_subset(original_method,
81
+ resource,
82
+ original_params,
83
+ original_payload,
84
+ extra)
85
+
86
+ ldebug ('Called no subset proxy')
87
+ call_tapi(original_method, resource, original_params, original_payload, extra, false)
88
+ end
89
+
90
+ def call_tapi(original_method,
91
+ resource,
92
+ original_params,
93
+ original_payload,
94
+ extra, use_subsets = true)
95
+
96
+ if (use_subsets && subset_resource = create_subset_route(resource))
97
+ ldebug "Doing subset call to #{subset_resource} (was : #{resource})"
98
+ response = do_subset_call("#{@api_url}/#{subset_resource}", params: original_params, method: original_method, payload: original_payload)
99
+ return {data: response, code: response.code}
100
+ else
101
+ if extra && extra[:do_upload]
102
+ url = @upload_url
103
+ else
104
+ url = "#{@api_url}/#{resource}"
105
+ end
106
+ client = default_rest_client(url, params: original_params, method: original_method, payload: original_payload)
107
+ response = client.execute
108
+ return {data: response, code: response.code}
109
+ end
110
+ rescue RestClient::ExceptionWithResponse => e
111
+ lerror nil, "Caught HTTP error when proxying call to tapi: #{e}"
112
+ return {data: e.response, error: e, code: e.response.code}
113
+ rescue Exception => e
114
+ lerror e, "Caught unexpected error when proxying call to tapi: #{e}"
115
+ return {data: e, error: e, code: 500}
116
+ end
117
+
118
+ def call_strata(original_method,
119
+ resource,
120
+ original_params,
121
+ original_payload,
122
+ _extra)
123
+
124
+ url = "#{@api_url}/#{resource}"
125
+ client = default_rest_client(url, params: original_params, method: original_method, payload: original_payload)
126
+ response = client.execute
127
+ return {data: response, code: response.code}
128
+ rescue RestClient::ExceptionWithResponse => e
129
+ lerror nil, "Caught HTTP error when proxying call to tapi: #{e}"
130
+ return {data: e.response, error: e, code: e.response.code}
131
+ rescue Exception => e
132
+ lerror e, "Caught unexpected error when proxying call to tapi: #{e}"
133
+ return {data: e, error: e, code: 500}
134
+ end
135
+
136
+ def get_machines
137
+ throw NotImplementedError
138
+ end
139
+
140
+ def get_branch_id
141
+ throw NotImplementedError
142
+ end
143
+
144
+ # Returns the machines hash used for /subset/$hash/
145
+ def get_hash(machines)
146
+ branch = get_branch_id
147
+ hash = Digest::SHA1.hexdigest(machines.join)
148
+ "#{branch}__#{hash}"
149
+ end
150
+
151
+ private
152
+
153
+ def ldebug(message)
154
+ @logger.debug "#{self.class.name}: #{message}" if @logger
155
+ end
156
+
157
+ def lerror(e, message)
158
+ if @logger
159
+ @logger.error ("#{self.class.name}: #{message}")
160
+ @logger.error (e.backtrace.join("\n")) if e
161
+ end
162
+ end
163
+
164
+ def do_subset_call(resource,
165
+ conf)
166
+ ldebug 'Doing subset call'
167
+ # Try subset
168
+ begin
169
+ ldebug "url: #{resource}"
170
+ client = default_rest_client resource, conf
171
+ response = client.execute
172
+ ldebug 'First subset call passed, CACHE_HIT'
173
+ ldebug(response.headers)
174
+ return response
175
+ rescue RestClient::ExceptionWithResponse => e
176
+
177
+ if e.response && e.response.code == 412
178
+ create_subset
179
+
180
+ # retry the original request
181
+ ldebug 'Subset creation passed calling newly created subset'
182
+ response = client.execute
183
+ return response
184
+ else
185
+ raise e
186
+ end
187
+ end
188
+ end
189
+
190
+
191
+ def create_subset
192
+ ldebug 'First subset call failed, CACHE_MISS'
193
+ subset_client = default_rest_client(@subset_url,
194
+ method: :post,
195
+ payload: {
196
+ hash: get_hash(get_machines),
197
+ branch_id: get_branch_id,
198
+ @subset_list_type => get_machines
199
+ }.to_json)
200
+ subset_client.execute
201
+ end
202
+
203
+
204
+ def default_rest_client(url, override_options)
205
+ opts = {
206
+ method: :get,
207
+ url: url
208
+ }
209
+ opts[:proxy] = @http_proxy unless @http_proxy.nil? || @http_proxy == ''
210
+ opts = opts.merge(get_auth_opts(@creds))
211
+ opts = opts.merge(override_options)
212
+ opts[:headers] = @http_headers if @http_headers
213
+ if override_options[:params]
214
+ opts[:url] = "#{url}?#{override_options[:params].to_query}"
215
+ override_options.delete(:params)
216
+ end
217
+ opts[:headers] = {} unless opts[:headers]
218
+ if opts[:headers]['content-type'].nil?
219
+ opts[:headers] = opts[:headers].merge('content-type' => 'application/json')
220
+ end
221
+ if opts[:headers]['accept'].nil?
222
+ opts[:headers] = opts[:headers].merge('accept' => 'application/json')
223
+ end
224
+ if @user_agent
225
+ opts[:headers] = opts[:headers].merge(user_agent: @user_agent)
226
+ end
227
+ RedHatSupportLib::Network::HttpRequest.new(opts)
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,24 @@
1
+ require 'open-uri'
2
+ module RedHatSupportLib
3
+ module Brokers
4
+ class Article < Broker
5
+ def initialize(connection)
6
+ super
7
+ end
8
+
9
+ def search(text, limit=10)
10
+ #TODO encode input and error handling
11
+ text = URI::encode(text)
12
+ result = @connection.get("/rs/articles?keyword=#{text}&limit=#{limit}", {:accept => :json})
13
+ result['article']
14
+ end
15
+
16
+ def get_article(id)
17
+ #TODO encode input and error handling
18
+ result = @connection.get("/rs/articles/#{id}", {:accept => :json})
19
+ #result.parsed_response
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,81 @@
1
+ require 'pathname'
2
+ require_relative '../network/ftp_connection'
3
+
4
+ module RedHatSupportLib
5
+ module Brokers
6
+ class Attachment < Broker
7
+
8
+ def initialize(connection, comments_broker, attachments_config)
9
+ super(connection)
10
+ @comments_broker = comments_broker
11
+ @attachments_config = attachments_config
12
+ end
13
+
14
+ def list(case_number, start_date, end_date, filter=[])
15
+
16
+ uri = "/rs/cases/#{case_number}/attachments"
17
+ param = ''
18
+ if start_date
19
+ param = "?startDate=#{start_date}"
20
+ end
21
+ if end_date
22
+ if start_date
23
+ param = param + "&endDate=#{end_date}"
24
+ else
25
+ param = param + "?endDate=#{end_date}"
26
+ end
27
+ end
28
+ result = @connection.get(uri+param, {:accept => :json})
29
+ end
30
+
31
+
32
+ def get(case_number, attachment_uuid, file_name, dest_dir)
33
+ #TODO
34
+
35
+ end
36
+
37
+ def delete(case_number, attachment_uuid)
38
+
39
+ uri = "/rs/cases/#{case_number}/attachments/#{attachment_uuid}";
40
+ result = @connection.delete(uri)
41
+ end
42
+
43
+ def add(case_number, is_public, file_name, description)
44
+ #puts "Sending attachment for case "+ case_number
45
+ attachment_id = nil
46
+ File.open(file_name) do |file|
47
+ if file.size < @attachments_config[:max_http_size]
48
+ headers = {:description => description}
49
+ @connection.upload("/rs/cases/#{case_number}/attachments",
50
+ file, headers) do |code, headers|
51
+ if code == 201
52
+ location = headers[:location]
53
+ attachment_id = get_id(location)
54
+ else
55
+ #What to return here?
56
+ raise "Attachment failed " + code
57
+ end
58
+ end
59
+ else
60
+ ftp_connection = RedHatSupportLib::Network::FtpConnection.new(@attachments_config[:ftp_host])
61
+ ftp_connection.upload(file_name,
62
+ @attachments_config[:ftp_remote_dir])
63
+ comment = StringIO.new
64
+ comment << "The file #{file_name} exceeds the byte limit to attach a file to a case;"
65
+ comment << " Therefore, the file was uploaded to"
66
+ comment << " #{@attachments_config[:ftp_host]} as #{File.basename(file_name)}"
67
+ @comments_broker.add(comment.string, case_number, false, is_public)
68
+ #TODO what to return here?
69
+ end
70
+ end
71
+ attachment_id
72
+ end
73
+
74
+ def get_id(uri)
75
+ parts = uri.split("/")
76
+ parts.pop
77
+ end
78
+
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,16 @@
1
+ module RedHatSupportLib
2
+ module Brokers
3
+ class Broker
4
+ attr_accessor :connection
5
+
6
+ def initialize (connection)
7
+ @connection = connection
8
+ end
9
+
10
+ def get_id(uri)
11
+ parts = uri.split("/")
12
+ parts.pop
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,145 @@
1
+ module RedHatSupportLib
2
+ module Brokers
3
+ class Case < Broker
4
+ def initialize(connection)
5
+ super
6
+ end
7
+
8
+ def list(keywords, include_closed, detail, group, start_date, end_date,
9
+ count, start, kwargs)
10
+ headers = {:content_type => 'application/xml', :accept => :json}
11
+ param =""
12
+ if detail
13
+ param = "?detail=true"
14
+ end
15
+ filter = self.create_filter(keywords, include_closed,
16
+ group, start_date,
17
+ end_date, count, start,
18
+ @connection.config.username)
19
+ result = @connection.post("/rs/cases/filter#{param}", filter, headers)
20
+
21
+ end
22
+
23
+ def list_severities
24
+ result = @connection.get("/rs/values/case/severity", {:accept => :json})
25
+ list = result["value"].map do |item|
26
+ item["name"]
27
+ end
28
+ end
29
+
30
+ def list_case_types
31
+ result = @connection.get("/rs/values/case/types", {:accept => :json})
32
+ list = result["value"].map do |item|
33
+ item["name"]
34
+ end
35
+ end
36
+
37
+
38
+ def get(id)
39
+ result = @connection.get("/rs/cases/#{id}", {:accept => :json})
40
+ end
41
+
42
+ def create(product, version, summary, description, severity, folder_number=nil)
43
+
44
+ headers = {:content_type => 'application/xml'}
45
+ data = StringIO.new
46
+ data << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
47
+ data << "<tns:case xmlns:tns=\"http://www.redhat.com/gss/strata\"> "
48
+ data << "<tns:summary>#{summary}</tns:summary>"
49
+ data << "<tns:description>#{description}</tns:description>"
50
+ data << "<tns:product>#{product}</tns:product>"
51
+ data << "<tns:version>#{version}</tns:version>"
52
+ data << "<tns:severity>#{severity}</tns:severity>"
53
+ if folder_number
54
+ data << "<tns:folderNumber>#{folder_number}</tns:folderNumber>"
55
+ end
56
+ data << "</tns:case>"
57
+ result = @connection.post("/rs/cases", data.string, headers) do |code, headers|
58
+ if code == 201
59
+ return get_id(headers[:location])
60
+ end
61
+ end
62
+ end
63
+
64
+ def update(case_number, product, version, alternate_id, status, severity, type)
65
+ headers = {:content_type => 'application/xml'}
66
+ data = create_update_data(product, version, alternate_id, status, severity, type)
67
+ result = @connection.put("/rs/cases/#{case_number}", data, headers) do |code, headers|
68
+ if code == 202
69
+ return get case_number
70
+ end
71
+ end
72
+ end
73
+
74
+ def create_update_data(product, version, alternate_id, status, severity, type)
75
+ #for now use xml version
76
+ data = StringIO.new
77
+ data << "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
78
+ if alternate_id
79
+ data << "<case xmlns=\"http://www.redhat.com/gss/strata\" alternateId=\"#{alternate_id}\">"
80
+ else
81
+ data << "<case xmlns=\"http://www.redhat.com/gss/strata\">"
82
+ end
83
+ if product
84
+ data << "<product>#{product}</product>"
85
+ end
86
+ if version
87
+ data << "<version>#{version}</version>"
88
+ end
89
+ if status
90
+ data << "<status>#{status}</status>"
91
+ end
92
+ if severity
93
+ data << "<severity>#{severity}</severity>"
94
+ end
95
+ if type
96
+ data << "<type>#{type}</type>"
97
+ end
98
+ data << "</case>"
99
+ return data.string
100
+ end
101
+
102
+ def create_filter(keywords, include_closed, group, start_date, end_date,
103
+ count, start, owner_sso_name)
104
+ #for now use xml version
105
+ filter = StringIO.new
106
+ filter << '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'
107
+ filter << '<caseFilter xmlns="http://www.redhat.com/gss/strata">'
108
+ if keywords
109
+ keywords.each do |keyword|
110
+ filter << "<keyword>#{keyword}</keyword>"
111
+ end
112
+ end
113
+ if include_closed
114
+ filter << "<includeClosed>true</includeClosed>"
115
+ end
116
+ if group.nil?
117
+ filter << "<onlyUngrouped>false</onlyUngrouped>"
118
+ else
119
+ filter << "<groupNumber>#{group}</groupNumber>"
120
+ end
121
+ if start_date
122
+ filter << "<startDate>#{start_date}</startDate>"
123
+ end
124
+ if end_date
125
+ filter << "<endDate>#{end_date}</endDate>"
126
+ end
127
+ if count
128
+ filter << "<count>#{count}</count>"
129
+ end
130
+ if start
131
+ filter << "<start>#{start}</start>"
132
+ end
133
+ filter << "<ownerSSOName>#{owner_sso_name}</ownerSSOName>"
134
+ filter << "</caseFilter>"
135
+ filter.string
136
+ end
137
+
138
+
139
+ end
140
+ # class CaseFilter
141
+ # attr_accessor :keywords, :include_closed, :detail,
142
+ # :group, :start_date, :end_date, :count, :start, :kwargs
143
+ # end
144
+ end
145
+ end