예제 #1
0
    def cleanup(self, project):
        if not self.api.item_exists(project):
            return False

        pkglist = self.api.list_packages(project)
        clean_list = set(pkglist) - set(self.api.cstaging_nocleanup)

        for package in clean_list:
            print "[cleanup] deleted %s/%s" % (project, package)
            delete_package(self.api.apiurl, project, package, force=True, msg="autocleanup")

        # wipe Test-DVD binaries and breaks kiwi build
        if project.startswith('openSUSE:'):
            for package in pkglist:
                if package.startswith('Test-DVD-'):
                    # intend to break the kiwi file
                    arch = package.split('-')[-1]
                    fakepkgname = 'I-am-breaks-kiwi-build'
                    oldkiwifile = self.api.load_file_content(project, package, 'PRODUCT-'+arch+'.kiwi')
                    if oldkiwifile is not None:
                        newkiwifile = re.sub(r'<repopackage name="openSUSE-release"/>', '<repopackage name="%s"/>' % fakepkgname, oldkiwifile)
                        self.api.save_file_content(project, package, 'PRODUCT-' + arch + '.kiwi', newkiwifile)

                    # do wipe binary now
                    query = { 'cmd': 'wipe' }
                    query['package'] = package
                    query['repository'] = 'images'

                    url = self.api.makeurl(['build', project], query)
                    try:
                        http_POST(url)
                    except urllib2.HTTPError, err:
                        # failed to wipe isos but we can just continue
                        pass
예제 #2
0
    def add_review(self, request_id, by_project=None, by_group=None, msg=None):
        """
        Adds review by project to the request
        :param request_id: request to add review to
        :param project: project to assign review to
        """
        req = get_request(self.apiurl, str(request_id))
        if not req:
            raise oscerr.WrongArgs('Request {} not found'.format(request_id))
        for i in req.reviews:
            if by_project and i.by_project == by_project and i.state == 'new':
                return
            if by_group and i.by_group == by_group and i.state == 'new':
                return

        # don't try to change reviews if the request is dead
        if req.state.name not in ('new', 'review'):
            return

        query = {}
        if by_project:
            query['by_project'] = by_project
            if not msg:
                msg = 'Being evaluated by staging project "{}"'
                msg = msg.format(by_project)
        if by_group:
            query['by_group'] = by_group
            if not msg:
                msg = 'Being evaluated by group "{}"'.format(by_group)
        if not query:
            raise oscerr.WrongArgs('We need a group or a project')
        query['cmd'] = 'addreview'
        url = self.makeurl(['request', str(request_id)], query)
        http_POST(url, data=msg)
예제 #3
0
    def update_staging_status(self, staging):
        openqa_infos = dict()
        for iso in self.staging_projects[staging]['isos']:
            self.fetch_openqa_jobs(staging, iso, openqa_infos)

        buildid = self.staging_projects[staging].get('id')
        if not buildid:
            self.logger.info("I don't know the build id of " + staging)
            return
        # all openQA jobs are created at the same URL
        url = self.api.makeurl(['status_reports', 'published', staging, 'images', 'reports', buildid])

        # make sure the names are unique
        taken_names = dict()
        for id in openqa_infos:
            name = openqa_infos[id]['name']
            if name in taken_names:
                openqa_infos[id]['name'] = openqa_infos[id]['name'] + "@" + openqa_infos[id]['machine']
                # the other id
                oid = taken_names[name]
                openqa_infos[oid]['name'] = openqa_infos[oid]['name'] + "@" + openqa_infos[oid]['machine']
                if openqa_infos[id]['name'] == openqa_infos[oid]['name']:
                    raise Exception(f'Names of job #{id} and #{oid} collide')
            taken_names[name] = id

        for info in openqa_infos.values():
            xml = self.openqa_check_xml(info['url'], info['state'], 'openqa:' + info['name'])
            try:
                http_POST(url, data=xml)
            except HTTPError:
                self.logger.error('failed to post status to ' + url)
