Example #1
0
def test_story_path_flag_invalid(client):
    """Tests getting the siblings for when the story_path flag is invalid."""
    Advisory.get_or_create({
        'actual_ship_date': datetime(2017, 8, 1, 15, 43, 51),
        'advisory_name': 'RHBA-2017:2251-03',
        'content_types': ['rpms'],
        '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]

    expected = {
        'message': ('Supplied story type is invalid. Select from: ModuleStoryManager, '
                    'ContainerStoryManager'),
        'status': 400}

    rv = client.get('/api/v1/siblings/advisory/12327?story_type=random')
    assert rv.status_code == 400
    assert json.loads(rv.data.decode('utf-8')) == expected
def test_event_to_complete(cb_one):
    """Test the Freshmaker handler when it receives an event to complete message."""
    advisory = Advisory.get_or_create({
        'id_': '34727',
        'advisory_name': 'RHBA-8018:0600-01'
    })[0]
    event = FreshmakerEvent.get_or_create({
        'id_': '2194',
        'state_name': 'BUILDING',
    })[0]
    event.successful_koji_builds.connect(cb_one)
    event.triggered_by_advisory.connect(advisory)
    # Load the message to pass to the handler
    with open(path.join(message_dir, 'freshmaker', 'event_to_complete.json'), 'r') as f:
        msg = json.load(f)
    # Make sure the handler can handle the message
    assert FreshmakerHandler.can_handle(msg) is True
    # Instantiate the handler
    handler = FreshmakerHandler(config)
    # Run the handler
    handler.handle(msg)

    event = FreshmakerEvent.nodes.get_or_none(id_='2194')
    assert event is not None
    assert event.state_name == 'COMPLETE'
    assert event.state_reason == '2 of 3 container image(s) failed to rebuild.'
    assert event.time_created == datetime(2019, 8, 21, 13, 42, 20, tzinfo=pytz.utc)
    assert event.time_done == datetime(2099, 8, 21, 13, 42, 20, tzinfo=pytz.utc)
    assert len(event.successful_koji_builds) == 1
    def builds_added_handler(self, msg):
        """
        Handle an Errata tool builds added message and update Neo4j if necessary.

        :param dict msg: a message to be processed
        """
        embargoed = msg['body']['headers']['brew_build'] == 'REDACTED'
        # We can't store information on embargoed advisories other than the ID
        if embargoed:
            return
        advisory = Advisory.get_or_create(
            {'id_': msg['body']['headers']['errata_id']})[0]

        nvr = msg['body']['headers']['brew_build']
        koji_build = self.get_or_create_build(nvr)

        time_attached_string = msg['body']['headers']['when']
        if time_attached_string.endswith(' UTC'):
            time_attached_string = time_attached_string[:-4]
        time_attached = timestamp_to_datetime(time_attached_string)

        attached_rel = advisory.attached_builds.relationship(koji_build)
        if attached_rel:
            if attached_rel.time_attached != time_attached:
                advisory.attached_builds.replace(
                    koji_build, {'time_attached': time_attached})
        else:
            advisory.attached_builds.connect(koji_build,
                                             {'time_attached': time_attached})
Example #4
0
def test_builds_added_handler(mock_koji_cs, mock_getBuild_one):
    """Test the Errata handler when it receives a new builds added message."""
    mock_koji_session = mock.Mock()
    mock_getBuild_one['state'] = 1
    mock_koji_session.getBuild.return_value = mock_getBuild_one
    mock_koji_cs.return_value = mock_koji_session

    advisory = Advisory.get_or_create({'id_': '34983'})[0]

    with open(path.join(message_dir, 'errata', 'builds_added.json'), 'r') as f:
        msg = json.load(f)
    # Make sure the handler can handle the message
    assert ErrataHandler.can_handle(msg) is True
    # Instantiate the handler
    handler = ErrataHandler(config)
    # Run the handler
    handler.handle(msg)

    build = KojiBuild.nodes.get_or_none(id_='710916')
    owner = User.nodes.get_or_none(username='******')
    assert build is not None
    assert build.name == 'e2e-container-test-product-container'
    assert build.version == '7.4'
    assert build.release == '36.1528968216'
    assert build.completion_time == datetime.datetime(2018,
                                                      6,
                                                      15,
                                                      20,
                                                      26,
                                                      38,
                                                      tzinfo=pytz.utc)
    assert build.creation_time == datetime.datetime(2018,
                                                    6,
                                                    15,
                                                    20,
                                                    20,
                                                    38,
                                                    tzinfo=pytz.utc)
    assert build.epoch == 'epoch'
    assert build.extra == '{"container_koji_task_id": 17511743}'
    assert build.id_ == '710916'
    assert build.start_time == datetime.datetime(2018,
                                                 6,
                                                 15,
                                                 20,
                                                 21,
                                                 38,
                                                 tzinfo=pytz.utc)
    assert build.state == 1

    assert advisory.attached_builds.is_connected(build)
    assert advisory.attached_builds.relationship(build).time_attached == \
        datetime.datetime(2018, 7, 3, 13, 34, 14, tzinfo=pytz.utc)
    assert build.owner.is_connected(owner)
Example #5
0
def test_build_added_rel():
    """Test BuildsAddedRel on KojiBuilds."""
    advisory = Advisory(id_='12345', advisory_name='RHBA-2018:12345-01').save()
    build = KojiBuild(id_='12345').save()
    time_attached = datetime(2017, 4, 2, 19, 39, 6, tzinfo=pytz.utc)
    rel = advisory.attached_builds.connect(build,
                                           {'time_attached': time_attached})
    rel.save()
    assert advisory.attached_builds.relationship(
        build).time_attached == time_attached
    assert rel.time_attached == time_attached
def test_builds_removed_embargoed():
    """Test the errata handler when it receives an embargoed builds removed message."""
    advisory = Advisory.get_or_create({
        'id_': '36130',
        'advisory_name': 'REDACTED'
    })[0]
    with open(path.join(message_dir, 'errata', 'builds_removed_redacted.json'),
              'r') as f:
        msg = json.load(f)
    assert ErrataHandler.can_handle(msg) is True
    handler = ErrataHandler(config)
    handler.handle(msg)
    assert advisory.attached_builds.all() == []
Example #7
0
def test_conditional_connect_zero_or_more():
    """Test EstuaryStructuredNode.conditional_connect on a ZeroOrMore relationship."""
    adv = Advisory(id_='12345', advisory_name='RHBA-2017:27760-01').save()
    bug = BugzillaBug(id_='2345').save()
    bug_two = BugzillaBug(id_='3456').save()

    assert len(adv.attached_bugs) == 0
    EstuaryStructuredNode.conditional_connect(adv.attached_bugs, bug)
    assert bug in adv.attached_bugs
    assert len(adv.attached_bugs) == 1

    EstuaryStructuredNode.conditional_connect(adv.attached_bugs, bug_two)
    assert bug in adv.attached_bugs
    assert bug_two in adv.attached_bugs
    assert len(adv.attached_bugs) == 2
Example #8
0
def test_conditional_connect_zero_or_one():
    """Test EstuaryStructuredNode.conditional_connect on a ZerorOrOne relationship."""
    adv = Advisory(id_='12345', advisory_name='RHBA-2017:27760-01').save()
    tbrady = User(username='******').save()
    thanks = User(username='******').save()

    assert len(adv.assigned_to) == 0
    EstuaryStructuredNode.conditional_connect(adv.assigned_to, tbrady)
    assert tbrady in adv.assigned_to
    assert len(adv.assigned_to) == 1

    EstuaryStructuredNode.conditional_connect(adv.assigned_to, thanks)
    assert tbrady not in adv.assigned_to
    assert thanks in adv.assigned_to
    assert len(adv.assigned_to) == 1
    def builds_removed_handler(self, msg):
        """
        Handle an Errata tool builds removed message and update Neo4j if necessary.

        :param dict msg: a message to be processed
        """
        embargoed = msg['body']['headers']['brew_build'] == 'REDACTED'
        # We can't store information on embargoed advisories other than the ID
        if embargoed:
            return
        advisory = Advisory.get_or_create(
            {'id_': msg['body']['headers']['errata_id']})[0]

        nvr = msg['body']['headers']['brew_build']
        koji_build = self.get_or_create_build(nvr)

        advisory.attached_builds.disconnect(koji_build)
    def event_state_handler(self, msg):
        """
        Handle a Freshmaker event state changed message and update Neo4j if necessary.

        :param dict msg: a message to be processed
        """
        msg_id = msg['body']['msg']['message_id']

        if msg['body']['msg'].get('dry_run'):
            return

        event_params = {
            'id_': str(msg['body']['msg']['id']),
            'state_name': msg['body']['msg']['state_name'],
            'state_reason': msg['body']['msg']['state_reason']
        }

        if 'time_created' in msg['body']['msg']:
            event_params['time_created'] = timestamp_to_datetime(
                msg['body']['msg']['time_created'])
        if 'time_done' in msg['body']['msg'] and msg['body']['msg'][
                'time_done'] is not None:
            event_params['time_done'] = timestamp_to_datetime(
                msg['body']['msg']['time_done'])

        event = FreshmakerEvent.create_or_update(event_params)[0]

        advisory_name = msg_id.rsplit('.', 1)[-1]
        if advisory_name[0:4] not in ('RHSA', 'RHBA', 'RHEA'):
            log.warn(
                'Unable to parse the advisory name from the Freshmaker message_id: {0}'
                .format(msg_id))
            advisory_name = None
        advisory = Advisory.get_or_create({
            'id_':
            msg['body']['msg']['search_key'],
            'advisory_name':
            advisory_name
        })[0]

        event.conditional_connect(event.triggered_by_advisory, advisory)
def test_event_to_complete(cb_one):
    """Test the Freshmaker handler when it receives an event to complete message."""
    advisory = Advisory.get_or_create({
        'id_': '34727',
        'advisory_name': 'RHBA-8018:0600-01'
    })[0]
    event = FreshmakerEvent.get_or_create({
        'id_':
        '2194',
        'state':
        1,
        'state_name':
        'BUILDING',
        'event_type_id':
        8,
        'message_id':
        'ID:messaging.domain.com-42045-1527890187852-9:1045742:0:0:1.RHBA-8018:0600-01'
    })[0]
    event.triggered_container_builds.connect(cb_one)
    event.triggered_by_advisory.connect(advisory)
    # Load the message to pass to the handler
    with open(path.join(message_dir, 'freshmaker', 'event_to_complete.json'),
              'r') as f:
        msg = json.load(f)
    # Make sure the handler can handle the message
    assert FreshmakerHandler.can_handle(msg) is True
    # Instantiate the handler
    handler = FreshmakerHandler(config)
    # Run the handler
    handler.handle(msg)

    event = FreshmakerEvent.nodes.get_or_none(id_='2194')
    assert event is not None
    assert event.event_type_id == 8
    assert event.message_id == \
        'ID:messaging.domain.com-42045-1527890187852-9:1045742:0:0:1.RHBA-8018:0600-01'
    assert event.state == 2
    assert event.state_name == 'COMPLETE'
    assert event.state_reason == '2 of 3 container image(s) failed to rebuild.'
    assert len(event.triggered_container_builds) == 1
def test_builds_removed_handler(mock_koji_cs, mock_getBuild_one, cb_one):
    """Test the Errata handler when it receives a new builds removed message."""
    mock_koji_session = mock.Mock()
    mock_getBuild_one['state'] = 1
    mock_koji_session.getBuild.return_value = mock_getBuild_one
    mock_koji_cs.return_value = mock_koji_session

    advisory = Advisory.get_or_create({'id_': '34983'})[0]
    advisory.attached_builds.connect(cb_one)

    with open(path.join(message_dir, 'errata', 'builds_removed.json'),
              'r') as f:
        msg = json.load(f)
    # Make sure the handler can handle the message
    assert ErrataHandler.can_handle(msg) is True
    # Instantiate the handler
    handler = ErrataHandler(config)
    # Run the handler
    handler.handle(msg)

    assert advisory is not None
    assert not advisory.attached_builds.is_connected(cb_one)
Example #13
0
    def event_state_handler(self, msg):
        """
        Handle a Freshmaker event state changed message and update Neo4j if necessary.

        :param dict msg: a message to be processed
        """
        msg_id = msg['body']['msg']['message_id']
        event = FreshmakerEvent.create_or_update({
            'id_':
            str(msg['body']['msg']['id']),
            'event_type_id':
            msg['body']['msg']['event_type_id'],
            'message_id':
            msg_id,
            'state':
            msg['body']['msg']['state'],
            'state_name':
            msg['body']['msg']['state_name'],
            'state_reason':
            msg['body']['msg']['state_reason']
        })[0]

        advisory_name = msg_id.rsplit('.', 1)[-1]
        if advisory_name[0:4] not in ('RHSA', 'RHBA', 'RHEA'):
            log.warn(
                'Unable to parse the advisory name from the Freshmaker message_id: {0}'
                .format(msg_id))
            advisory_name = None
        advisory = Advisory.get_or_create({
            'id_':
            msg['body']['msg']['search_key'],
            'advisory_name':
            advisory_name
        })[0]

        event.conditional_connect(event.triggered_by_advisory, advisory)
Example #14
0
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
Example #15
0
def test_get_recent_nodes():
    """Test the get_recent_nodes function."""
    BugzillaBug.get_or_create({
        'id_':
        '11111',
        'modified_time':
        datetime(2017, 4, 26, 11, 44, 38)
    })
    BugzillaBug.get_or_create({
        'id_':
        '22222',
        'modified_time':
        datetime(2017, 6, 26, 11, 44, 38)
    })
    BugzillaBug.get_or_create({
        'id_':
        '33333',
        'modified_time':
        datetime(2017, 5, 26, 11, 44, 38)
    })
    KojiBuild.get_or_create({
        'id_':
        '44444',
        'completion_time':
        datetime(2017, 5, 27, 11, 44, 38)
    })
    DistGitCommit.get_or_create({
        'hash_': '55555',
        'commit_date': datetime(2017, 5, 2, 11, 44, 38)
    })
    Advisory.get_or_create({
        'id_': '66666',
        'update_date': datetime(2017, 5, 30, 11, 44, 38)
    })
    Advisory.get_or_create({'id_': '66666', 'update_date': None})
    FreshmakerEvent.get_or_create({
        'id_':
        '77777',
        'time_created':
        datetime(2017, 5, 30, 11, 44, 38),
    })

    nodes, meta = estuary.utils.recents.get_recent_nodes()
    assert nodes['Advisory'][0]['id'] == '66666'
    assert nodes['DistGitCommit'][0]['hash'] == '55555'
    assert nodes['FreshmakerEvent'][0]['id'] == '77777'
    assert nodes['KojiBuild'][0]['id'] == '44444'
    assert nodes['BugzillaBug'][0]['id'] == '22222'
    assert nodes['BugzillaBug'][1]['id'] == '33333'
    assert nodes['BugzillaBug'][2]['id'] == '11111'

    id_dict = {
        FreshmakerEvent.__label__: 'id',
        BugzillaBug.__label__: 'id',
        DistGitCommit.__label__: 'hash',
        KojiBuild.__label__: 'id',
        Advisory.__label__: 'id'
    }
    timestamp_dict = {
        FreshmakerEvent.__label__: 'time_created',
        BugzillaBug.__label__: 'modified_time',
        DistGitCommit.__label__: 'commit_date',
        KojiBuild.__label__: 'completion_time',
        Advisory.__label__: 'update_date'
    }

    assert meta['id_keys'] == id_dict
    assert meta['timestamp_keys'] == timestamp_dict
Example #16
0
def test_get_stories_fallback(client):
    """Test getting all the stories for a resource and falling back to a different label."""
    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]
    advisory = Advisory.get_or_create({
        'actual_ship_date': datetime(2017, 8, 1, 15, 43, 51),
        'advisory_name': 'RHBA-2017:2251-02',
        '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',
        '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]

    build.advisories.connect(advisory, {'time_attached': datetime(2017, 4, 3, 14, 47, 23)})
    expected = [{
        'data': [
            {
                'advisories': [{
                    'actual_ship_date': '2017-08-01T15:43:51Z',
                    'advisory_name': 'RHBA-2017:2251-02',
                    'created_at': '2017-04-03T14:47:23Z',
                    'display_name': 'RHBA-2017:2251-02',
                    'id': '27825',
                    'issue_date': '2017-08-01T05:59:34Z',
                    'product_name': 'Red Hat Enterprise Linux',
                    'release_date': None,
                    'resource_type': 'Advisory',
                    'security_impact': 'None',
                    'security_sla': None,
                    'state': 'SHIPPED_LIVE',
                    'status_time': '2017-08-01T15:43:51Z',
                    'synopsis': 'cifs-utils bug fix update',
                    'update_date': '2017-08-01T07:16:00Z'
                }],
                'commit': None,
                'completion_time': '2017-04-02T19:39:06Z',
                'creation_time': '2017-04-02T19:39:06Z',
                'epoch': '0',
                'id': '2345',
                'module_builds': [],
                'name': 'slf4j',
                'owner': None,
                'release': '4.el7_4',
                'resource_type': 'KojiBuild',
                'display_name': u'slf4j-1.7.4-4.el7_4',
                'start_time': '2017-04-02T19:39:06Z',
                'state': 1,
                'timeline_timestamp': '2017-04-02T19:39:06Z',
                'version': '1.7.4'
            },
            {
                'actual_ship_date': '2017-08-01T15:43:51Z',
                'advisory_name': 'RHBA-2017:2251-02',
                'created_at': '2017-04-03T14:47:23Z',
                'id': '27825',
                'issue_date': '2017-08-01T05:59:34Z',
                'product_name': 'Red Hat Enterprise Linux',
                'release_date': None,
                'resource_type': 'Advisory',
                'display_name': 'RHBA-2017:2251-02',
                'security_impact': 'None',
                'security_sla': None,
                'state': 'SHIPPED_LIVE',
                'status_time': '2017-08-01T15:43:51Z',
                'synopsis': 'cifs-utils bug fix update',
                'update_date': '2017-08-01T07:16:00Z',
                'timeline_timestamp': '2017-04-03T14:47:23Z'
            }
        ],
        'meta': {
            'requested_node_index': 0,
            'story_related_nodes_forward': [0, 0],
            'story_related_nodes_backward': [0, 0],
            'wait_times': [68897.0],
            'total_lead_time': 10440285.0,
            'total_processing_time': 10371388.0,
            'processing_time_flag': False,
            'total_wait_time': 68897.0,
            'story_type': 'container'
        }
    }]

    rv = client.get('/api/v1/allstories/containerkojibuild/2345?fallback=kojibuild')
    assert rv.status_code == 200
    assert json.loads(rv.data.decode('utf-8')) == expected
Example #17
0
    def query_api_and_update_neo4j(self):
        """
        Scrape the Freshmaker API and upload the data to Neo4j.

        :param str start_date: a datetime to start scraping data from
        """
        # Initialize session and url
        session = retry_session()
        fm_url = self.freshmaker_url
        while True:
            log.debug('Querying {0}'.format(fm_url))
            rv_json = session.get(fm_url, timeout=15).json()
            for fm_event in rv_json['items']:
                try:
                    int(fm_event['search_key'])
                except ValueError:
                    # Skip Freshmaker Events that don't have the search_key as the Advisory ID
                    continue
                event = FreshmakerEvent.create_or_update(dict(
                    id_=fm_event['id'],
                    event_type_id=fm_event['event_type_id'],
                    message_id=fm_event['message_id'],
                    state=fm_event['state'],
                    state_name=fm_event['state_name'],
                    state_reason=fm_event['state_reason'],
                    url=fm_event['url']
                ))[0]

                advisory = Advisory.get_or_create(dict(
                    id_=fm_event['search_key']
                ))[0]

                event.conditional_connect(event.triggered_by_advisory, advisory)

                for build_dict in fm_event['builds']:
                    # To handle a faulty container build in Freshmaker
                    if not build_dict['build_id'] or int(build_dict['build_id']) < 0:
                        continue

                    # The build ID obtained from Freshmaker API is actually a Koji task ID
                    task_result = self.get_koji_task_result(build_dict['build_id'])
                    if not task_result:
                        continue

                    # Extract the build ID from a task result
                    xml_root = ET.fromstring(task_result)
                    # TODO: Change this if a task can trigger multiple builds
                    try:
                        build_id = xml_root.find(".//*[name='koji_builds'].//string").text
                    except AttributeError:
                        build_id = None

                    if build_id:
                        build = ContainerKojiBuild.get_or_create(dict(
                            id_=build_id,
                            original_nvr=build_dict['original_nvr']
                        ))[0]
                        event.triggered_container_builds.connect(build)

            if rv_json['meta'].get('next'):
                fm_url = rv_json['meta']['next']
            else:
                break
Example #18
0
    def update_neo4j(self, advisories):
        """
        Update Neo4j with Errata Tool advisories from Teiid.

        :param list advisories: a list of dictionaries of advisories
        """
        count = 0
        for advisory in advisories:
            count += 1
            log.info('Processing advisory {0}/{1}'.format(
                count, len(advisories)))
            # The content_types column is a string with YAML in it, so convert it to a list
            content_types = yaml.safe_load(advisory['content_types'])
            adv = Advisory.create_or_update({
                'actual_ship_date':
                advisory['actual_ship_date'],
                'advisory_name':
                advisory['advisory_name'],
                'content_types':
                content_types,
                'created_at':
                advisory['created_at'],
                'id_':
                advisory['id'],
                'issue_date':
                advisory['issue_date'],
                'product_name':
                advisory['product_name'],
                'product_short_name':
                advisory['product_short_name'],
                'release_date':
                advisory['release_date'],
                'security_impact':
                advisory['security_impact'],
                'security_sla':
                advisory['security_sla'],
                'state':
                advisory['state'],
                'status_time':
                advisory['status_time'],
                'synopsis':
                advisory['synopsis'],
                'update_date':
                advisory['update_date'],
            })[0]
            container_adv = False

            for associated_build in self.get_associated_builds(advisory['id']):
                # Even if a node has two labels in the database, Neo4j returns the node
                # only with the specific label you asked for. Hence we check for labels
                # ContainerKojiBuild and KojiBuild separately for the same node.
                build = ContainerKojiBuild.nodes.get_or_none(
                    id_=associated_build['id_'])
                if not build:
                    build = KojiBuild.nodes.get_or_none(
                        id_=associated_build['id_'])

                if build and not container_adv:
                    if build.__label__ == 'ContainerKojiBuild':
                        adv.add_label(ContainerAdvisory.__label__)
                        container_adv = True

                # If this is set, that means it was once part of the advisory but not anymore.
                # This relationship needs to be deleted if it exists.
                if associated_build['removed_index_id']:
                    if build:
                        adv.attached_builds.disconnect(build)
                else:
                    # Query Teiid and create the entry only if the build is not present in Neo4j
                    if not build:
                        attached_build = self.get_koji_build(
                            associated_build['id_'])
                        if attached_build:
                            if self.is_container_build(attached_build):
                                build = ContainerKojiBuild.get_or_create(
                                    {'id_': associated_build['id_']})[0]
                            else:
                                build = KojiBuild.get_or_create(
                                    {'id_': associated_build['id_']})[0]

                    # This will happen only if we do not find the build we are looking for in Teiid
                    # which shouldn't usually happen under normal conditions
                    if not build:
                        log.warn(
                            'The Koji build with ID {} was not found in Teiid!'
                            .format(associated_build['id_']))
                        continue

                    if adv.__label__ != ContainerAdvisory.__label__ \
                            and build.__label__ == ContainerKojiBuild.__label__:
                        adv.add_label(ContainerAdvisory.__label__)

                    attached_rel = adv.attached_builds.relationship(build)
                    time_attached = associated_build['time_attached']
                    if attached_rel:
                        if attached_rel.time_attached != time_attached:
                            adv.attached_builds.replace(
                                build, {'time_attached': time_attached})
                    else:
                        adv.attached_builds.connect(
                            build, {'time_attached': time_attached})

            assigned_to = User.get_or_create(
                {'username': advisory['assigned_to'].split('@')[0]})[0]
            adv.conditional_connect(adv.assigned_to, assigned_to)
            reporter = User.get_or_create(
                {'username': advisory['reporter'].split('@')[0]})[0]
            adv.conditional_connect(adv.reporter, reporter)

            for attached_bug in self.get_attached_bugs(advisory['id']):
                bug = BugzillaBug.get_or_create(attached_bug)[0]
                adv.attached_bugs.connect(bug)
Example #19
0
    def query_api_and_update_neo4j(self):
        """
        Scrape the Freshmaker API and upload the data to Neo4j.

        :param str start_date: a datetime to start scraping data from
        """
        # Initialize session and url
        session = retry_session()
        fm_url = self.freshmaker_url
        while True:
            log.debug('Querying {0}'.format(fm_url))
            try:
                rv_json = session.get(fm_url, timeout=60).json()
            except ConnectionError:
                # TODO: Remove this once FACTORY-3955 is resolved
                log.error(
                    'The connection to Freshmaker at %s failed. Skipping the rest of the scraper.',
                    fm_url,
                )
                break

            for fm_event in rv_json['items']:
                try:
                    int(fm_event['search_key'])
                except ValueError:
                    # Skip Freshmaker Events that don't have the search_key as the Advisory ID
                    continue
                log.debug('Creating FreshmakerEvent {0}'.format(fm_event['id']))
                event_params = dict(
                    id_=fm_event['id'],
                    event_type_id=fm_event['event_type_id'],
                    message_id=fm_event['message_id'],
                    state=fm_event['state'],
                    state_name=fm_event['state_name'],
                    state_reason=fm_event['state_reason'],
                    url=fm_event['url']
                )
                if fm_event.get('time_created'):
                    event_params['time_created'] = timestamp_to_datetime(fm_event['time_created'])
                if fm_event.get('time_done'):
                    event_params['time_done'] = timestamp_to_datetime(fm_event['time_created'])
                event = FreshmakerEvent.create_or_update(event_params)[0]

                log.debug('Creating Advisory {0}'.format(fm_event['search_key']))
                advisory = Advisory.get_or_create(dict(
                    id_=fm_event['search_key']
                ))[0]

                event.conditional_connect(event.triggered_by_advisory, advisory)

                for build_dict in fm_event['builds']:
                    # To handle a faulty container build in Freshmaker
                    if build_dict['build_id'] and int(build_dict['build_id']) < 0:
                        continue
                    log.debug('Creating FreshmakerBuild {0}'.format(build_dict['build_id']))
                    fb_params = dict(
                        id_=build_dict['id'],
                        dep_on=build_dict['dep_on'],
                        name=build_dict['name'],
                        original_nvr=build_dict['original_nvr'],
                        rebuilt_nvr=build_dict['rebuilt_nvr'],
                        state=build_dict['state'],
                        state_name=build_dict['state_name'],
                        state_reason=build_dict['state_reason'],
                        time_submitted=timestamp_to_datetime(build_dict['time_submitted']),
                        type_=build_dict['type'],
                        type_name=build_dict['type_name'],
                        url=build_dict['url']
                    )
                    if build_dict['time_completed']:
                        fb_params['time_completed'] = timestamp_to_datetime(
                            build_dict['time_completed'])
                    if build_dict['build_id']:
                        fb_params['build_id'] = build_dict['build_id']
                    fb = FreshmakerBuild.create_or_update(fb_params)[0]
                    event.requested_builds.connect(fb)

                    # The build ID obtained from Freshmaker API is actually a Koji task ID
                    task_result = None
                    if build_dict['build_id']:
                        task_result = self.get_koji_task_result(build_dict['build_id'])

                    if not task_result:
                        continue

                    # Extract the build ID from a task result
                    xml_root = ET.fromstring(task_result)
                    # TODO: Change this if a task can trigger multiple builds
                    try:
                        build_id = xml_root.find(".//*[name='koji_builds'].//string").text
                    except AttributeError:
                        build_id = None

                    if not build_id:
                        continue

                    log.debug('Creating ContainerKojiBuild {0}'.format(build_id))
                    build_params = {
                        'id_': build_id,
                        'original_nvr': build_dict['original_nvr']
                    }
                    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_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]

                    event.successful_koji_builds.connect(build)

            if rv_json['meta'].get('next'):
                fm_url = rv_json['meta']['next']
            else:
                break
def test_get_resources(client, resource, uid, expected):
    """Test getting a resource from Neo4j with its relationships."""
    tbrady = User.get_or_create({
        'email': '*****@*****.**',
        'username': '******'
    })[0]
    mprahl = User.get_or_create({
        'email': '*****@*****.**',
        'username': '******'
    })[0]
    jsmith = User.get_or_create({
        'email': '*****@*****.**',
        'username': '******'
    })[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]
    commit_two = DistGitCommit.get_or_create({
        'author_date': datetime(2017, 4, 27, 11, 44, 38),
        'commit_date': datetime(2017, 4, 27, 11, 44, 38),
        'hash_': '1263adb248ba633e205067e1ad6dc61931727c2d',
        'log_message': 'Related: #12345 - fix xz'
    })[0]
    commit_three = DistGitCommit.get_or_create({
        'author_date': datetime(2017, 4, 27, 11, 44, 38),
        'commit_date': datetime(2017, 4, 27, 11, 44, 38),
        'hash_': '5663adb248ba633e205067e1ad6dc61931727123',
        'log_message': 'Revert: #12345'
    })[0]
    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]
    bug_two = BugzillaBug.get_or_create({
        'classification': 'Red Hat',
        'creation_time': datetime(2017, 4, 2, 19, 39, 6),
        'id_': '67890',
        'modified_time': datetime(2018, 2, 7, 19, 30, 47),
        'priority': 'medium',
        'product_name': 'Red Hat Enterprise Linux',
        'product_version': '7.3',
        'resolution': '',
        'severity': 'low',
        'short_description': 'Some description',
        'status': 'VERIFIED',
        'target_milestone': 'rc',
        'votes': 0
    })[0]
    bug_three = BugzillaBug.get_or_create({
        'classification': 'Red Hat',
        'creation_time': datetime(2017, 4, 2, 19, 39, 6),
        'id_': '272895',
        'modified_time': datetime(2018, 2, 7, 19, 30, 47),
        'priority': 'low',
        'product_name': 'Satellite',
        'product_version': '3',
        'resolution': '',
        'severity': 'medium',
        'short_description': 'Some description',
        'status': 'VERIFIED',
        'target_milestone': 'rc',
        'votes': 0
    })[0]
    repo = DistGitRepo.get_or_create({
        'name': 'some_repo',
        'namespace': 'some_namespace',
    })[0]
    branch = DistGitBranch.get_or_create({
        'name': 'some_branch_name',
        'repo_name': 'some_repo_name',
        'repo_namespace': 'some_repo_namespace'
    })[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]
    tag = KojiTag.get_or_create({
        'id_': '2702',
        'name': 'some_active_tag'
    })[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]
    fm_build = FreshmakerBuild.get_or_create({
        'id_': 398,
        'build_id': 15639305,
        'dep_on': "jboss-eap-7-eap70-openshift-docker",
        'name': "metrics-hawkular-metrics-docker",
        'original_nvr': "metrics-hawkular-metrics-docker-v3.7.23-10",
        'rebuilt_nvr': "metrics-hawkular-metrics-docker-v3.7.23-10.1522094767",
        'state': 1,
        'state_name': "DONE",
        'state_reason': "Built successfully.",
        'time_completed': datetime(2017, 4, 2, 19, 39, 6),
        'time_submitted': datetime(2017, 4, 2, 19, 39, 6),
        'type_': 1,
        'type_name': "IMAGE",
        'url': "/api/1/builds/398"
    })[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]

    if resource == 'bugzillabug':
        bug.assignee.connect(mprahl)
        bug.qa_contact.connect(jsmith)
        bug.reporter.connect(tbrady)
        commit.resolved_bugs.connect(bug)
        commit_two.resolved_bugs.connect(bug)
        commit_three.reverted_bugs.connect(bug)
        advisory.attached_bugs.connect(bug)

    if resource == 'distgitcommit':
        commit.author.connect(tbrady)
        commit.parent.connect(commit_two)
        commit_three.parent.connect(commit)
        commit.related_bugs.connect(bug)
        commit.related_bugs.connect(bug_three)
        commit.reverted_bugs.connect(bug_two)
        repo.commits.connect(commit)
        branch.commits.connect(commit)
        commit.resolved_bugs.connect(bug)
        commit.resolved_bugs.connect(bug_two)

    if resource == 'kojibuild':
        build.owner.connect(mprahl)
        build.commit.connect(commit_two)
        tag.builds.connect(build)

    if resource == 'advisory':
        advisory.assigned_to.connect(mprahl)
        advisory.reporter.connect(jsmith)
        advisory.attached_builds.connect(build)
        advisory.attached_bugs.connect(bug)

    if resource == 'freshmakerevent':
        fm_event.triggered_by_advisory.connect(advisory)
        fm_event.successful_koji_builds.connect(cb)
        fm_event.requested_builds.connect(fm_build)

    if resource == 'containerbuild':
        fm_event.successful_koji_builds.connect(cb)

    rv = client.get('/api/v1/{0}/{1}'.format(resource, uid))
    assert rv.status_code == 200
    assert json.loads(rv.data.decode('utf-8')) == expected
Example #21
0
def test_get_stories(client, resource, uid, expected):
    """Test getting a resource story from Neo4j with its relationships."""
    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]
    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',
        'type_':
        'RHBA',
        'update_date':
        datetime(2017, 8, 1, 7, 16),
        'updated_at':
        datetime(2017, 8, 1, 15, 43, 51)
    })[0]
    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]
    bug_two = BugzillaBug.get_or_create({
        'classification':
        'Red Hat',
        'creation_time':
        datetime(2017, 4, 2, 6, 43, 58),
        'id_':
        '5555',
        'modified_time':
        datetime(2017, 12, 5, 10, 12, 47),
        'priority':
        'unspecified',
        'product_name':
        'Red Hat CloudForms Management Engine',
        'product_version':
        '5.7.0',
        'resolution':
        'WORKSFORME',
        'severity':
        'unspecified',
        'short_description':
        'Fail to delete OSP tenant by CFME',
        'status':
        'CLOSED',
        'target_milestone':
        'GA',
        'votes':
        0
    })[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]
    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.',
        'url': '/api/1/events/1180'
    })[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]

    commit.resolved_bugs.connect(bug_two)
    commit.resolved_bugs.connect(bug)
    commit.koji_builds.connect(build)
    build.advisories.connect(advisory)
    advisory.attached_builds.connect(build)
    fm_event.triggered_by_advisory.connect(advisory)
    fm_event.triggered_container_builds.connect(cb)

    rv = client.get('/api/v1/story/{0}/{1}'.format(resource, uid))
    assert rv.status_code == 200
    assert json.loads(rv.data.decode('utf-8')) == expected
