Merge pull request #1573 from coolo/use_attributes

Use attribute to store staging config
This commit is contained in:
Stephan Kulow 2018-06-19 06:38:32 +02:00 committed by GitHub
commit 67121e297e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 273 additions and 159 deletions

View File

@ -14,6 +14,7 @@ import yaml
import metrics_release
import osc.conf
import osc.core
from osc.core import HTTPError
from osc.core import get_commitlog
import osclib.conf
from osclib.cache import Cache
@ -351,10 +352,14 @@ def ingest_release_schedule(project):
def revision_index(api):
if not hasattr(revision_index, 'index'):
root = ET.fromstring(''.join(
get_commitlog(api.apiurl, api.cstaging, 'dashboard', None, format='xml')))
revision_index.index = {}
try:
root = ET.fromstring(''.join(
get_commitlog(api.apiurl, api.cstaging, 'dashboard', None, format='xml')))
except HTTPError as e:
return revision_index.index
for logentry in root.findall('logentry'):
date = date_parse(logentry.find('date').text)
revision_index.index[date] = logentry.get('revision')
@ -464,6 +469,74 @@ def ingest_dashboard_revision_get():
return None
def ingest_attributes(api):
url = api.makeurl(['source', api.project, '_project', '_history'], {'meta': 1})
root = ET.parse(osc.core.http_GET(url))
points = []
count = 0
revision = 0
last_attribute_md5 = ''
last_values = {}
for rev in root.findall('./revision'):
revision = rev.get('rev')
time = datetime.utcfromtimestamp(float(rev.find('./time').text))
url = api.makeurl(['source', api.project, '_project'],
{'meta': 1, 'rev': revision})
root = ET.parse(osc.core.http_GET(url))
attribute = root.find('.//entry[@name="_attribute"]')
if attribute is None:
continue
attribute_md5 = attribute.get('md5')
if attribute_md5 == last_attribute_md5:
continue
last_attribute_md5 = attribute_md5
url = api.makeurl(['source', api.project, '_project', '_attribute'],
{'meta': 1, 'rev': revision})
root = ET.parse(osc.core.http_GET(url))
#print revision, time, ET.tostring(root)
for v in root.findall('.//attribute[@namespace="OSRT"]'):
attribute_name = v.get('name')
last_values.setdefault(attribute_name, None)
if last_values[attribute_name] == v.find('value').text:
continue
# TODO: no idea what fields to make
fields = {revision: revision }
points.append({
'measurement': 'attribute_osrt_{}'.format(attribute_name),
'fields': fields,
'time': time,
})
points.append({
'measurement': 'project_meta_revision',
'fields': {
'revision': revision,
},
'time': time,
})
if len(points) >= 1000:
client.write_points(points, 's')
count += len(points)
points = []
if len(points):
client.write_points(points, 's')
count += len(points)
print('last revision processed: {}'.format(revision))
return count
def ingest_dashboard(api):
index = revision_index(api)
@ -478,7 +551,9 @@ def ingest_dashboard(api):
count = 0
points = []
max_revision = 0
for made, revision in sorted(index.items()):
max_revision = revision
if not past:
if revision == revision_last:
past = True
@ -516,7 +591,7 @@ def ingest_dashboard(api):
client.write_points(points, 's')
count += len(points)
print('last revision processed: {}'.format(revision))
print('last revision processed: {}'.format(max_revision))
return count
@ -544,9 +619,11 @@ def main(args):
Cache.PATTERNS['/source/[^/]+/dashboard/[^/]+\?rev=.*'] = sys.maxint
Cache.init()
Config(args.project)
c = Config(args.project)
api = StagingAPI(osc.conf.config['apiurl'], args.project)
c.apply_remote(api)
print('attributes: wrote {:,} points'.format(ingest_attributes(api)))
print('dashboard: wrote {:,} points'.format(ingest_dashboard(api)))
global who_workaround_swap, who_workaround_miss

View File

