redhat_access_lib 1.0.6

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.
@@ -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