Example #22
0
    def update_neo4j(self, advisories):
        """
        Update Neo4j with Errata Tool advisories from Teiid.

        :param list advisories: a list of dictionaries of advisories
        """
        count = 0
        for advisory in advisories:
            count += 1
            log.info('Processing advisory {0}/{1}'.format(
                count, len(advisories)))
            # The content_types column is a string with YAML in it, so convert it to a list
            content_types = yaml.safe_load(advisories[0]['content_types'])
            adv = Advisory.create_or_update({
                'actual_ship_date':
                advisory['actual_ship_date'],
                'advisory_name':
                advisory['advisory_name'],
                'content_types':
                content_types,
                'created_at':
                advisory['created_at'],
                'id_':
                advisory['id'],
                'issue_date':
                advisory['issue_date'],
                'product_name':
                advisory['product_name'],
                'product_short_name':
                advisory['product_short_name'],
                'release_date':
                advisory['release_date'],
                'security_impact':
                advisory['security_impact'],
                'security_sla':
                advisory['security_sla'],
                'state':
                advisory['state'],
                'status_time':
                advisory['status_time'],
                'synopsis':
                advisory['synopsis'],
                'type_':
                advisory['type'],
                'update_date':
                advisory['update_date'],
                'updated_at':
                advisory['updated_at']
            })[0]
            assigned_to = User.get_or_create(
                {'username': advisory['assigned_to'].split('@')[0]})[0]
            adv.conditional_connect(adv.assigned_to, assigned_to)
            package_owner = User.get_or_create(
                {'username': advisory['package_owner'].split('@')[0]})[0]
            adv.conditional_connect(adv.package_owner, package_owner)
            reporter = User.get_or_create(
                {'username': advisory['reporter'].split('@')[0]})[0]
            adv.conditional_connect(adv.reporter, reporter)

            for state in self.get_advisory_states(advisory['id']):
                adv_state = AdvisoryState.create_or_update({
                    'id_':
                    state['id'],
                    'name':
                    state['name'],
                    'created_at':
                    state['created_at'],
                    'updated_at':
                    state['updated_at']
                })[0]
                adv_state.conditional_connect(adv_state.advisory, adv)
                state_creator = User.get_or_create(
                    {'username': state['username'].split('@')[0]})[0]
                adv_state.conditional_connect(adv_state.creator, state_creator)

            for attached_bug in self.get_attached_bugs(advisory['id']):
                bug = BugzillaBug.get_or_create(attached_bug)[0]
                adv.attached_bugs.connect(bug)

            for associated_build in self.get_associated_builds(advisory['id']):
                # If this is set, that means it was once part of the advisory but not anymore.
                # This relationship needs to be deleted if it exists.
                if associated_build['removed_index_id']:
                    build = KojiBuild.nodes.get_or_none(
                        id_=associated_build['id_'])
                    if build:
                        adv.attached_builds.disconnect(build)
                else:
                    # This key shouldn't be stored in Neo4j
                    del associated_build['removed_index_id']
                    build = KojiBuild.get_or_create(associated_build)[0]
                    adv.attached_builds.connect(build)