@ -422,10 +422,11 @@ def do_staging(self, subcmd, opts, *args):
if opts.wipe_cache:
Cache.delete_all()
api = StagingAPI(opts.apiurl, opts.project)
config.apply_remote(api)
needed = lock_needed(cmd, opts)
with OBSLock(opts.apiurl, opts.project, reason=cmd, needed=needed) as lock:
api = StagingAPI(opts.apiurl, opts.project)
config.apply_remote(api)
# call the respective command and parse args by need
if cmd == 'check':

View File

@ -90,6 +90,7 @@ class Cache(object):
'/source/([^/]+)/_meta$': TTL_LONG,
'/source/([^/]+)/(?:[^/]+)/(?:_meta|_link)$': TTL_LONG,
'/source/([^/]+)/dashboard/[^/]+': TTL_LONG,
'/source/([^/]+)/_attribute/[^/]+': TTL_MEDIUM,
# Handles clearing local cache on package deletes. Lots of queries like
# updating project info, comment, and package additions.
'/source/([^/]+)/(?:[^/?]+)(?:\?[^/]+)?$': TTL_LONG,

View File

@ -14,6 +14,8 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from __future__ import print_function
from ConfigParser import ConfigParser
from collections import OrderedDict
import io
@ -103,48 +105,6 @@ DEFAULT = {
'mail-noreply': 'noreply@opensuse.org',
'mail-release-list': 'opensuse-releaseteam@opensuse.org',
},
r'SUSE:(?P<project>SLE-15.*$)': {
'staging': 'SUSE:%(project)s:Staging',
'staging-group': 'sle-staging-managers', # '%(project.lower)s-staging',
'staging-archs': 'i586 x86_64',
'staging-dvd-archs': '',
'rings': 'SUSE:%(project)s:Rings',
'nonfree': None,
'rebuild': None,
'product': None,
'openqa': None,
'lock': 'SUSE:%(project)s:Staging',
'lock-ns': 'SUSE',
'leaper-override-group': 'sle-release-managers',
'delreq-review': None,
'main-repo': 'standard',
# check_source.py
'check-source-in-air-rename-allow': 'True',
'repo-checker': 'repo-checker',
'repo_checker-package-comment-devel': '',
'pkglistgen-archs': 'x86_64',
'pkglistgen-ignore-unresolvable': '1',
'pkglistgen-ignore-recommended': '1',
'pkglistgen-product-family-last': 'SUSE:SLE-11:GA',
},
r'SUSE:(?P<project>.*$)': {
'staging': 'SUSE:%(project)s:Staging',
'staging-group': 'sle-staging-managers', # '%(project.lower)s-staging',
'staging-archs': 'i586 x86_64',
'staging-dvd-archs': '',
'nocleanup-packages': 'Test-DVD-x86_64 sles-release',
'rings': None,
'nonfree': None,
'rebuild': None,
'product': None,
'openqa': None,
'lock': 'SUSE:%(project)s:Staging',
'lock-ns': 'SUSE',
'remote-config': False,
'delreq-review': None,
'main-repo': 'standard',
'priority': '100', # Lower than SLE-15 since less specific.
},
# Allows devel projects to utilize tools that require config, but not
# complete StagingAPI support.
r'(?P<project>.*$)': {
@ -161,7 +121,6 @@ DEFAULT = {
'lock-ns': None,
'delreq-review': None,
'main-repo': 'openSUSE_Factory',
'remote-config': False,
'priority': '1000', # Lowest priority as only a fallback.
},
}
@ -244,18 +203,32 @@ class Config(object):
else:
return defaults
def _migrate_staging_config(self, api):
# first try staging project's dashboard. Can't rely on cstaging as it's
# defined by config
config = api.load_file_content(self.project + ':Staging', 'dashboard', 'config')
if not config:
config = api.load_file_content(self.project, 'dashboard', 'config')
if not config:
return None
print("Found config in staging dashboard - migrate now [y/n] (y)? ", end='')
response = raw_input().lower()
if response != '' and response != 'y':
return config
api.attribute_value_save('Config', config)
def apply_remote(self, api):
"""Fetch remote config and re-process (defaults, remote, .oscrc)."""
if not conf.config[self.project].get('remote-config', True):
return
config = api.dashboard_content_load('config')
config = api.attribute_value_load('Config')
if not config:
# try the old way
config = self._migrate_staging_config(api)
if config:
cp = ConfigParser()
config = '[remote]\n' + config
cp.readfp(io.BytesIO(config))
self.remote_values = dict(cp.items('remote'))
self.populate_conf()
elif config is None:
# Write empty config to allow for caching.
api.dashboard_content_save('config', '')

