Esempio n. 1
0
class DendriteTest(unittest.TestCase):
    'These tests require a MQTT broker'

    def setUp(self):
        self.dendrite = Dendrite()
        self.mqtt = client.Client()
        self.mqtt.connect(Dendrite.MQTT_HOST, Dendrite.MQTT_PORT)

    def tearDown(self):
        self.dendrite.finish()
        self.mqtt.disconnect()

    def test_publish(self):
        topic1 = 'test/topic1'
        topic2 = 'test/topic2'
        msg1 = dict(test='OK')

        self.mqtt.subscribe(topic1)
        self.mqtt.subscribe(topic2)

        future = concurrent.futures.Future()

        def on_message(client, userdata, message):
            future.set_result(message)

        self.mqtt.on_message = on_message
        self.mqtt.loop_start()

        time.sleep(1)
        self.dendrite.publish(topic1, msg1)

        msg = future.result(2)

        self.assertEqual(json.loads(msg.payload.decode()), msg1)
        self.assertEqual(msg.topic, topic1)

        msg2 = dict(test=dict(OK='ok'), OK='ok')

        results = []
        future = concurrent.futures.Future()

        def on_message2(client, userdata, message):
            results.append(message)
            if len(results) == 3:
                future.set_result(True)

        self.mqtt.on_message = on_message2

        self.dendrite.publish(topic2, msg1)
        self.dendrite.publish(topic2, msg2)
        self.dendrite.publish(topic1, msg2)

        future.result(2)

        self.assertEqual(json.loads(results[0].payload.decode()), msg1)
        self.assertEqual(results[0].topic, topic2)

        self.assertEqual(json.loads(results[1].payload.decode()), msg2)
        self.assertEqual(results[1].topic, topic2)

        self.assertEqual(json.loads(results[2].payload.decode()), msg2)
        self.assertEqual(results[2].topic, topic1)

    def test_subscribe(self):
        topic1 = 'test/topic1'
        msg1 = dict(test='OK', msg=1)

        future = concurrent.futures.Future()

        def get_msg(msg, topic):
            future.set_result({ 'msg': msg, 'topic': topic})

        self.dendrite.subscribe(topic1, get_msg)

        time.sleep(1)

        self.mqtt.publish(topic1, json.dumps(msg1))

        result = future.result(2)
        self.assertEqual(result, {'msg': msg1, 'topic': topic1})

    def test_subscribe_1arg(self):
        topic1 = 'test/topic1'
        msg1 = dict(test='OK', msg=1)

        future = concurrent.futures.Future()

        def get_msg(msg):
            future.set_result(msg)

        self.dendrite.subscribe(topic1, get_msg)

        time.sleep(1)

        self.mqtt.publish(topic1, json.dumps(msg1))

        result = future.result(2)

        self.assertEqual(result, msg1)

    def test_subscribe_1arg_method(self):
        topic1 = 'test/topic1'
        msg1 = dict(test='OK', msg=1)

        future = concurrent.futures.Future()

        class Dummy:

            def get_msg(self, msg):
                future.set_result(msg)

        d = Dummy()
        self.dendrite.subscribe(topic1, d.get_msg)

        time.sleep(1)

        self.mqtt.publish(topic1, json.dumps(msg1))

        result = future.result(2)

        self.assertEqual(result, msg1)

    def test_call_and_provide(self):

        def cb(data):
            return 'Test OK: ' + data

        service = 'test/fct'
        self.dendrite.provide('test/fct', cb)

        params = str(uuid4())

        result = self.dendrite.call(service, params)

        self.assertEqual(result, 'Test OK: ' + params)

    def test_call_and_provide_exception(self):

        def cb(data):
            raise RequestError({'something': 'happened'}, 'Error: Something Happened !')

        service = 'test/fct2'
        self.dendrite.provide('test/fct2', cb)

        with self.assertRaises(RequestError) as cm:
            self.dendrite.call(service, {})
        self.assertEqual(cm.exception.error_str, 'Error: Something Happened !')
        self.assertEqual(cm.exception.errors, {'something': 'happened'})

    def test_get(self):
        dummy = str(uuid4())
        self.dendrite.publish('test/get', dummy, retain=True)
        result = self.dendrite.get('test/get')

        self.assertEqual(result, dummy)

        Dendrite.publish_single('test/get', retain=True)

        time.sleep(1)

        with self.assertRaises(RequestTimeout):
            self.dendrite.get('test/get')

    def test_get_from_cb(self):
        get_result = []
        dummy = str(uuid4())

        def cb(data):
            self.dendrite.publish('test/get', dummy, retain=True)
            get_result.append(self.dendrite.get('test/get'))
            return 'Test OK: ' + data

        service = 'test/fct'
        self.dendrite.provide('test/fct', cb)

        params = str(uuid4())

        call_result = self.dendrite.call(service, params, timeout=5)

        self.assertEqual(call_result, 'Test OK: ' + params)
        self.assertEqual(get_result[0], dummy)

        Dendrite.publish_single('test/get', retain=True)

    def test_subscribe_cb_exception_catch(self):
        event_instance = Mock()
        with patch('elan.event.ExceptionEvent', return_value=event_instance) as ExceptionEventMock:
            topic1 = 'test/topic1'
            msg1 = dict(test='OK', msg=1)

            future = concurrent.futures.Future()

            def get_msg(msg, topic):
                future.set_result({ 'msg': msg, 'topic': topic})
                raise KeyError("foo")

            self.dendrite.subscribe(topic1, get_msg)

            time.sleep(1)

            self.mqtt.publish(topic1, json.dumps(msg1))

            result = future.result(2)

            time.sleep(1)
            ExceptionEventMock.assert_called_with(source='dendrite-subscribe-cb')

        event_instance.notify.assert_called_once_with()