Example #23
0
def test_get_stories_just_artifact(client):
    """Test getting the story for a resource but only the artifact is returned."""
    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',
        'type_': 'RHBA',
        'update_date': datetime(2017, 8, 1, 7, 16),
        'updated_at': datetime(2017, 8, 1, 15, 43, 51)
    })[0]
    expected = {
        'data': [{
            'actual_ship_date': '2017-08-01T15:43:51+00:00',
            'advisory_name': 'RHBA-2017:2251-02',
            'assigned_to': None,
            'attached_bugs': [],
            'attached_builds': [],
            'content_types': ['docker'],
            'created_at': '2017-04-03T14:47:23+00:00',
            'id': '27825',
            'issue_date': '2017-08-01T05:59:34+00:00',
            'package_owner': None,
            'product_name': 'Red Hat Enterprise Linux',
            'product_short_name': 'RHEL',
            'release_date': None,
            'reporter': None,
            'resource_type': 'Advisory',
            'security_impact': 'None',
            'security_sla': None,
            'state': 'SHIPPED_LIVE',
            'states': [],
            'status_time': '2017-08-01T15:43:51+00:00',
            'synopsis': 'cifs-utils bug fix update',
            'triggered_freshmaker_event': [],
            'type': 'RHBA',
            'update_date': '2017-08-01T07:16:00+00:00',
            'updated_at': '2017-08-01T15:43:51+00:00'
        }],
        'meta': {
            'related_nodes': {
                'Advisory': 0,
                'BugzillaBug': 0,
                'ContainerKojiBuild': 0,
                'DistGitCommit': 0,
                'FreshmakerEvent': 0,
                'KojiBuild': 0
            }
        }
    }

    rv = client.get('/api/v1/story/advisory/27825')
    assert rv.status_code == 200
    assert json.loads(rv.data.decode('utf-8')) == expected