View File

@ -74,7 +74,7 @@ class OBSLock(object):
return signature
def _write(self, signature):
url = makeurl(self.apiurl, ['source', self.lock, '_attribute', '%s:LockedBy' % self.ns])
url = makeurl(self.apiurl, ['source', self.lock, '_attribute'])
data = """
<attributes>
<attribute namespace='%s' name='LockedBy'>

View File

@ -20,7 +20,12 @@ import dateutil.parser
import json
import logging
import textwrap
import urllib2
try:
from urllib.error import HTTPError, URLError
except ImportError:
#python 2.x
from urllib2 import HTTPError, URLError
import time
import re
from lxml import etree as ET
@ -154,7 +159,7 @@ class StagingAPI(object):
if data is not None:
return func(url, data=data)
return func(url)
except urllib2.HTTPError as e:
except HTTPError as e:
if 500 <= e.code <= 599:
print 'Error {}, retrying {} in {}s'.format(e.code, url, retry_sleep_seconds)
time.sleep(retry_sleep_seconds)
@ -292,7 +297,7 @@ class StagingAPI(object):
content = http_GET(url)
for entry in ET.parse(content).getroot().findall('entry'):
filelist.append(entry.attrib['name'])
except urllib2.HTTPError as err:
except HTTPError as err:
if err.code == 404:
# The package we were supposed to query does not exist
# we can pass this up and return the empty filelist
@ -389,7 +394,7 @@ class StagingAPI(object):
try:
url = self.makeurl(['source', prj, '_project', '_frozenlinks'], {'meta': '1'})
root = ET.parse(http_GET(url)).getroot()
except urllib2.HTTPError as e:
except HTTPError as e:
if e.code == 404:
return None
meta = self.get_prj_pseudometa(prj)
@ -470,7 +475,7 @@ class StagingAPI(object):
url = makeurl(self.apiurl, ('source', project, package), query=query)
try:
return ET.parse(http_GET(url)).getroot()
except (urllib2.HTTPError, urllib2.URLError):
except (HTTPError, URLError):
return None
def source_info_request(self, request):
@ -524,7 +529,7 @@ class StagingAPI(object):
replace_old = request_old.find('state').get('name') in ['revoked', 'superseded']
if (request_new.find('action').get('type') == 'delete' and
request_old.find('action').get('type') == 'delete'):
request_old.find('action').get('type') == 'delete'):
# Both delete requests.
if replace_old:
# Pointless since identical requests, but user desires.
@ -534,11 +539,11 @@ class StagingAPI(object):
message = 'sr#{} is an identical delete and is already staged'.format(
request_old.get('id'))
self.do_change_review_state(request_id, 'declined',
by_group=self.cstaging_group, message=message)
by_group=self.cstaging_group, message=message)
return stage_info, True
if (request_new.find('action').get('type') !=
request_old.find('action').get('type')):
request_old.find('action').get('type')):
# One delete and one submit.
if replace_old:
if self.ring_packages.get(target_package):
@ -554,7 +559,7 @@ class StagingAPI(object):
message = 'sr#{} of a different type should be revoked first'.format(
request_old.get('id'))
self.do_change_review_state(request_id, 'declined',
by_group=self.cstaging_group, message=message)
by_group=self.cstaging_group, message=message)
return stage_info, True
# If both submits are from different source projects then check
@ -578,7 +583,7 @@ class StagingAPI(object):
if source_same:
# Keep the original request and decline this identical one.
self.do_change_review_state(request_id, 'declined',
by_group=self.cstaging_group, message=message)
by_group=self.cstaging_group, message=message)
else:
# Ingore the new request pending manual review.
IgnoreCommand(self).perform([str(request_id)], message)
@ -851,7 +856,8 @@ class StagingAPI(object):
if self._supersede:
self.is_package_disabled(sub_prj, sub_pkg, store=True)
# Skip inner-project links for letter staging
if not self.is_adi_project(project) and sub_prj == project: continue
if not self.is_adi_project(project) and sub_prj == project:
continue
delete_package(self.apiurl, sub_prj, sub_pkg, force=True, msg=msg)
# Delete the main package in the last
@ -957,9 +963,9 @@ class StagingAPI(object):
# to protect us against control characters
import string
all_bytes = string.maketrans('', '')
remove_bytes = all_bytes[:8] + all_bytes[14:32] # accept tabs and newlines
remove_bytes = all_bytes[:8] + all_bytes[14:32] # accept tabs and newlines
query = {'nostream' : '1', 'start' : '%s' % offset}
query = {'nostream': '1', 'start': '%s' % offset}
if last:
query['last'] = 1
log = StringIO()
@ -1255,13 +1261,14 @@ class StagingAPI(object):
# dynamically generated and static baselibs.conf.
baselibs = False if self.is_adi_project(project) else None
if baselibs is False and 'baselibs.conf' in str(self.load_file_content(
src_prj, src_pkg, '{}.spec'.format(src_pkg), src_rev)):
src_prj, src_pkg, '{}.spec'.format(src_pkg), src_rev)):
baselibs = True
for sub_prj, sub_pkg in self.get_sub_packages(tar_pkg, project):
sub_prj = self.map_ring_package_to_subject(project, sub_pkg)
# Skip inner-project links for letter staging
if not self.is_adi_project(project) and sub_prj == project: continue
if not self.is_adi_project(project) and sub_prj == project:
continue
if self._supersede:
disable_build = self._package_disabled.get('/'.join([sub_prj, sub_pkg]), False)
self.create_package_container(sub_prj, sub_pkg, disable_build=disable_build)
@ -1271,7 +1278,7 @@ class StagingAPI(object):
http_PUT(url, data=ET.tostring(root))
if baselibs is False and 'baselibs.conf' in str(self.load_file_content(
src_prj, src_pkg, '{}.spec'.format(sub_pkg), src_rev)):
src_prj, src_pkg, '{}.spec'.format(sub_pkg), src_rev)):
baselibs = True
if baselibs:
@ -1462,7 +1469,7 @@ class StagingAPI(object):
url = self.makeurl(['source', project, '_meta'])
try:
http_GET(url)
except urllib2.HTTPError:
except HTTPError:
return False
return True
@ -1494,7 +1501,7 @@ class StagingAPI(object):
url = self.makeurl(['build', project, repository, arch, '_repository', "%s?view=fileinfo" % rpm])
try:
return ET.parse(http_GET(url)).getroot().find('version').text
except urllib2.HTTPError as e:
except HTTPError as e:
if e.code == 404:
return None
raise
@ -1530,6 +1537,36 @@ class StagingAPI(object):
if content != self.dashboard_content_load(filename):
self.dashboard_content_save(filename, content, comment)
def attribute_value_load(self, attribute):
url = self.makeurl(['source', self.project, '_attribute', 'OSRT:' + attribute])
try:
f = self.retried_GET(url)
except HTTPError as e:
if e.code == 404:
return None
raise e
root = ET.parse(f).getroot()
root = root.find('./attribute/value')
if root is None:
return None
return root.text
# to create a new attribute 'type' you need to do some manual step
# create a xml file analoge to what
# osc api /attribute/OSRT/IgnoredIssues/_meta outputs
# you need to think about roles, groups and users that should be
# able to write the attribute
# after that osc api -T $xml /attribute/OSRT/$NEWATTRIBUTE/_meta
# (preferably do this right away for ibs and obs)
def attribute_value_save(self, attribute, text):
root = ET.fromstring('<attributes><attribute name="" namespace="OSRT">' +
'<value/></attribute></attributes>')
root.find('./attribute').set('name', attribute)
root.find('./attribute/value').text = text
# the OBS API of attributes is super strange, you POST updates
url = self.makeurl(['source', self.project, '_attribute'])
self.retried_POST(url, data=ET.tostring(root))
def update_status_or_deactivate(self, project, command):
meta = self.get_prj_pseudometa(project)
if len(meta['requests']) == 0:
@ -1573,7 +1610,7 @@ class StagingAPI(object):
len(requests_old) - len(requests_common),
command
))
lines.append('') # Blank line.
lines.append('') # Blank line.
requests = []
for req in meta['requests']:
@ -1594,7 +1631,7 @@ class StagingAPI(object):
dashboard_url = '{}/project/staging_projects/{}/{}'.format(
self.apiurl, self.project, self.extract_staging_short(project))
lines.append('Requests ([dashboard]({})):'.format(dashboard_url))
lines.append('') # Blank line.
lines.append('') # Blank line.
requests = meta['requests']
@ -1686,7 +1723,6 @@ class StagingAPI(object):
except:
print "could not trigger rebuild for project '%s' package '%s'" % (prj, pkg)
def _candidate_adi_project(self):
"""Decide a candidate name for an ADI project."""
adi_projects = self.get_adi_projects()

View File

@ -27,12 +27,16 @@ class TestConfig(unittest.TestCase):
self.assertEqual('local', conf.config[PROJECT]['overridden-by-local'])
self.assertEqual('remote-indeed', conf.config[PROJECT]['remote-only'])
def test_remote_none(self):
self.api.dashboard_content_save('config', '')
self.assertEqual(self.obs.dashboard_counts['config'], 1)
self.api.attribute_value_save('Config', 'remote-only = nope')
self.config.apply_remote(self.api)
self.assertEqual('local', conf.config[PROJECT]['overridden-by-local'])
self.assertEqual('nope', conf.config[PROJECT]['remote-only'])
def test_remote_none(self):
self.api.attribute_value_save('Config', '')
# don't crash
self.config.apply_remote(self.api)
# Ensure blank file not overridden.
self.assertEqual(self.obs.dashboard_counts['config'], 1)
def test_pattern_order(self):
# Add pattern to defaults in order to identify which was matched.

View File

@ -1,2 +0,0 @@
overridden-by-local = remote-nope
remote-only = remote-indeed

View File

@ -14,6 +14,8 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from __future__ import print_function
from datetime import datetime, timedelta
import os
import re
@ -53,9 +55,11 @@ def router_handler(route_table, method, request, uri, headers):
uri_parsed = urlparse.urlparse(uri)
for path, fn in route_table:
match = False
if isinstance(path, basestring) and uri_parsed.path == path:
if not isinstance(path, str):
print(path.pattern)
if isinstance(path, str) and uri_parsed.path == path:
match = True
elif not isinstance(path, basestring) and path.search(uri_parsed.path):
elif not isinstance(path, str) and path.search(uri_parsed.path):
match = True
if match:
return fn(request, uri, headers)
@ -141,7 +145,6 @@ class OBS(object):
# build the responses. We will try to put responses as XML
# templates in the fixture directory.
self.dashboard = {}
self.dashboard_counts = {}
self.requests = {
'123': {
@ -229,7 +232,7 @@ class OBS(object):
'project': 'openSUSE:Factory:Staging:C',
'title': 'A project ready to be accepted',
'description': ('requests:\n- {id: 501, package: apparmor, author: Admin, type: submit}\n'
'- {id: 502, package: mariadb, author: Admin, type: submit}'),
'- {id: 502, package: mariadb, author: Admin, type: submit}'),
},
'J': {
'project': 'openSUSE:Factory:Staging:J',
@ -267,7 +270,14 @@ class OBS(object):
},
}
self.lock = None
self.attributes = {
'openSUSE:Factory': {
'OSRT': {
'Config': 'overridden-by-local = remote-nope\n'
'remote-only = remote-indeed'
}
}
}
self.meta = {}
@ -408,10 +418,10 @@ class OBS(object):
response = (200, headers, template.substitute(self.requests[request_id]))
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'REQUEST', uri, response
print('REQUEST', uri, response)
return response
@ -448,10 +458,10 @@ class OBS(object):
response = (200, headers, self._request(request_id))
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'REVIEW REQUEST', uri, response
print('REVIEW REQUEST', uri, response)
return response
@ -479,10 +489,10 @@ class OBS(object):
response = (200, headers, result)
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'SEARCH REQUEST', uri, response
print('SEARCH REQUEST', uri, response)
return response
@ -490,30 +500,52 @@ class OBS(object):
# /source/
#
@GET(re.compile(r'/source/openSUSE:Factory:Staging/_attribute/openSUSE:LockedBy'))
def source_staging_lock(self, request, uri, headers):
"""Return staging lock."""
response = (404, headers, '<result>Not found</result>')
try:
lock = self.lock if self.lock else self._fixture(uri)
response = (200, headers, lock)
except Exception as e:
if DEBUG:
print uri, e
@GET(re.compile(r'/source/[\w:]+/_attribute/[\w:]+$'))
def source_attribute(self, request, uri, headers):
"""Return attribute."""
match = re.search(r'/source/([\w:]+)/_attribute/(\w+):(\w+)$', uri)
project = match.group(1)
ns = match.group(2)
name = match.group(3)
# never returns 404 - unless the project does not exist,
# which we can't (and don't need) to model
response = (200, headers, '<attributes/>')
print(self.attributes, project, ns, name)
if not project in self.attributes:
return response
hash = self.attributes[project]
if not ns in hash and not name in hash[ns]:
return response
root = ET.fromstring('<attributes><attribute name="" namespace="">' +
'<value/></attribute></attributes>')
root.find('./attribute').set('name', name)
root.find('./attribute').set('namespace', ns)
root.find('./attribute/value').text = hash[ns][name]
response = (200, headers, ET.tostring(root))
if DEBUG:
print 'STAGING LOCK', uri, response
print('GET ATTRIBUTE', uri, response)
return response
@POST(re.compile(r'/source/openSUSE:Factory:Staging/_attribute/openSUSE:LockedBy'))
def source_staging_lock_put(self, request, uri, headers):
"""Set the staging lock."""
self.lock = request.body
response = (200, headers, self.lock)
@POST(re.compile(r'/source/[\w:]+/_attribute$'))
def source_attribute_post(self, request, uri, headers):
"""Set an attribute"""
project = re.search(r'/source/([\w:]+)/_attribute', uri).group(1)
_attrib = ET.fromstring(request.body).find('./attribute')
hash = self.attributes.setdefault(project, {})
hash = hash.setdefault(_attrib.get('namespace'), {})
text = _attrib.find('./value').text
hash[_attrib.get('name')] = text or ''
response = (200, headers, request.body)
if DEBUG:
print 'PUT STAGING LOCK', uri, response
print('PUT ATTRIBUTE', uri, response)
return response
@ -527,10 +559,10 @@ class OBS(object):
response = (200, headers, contents)
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'STAGING DASHBOARD FILE', uri, response
print('STAGING DASHBOARD FILE', uri, response)
return response
@ -539,11 +571,10 @@ class OBS(object):
"""Set the staging dashboard file contents."""
filename = re.search(r'/source/[\w:]+/\w+/(\w+)', uri).group(1)
self.dashboard[filename] = request.body
self.dashboard_counts[filename] = self.dashboard_counts.get(filename, 0) + 1
response = (200, headers, request.body)
if DEBUG:
print 'PUT STAGING DASHBOARD FILE', uri, response
print('PUT STAGING DASHBOARD FILE', uri, response)
return response
@ -565,10 +596,10 @@ class OBS(object):
response = (200, headers, history)
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'STAGING PROJECT _history META', uri, response
print('STAGING PROJECT _history META', uri, response)
return response
@ -592,10 +623,10 @@ class OBS(object):
response = (200, headers, meta)
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'STAGING PROJECT _project _meta', uri, response
print('STAGING PROJECT _project _meta', uri, response)
return response
@ -614,10 +645,10 @@ class OBS(object):
response = (200, headers, project)
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'STAGING PROJECT _PROJECT', uri, response
print('STAGING PROJECT _PROJECT', uri, response)
return response
@ -636,10 +667,10 @@ class OBS(object):
response = (200, headers, meta)
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'STAGING PROJECT [PACKAGE] _META', uri, response
print('STAGING PROJECT [PACKAGE] _META', uri, response)
return response
@ -654,7 +685,7 @@ class OBS(object):
response = (200, headers, meta)
if DEBUG:
print 'PUT STAGING PROJECT [PACKAGE] _META', uri, response
print('PUT STAGING PROJECT [PACKAGE] _META', uri, response)
return response
@ -668,10 +699,10 @@ class OBS(object):
response = (200, headers, template.substitute(self.links[package]))
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'SOURCE WINE', uri, response
print('SOURCE WINE', uri, response)
return response
@ -685,10 +716,10 @@ class OBS(object):
response = (200, headers, '<result>Ok</result>')
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'DELETE', uri, response
print('DELETE', uri, response)
return response
@ -709,10 +740,10 @@ class OBS(object):
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'SOURCE APPARMOR', uri, response
print('SOURCE APPARMOR', uri, response)
return response
@ -732,10 +763,10 @@ class OBS(object):
response = (200, headers, template.substitute(self.package[index]))
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'SOURCE HOME:ADMIN', package, uri, response
print('SOURCE HOME:ADMIN', package, uri, response)
return response
@ -753,10 +784,10 @@ class OBS(object):
response = (200, headers, template.substitute(self.links[project_package]))
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'SOURCE HOME:ADMIN WINE', uri, response
print('SOURCE HOME:ADMIN WINE', uri, response)
return response
@ -777,10 +808,10 @@ class OBS(object):
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'PUT SOURCE WINE _LINK', uri, response
print('PUT SOURCE WINE _LINK', uri, response)
return response
@ -828,10 +859,10 @@ class OBS(object):
response = (200, headers, result)
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'SEARCH PROJECT ID', uri, response
print('SEARCH PROJECT ID', uri, response)
return response
@ -867,10 +898,10 @@ class OBS(object):
response = (200, headers, result)
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'SEARCH REQUEST', uri, response
print('SEARCH REQUEST', uri, response)
return response
@ -900,10 +931,10 @@ class OBS(object):
response = (200, headers, result)
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'SEARCH REQUEST', uri, response
print('SEARCH REQUEST', uri, response)
return response
@ -968,10 +999,10 @@ class OBS(object):
}))
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'REQUEST', uri, response
print('REQUEST', uri, response)
return response
@ -987,10 +1018,10 @@ class OBS(object):
response = (200, headers, self._fixture(uri))
except Exception as e:
if DEBUG:
print uri, e
print(uri, e)
if DEBUG:
print 'DEFAULT', uri, response
print('DEFAULT', uri, response)
return response

View File

@ -71,12 +71,9 @@ class ToTestBase(object):
self.amqp_url = osc.conf.config.get('ttm_amqp_url')
def load_issues_to_ignore(self):
url = self.api.makeurl(['source', self.project, '_attribute', 'OSRT:IgnoredIssues'])
f = self.api.retried_GET(url)
root = ET.parse(f).getroot()
root = root.find('./attribute/value')
if root is not None:
root = yaml.load(root.text)
text = self.api.attribute_value_load('IgnoredIssues')
if text:
root = yaml.load(text)
self.issues_to_ignore = root.get('last_seen')
else:
self.issues_to_ignore = dict()
@ -85,11 +82,7 @@ class ToTestBase(object):
if self.dryrun:
return
text = yaml.dump({'last_seen': self.issues_to_ignore}, default_flow_style=False)
root = ET.fromstring('<attributes><attribute name="IgnoredIssues" namespace="OSRT">' +
'<value/></attribute></attributes>')
root.find('./attribute/value').text = text
url = self.api.makeurl(['source', self.project, '_attribute'])
self.api.retried_POST(url, data=ET.tostring(root))
self.api.attribute_value_save('IgnoredIssues', text)
def openqa_group(self):
return self.project