예제 #4
0
    def add_review(self, request_id, by_project=None, by_group=None, msg=None):
        """
        Adds review by project to the request
        :param request_id: request to add review to
        :param project: project to assign review to
        """
        req = get_request(self.apiurl, str(request_id))
        if not req:
            raise oscerr.WrongArgs('Request {} not found'.format(request_id))
        for i in req.reviews:
            if by_project and i.by_project == by_project and i.state == 'new':
                return
            if by_group and i.by_group == by_group and i.state == 'new':
                return

        # don't try to change reviews if the request is dead
        if req.state.name not in ('new', 'review'):
            return

        query = {}
        if by_project:
            query['by_project'] = by_project
            if not msg:
                msg = 'Being evaluated by staging project "{}"'
                msg = msg.format(by_project)
        if by_group:
            query['by_group'] = by_group
            if not msg:
                msg = 'Being evaluated by group "{}"'.format(by_group)
        if not query:
            raise oscerr.WrongArgs('We need a group or a project')
        query['cmd'] = 'addreview'
        url = self.makeurl(['request', str(request_id)], query)
        http_POST(url, data=msg)
예제 #5
0
    def fetch_openqa_jobs(self, staging, iso):
        buildid = self.staging_projects[staging].get('id')
        if not buildid:
            self.logger.info("I don't know the build id of " + staging)
            return
        # all openQA jobs are created at the same URL
        url = self.api.makeurl(['status_reports', 'published', staging, 'images', 'reports', buildid])
        openqa = self.listener.jobs_for_iso(iso)
        # collect job infos to pick names
        openqa_infos = dict()
        for job in openqa:
            print(staging, iso, job['id'], job['state'], job['result'],
                  job['settings']['MACHINE'], job['settings']['TEST'])
            openqa_infos[job['id']] = {'url': self.listener.test_url(job)}
            openqa_infos[job['id']]['state'] = self.map_openqa_result(job)
            openqa_infos[job['id']]['name'] = job['settings']['TEST']
            openqa_infos[job['id']]['machine'] = job['settings']['MACHINE']

        # make sure the names are unique
        taken_names = dict()
        for id in openqa_infos:
            name = openqa_infos[id]['name']
            if name in taken_names:
                openqa_infos[id]['name'] = openqa_infos[id]['name'] + "@" + openqa_infos[id]['machine']
                # the other id
                id = taken_names[name]
                openqa_infos[id]['name'] = openqa_infos[id]['name'] + "@" + openqa_infos[id]['machine']
            taken_names[name] = id

        for info in openqa_infos.values():
            xml = self.openqa_check_xml(info['url'], info['state'], 'openqa:' + info['name'])
            try:
                http_POST(url, data=xml)
            except HTTPError:
                self.logger.error('failed to post status to ' + url)
예제 #6
0
 def _write(self, signature):
     url = makeurl(self.apiurl, ['source', self.lock, '_attribute'])
     data = """
     <attributes>
       <attribute namespace='%s' name='LockedBy'>
         <value>%s</value>
       </attribute>
     </attributes>""" % (self.ns, signature)
     http_POST(url, data=data)
예제 #7
0
 def _write(self, signature):
     url = makeurl(self.apiurl, ['source', self.lock, '_attribute', '%s:LockedBy' % self.ns])
     data = """
     <attributes>
       <attribute namespace='%s' name='LockedBy'>
         <value>%s</value>
       </attribute>
     </attributes>""" % (self.ns, signature)
     http_POST(url, data=data)
예제 #8
0
    def create_and_wipe_package(self, project, package):
        """
        Helper function for delete requests
        """
        # create build disabled package
        self.create_package_container(project, package, disable_build=True)

        # now trigger wipebinaries to emulate a delete
        url = self.makeurl(['build', project],
                           {'cmd': 'wipe', 'package': package})
        http_POST(url)