Example #24
0
def test_all_stories(client, resource, uid, expected):
    """Test getting all unique stories for an artifact."""
    bug = BugzillaBug.get_or_create({
        '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',
    })[0]
    bug_two = BugzillaBug.get_or_create({
        'creation_time': datetime(2017, 4, 1, 17, 41, 4),
        'severity': 'medium',
        'short_description': 'some description',
        'product_version': '7.2',
        'priority': 'unspecified',
        'product_name': 'Red Hat Enterprise Linux 7',
        'resolution': 'DUPLICATE',
        'target_milestone': 'rc',
        'modified_time': datetime(2018, 3, 14, 5, 53, 19),
        'id_': '1245',
        'status': 'CLOSED'
    })[0]
    commit = DistGitCommit.get_or_create({
        'author_date': datetime(2017, 4, 26, 11, 44, 38),
        'commit_date': datetime(2018, 5, 2, 10, 36, 47),
        'hash_': '8a63adb248ba633e200067e1ad6dc61931727bad',
        'log_message': 'Related: #12345 - fix xyz'
    })[0]
    commit_two = DistGitCommit.get_or_create({
        'commit_date': datetime(2018, 3, 14, 5, 52, 19),
        'author_date': datetime(2018, 3, 14, 5, 53, 25),
        'log_message': 'Repo creation',
        'hash_': 'f4dfc64c10a90492303e4f14ad3549a1a2b13575'
    })[0]
    build = KojiBuild.get_or_create({
        'completion_time': datetime(2018, 6, 2, 10, 55, 47),
        'creation_time': datetime(2018, 6, 2, 10, 36, 47),
        'epoch': '0',
        'id_': '2345',
        'name': 'slf4j',
        'release': '4.el7_4',
        'start_time': datetime(2018, 6, 2, 10, 36, 47),
        'state': 1,
        'version': '1.7.4'
    })[0]
    advisory = Advisory.get_or_create({
        'actual_ship_date': datetime(2017, 8, 1, 15, 43, 51),
        'advisory_name': 'RHBA-2017:2251-02',
        'created_at': datetime(2018, 6, 13, 10, 36, 47),
        'id_': '27825',
        'issue_date': datetime(2017, 8, 1, 5, 59, 34),
        'product_name': 'Red Hat Enterprise Linux',
        '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]
    advisory_two = Advisory.get_or_create({
        'security_impact': 'None',
        'created_at': datetime(2018, 4, 21, 19, 36, 47),
        'synopsis': 'This is a synopsis of a test advisory.',
        'product_name': 'Release End2End Test',
        'update_date': datetime(2018, 4, 21, 19, 36, 47),
        'advisory_name': 'RHBA-2017:27760-01',
        'issue_date': datetime(2018, 3, 14, 5, 53, 25),
        'status_time': datetime(2018, 3, 14, 7, 53, 25),
        'state': 'DROPPED_NO_SHIP',
        'id_': '123456'
    })[0]
    fm_event = FreshmakerEvent.get_or_create({
        'id_': '1180',
        'state_name': 'COMPLETE',
        'state_reason': 'All container images have been rebuilt.',
        'time_created': datetime(2018, 8, 13, 10, 36, 47),
        'time_done': datetime(2018, 8, 13, 12, 45, 47)
    })[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, 8, 17, 13, 55, 47),
        'creation_time': datetime(2018, 8, 17, 8, 32, 47),
        'epoch': '0',
        'id_': '811',
        'name': 'some_build',
        'release': '4.el7_4_as',
        'start_time': datetime(2018, 8, 17, 8, 32, 47),
        'state': 2,
        'version': '1.7.5'
    })[0]

    # Longest story
    commit.resolved_bugs.connect(bug)
    commit.koji_builds.connect(build)
    build.advisories.connect(advisory, {'time_attached': datetime(2018, 6, 13, 10, 36, 47)})
    fm_event.triggered_by_advisory.connect(advisory)
    fm_event.successful_koji_builds.connect(cb)
    fm_event.successful_koji_builds.connect(cb_two)

    # Unique partial stories
    commit_two.resolved_bugs.connect(bug_two)
    commit_two.koji_builds.connect(build)
    build.advisories.connect(advisory_two, {'time_attached': datetime(2018, 4, 21, 19, 36, 47)})

    rv = client.get('/api/v1/allstories/{0}/{1}'.format(resource, uid))
    assert rv.status_code == 200
    assert json.loads(rv.data.decode('utf-8')) == expected
    def advisory_handler(self, msg):
        """
        Handle an Errata tool advisory changes and update Neo4j if necessary.

        :param dict msg: a message to be processed
        """
        advisory_id = msg['body']['headers']['errata_id']

        erratum_url = '{0}/api/v1/erratum/{1}'.format(
            self.config['estuary_updater.errata_url'].rstrip('/'), advisory_id)
        response = requests.get(erratum_url,
                                auth=requests_kerberos.HTTPKerberosAuth(),
                                timeout=10)
        advisory_json = response.json()

        advisory_type = msg['body']['headers']['type'].lower()
        advisory_info = advisory_json['errata'][advisory_type]

        embargoed = msg['body']['headers']['synopsis'] == 'REDACTED'
        # We can't store information on embargoed advisories other than the ID
        if not embargoed:
            product_url = '{0}/products/{1}.json'.format(
                self.config['estuary_updater.errata_url'].rstrip('/'),
                advisory_info['product_id'])
            response = requests.get(product_url,
                                    auth=requests_kerberos.HTTPKerberosAuth(),
                                    timeout=10)
            product_json = response.json()

            reporter_url = '{0}/api/v1/user/{1}'.format(
                self.config['estuary_updater.errata_url'].rstrip('/'),
                advisory_info['reporter_id'])
            response = requests.get(reporter_url,
                                    auth=requests_kerberos.HTTPKerberosAuth(),
                                    timeout=10)
            reporter_json = response.json()

            reporter = User.create_or_update({
                'username':
                reporter_json['login_name'].split('@')[0],
                'email':
                reporter_json['email_address']
            })[0]

            assigned_to_url = '{0}/api/v1/user/{1}'.format(
                self.config['estuary_updater.errata_url'].rstrip('/'),
                advisory_info['assigned_to_id'])
            response = requests.get(assigned_to_url,
                                    auth=requests_kerberos.HTTPKerberosAuth(),
                                    timeout=10)
            assigned_to_json = response.json()

            assigned_to = User.create_or_update({
                'username':
                assigned_to_json['login_name'].split('@')[0],
                'email':
                assigned_to_json['email_address']
            })[0]

            advisory_params = {
                'advisory_name': advisory_info['fulladvisory'],
                'id_': advisory_id,
                'product_name': product_json['product']['name'],
                'security_impact': advisory_info['security_impact'],
                'state': advisory_info['status'],
                'synopsis': msg['body']['headers']['synopsis']
            }
            for dt in ('actual_ship_date', 'created_at', 'issue_date',
                       'release_date', 'security_sla', 'status_updated_at',
                       'update_date'):
                if advisory_info[dt]:
                    if dt == 'status_updated_at':
                        estuary_key = 'status_time'
                    else:
                        estuary_key = dt
                    advisory_params[estuary_key] = timestamp_to_datetime(
                        advisory_info[dt])
        else:
            advisory_params = {
                'id_': advisory_id,
                # Set this to REDACTED and it'll be updated when it becomes public
                'advisory_name': 'REDACTED'
            }

        if 'docker' in advisory_info['content_types']:
            try:
                advisory = ContainerAdvisory.create_or_update(
                    advisory_params)[0]
            except neomodel.exceptions.ConstraintValidationFailed:
                # This must have errantly been created as an Advisory instead of a
                # ContainerAdvisory, so let's fix that.
                advisory = Advisory.nodes.get_or_none(id_=advisory_id)
                if not advisory:
                    # If there was a constraint validation failure and the advisory isn't just
                    # the wrong label, then we can't recover.
                    raise
                advisory.add_label(ContainerAdvisory.__label__)
                advisory = ContainerAdvisory.create_or_update(
                    advisory_params)[0]
        else:
            # Check to see if a ContainerAdvisory using this id already exists, and if so remove its
            # label because it should not be a ContainerAdvisory if docker isn't a content type.
            container_adv = ContainerAdvisory.nodes.get_or_none(
                id_=advisory_id)
            if container_adv:
                container_adv.remove_label(ContainerAdvisory.__label__)
            advisory = Advisory.create_or_update(advisory_params)[0]

        if not embargoed:
            advisory.conditional_connect(advisory.reporter, reporter)
            advisory.conditional_connect(advisory.assigned_to, assigned_to)

            bugs = advisory_json['bugs']['bugs']

            for bug in bugs:
                bug = BugzillaBug.get_or_create({'id_': bug['bug']['id']})[0]
                advisory.attached_bugs.connect(bug)
