コード例 #1
0
    def test_core_submission(self):
        data = 'I am an ELF binary. No, really.'
        core_io = StringIO(data)
        uuid = '12345678-1234-5678-1234-567812345678'
        environ = {
            'QUERY_STRING': 'uuid=%s&arch=amd64' % uuid,
            'CONTENT_TYPE': 'application/octet-stream',
            'wsgi.input': core_io,
            'PATH_INFO': '/%s/submit-core/amd64' % uuid
        }
        stack_addr_sig = (
            '/usr/bin/foo:11:x86_64/lib/x86_64-linux-gnu/libc-2.15.so+e4d93:'
            '/usr/bin/foo+1e071')
        path = tempfile.mkdtemp()
        self.addCleanup(shutil.rmtree, path)
        pool = pycassa.ConnectionPool(self.keyspace,
                                      config.cassandra_hosts,
                                      credentials=self.creds)
        oops_cf = pycassa.ColumnFamily(pool, 'OOPS')
        oops_cf.insert(uuid, {'StacktraceAddressSignature': stack_addr_sig})

        with mock.patch('daisy.submit_core.config', autospec=True) as cfg:
            cfg.core_storage = {'local': {'type': 'local', 'path': path}}
            cfg.storage_write_weights = {'local': 1.0}
            cfg.write_weight_ranges = {'local': (0.0, 1.0)}
            wsgi.app(environ, self.start_response)
        self.assertEqual(self.start_response.call_args[0][0], '200 OK')

        # Did we actually write the core file to disk?
        with open(os.path.join(path, uuid)) as fp:
            contents = fp.read()
        self.assertEqual(contents, data)

        # Did we put the crash on the retracing queue?
        channel = self.conn_mock.return_value.channel
        basic_publish_call = channel.return_value.basic_publish.call_args
        kwargs = basic_publish_call[1]
        self.assertEqual(kwargs['routing_key'], 'retrace_amd64')
        self.assertEqual(kwargs['exchange'], '')
        msg = '%s:local' % uuid
        self.assertEqual(self.msg_mock.call_args[0][0], msg)
        self.assertTrue(os.path.exists(os.path.join(path, uuid)))

        # did we mark this as retracing in Cassandra?
        indexes_cf = pycassa.ColumnFamily(pool, 'Indexes')
        indexes_cf.get('retracing', [stack_addr_sig])
コード例 #2
0
    def test_binary_submission_not_retraced(self):
        '''If a binary crash has been submitted that we do not have a core file
        for, either already retraced or awaiting to be retraced.'''

        resp = wsgi.app(self.environ, self.start_response)[0]
        self.assertEqual(self.start_response.call_args[0][0], '200 OK')
        # We should get back a request for the core file:
        self.assertTrue(resp.endswith(' CORE'))

        # It should end up in the AwaitingRetrace CF queue.
        pool = pycassa.ConnectionPool(self.keyspace,
                                      config.cassandra_hosts,
                                      credentials=self.creds)
        awaiting_retrace_cf = pycassa.ColumnFamily(pool, 'AwaitingRetrace')
        oops_cf = pycassa.ColumnFamily(pool, 'OOPS')
        oops_id = oops_cf.get_range().next()[0]
        self.assertEqual(
            awaiting_retrace_cf.get(self.stack_addr_sig).keys()[0], oops_id)
コード例 #3
0
    def test_binary_submission_already_retraced(self):
        '''If a binary crash has been submitted that we have a fully-retraced
        core file for.'''
        pool = pycassa.ConnectionPool(self.keyspace,
                                      config.cassandra_hosts,
                                      credentials=self.creds)
        indexes_cf = pycassa.ColumnFamily(pool, 'Indexes')
        bucket_cf = pycassa.ColumnFamily(pool, 'Bucket')
        oops_cf = pycassa.ColumnFamily(pool, 'OOPS')

        indexes_cf.insert('crash_signature_for_stacktrace_address_signature',
                          {self.stack_addr_sig: 'fake-crash-signature'})

        resp = wsgi.app(self.environ, self.start_response)[0]
        self.assertEqual(self.start_response.call_args[0][0], '200 OK')
        # We should not get back a request for the core file:
        self.assertEqual(resp, '')

        # Make sure 'foo' ends up in the bucket.
        oops_id = oops_cf.get_range().next()[0]
        bucket_contents = bucket_cf.get('fake-crash-signature').keys()
        self.assertEqual(bucket_contents, [pycassa.util.uuid.UUID(oops_id)])