예제 #9
0
    def create_and_wipe_package(self, project, package):
        """
        Helper function for delete requests
        """
        # create build disabled package
        self.create_package_container(project, package, disable_build=True)

        # now trigger wipebinaries to emulate a delete
        url = self.makeurl(['build', project],
                           {'cmd': 'wipe', 'package': package})
        http_POST(url)
예제 #10
0
def attribute_value_save(apiurl, project, name, value, namespace='OSRT'):
    root = ET.Element('attributes')

    attribute = ET.SubElement(root, 'attribute')
    attribute.set('namespace', namespace)
    attribute.set('name', name)

    ET.SubElement(attribute, 'value').text = value

    # The OBS API of attributes is super strange, POST to update.
    url = makeurl(apiurl, ['source', project, '_attribute'])
    http_POST(url, data=ET.tostring(root))
예제 #11
0
def attribute_value_save(apiurl, project, name, value, namespace='OSRT'):
    root = ET.Element('attributes')

    attribute = ET.SubElement(root, 'attribute')
    attribute.set('namespace', namespace)
    attribute.set('name', name)

    ET.SubElement(attribute, 'value').text = value

    # The OBS API of attributes is super strange, POST to update.
    url = makeurl(apiurl, ['source', project, '_attribute'])
    http_POST(url, data=ET.tostring(root))
예제 #12
0
    def rebuild_pkg(self, package, prj, arch, code=None):
        query = {'cmd': 'rebuild', 'arch': arch}
        if package:
            query['package'] = package
        pkg = query['package']

        u = self.makeurl(['build', prj], query=query)

        try:
            print "tried to trigger rebuild for project '%s' package '%s'" % (
                prj, pkg)
            http_POST(u)
        except:
            print "could not trigger rebuild for project '%s' package '%s'" % (
                prj, pkg)
예제 #13
0
    def change_review_state(self, request_id, newstate, message=''):
        """Based on osc/osc/core.py. Fixed 'by_user'."""
        query = {
            'cmd': 'changereviewstate',
            'newstate': newstate,
            # XXX TODO - We force the user here, check if the user
            # expressed in .oscrc (with the password stored) have
            # rights to become this user.
            'by_user': '******',
        }

        review_state = self.get_review_state(request_id)
        if review_state == 'accepted' and newstate != 'accepted':
            print ' - Avoid change state %s -> %s (%s)' % (review_state, newstate, message)

        code = 404
        url = makeurl(self.apiurl, ('request', str(request_id)), query=query)
        if self.readonly:
            print 'DRY RUN: POST %s' % url
            return 200
        try:
            root = ET.parse(http_POST(url, data=message)).getroot()
            code = root.attrib['code']
        except urllib2.HTTPError, e:
            print('ERROR in URL %s [%s]' % (url, e))
예제 #14
0
    def rebuild_pkg(self, package, prj, arch, code=None):
        query = {
            'cmd': 'rebuild',
            'arch': arch
        }
        if package:
            query['package'] = package
        pkg = query['package']

        u = self.makeurl(['build', prj], query=query)

        try:
            print "tried to trigger rebuild for project '%s' package '%s'" % (prj, pkg)
            http_POST(u)
        except:
            print "could not trigger rebuild for project '%s' package '%s'" % (prj, pkg)
예제 #15
0
    def add_comment(self,
                    request_id=None,
                    project_name=None,
                    package_name=None,
                    comment=None,
                    parent_id=None):
        """Add a comment in an object in OBS.

        :param request_id: Request where to write a comment.
        :param project_name: Project name where to write a comment.
        :param package_name: Package name where to write a comment.
        :param comment: Comment to be published.
        :return: Comment id.
        """
        if not comment:
            raise ValueError('Empty comment.')

        comment = self.truncate(comment.strip())

        # OBS returns unicode from some APIs, but comment API does not accept
        # when included. Rather than handle everywhere just strip here.
        comment = comment.encode('ascii', 'ignore')

        query = {}
        if parent_id:
            query['parent_id'] = parent_id
        url = self._prepare_url(request_id, project_name, package_name, query)
        return http_POST(url, data=comment)
