def get_or_create_build(self, identifier, original_nvr=None, force_container_label=False): """ Get a Koji build from Neo4j, or create it if it does not exist in Neo4j. :param str/int identifier: an NVR (str) or build ID (int), or a dict of info from Koji API :kwarg str original_nvr: original_nvr property for the ContainerKojiBuild :kwarg bool force_container_label: when true, this skips the check to see if the build is a container and just creates the build with the ContainerKojiBuild label :rtype: KojiBuild :return: the Koji Build retrieved or created from Neo4j """ if type(identifier) is dict: build_info = identifier else: try: build_info = self.koji_session.getBuild(identifier, strict=True) except Exception: log.error( 'Failed to get brew build using the identifier {0}'.format( identifier)) raise build_params = { 'epoch': build_info['epoch'], 'id_': str(build_info['id']), 'name': build_info['package_name'], 'release': build_info['release'], 'state': build_info['state'], 'version': build_info['version'] } if build_info.get('extra'): build_params['extra'] = json.dumps(build_info['extra']) # To handle the case when a message has a null timestamp for time_key in ('completion_time', 'creation_time', 'start_time'): # Certain Koji API endpoints omit the *_ts values but have the *_time values, so that's # why the *_time values are used if build_info[time_key]: ts_format = r'%Y-%m-%d %H:%M:%S' if len(build_info[time_key].rsplit('.', 1)) == 2: # If there are microseconds, go ahead and parse that too ts_format += r'.%f' build_params[time_key] = datetime.strptime( build_info[time_key], ts_format) owner = User.create_or_update({ 'username': build_info['owner_name'], 'email': '{0}@redhat.com'.format(build_info['owner_name']) })[0] if force_container_label or self.is_container_build(build_info): if original_nvr: build_params['original_nvr'] = original_nvr build = ContainerKojiBuild.create_or_update(build_params)[0] elif self.is_module_build(build_info): module_extra_info = build_info['extra'].get('typeinfo', {}).get('module') build_params['context'] = module_extra_info.get('context') build_params['mbs_id'] = module_extra_info.get( 'module_build_service_id') build_params['module_name'] = module_extra_info.get('name') build_params['module_stream'] = module_extra_info.get('stream') build_params['module_version'] = module_extra_info.get('version') try: build = ModuleKojiBuild.create_or_update(build_params)[0] except neomodel.exceptions.ConstraintValidationFailed: # This must have errantly been created as a KojiBuild instead of a # ModuleKojiBuild, so let's fix that. build = KojiBuild.nodes.get_or_none(id_=build_params['id_']) if not build: # If there was a constraint validation failure and the build isn't just the # wrong label, then we can't recover. raise build.add_label(ModuleKojiBuild.__label__) build = ModuleKojiBuild.create_or_update(build_params)[0] else: build = KojiBuild.create_or_update(build_params)[0] build.conditional_connect(build.owner, owner) return build
def test_module_story_node_siblings(client, resource, uid, backward_rel, expected): """Tests getting the siblings of an artifact's adjacent node in the module story path.""" bug = BugzillaBug.get_or_create({ 'classification': 'Red Hat', 'creation_time': datetime(2017, 4, 2, 19, 39, 6), 'id_': '12345', 'modified_time': datetime(2018, 2, 7, 19, 30, 47), 'priority': 'high', 'product_name': 'Red Hat Enterprise Linux', 'product_version': '7.5', 'resolution': '', 'severity': 'low', 'short_description': 'Some description', 'status': 'VERIFIED', 'target_milestone': 'rc', 'votes': 0 })[0] commit = DistGitCommit.get_or_create({ 'author_date': datetime(2017, 4, 26, 11, 44, 38), 'commit_date': datetime(2017, 4, 26, 11, 44, 38), 'hash_': '8a63adb248ba633e200067e1ad6dc61931727bad', 'log_message': 'Related: #12345 - fix xyz' })[0] build = KojiBuild.get_or_create({ 'completion_time': datetime(2017, 4, 2, 19, 39, 6), 'creation_time': datetime(2017, 4, 2, 19, 39, 6), 'epoch': '0', 'id_': '2345', 'name': 'slf4j', 'release': '4.el7_4', 'start_time': datetime(2017, 4, 2, 19, 39, 6), 'state': 1, 'version': '1.7.4' })[0] build_two = KojiBuild.get_or_create({ 'completion_time': datetime(2017, 4, 2, 19, 39, 6), 'creation_time': datetime(2017, 4, 2, 19, 39, 6), 'epoch': '0', 'id_': '3456', 'name': 'slf3j', 'release': '4.el6_3', 'start_time': datetime(2017, 4, 2, 19, 39, 6), 'state': 2, 'version': '1.7.1' })[0] module_build = ModuleKojiBuild.get_or_create({ 'completion_time': datetime(2017, 4, 2, 19, 39, 6), 'creation_time': datetime(2017, 4, 2, 19, 39, 6), 'epoch': '0', 'id_': '2345', 'name': '389-ds', 'context': 'a2037af3', 'release': '20180805121332.a2037af3', 'start_time': datetime(2017, 4, 2, 19, 39, 6), 'mbs_id': 1338, 'module_name': '389-ds', 'module_version': '20180805121332', 'module_stream': '1.4' })[0] advisory = Advisory.get_or_create({ 'actual_ship_date': datetime(2017, 8, 1, 15, 43, 51), 'advisory_name': 'RHBA-2017:2251-02', 'content_types': ['docker'], 'created_at': datetime(2017, 4, 3, 14, 47, 23), 'id_': '27825', 'issue_date': datetime(2017, 8, 1, 5, 59, 34), 'product_name': 'Red Hat Enterprise Linux', 'product_short_name': 'RHEL', 'security_impact': 'None', 'state': 'SHIPPED_LIVE', 'status_time': datetime(2017, 8, 1, 15, 43, 51), 'synopsis': 'cifs-utils bug fix update', 'update_date': datetime(2017, 8, 1, 7, 16) })[0] fm_event = FreshmakerEvent.get_or_create({ 'event_type_id': 8, 'id_': '1180', 'message_id': 'ID:messaging-devops-broker01.test', 'state': 2, 'state_name': 'COMPLETE', 'state_reason': 'All container images have been rebuilt.', 'time_created': datetime(2019, 8, 21, 13, 42, 20), 'time_done': datetime(2099, 8, 21, 13, 42, 20) })[0] cb = ContainerKojiBuild.get_or_create({ 'completion_time': datetime(2017, 4, 2, 19, 39, 6), 'creation_time': datetime(2017, 4, 2, 19, 39, 6), 'epoch': '0', 'id_': '710', 'name': 'slf4j_2', 'release': '4.el7_4_as', 'start_time': datetime(2017, 4, 2, 19, 39, 6), 'state': 1, 'version': '1.7.4' })[0] cb_two = ContainerKojiBuild.get_or_create({ 'completion_time': datetime(2018, 4, 2, 19, 39, 6), 'creation_time': datetime(2018, 4, 2, 19, 39, 6), 'epoch': '0', 'id_': '811', 'name': 'some_build', 'release': '4.el7_4_as', 'start_time': datetime(2018, 4, 2, 19, 39, 6), 'state': 2, 'version': '1.7.5' })[0] ca = ContainerAdvisory.get_or_create({ 'actual_ship_date': datetime(2017, 8, 1, 15, 43, 51), 'advisory_name': 'RHBA-2017:2251-03', 'content_types': ['docker'], 'created_at': datetime(2017, 4, 3, 14, 47, 23), 'id_': '12327', 'issue_date': datetime(2017, 8, 1, 5, 59, 34), 'product_name': 'Red Hat Enterprise Linux', 'product_short_name': 'RHEL', 'security_impact': 'None', 'state': 'SHIPPED_LIVE', 'status_time': datetime(2017, 8, 1, 15, 43, 51), 'synopsis': 'cifs-utils bug fix update', 'update_date': datetime(2017, 8, 1, 7, 16) })[0] commit.resolved_bugs.connect(bug) commit.koji_builds.connect(build) build.advisories.connect(advisory) build_two.advisories.connect(advisory) fm_event.triggered_by_advisory.connect(advisory) fm_event.successful_koji_builds.connect(cb) fm_event.successful_koji_builds.connect(cb_two) ca.attached_builds.connect(cb) ca.attached_builds.connect(cb_two) module_build.components.connect(build) module_build.components.connect(build_two) module_build.advisories.connect(advisory) url = '/api/v1/siblings/{0}/{1}?story_type=module'.format(resource, uid) if backward_rel: url = '{0}&backward_rel=true'.format(url) rv = client.get(url) assert rv.status_code == 200 assert json.loads(rv.data.decode('utf-8')) == expected
def update_neo4j(self, builds): """ Update Neo4j with Koji build information from Teiid. :param list builds: a list of dictionaries """ # Uploads builds data to their respective nodes log.info('Beginning to upload data to Neo4j') count = 0 for build_dict in builds: build_params = dict( id_=build_dict['id'], epoch=build_dict['epoch'], state=build_dict['state'], creation_time=build_dict['creation_time'], start_time=build_dict['start_time'], completion_time=build_dict['completion_time'], name=build_dict['package_name'], version=build_dict['version'], release=build_dict['release'] ) try: extra_json = json.loads(build_dict['extra']) except (ValueError, TypeError): extra_json = {} if self.is_container_build(build_dict): build_params['operator'] = bool( extra_json.get('typeinfo', {}).get('operator-manifests', {}).get('archive') ) try: build = ContainerKojiBuild.create_or_update(build_params)[0] except neomodel.exceptions.ConstraintValidationFailed: # This must have errantly been created as a KojiBuild instead of a # ContainerKojiBuild, so let's fix that. build = KojiBuild.nodes.get_or_none(id_=build_params['id_']) if not build: # If there was a constraint validation failure and the build isn't just the # wrong label, then we can't recover. raise build.add_label(ContainerKojiBuild.__label__) build = ContainerKojiBuild.create_or_update(build_params)[0] elif self.is_module_build(build_dict): module_extra_info = extra_json.get('typeinfo', {}).get('module') try: build_params['context'] = module_extra_info.get('context') build_params['mbs_id'] = module_extra_info.get('module_build_service_id') build_params['module_name'] = module_extra_info.get('name') build_params['module_stream'] = module_extra_info.get('stream') build_params['module_version'] = module_extra_info.get('version') build = ModuleKojiBuild.create_or_update(build_params)[0] except neomodel.exceptions.ConstraintValidationFailed: # This must have errantly been created as a KojiBuild instead of a # ModuleKojiBuild, so let's fix that. build = KojiBuild.nodes.get_or_none(id_=build_params['id_']) if not build: # If there was a constraint validation failure and the build isn't just the # wrong label, then we can't recover. raise build.add_label(ModuleKojiBuild.__label__) build = ModuleKojiBuild.create_or_update(build_params)[0] else: build = KojiBuild.create_or_update(build_params)[0] username = build_dict['owner_name'] user = User.get_or_create(dict(username=username))[0] build.conditional_connect(build.owner, user) if build.__label__ == ModuleKojiBuild.__label__: module_build_tag_name = module_extra_info.get('content_koji_tag') if module_build_tag_name: module_components = self.get_tag_info(module_build_tag_name) # Some modules don't have components if module_components: for item in module_components: module_component = KojiBuild.get_or_create(dict( id_=item['build_id'] ))[0] build.components.connect(module_component) component_builds = self.get_build_info( [item['build_id'] for item in module_components]) self.update_neo4j(component_builds) count += 1 log.info('Uploaded {0} builds out of {1}'.format(count, len(builds))) container_koji_task_id = extra_json.get('container_koji_task_id') if build_dict['task_id']: task_id = build_dict['task_id'] elif container_koji_task_id: task_id = container_koji_task_id else: # Continue if the task_id is None continue # Getting task related to the current build try: task_dict = self.get_task(task_id)[0] except IndexError: continue commit_hash = None # Only look for the commit hash if the build is an RPM or container if task_dict['method'] in ('build', 'buildContainer'): xml_root = ET.fromstring(task_dict['request']) for child in xml_root.iter('string'): if child.text and child.text.startswith('git'): commit_hash = child.text.rsplit('#', 1)[1] break if commit_hash: commit = DistGitCommit.get_or_create(dict(hash_=commit_hash))[0] build.conditional_connect(build.commit, commit)