Example #26
0
def test_get_recent_nodes(client):
    """Test the get_recent_nodes function."""
    id_dict = {
        FreshmakerEvent.__label__: 'id',
        BugzillaBug.__label__: 'id',
        DistGitCommit.__label__: 'hash',
        KojiBuild.__label__: 'id',
        Advisory.__label__: 'id'
    }
    timestamp_dict = {
        FreshmakerEvent.__label__: 'time_created',
        BugzillaBug.__label__: 'modified_time',
        DistGitCommit.__label__: 'commit_date',
        KojiBuild.__label__: 'completion_time',
        Advisory.__label__: 'update_date'
    }
    expected = {
        'data': {
            'Advisory': [{
                'advisory_name': 'RHBA-2017:27760-01',
                'update_date': '2017-05-30T11:44:38Z',
                'issue_date': None,
                'created_at': None,
                'state': None,
                'product_name': None,
                'security_sla': None,
                'synopsis': None,
                'security_impact': None,
                'status_time': None,
                'actual_ship_date': None,
                'release_date': None,
                'id': '66666',
                'display_name': 'RHBA-2017:27760-01',
                'resource_type': 'Advisory',
                'assigned_to': None,
                'attached_bugs': [],
                'attached_builds': [],
                'triggered_freshmaker_event': [],
                'reporter': None
            }],
            'DistGitCommit': [{
                'log_message': None,
                'author': None,
                'author_date': None,
                'koji_builds': [],
                'hash': '55555',
                'commit_date': '2017-05-02T11:44:38Z',
                'display_name': 'commit #55555',
                'resource_type': 'DistGitCommit',
                'related_bugs': [],
                'repos': [],
                'resolved_bugs': [],
                'reverted_bugs': []
            }],
            'FreshmakerEvent': [{
                'state_reason': None,
                'state_name': None,
                'time_created': '2017-05-30T11:44:38Z',
                'time_done': None,
                'id': '77777',
                'display_name': 'Freshmaker event 77777',
                'resource_type': 'FreshmakerEvent',
                'requested_builds': [],
                'successful_koji_builds': [],
                'triggered_by_advisory': None,
            }],
            'KojiBuild': [{
                'name': 'slf4j',
                'start_time': None,
                'creation_time': None,
                'state': None,
                'completion_time': '2017-05-27T11:44:38Z',
                'epoch': None,
                'version': '1.7.4',
                'release': '4.el7_4',
                'id': '44444',
                'display_name': 'slf4j-1.7.4-4.el7_4',
                'resource_type': 'KojiBuild',
                'module_builds': [],
                'owner': None,
                'commit': None,
                'advisories': []
            }],
            'BugzillaBug': [{
                'status': None,
                'severity': None,
                'resolution': None,
                'product_version': None,
                'creation_time': None,
                'modified_time': '2017-06-26T11:44:38Z',
                'product_name': None,
                'priority': None,
                'short_description': None,
                'target_milestone': None,
                'id': '22222',
                'display_name': 'RHBZ#22222',
                'resource_type': 'BugzillaBug',
                'assignee': None,
                'attached_advisories': [],
                'qa_contact': None,
                'related_by_commits': [],
                'reporter': None,
                'resolved_by_commits': [],
                'reverted_by_commits': []
            }, {
                'status': None,
                'severity': None,
                'resolution': None,
                'product_version': None,
                'creation_time': None,
                'modified_time': '2017-05-26T11:44:38Z',
                'product_name': None,
                'priority': None,
                'short_description': None,
                'target_milestone': None,
                'id': '33333',
                'display_name': 'RHBZ#33333',
                'resource_type': 'BugzillaBug',
                'assignee': None,
                'attached_advisories': [],
                'qa_contact': None,
                'related_by_commits': [],
                'reporter': None,
                'resolved_by_commits': [],
                'reverted_by_commits': []
            }, {
                'status': None,
                'severity': None,
                'resolution': None,
                'product_version': None,
                'creation_time': None,
                'modified_time': '2017-04-26T11:44:38Z',
                'product_name': None,
                'priority': None,
                'short_description': None,
                'target_milestone': None,
                'id': '11111',
                'display_name': 'RHBZ#11111',
                'resource_type': 'BugzillaBug',
                'assignee': None,
                'attached_advisories': [],
                'qa_contact': None,
                'related_by_commits': [],
                'reporter': None,
                'resolved_by_commits': [],
                'reverted_by_commits': []
            }]
        },
        'metadata': {
            'id_keys': id_dict,
            'timestamp_keys': timestamp_dict
        }
    }

    BugzillaBug.get_or_create({
        'id_':
        '11111',
        'modified_time':
        datetime(2017, 4, 26, 11, 44, 38)
    })
    BugzillaBug.get_or_create({
        'id_':
        '22222',
        'modified_time':
        datetime(2017, 6, 26, 11, 44, 38)
    })
    BugzillaBug.get_or_create({
        'id_':
        '33333',
        'modified_time':
        datetime(2017, 5, 26, 11, 44, 38)
    })
    KojiBuild.get_or_create({
        'id_':
        '44444',
        'completion_time':
        datetime(2017, 5, 27, 11, 44, 38),
        'name':
        'slf4j',
        'version':
        '1.7.4',
        'release':
        '4.el7_4'
    })
    DistGitCommit.get_or_create({
        'hash_': '55555',
        'commit_date': datetime(2017, 5, 2, 11, 44, 38)
    })
    Advisory.get_or_create({
        'id_': '66666',
        'update_date': datetime(2017, 5, 30, 11, 44, 38),
        'advisory_name': 'RHBA-2017:27760-01'
    })
    FreshmakerEvent.get_or_create({
        'id_':
        '77777',
        'time_created':
        datetime(2017, 5, 30, 11, 44, 38),
    })

    rv = client.get('/api/v1/recents')
    assert rv.status_code == 200
    assert json.loads(rv.data.decode('utf-8')) == expected