예제 #16
0
def _check_repo_change_review_state(self,
                                    opts,
                                    id_,
                                    newstate,
                                    message='',
                                    supersed=None):
    """Taken from osc/osc/core.py, improved:
       - verbose option added,
       - empty by_user=& removed.
       - numeric id can be int().
    """
    query = {
        'cmd': 'changereviewstate',
        'newstate': newstate,
        'by_user': '******',
    }
    if supersed:
        query['superseded_by'] = supersed
    # if message:
    #     query['comment'] = message

    code = 404
    u = makeurl(opts.apiurl, ['request', str(id_)], query=query)
    try:
        f = http_POST(u, data=message)
        root = ET.parse(f).getroot()
        code = root.attrib['code']
    except urllib2.HTTPError, e:
        print 'ERROR in URL %s [%s]' % (u, e)
예제 #17
0
    def change_review_state(self, request_id, newstate, message=''):
        """Based on osc/osc/core.py. Fixed 'by_user'."""
        query = {
            'cmd': 'changereviewstate',
            'newstate': newstate,
            # XXX TODO - We force the user here, check if the user
            # expressed in .oscrc (with the password stored) have
            # rights to become this user.
            'by_user': '******',
        }

        review_state = self.get_review_state(request_id)
        if review_state == 'accepted' and newstate != 'accepted':
            print ' - Avoid change state %s -> %s (%s)' % (review_state,
                                                           newstate, message)

        code = 404
        url = makeurl(self.apiurl, ('request', str(request_id)), query=query)
        if self.readonly:
            print 'DRY RUN: POST %s' % url
            return 200
        try:
            root = ET.parse(http_POST(url, data=message)).getroot()
            code = root.attrib['code']
        except urllib2.HTTPError, e:
            print('ERROR in URL %s [%s]' % (url, e))
예제 #18
0
    def cleanup(self, project):
        if not self.api.item_exists(project):
            return False

        pkglist = self.api.list_packages(project)
        clean_list = set(pkglist) - set(self.api.cnocleanup_packages)

        for package in clean_list:
            print("[cleanup] deleted %s/%s" % (project, package))
            delete_package(self.api.apiurl,
                           project,
                           package,
                           force=True,
                           msg="autocleanup")

        # wipe Test-DVD binaries and breaks kiwi build
        if project.startswith('openSUSE:'):
            for package in pkglist:
                if package.startswith('Test-DVD-'):
                    # intend to break the kiwi file
                    arch = package.split('-')[-1]
                    fakepkgname = 'I-am-breaks-kiwi-build'
                    oldkiwifile = source_file_load(self.api.apiurl, project,
                                                   package,
                                                   'PRODUCT-' + arch + '.kiwi')
                    if oldkiwifile is not None:
                        newkiwifile = re.sub(
                            r'<repopackage name="openSUSE-release"/>',
                            '<repopackage name="%s"/>' % fakepkgname,
                            oldkiwifile)
                        source_file_save(self.api.apiurl, project, package,
                                         'PRODUCT-' + arch + '.kiwi',
                                         newkiwifile)

                    # do wipe binary now
                    query = {'cmd': 'wipe'}
                    query['package'] = package
                    query['repository'] = 'images'

                    url = self.api.makeurl(['build', project], query)
                    try:
                        http_POST(url)
                    except HTTPError as err:
                        # failed to wipe isos but we can just continue
                        pass

        return True
예제 #19
0
 def retried_POST(self, url):
     try:
         return http_POST(url)
     except urllib2.HTTPError, e:
         if e.code == 504:
             print 'Timeout on {}'.format(url)
             return '<status code="timeout"/>'
         if e.code / 100 == 5:
             print 'Retrying {}'.format(url)
             return self.retried_POST(url)
         raise e