コード例 #4
0
    def test_binary_submission_retrace_queued(self):
        '''If a binary crash has been submitted that we do have a core file
        for, but it has not been retraced yet.'''
        # Lets pretend we've seen the stacktrace address signature before, and
        # have received a core file for it, but have not finished retracing it:
        pool = pycassa.ConnectionPool(self.keyspace,
                                      config.cassandra_hosts,
                                      credentials=self.creds)
        awaiting_retrace_cf = pycassa.ColumnFamily(pool, 'AwaitingRetrace')
        oops_cf = pycassa.ColumnFamily(pool, 'OOPS')
        indexes_cf = pycassa.ColumnFamily(pool, 'Indexes')
        indexes_cf.insert('retracing', {self.stack_addr_sig: ''})

        resp = wsgi.app(self.environ, self.start_response)[0]
        self.assertEqual(self.start_response.call_args[0][0], '200 OK')
        # We should not get back a request for the core file:
        self.assertEqual(resp, '')
        # Ensure the crash was bucketed and added to the AwaitingRetrace CF
        # queue:
        oops_id = oops_cf.get_range().next()[0]
        self.assertEqual(
            awaiting_retrace_cf.get(self.stack_addr_sig).keys()[0], oops_id)
コード例 #5
0
    def test_python_submission(self):
        '''Ensure that a Python crash is accepted, bucketed, and that the
        retracing ColumnFamilies remain untouched.'''

        report = apport.Report()
        report['ProblemType'] = 'Crash'
        report['InterpreterPath'] = '/usr/bin/python'
        report['ExecutablePath'] = '/usr/bin/foo'
        report['DistroRelease'] = 'Ubuntu 12.04'
        report['Package'] = 'ubiquity 2.34'
        report['Traceback'] = ('Traceback (most recent call last):\n'
                               '  File "/usr/bin/foo", line 1, in <module>\n'
                               '    sys.exit(1)')
        report_bson = bson.BSON.encode(report.data)
        report_io = StringIO(report_bson)
        environ = {
            'CONTENT_TYPE': 'application/octet-stream',
            'PATH_INFO': sha512_system_uuid,
            'wsgi.input': report_io
        }

        wsgi.app(environ, self.start_response)
        self.assertEqual(self.start_response.call_args[0][0], '200 OK')

        pool = pycassa.ConnectionPool(self.keyspace,
                                      config.cassandra_hosts,
                                      credentials=self.creds)
        oops_cf = pycassa.ColumnFamily(pool, 'OOPS')
        bucket_cf = pycassa.ColumnFamily(pool, 'Bucket')
        # Ensure the crash was bucketed:
        oops_id = oops_cf.get_range().next()[0]
        crash_signature = '/usr/bin/foo:    sys.exit(1):/usr/bin/foo@1'
        self.assertEqual(pycassa.util.uuid.UUID(oops_id),
                         bucket_cf.get(crash_signature).keys()[0])

        # A Python crash shouldn't touch the retracing CFs:
        for fam in ('AwaitingRetrace', 'Stacktrace', 'Indexes'):
            cf = pycassa.ColumnFamily(pool, fam)
            self.assertEqual([x for x in cf.get_range()], [])
        cf = pycassa.ColumnFamily(pool, 'DayBucketsCount')
        counts = [x for x in cf.get_range()]
        day_key = time.strftime('%Y%m%d', time.gmtime())
        resolutions = (day_key, day_key[:4], day_key[:6])
        release = report['DistroRelease']
        keys = []
        for resolution in resolutions:
            keys.append('%s:%s' % (release, resolution))
        for resolution in resolutions:
            keys.append('%s:ubiquity:%s' % (release, resolution))
        for resolution in resolutions:
            keys.append('%s:ubiquity:2.34:%s' % (release, resolution))
        for resolution in resolutions:
            keys.append('ubiquity:2.34:%s' % resolution)
        'ubiquity:2.34'

        for key in keys:
            found = False
            for count in counts:
                if count[0] == key:
                    found = True
            self.assertTrue(found, 'Could not find %s' % key)
            for count in counts:
                self.assertEqual(count[1].values(), [1])
コード例 #6
0
 def test_bogus_submission(self):
     environ = {'PATH_INFO': '/', 'wsgi.input': StringIO('')}
     wsgi.app(environ, self.start_response)
     self.assertEqual(self.start_response.call_args[0][0],
                      '400 Bad Request')