Esempio n. 2
0
class AxonMapper:
    def __init__(self):
        self.dendrite = Dendrite()

    def run(self):
        configure_axon()

        self.dendrite.provide('register', self.register)
        self.dendrite.provide('check-connectivity', self.check_connectivity)
        self.dendrite.provide('guest-request', self.guest_request)
        self.dendrite.subscribe('notify-knowledge', self.notify_knowledge)

        self.dendrite.wait_complete()

    def notify_knowledge(self, info):
        if 'sessions' in info:
            session.notify_current_sessions()
        if 'hostnames' in info:
            device.notify_known_hostnames()
        if 'fingerprints' in info:
            device.notify_known_fingerprints()

    def guest_request(self, request):
        response = self.dendrite.call('elan-center/guest-request', request)

        if response['sponsor_email'] or response['fixed_recipients']:
            # send mail
            lookup = TemplateLookup(['/elan-agent/elan-center', '.'])
            html_template = Template(
                filename='/elan-agent/elan-center/guest-request-email.html',
                lookup=lookup)
            text_template = Template(
                filename='/elan-agent/elan-center/guest-request-email.txt',
                lookup=lookup)
            html = html_template.render(**response)
            text = text_template.render(**response)

            if not response['sponsor_email']:
                recipients = response['fixed_recipients']
                bcc_recipients = []
            else:
                recipients = [response['sponsor_email']]
                bcc_recipients = response['fixed_recipients']

            send_mail(recipients=recipients,
                      bcc_recipients=bcc_recipients,
                      html=html,
                      text=text,
                      mail_subject='Guest Request for Network Access')

        return response

    def check_connectivity(self, data=None):
        # check elan-center connectivity
        try:
            connected = bool(
                int(
                    self.dendrite.get(
                        '$SYS/broker/connection/{uuid}/state'.format(
                            uuid=synapse.get(AGENT_UUID_PATH)))))
        except RequestTimeout:
            connected = False

        if connected:
            return {'status': 'connected'}
        raise RequestError('Connection to ELAN Center down')

    def register(self, data):
        # settings.configure must have been called before this imort
        from django.contrib.auth.hashers import make_password

        # check elan-center connectivity
        self.check_connectivity()

        if not data:
            return {'status': 'available'}

        data['interfaces'] = sorted(utils.physical_ifaces())

        result = self.dendrite.call(
            'elan-center/register',
            data)  # raises RequestError if registration fails

        # store this admin in conf (should be overridien once Axon correctly configured)
        self.dendrite.publish_conf('administrator', [
            dict(login=data['login'], password=make_password(data['password']))
        ])

        synapse.set(ACCOUNT_ID_PATH, result['account'])
        synapse.set(AGENT_ID_PATH, result['id'])
        synapse.set(AGENT_UUID_PATH, result['uuid'])

        # delay configuration so that caller has time to receive response...
        def delayed_action():
            configure_axon()
            # wait axon really started.
            time.sleep(5.0)
            session.notify_current_sessions()
            device.notify_known_hostnames()
            device.notify_known_fingerprints()

        t = threading.Timer(3.0, delayed_action)
        t.start()

        return {'status': 'registered'}