예제 #20
0
 def retried_POST(self, url):
     try:
         return http_POST(url)
     except urllib2.HTTPError, e:
         if e.code == 504:
             print 'Timeout on {}'.format(url)
             return '<status code="timeout"/>'
         if e.code / 100 == 5:
             print 'Retrying {}'.format(url)
             return self.retried_POST(url)
         raise e
예제 #21
0
    def add_comment(self, request_id=None, project_name=None,
                    package_name=None, comment=None):
        """Add a comment in an object in OBS.

        :param request_id: Request where to write a comment.
        :param project_name: Project name where to write a comment.
        :param package_name: Package name where to write a comment.
        :param comment: Comment to be published.
        :return: Comment id.
        """
        if not comment:
            raise ValueError('Empty comment.')

        url = self._prepare_url(request_id, project_name, package_name)
        return http_POST(url, data=comment)
예제 #22
0
 def reqReview(self, reqid, user='', group='', msg=''):
     """ This method is called to add review msg to a request
         Success: return None
         Failed:  return string of error message
     """
     try:
         query = { 'cmd': 'addreview' }
         if user:
             query['by_user'] = user
         if group:
             query['by_group'] = group
         u = core.makeurl(self.apiurl, ['request', reqid], query=query)
         f = core.http_POST(u, data=msg)
         root = ElementTree.parse(f).getroot()
         root.get('code')
     except Exception, e:
         return str(e)
예제 #23
0
    def add_comment(self,
                    request_id=None,
                    project_name=None,
                    package_name=None,
                    comment=None):
        """Add a comment in an object in OBS.

        :param request_id: Request where to write a comment.
        :param project_name: Project name where to write a comment.
        :param package_name: Package name where to write a comment.
        :param comment: Comment to be published.
        :return: Comment id.
        """
        if not comment:
            raise ValueError('Empty comment.')

        url = self._prepare_url(request_id, project_name, package_name)
        return http_POST(url, data=comment)
예제 #24
0
    def get_sub_packages(self, pkg, project=None):
        """
        Returns a list of packages that need to be linked into rings
        too. A package is actually a tuple of project and package name
        """
        ret = []
        if not project:
            project = self.ring_packages.get(pkg)
        if not project:
            return ret
        url = self.makeurl(['source', project, pkg], {'cmd': 'showlinked'})

        # showlinked is a POST for rather bizzare reasons
        f = http_POST(url)
        root = ET.parse(f).getroot()

        for pkg in root.findall('package'):
            ret.append((pkg.get('project'), pkg.get('name')))

        return ret
예제 #25
0
    def get_sub_packages(self, pkg, project=None):
        """
        Returns a list of packages that need to be linked into rings
        too. A package is actually a tuple of project and package name
        """
        ret = []
        if not project:
            project = self.ring_packages.get(pkg)
        if not project:
            return ret
        url = self.makeurl(['source', project, pkg],
                           {'cmd': 'showlinked'})

        # showlinked is a POST for rather bizzare reasons
        f = http_POST(url)
        root = ET.parse(f).getroot()

        for pkg in root.findall('package'):
            ret.append((pkg.get('project'), pkg.get('name')))

        return ret
예제 #26
0
    def add_comment(self, request_id=None, project_name=None,
                    package_name=None, comment=None, parent_id=None):
        """Add a comment in an object in OBS.

        :param request_id: Request where to write a comment.
        :param project_name: Project name where to write a comment.
        :param package_name: Package name where to write a comment.
        :param comment: Comment to be published.
        :return: Comment id.
        """
        if not comment:
            raise ValueError('Empty comment.')

        comment = self.truncate(comment.strip())

        # OBS returns unicode from some APIs, but comment API does not accept
        # when included. Rather than handle everywhere just strip here.
        comment = comment.encode('ascii', 'ignore')

        query = {}
        if parent_id:
            query['parent_id'] = parent_id
        url = self._prepare_url(request_id, project_name, package_name, query)
        return http_POST(url, data=comment)