コード例 #7
0
    def test_kerneloops_submission(self):
        oops_text = '''BUG: unable to handle kernel paging request at ffffb4ff
IP: [<c11e4690>] ext4_get_acl+0x80/0x210
*pde = 01874067 *pte = 00000000 
Oops: 0000 [#1] SMP 
Modules linked in: bnep rfcomm bluetooth dm_crypt olpc_xo1 scx200_acb snd_cs5535audio snd_ac97_codec ac97_bus snd_pcm snd_seq_midi snd_rawmidi snd_seq_midi_event snd_seq snd_timer snd_seq_device snd cs5535_gpio soundcore snd_page_alloc binfmt_misc geode_aes cs5535_mfd geode_rng msr vesafb usbhid hid 8139too pata_cs5536 8139cp

Pid: 1798, comm: gnome-session-c Not tainted 3.0.0-11-generic #17-Ubuntu First International Computer, Inc.  ION603/ION603
EIP: 0060:[<c11e4690>] EFLAGS: 00010286 CPU: 0
EIP is at ext4_get_acl+0x80/0x210
EAX: f5d3009c EBX: f5d30088 ECX: 00000000 EDX: f5d301d8
ESI: ffffb4ff EDI: 00008000 EBP: f29b3dc8 ESP: f29b3da4
 DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
Process gnome-session-c (pid: 1798, ti=f29b2000 task=f2bd72c0 task.ti=f29b2000)
Stack:
 f29b3db0 c113bb90 f5d301d8 f29b3de4 c11b9016 f5d3009c f5d30088 f5d30088
 00000001 f29b3ddc c11e4cca 00000001 f5d30088 000081ed f29b3df0 c11313b7
 00000021 00000021 f5d30088 f29b3e08 c1131b45 c11e4c80 f5d30088 00000021
Call Trace:
 [<c113bb90>] ? d_splice_alias+0x40/0x50
 [<c11b9016>] ? ext4_lookup.part.30+0x56/0x120
 [<c11e4cca>] ext4_check_acl+0x4a/0x90
 [<c11313b7>] acl_permission_check+0x97/0xa0
 [<c1131b45>] generic_permission+0x25/0xc0
 [<c11e4c80>] ? ext4_xattr_set_acl+0x160/0x160
 [<c1131c79>] inode_permission+0x99/0xd0
 [<c11e4c80>] ? ext4_xattr_set_acl+0x160/0x160
 [<c1131d1b>] may_open+0x6b/0x110
 [<c1134566>] do_last+0x1a6/0x640
 [<c113595d>] path_openat+0x9d/0x350
 [<c10de692>] ? unlock_page+0x42/0x50
 [<c10fb960>] ? __do_fault+0x3b0/0x4b0
 [<c1135c41>] do_filp_open+0x31/0x80
 [<c124c743>] ? aa_dup_task_context+0x33/0x60
 [<c1250eed>] ? apparmor_cred_prepare+0x2d/0x50
 [<c112e9ef>] open_exec+0x2f/0x110
 [<c112eef7>] ? check_unsafe_exec+0xb7/0xf0
 [<c112efba>] do_execve_common+0x8a/0x270
 [<c112f1b7>] do_execve+0x17/0x20
 [<c100a0a7>] sys_execve+0x37/0x70
 [<c15336ae>] ptregs_execve+0x12/0x18
 [<c152c8d4>] ? syscall_call+0x7/0xb
Code: 8d 76 00 8d 93 54 01 00 00 8b 32 85 f6 74 e2 8d 43 14 89 55 e4 89 45 f0 e8 2e 7e 34 00 8b 55 e4 8b 32 83 fe ff 74 07 85 f6 74 03 <3e> ff 06 8b 45 f0 e8 25 19 e4 ff 90 83 fe ff 75 b5 81 ff 00 40 
EIP: [<c11e4690>] ext4_get_acl+0x80/0x210 SS:ESP 0068:f29b3da4
CR2: 00000000ffffb4ff
---[ end trace b567e6a3070ffb42 ]---'''
        bucket = 'kernel paging request:ext4_get_acl+0x80/0x210:ext4_check_acl+0x4a/0x90:acl_permission_check+0x97/0xa0:generic_permission+0x25/0xc0:inode_permission+0x99/0xd0:may_open+0x6b/0x110:do_last+0x1a6/0x640:path_openat+0x9d/0x350:do_filp_open+0x31/0x80:open_exec+0x2f/0x110:do_execve_common+0x8a/0x270:do_execve+0x17/0x20:sys_execve+0x37/0x70:ptregs_execve+0x12/0x18'
        report = apport.Report()
        report['ProblemType'] = 'KernelOops'
        report['OopsText'] = oops_text
        report_bson = bson.BSON.encode(report.data)
        report_io = StringIO(report_bson)
        environ = {
            'CONTENT_TYPE': 'application/octet-stream',
            'PATH_INFO': sha512_system_uuid,
            'wsgi.input': report_io
        }

        wsgi.app(environ, self.start_response)
        pool = pycassa.ConnectionPool(self.keyspace,
                                      config.cassandra_hosts,
                                      credentials=self.creds)
        oops_cf = pycassa.ColumnFamily(pool, 'OOPS')
        bucket_cf = pycassa.ColumnFamily(pool, 'Bucket')
        oops_id = oops_cf.get_range().next()[0]
        bucket_id, unused_oops_id = bucket_cf.get_range().next()
        self.assertEqual(bucket_id, bucket)