예제 #27
0
def _check_repo_change_review_state(self, opts, id_, newstate, message='', supersed=None):
    """Taken from osc/osc/core.py, improved:
       - verbose option added,
       - empty by_user=& removed.
       - numeric id can be int().
    """
    query = {
        'cmd': 'changereviewstate',
        'newstate': newstate,
        'by_user': '******',
    }
    if supersed:
        query['superseded_by'] = supersed
    # if message:
    #     query['comment'] = message

    code = 404
    url = makeurl(opts.apiurl, ['request', str(id_)], query=query)
    try:
        f = http_POST(url, data=message)
        root = ET.parse(f).getroot()
        code = root.attrib['code']
    except urllib2.HTTPError, e:
        print 'ERROR in URL %s [%s]' % (url, e)
예제 #28
0
def request_state_change(apiurl, request_id, state):
    query = { 'newstate': state, 'cmd': 'changestate' }
    url = makeurl(apiurl, ['request', request_id], query)
    return ETL.parse(http_POST(url)).getroot().get('code')
    def accept_all(self, projects, force=False, cleanup=True):
        accept_all_green = len(projects) == 0
        if accept_all_green:
            print('Accepting all acceptable projects')
            if force:
                print('ERROR: Not compatible with force option')
                return False

        self.requests = { 'delete': [], 'submit': [] }
        staging_packages = {}

        if accept_all_green:
            projects = self.api.get_staging_projects()

        for prj in projects:
            project = self.api.prj_from_letter(prj)

            status = self.api.project_status(project)
            if status.get('state') != 'acceptable':
                if accept_all_green:
                    continue
                if not force:
                    print('The project "{}" is not yet acceptable.'.format(project))
                    return False

            staging_packages[project] = []
            for request in status.findall('staged_requests/request'):
                self.requests[request.get('type')].append(request.get('package'))
                staging_packages[project].append(request.get('package'))

        other_new = self.find_new_requests(self.api.project)
        for req in other_new:
            self.requests[req['type']].append(req['package'])

        print('delete links to packages pending deletion...')
        self.delete_linked()

        # we have checked ourselves and accepting one staging project creates a race
        # for the other staging projects to appear building again
        opts = { 'force': '1' }

        print('triggering staging accepts...')
        for project in staging_packages.keys():
            u = self.api.makeurl(['staging', self.api.project, 'staging_projects', project, 'accept'], opts)
            http_POST(u)

        for req in other_new:
            print(f"Accepting request {req['id']}: {req['package']}")
            change_request_state(self.api.apiurl, str(req['id']), 'accepted', message='Accept to %s' % self.api.project)

        for project in sorted(staging_packages.keys()):
            print(f'waiting for staging project {project} to be accepted')

            while True:
                status = self.api.project_status(project, reload=True)
                if status.get('state') == 'empty':
                    break
                print('{} requests still staged - waiting'.format(status.find('staged_requests').get('count')))
                time.sleep(1)

            self.api.accept_status_comment(project, staging_packages[project])
            if self.api.is_adi_project(project):
                self.api.delete_empty_adi_project(project)
                continue

            self.api.staging_deactivate(project)

            self.reset_rebuild_data(project)

            if cleanup:
                self.cleanup(project)

        for package in self.requests['submit']:
            self.fix_linking_packages(package)

        if self.api.project.startswith('openSUSE:'):
            self.update_factory_version()
            if self.api.crebuild and self.api.item_exists(self.api.crebuild):
                self.sync_buildfailures()

        return True
예제 #30
0
def person_clone_after(apiurl_source, apiurl_target, person):
    url = makeurl(apiurl_target, ['person', person.find('login').text], {'cmd': 'change_password'})
    http_POST(url, data='opensuse')
예제 #31
0
def person_clone_after(apiurl_source, apiurl_target, person):
    url = makeurl(apiurl_target, ['person', person.find('login').text], {'cmd': 'change_password'})
    http_POST(url, data='opensuse')