def __init__(self): super(MQTTClientHandler, self).__init__() e = EventMaker() goodbye = e.Event(e.ClientLeave(e.Id(Environment.getInstance().uuid))) self.will_set("%s/client/%s" % (self.domain, self.env.uuid), goodbye, qos=2)
def test_send_event(self): e = EventMaker() event = e.Event(e.ClientPoll()) self.mqtt.send_event(event, "test/topic") self.mqtt.get_client().publish.assert_called_with( "test/topic", etree.tostring(event, pretty_print=True).decode(), qos=0)
def test_notification(self, mocked_resolver): e = EventMaker() with mock.patch("gosa.backend.routes.sse.main.SseHandler.send_message" ) as m_send: event = e.Event( e.Notification(e.Target('admin'), e.Body('Test'), e.Title('Notification'), e.Icon('test-icon'), e.Timeout("1000"))) event_object = objectify.fromstring( etree.tostring(event, pretty_print=True).decode('utf-8')) SseHandler.notify(event_object, event_object.Notification.Target) m_send.assert_called_with( { "title": "Notification", "body": "Test", "icon": "test-icon", "timeout": 1000 }, topic="notification", channel="admin") SseHandler.notify(event_object) m_send.assert_called_with( { "title": "Notification", "body": "Test", "icon": "test-icon", "timeout": 1000 }, topic="notification", channel="broadcast")
def test_clientLeave(self): service = PluginRegistry.getInstance("MQTTRPCService") e = EventMaker() goodbye = e.Event(e.ClientLeave(e.Id("fake_uuid"))) data = etree.tostring(goodbye).decode('utf-8') with mock.patch.object(PluginRegistry.getInstance("BackendRegistry"), "unregisterBackend") as m: service.handle_request( "%s/proxy" % Environment.getInstance().domain, data) m.assert_called_with("fake_uuid")
def __handle_events(self, event): """ React on object modifications to keep active ACLs up to date. """ if event.__class__.__name__ == "IndexScanFinished": self.__refresh() elif event.__class__.__name__ == "ACLChanged": if self.env.mode != "proxy": e = EventMaker() trigger = e.Event(e.Trigger(e.Type(event.__class__.__name__))) self.mqtt.send_event(trigger, "%s/proxy" % self.env.domain)
def test_ZopeEventConsumer(self): e = EventMaker() callback = unittest.mock.Mock() zec = ZopeEventConsumer(callback=callback) event = Event(unittest.mock.MagicMock()) zope.event.notify(event) callback.assert_called_once_with(event.get_data()) callback = unittest.mock.Mock() event = Event(e.Event(e.TestEvent)) zec = ZopeEventConsumer(callback=callback, event_type="TestEvent") zope.event.notify(event) callback.assert_called_once_with(event.get_data())
def __update_population(self): # collect current attribute values data = {} for prop in self._get_attributes(): data[prop] = getattr(self, prop) changes = {} for key in self.__attribute_map: if self.__attribute_map[key][ 'values_populate'] and self.__attribute_map[key][ 're_populate_on_update'] is True: cr = PluginRegistry.getInstance('CommandRegistry') values = cr.call(self.__attribute_map[key]['values_populate'], data) if self.__attribute_map[key]['values'] != values: changes[key] = values self.__attribute_map[key]['values'] = values if len(changes.keys()) and self.__user is not None: e = EventMaker() changed = list() for key, values in changes.items(): change = e.Change(e.PropertyName(key), e.NewValues(dumps(values))) changed.append(change) ev = e.Event( e.ObjectPropertyValuesChanged(e.UUID(self.uuid), *changed)) event_object = objectify.fromstring( etree.tostring(ev).decode('utf-8')) SseHandler.notify(event_object, channel="user.%s" % self.__user)
def test_objectCloseAnnouncement(self, mocked_resolver): e = EventMaker() with mock.patch("gosa.backend.routes.sse.main.SseHandler.send_message" ) as m_send: event = e.Event( e.ObjectCloseAnnouncement(e.UUID('fake_uuid'), e.Minutes('1'), e.State('fake_state'), e.SessionId('fake_session_id'))) event_object = objectify.fromstring( etree.tostring(event, pretty_print=True).decode('utf-8')) SseHandler.notify(event_object, "admin") m_send.assert_called_with( { "uuid": "fake_uuid", "minutes": "1", "state": "fake_state", }, topic="objectCloseAnnouncement", channel="admin", session_id="fake_session_id") SseHandler.notify(event_object) m_send.assert_called_with( { "uuid": "fake_uuid", "minutes": "1", "state": "fake_state", }, topic="objectCloseAnnouncement", channel="broadcast", session_id="fake_session_id")
def test_objectChanged(self, mocked_resolver): e = EventMaker() mod = datetime.datetime.now().strftime("%Y%m%d%H%M%SZ") with mock.patch("gosa.backend.routes.sse.main.SseHandler.send_message" ) as m_send: event = e.Event( e.ObjectChanged(e.UUID('fake_uuid'), e.DN('fake_dn'), e.ModificationTime(mod), e.ChangeType('fake_change_type'))) event_object = objectify.fromstring( etree.tostring(event, pretty_print=True).decode('utf-8')) SseHandler.notify(event_object, "admin") m_send.assert_called_with( { "uuid": "fake_uuid", "dn": "fake_dn", "lastChanged": mod, "changeType": "fake_change_type" }, topic="objectChange", channel="admin") SseHandler.notify(event_object) m_send.assert_called_with( { "uuid": "fake_uuid", "dn": "fake_dn", "lastChanged": mod, "changeType": "fake_change_type" }, topic="objectChange", channel="broadcast")
def notification2event(self, user, title, message, timeout, icon): e = EventMaker() data = [e.Target(user)] if title: data.append(e.Title(title)) data.append(e.Body(message)) if timeout: data.append(e.Timeout(str(timeout * 1000))) if icon != "_no_icon_": data.append(e.Icon(icon)) return e.Event(e.Notification(*data))
def report_to_event(self, file_name): e = EventMaker() amqp_service = PluginRegistry.getInstance("AMQPClientService") with open(file_name, "r") as f: yml = yaml.load(f) logs = [e.Id(self.env.id)] for log in yml.logs: data = [ e.Timestamp(str(mktime(log.time.timetuple()))), e.Level(log.level), e.Message(log.message), ] # Append <Tag> tag try: tags = e.Tag() for tag in log.tags: tags.append(e.value(tag)) data.append(tags) except: pass # Add optional tags try: data.append[e.Source(log.source)] except: pass try: data.append[e.Line(log.line)] except: pass try: data.append[e.File(log.file)] except: pass try: data.append[e.Version(log.version)] except: pass logs.append(e.PuppetLog(*data)) return e.Event(e.PuppetReport(*logs))
def test_handle_backend_message(self): e = EventMaker() # send client poll with mock.patch.object(self.service.proxy_mqtt, "send_message") as mps: # send ACLChanged m_resolver = PluginRegistry.getInstance("ACLResolver") self.service._handle_backend_message( "%s/proxy" % self.env.domain, etree.tostring(e.Event(e.Trigger(e.Type("ACLChanged"))), pretty_print=True).decode()) assert m_resolver.load_acls.called assert not mps.called m_index = PluginRegistry.getInstance("ObjectIndex") self.service._handle_backend_message( "%s/client/broadcast" % self.env.domain, etree.tostring(e.Event(e.ClientPoll()), pretty_print=True).decode()) assert m_index.registerProxy.called assert mps.called mps.reset_mock() # send client RPC payload = dumps({"id": "jsonrpc", "method": "test", "params": []}) topic = "%s/client/client_id/request_id/request" % self.env.domain self.service._handle_backend_message(topic, payload) mps.assert_called_with(payload, topic, qos=1)
def shutdown(a=None, b=None): global dr env = Environment.getInstance() log = logging.getLogger(__name__) # Function to shut down the client. Do some clean up and close sockets. mqtt = PluginRegistry.getInstance("MQTTClientHandler") # Tell others that we're away now e = EventMaker() goodbye = e.Event(e.ClientLeave(e.Id(env.uuid))) if mqtt: mqtt.send_event(goodbye) mqtt.close() # Shutdown plugins PluginRegistry.shutdown() #TODO: remove this hack wait = 1 for t in env.threads: if t.isAlive(): log.warning("thread %s still alive" % t.getName()) if hasattr(t, 'stop'): log.warning("calling 'stop' for thread %s" % t.getName()) t.stop() if hasattr(t, 'cancel'): log.warning("calling 'cancel' for thread %s" % t.getName()) t.cancel() t.join(wait) if t.is_alive(): try: log.warning("calling built in 'stop' for thread %s" % t.getName()) t._stop() except: log.error("could not stop thread %s" % t.getName()) dr.stop() log.info("shut down") logging.shutdown()
def serve(self): self.backend_mqtt = MQTTHandler( host=self.env.config.get("backend.mqtt-host"), port=self.env.config.getint("backend.mqtt-port", default=1883)) # subscribe to all client relevant topics self.backend_mqtt.get_client().add_subscription("%s/client/#" % self.env.domain, qos=1) # subscribe to proxy topic self.backend_mqtt.get_client().add_subscription("%s/proxy" % self.env.domain, qos=1) self.backend_mqtt.set_subscription_callback(self._handle_backend_message) # set our last will and testament e = EventMaker() goodbye = e.Event(e.ClientLeave(e.Id(self.env.core_uuid))) self.backend_mqtt.will_set("%s/proxy" % self.env.domain, goodbye, qos=1) # connect to the proxy MQTT broker (where the clients are listening) self.proxy_mqtt = MQTTHandler( host=self.env.config.get("mqtt.host"), port=self.env.config.getint("mqtt.port", default=1883)) self.proxy_mqtt.get_client().add_subscription("%s/client/#" % self.env.domain, qos=1) self.proxy_mqtt.set_subscription_callback(self._handle_proxy_message)
def netactivity(online): global netstate env = Environment.getInstance() if online: netstate = True env.active = True else: env = Environment.getInstance() netstate = False # Function to shut down the client. Do some clean up and close sockets. mqtt = PluginRegistry.getInstance("MQTTClientHandler") # Tell others that we're away now e = EventMaker() goodbye = e.Event(e.ClientLeave(e.Id(env.uuid))) if mqtt: mqtt.send_event(goodbye) mqtt.close() env.reset_requested = True env.active = False
def extract(self, fn, real_name): try: with ZipFile(fn, 'r') as widget_zip: if widget_zip.testzip(): self.log.error("bad widget zip uploaded") return # extract filename from zip widget_zip.extractall( os.path.join(frontend_path, "gosa", "uploads", "widgets")) # send the event to the clients e = EventMaker() ev = e.Event( e.PluginUpdate(e.Namespace(real_name.split(".")[0]))) event_object = objectify.fromstring( etree.tostring(ev, pretty_print=True).decode('utf-8')) SseHandler.notify(event_object, channel="broadcast") except Exception as e: print(e) raise e
def sendSessionNotification(self): # Build event mqtt = PluginRegistry.getInstance("MQTTClientHandler") e = EventMaker() more = set([x['uid'] for x in self.__sessions.values()]) more = map(e.Name, more) info = e.Event(e.UserSession(e.Id(self.env.uuid), e.User(*more))) mqtt.send_event(info)
def __refresh_reference_object(self, new_dn, override=False): attributes_changed = [] if not self.__reference_object: if new_dn is None: return # initial setting self.__reference_object = ObjectProxy(new_dn) elif self.__reference_object.dn == new_dn: # no change return elif new_dn is None: # reset object for key in self.__attribute: if hasattr(self.__reference_object, key) and \ getattr(self.__reference_object, key) is not None and \ getattr(self, key) == getattr(self.__reference_object, key) and \ self.__attribute_map[key]['mandatory'] is False: setattr(self, key, None) attributes_changed.append(key) self.__reference_object = None return else: self.__reference_object = ObjectProxy(new_dn) # update all attribute values that are not set yet if self.__reference_object is not None: for key in self.__attribute: if hasattr(self.__reference_object, key) and \ getattr(self.__reference_object, key) is not None and \ (getattr(self, key) is None or override is True): setattr(self, key, getattr(self.__reference_object, key)) attributes_changed.append(key) if len(attributes_changed) > 0: # tell the GUI to reload the changes attributes e = EventMaker() ev = e.Event( e.ObjectChanged( e.UUID(self.uuid), e.DN(new_dn), e.ModificationTime( datetime.datetime.now().strftime("%Y%m%d%H%M%SZ")), e.ChangeType("update"))) event_object = objectify.fromstring( etree.tostring(ev, pretty_print=True).decode('utf-8')) SseHandler.notify(event_object, channel="user.%s" % self.__user)
def test_post(self): # create webhook post e = EventMaker() update = e.Event( e.BackendChange( e.DN("cn=Test,ou=people,dc=example,dc=net"), e.ModificationTime(datetime.now().strftime("%Y%m%d%H%M%SZ")), e.ChangeType("update") ) ) payload = etree.tostring(update) token = bytes(Environment.getInstance().config.get("webhooks.ldap_monitor_token"), 'ascii') signature_hash = hmac.new(token, msg=payload, digestmod="sha512") signature = 'sha1=' + signature_hash.hexdigest() headers = { 'Content-Type': 'application/vnd.gosa.event+xml', 'HTTP_X_HUB_SENDER': 'backend-monitor', 'HTTP_X_HUB_SIGNATURE': signature } with mock.patch("gosa.backend.plugins.webhook.registry.zope.event.notify") as m_notify: AsyncHTTPTestCase.fetch(self, "/hooks/", method="POST", headers=headers, body=payload) assert m_notify.called m_notify.reset_mock() # unregistered sender headers['HTTP_X_HUB_SENDER'] = 'unknown' resp = AsyncHTTPTestCase.fetch(self, "/hooks/", method="POST", headers=headers, body=payload) assert resp.code == 401 assert not m_notify.called # wrong signature headers['HTTP_X_HUB_SENDER'] = 'backend-monitor' headers['HTTP_X_HUB_SIGNATURE'] = 'sha1=823rjadfkjlasasddfdgasdfgasd' resp = AsyncHTTPTestCase.fetch(self, "/hooks/", method="POST", headers=headers, body=payload) assert resp.code == 401 assert not m_notify.called # no signature del headers['HTTP_X_HUB_SIGNATURE'] resp = AsyncHTTPTestCase.fetch(self, "/hooks/", method="POST", headers=headers, body=payload) assert resp.code == 401 assert not m_notify.called # no handler for content type headers['HTTP_X_HUB_SIGNATURE'] = signature headers['Content-Type'] = 'application/vnd.gosa.unknown+xml' resp = AsyncHTTPTestCase.fetch(self, "/hooks/", method="POST", headers=headers, body=payload) assert resp.code == 401 assert not m_notify.called
def error_notify_user(cls, prefix, ex, user=None): if user is not None: channel = "user.%s" % user else: channel = "broadcast" logging.getLogger(__name__).error("%s: %s" % (prefix, str(ex))) # report to clients e = EventMaker() ev = e.Event( e.BackendException(e.BackendName("Foreman"), e.ErrorMessage(ex.message), e.Operation(ex.method))) event_object = objectify.fromstring( etree.tostring(ev, pretty_print=True).decode('utf-8')) SseHandler.notify(event_object, channel=channel)
def test_MqttEventConsumer(self): schema = '<?xml version="1.0"?>' \ '<schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:e="http://www.gonicus.de/Events" ' \ 'targetNamespace="http://www.gonicus.de/Events" elementFormDefault="qualified">'\ '<include schemaLocation="%s"/>'\ '<complexType name="Event">'\ '<choice maxOccurs="1" minOccurs="1">'\ '<group ref="e:Events"/>'\ '</choice>'\ '</complexType>'\ '<group name="Events">'\ '<choice>'\ '<element name="BackendChange" type="e:BackendChange"/>'\ '</choice>'\ '</group>'\ '<element name="Event" type="e:Event"/>'\ '</schema>' % resource_filename('gosa.backend', 'data/events/BackendChange.xsd') with unittest.mock.patch("gosa.common.events.PluginRegistry.getEventSchema", return_value=schema): e = EventMaker() callback = unittest.mock.Mock() event = e.Event( e.BackendChange( e.DN("dn"), e.ModificationTime("mod_time"), e.ChangeType("type") ) ) mec = MqttEventConsumer(callback=callback, event_type="BackendChange") payload = dumps({ "sender_id": None, "content": etree.tostring(event, pretty_print=True).decode('utf-8') }) message = unittest.mock.MagicMock() message.payload = payload message.topic = "%s/events" % Environment.getInstance().domain mec.mqtt.get_client().client.on_message(None, None, message) args, kwargs = callback.call_args assert etree.tostring(args[0], pretty_print=True).decode('utf-8') == etree.tostring(event, pretty_print=True).decode('utf-8') PluginRegistry._event_parser = None
def test_subscribe(self, mocked_resolver): mocked_resolver.return_value.check.return_value = True # not authorized response = self.fetch('/events') assert response.code == 401 self.login() self.fetch_async(self.get_url('/events'), streaming_callback=self.handle_message) # post something self.check_data = {"uuid": "uuid", "changeType": "modify"} e = EventMaker() self.check_event = "objectChange" self.io_loop.call_later( 1, lambda: self.send_event( 'admin', e.Event( e.ObjectChanged(e.UUID('uuid'), e.ModificationTime("20150101000000Z"), e.ChangeType("modify"))))) self.wait()
def extract(self, fn, real_name): try: with ZipFile(fn) as workflow_zip: if workflow_zip.testzip(): self.log.error("bad workflow zip uploaded") return env = Environment.getInstance() schema = etree.XMLSchema(file=resource_filename( "gosa.backend", "data/workflow.xsd")) parser = objectify.makeparser(schema=schema) try: with workflow_zip.open('workflow.xml') as dsc: root = objectify.fromstring(dsc.read(), parser) id = objectify.ObjectPath("Workflow.Id")(root)[0].text target = os.path.join( env.config.get("core.workflow_path", "/var/lib/gosa/workflows"), id) workflow_zip.extractall(target) WorkflowRegistry.get_instance().refresh() # send the event to the clients e = EventMaker() ev = e.Event( e.WorkflowUpdate(e.Id(id), e.ChangeType("create"))) event_object = objectify.fromstring( etree.tostring(ev, pretty_print=True).decode('utf-8')) SseHandler.notify(event_object, channel="broadcast") except KeyError: self.log.error( "bad workflow zip uploaded - no workflow.xml present") except Exception as e: print(e) raise e
def removeWorkflow(self, user, id): aclresolver = PluginRegistry.getInstance("ACLResolver") topic = "%s.workflows.%s" % (self.env.domain, id) if not user or aclresolver.check(user, topic, "d", base=self.env.base): try: shutil.rmtree(os.path.join(self.__path, id)) except OSError as e: raise WorkflowException( C.make_error('WORKFLOW_DELETE_ERROR', id=id, error=str(e))) self._update_map() # send the event to the clients e = EventMaker() ev = e.Event(e.WorkflowUpdate(e.Id(id), e.ChangeType("remove"))) event_object = objectify.fromstring( etree.tostring(ev, pretty_print=True).decode('utf-8')) SseHandler.notify(event_object, channel="broadcast") else: raise WorkflowException( C.make_error('WORKFLOW_PERMISSION_DELETE', id=id))
def monitor(path, modifier, token, webhook_target, initially_failed=False): # Initialize dn, timestamp and change type. dn = None ts = None ct = None try: with open(path, encoding='utf-8', errors='ignore') as f: # Collect lines until a newline occurs, fill # dn, ts and ct accordingly. Entries that only # change administrative values. for line in tail(f, initially_failed): # Catch dn if line.startswith("dn::"): dn = b64decode(line[5:]).decode('utf-8') continue elif line.startswith("dn:"): dn = line[4:] continue # Catch modifyTimestamp if line.startswith("modifyTimestamp:"): ts = line[17:] continue # Catch changetype if line.startswith("changetype:"): ct = line[12:] continue # Check modifiers name and if it's the # gosa-backend who triggered the change, # just reset the DN, because we don't need # to propagate this change. if line.startswith("modifiersName:"): if line[14:].lower() == modifier.lower(): dn = None continue # Trigger on newline. if line == "": if dn: if not ts: ts = datetime.now().strftime("%Y%m%d%H%M%SZ") e = EventMaker() update = e.Event( e.BackendChange( e.DN(dn), e.ModificationTime(ts), e.ChangeType(ct) ) ) payload = etree.tostring(update) headers = { 'Content-Type': 'application/vnd.gosa.event+xml', 'HTTP_X_HUB_SENDER': 'backend-monitor', 'HTTP_X_HUB_SIGNATURE': get_signature(token, payload) } requests.post(webhook_target, data=payload, headers=headers) dn = ts = ct = None except Exception as e: print("Error:", str(e))
def __gc(self): self.env.log.debug("running garbage collector on object store") ten_minutes_ago = datetime.datetime.now() - datetime.timedelta( minutes=self.__inactivity_timeout) e = EventMaker() command = PluginRegistry.getInstance("CommandRegistry") sched = PluginRegistry.getInstance("SchedulerService").getScheduler() for ref, item in list(self.__stack.items()): uuid = item['object']['uuid'] if uuid is None: # new items without uuid do not need to be closed by timeout continue last_interaction_time = item[ 'last_interaction'] if 'last_interaction' in item else item[ 'created'] if last_interaction_time < ten_minutes_ago: if 'mark_for_deletion' in item: if item['mark_for_deletion'] <= datetime.datetime.now(): if 'countdown_job' in item: try: sched.unschedule_job(item['countdown_job']) except KeyError: pass finally: del item['countdown_job'] del self.__stack[ref] with make_session() as session: session.query(OpenObject).filter( OpenObject.ref == ref).delete() event = e.Event( e.ObjectCloseAnnouncement( e.Target(item['user']), e.SessionId(item['session_id']), e.State("closed"), e.UUID(uuid))) command.sendEvent(item['user'], event) else: # notify user to do something otherwise the lock gets removed in 1 minute event = e.Event( e.ObjectCloseAnnouncement( e.Target(item['user']), e.SessionId(item['session_id']), e.State("closing"), e.UUID(uuid), e.Minutes("1"))) command.sendEvent(item['user'], event) item['mark_for_deletion'] = datetime.datetime.now( ) + datetime.timedelta(seconds=59) if 'countdown_job' in item: try: sched.unschedule_job(item['countdown_job']) except KeyError: pass finally: del item['countdown_job'] item['countdown_job'] = sched.add_date_job( self.__gc, datetime.datetime.now() + datetime.timedelta(minutes=1), tag="_internal", jobstore="ram") elif 'mark_for_deletion' in item: # item has been modified -> remove the deletion mark del item['mark_for_deletion'] event = e.Event( e.ObjectCloseAnnouncement(e.Target(item['user']), e.SessionId(item['session_id']), e.State("closing_aborted"), e.UUID(uuid))) command.sendEvent(item['user'], event) if 'countdown_job' in item: try: sched.unschedule_job(item['countdown_job']) except KeyError: pass finally: del item['countdown_job']
def __handle_events(self, event): if isinstance(event, objectify.ObjectifiedElement): self.__backend_change_processor(event) elif isinstance(event, ObjectChanged): change_type = None _uuid = event.uuid _dn = None _last_changed = datetime.datetime.now() # Try to find the affected DN e = self.__session.query(ObjectInfoIndex).filter( ObjectInfoIndex.uuid == _uuid).one_or_none() if e: # New pre-events don't have a dn. Just skip is in this case... if hasattr(e, 'dn'): _dn = e.dn _last_changed = e._last_modified else: _dn = "not known yet" if event.reason == "post object remove": self.log.debug("removing object index for %s" % _uuid) self.remove_by_uuid(_uuid) change_type = "remove" if event.reason == "post object move": self.log.debug("updating object index for %s" % _uuid) obj = ObjectProxy(event.dn) self.update(obj) _dn = obj.dn change_type = "move" if event.reason == "post object create": self.log.debug("creating object index for %s" % _uuid) obj = ObjectProxy(event.dn) self.insert(obj) _dn = obj.dn change_type = "create" if event.reason in ["post object update"]: self.log.debug("updating object index for %s" % _uuid) if not event.dn: dn = self.__session.query(ObjectInfoIndex.dn).filter( ObjectInfoIndex.uuid == _uuid).one_or_none() if dn: event.dn = dn obj = ObjectProxy(event.dn) self.update(obj) change_type = "update" # send the event to the clients e = EventMaker() if event.reason[0:4] == "post" and _uuid and _dn and change_type: ev = e.Event( e.ObjectChanged( e.UUID(_uuid), e.DN(_dn), e.ModificationTime( _last_changed.strftime("%Y%m%d%H%M%SZ")), e.ChangeType(change_type))) event = "<?xml version='1.0'?>\n%s" % etree.tostring( ev, pretty_print=True).decode('utf-8') # Validate event xml = objectify.fromstring(event, PluginRegistry.getEventParser()) SseHandler.notify(xml, channel="broadcast")
def __refresh(self): # Initially check if we need to ask for client caps if not self.__client: e = EventMaker() self.mqtt.send_event(e.Event(e.ClientPoll()), "%s/client/broadcast" % self.env.domain)
def test_backend_change_processor(self): e = EventMaker() def send_change(dn, type, mod_time, new_dn=None): if dn is not None: if new_dn is not None: event = e.Event( e.BackendChange(e.ModificationTime(mod_time), e.ChangeType(type), e.DN(dn), e.NewDN(new_dn))) else: event = e.Event( e.BackendChange(e.ModificationTime(mod_time), e.ChangeType(type), e.DN(dn))) else: event = e.Event( e.BackendChange(e.ModificationTime(mod_time), e.ChangeType(type))) xml = objectify.fromstring(etree.tostring(event), PluginRegistry.getEventParser()) zope.event.notify(xml) index = PluginRegistry.getInstance("ObjectIndex") with mock.patch.object(index, "insert") as m_insert,\ mock.patch.object(index, "update") as m_update, \ mock.patch.object(index, "remove_by_uuid") as m_remove_by_uuid, \ mock.patch.object(index, "remove") as m_remove: send_change(None, "modify", "20150101000000Z") assert not m_update.called assert not m_insert.called assert not m_remove_by_uuid.called send_change("cn=Frank Reich,ou=people,dc=example,dc=net", "modify", "20150101000000Z") assert m_update.called assert not m_insert.called assert not m_remove_by_uuid.called m_update.reset_mock() # unknown user send_change("cn=Peter Lustig,ou=people,dc=example,dc=net", "modify", "20150101000000Z") assert not m_insert.called assert not m_remove_by_uuid.called send_change("cn=Frank Reich,ou=people,dc=example,dc=net", "delete", "20150101000000Z") assert not m_remove_by_uuid.called assert m_remove.called m_remove_by_uuid.reset_mock() send_change("cn=Frank Reich,ou=people,dc=example,dc=net", "add", "20150101000000Z") assert m_insert.called m_insert.reset_mock() mocked_object = mock.MagicMock() mocked_object.uuid = "fakeuuid" mocked_object.dn = "cn=Frank Reich,ou=people,dc=example,dc=net" with mock.patch.object(index, "_get_object", return_value=mocked_object): send_change("cn=Frank Reich,ou=people,dc=example,dc=net", "moddn", "20150101000000Z", new_dn="cn=Frank Räich,ou=people," "dc=example,dc=net") assert m_update.called
def __ping(self): e = EventMaker() mqtt = PluginRegistry.getInstance('MQTTClientHandler') info = e.Event(e.ClientPing(e.Id(self.env.uuid))) mqtt.send_event(info)
def __announce(self, initial=False): mqtt = PluginRegistry.getInstance('MQTTClientHandler') e = EventMaker() # Assemble network information more = [] netinfo = [] for interface in netifaces.interfaces(): i_info = netifaces.ifaddresses(interface) # Skip lo interfaces if not netifaces.AF_INET in i_info: continue # Skip lo interfaces if not netifaces.AF_LINK in i_info: continue if i_info[netifaces.AF_LINK][0]['addr'] == '00:00:00:00:00:00': continue # Assemble ipv6 information ip6 = "" if netifaces.AF_INET6 in i_info: ip = IPNetwork( "%s/%s" % (i_info[netifaces.AF_INET6][0]['addr'].split( "%", 1)[0], i_info[netifaces.AF_INET6][0]['netmask'])) ip6 = str(ip) netinfo.append( e.NetworkDevice( e.Name(interface), e.IPAddress(i_info[netifaces.AF_INET][0]['addr']), e.IPv6Address(ip6), e.MAC(i_info[netifaces.AF_LINK][0]['addr']), e.Netmask(i_info[netifaces.AF_INET][0]['netmask']), e.Broadcast(i_info[netifaces.AF_INET][0]['broadcast']))) more.append(e.NetworkInformation(*netinfo)) # Build event if initial: info = e.Event( e.ClientAnnounce(e.Id(self.env.uuid), e.Name(self.env.id), *more)) mqtt.send_event(info) # Assemble capabilities more = [] caps = [] for command, dsc in self.__cr.commands.items(): caps.append( e.ClientMethod(e.Name(command), e.Path(dsc['path']), e.Signature(','.join(dsc['sig'])), e.Documentation(dsc['doc']))) more.append(e.ClientCapabilities(*caps)) info = e.Event( e.ClientSignature(e.Id(self.env.uuid), e.Name(self.env.id), *more)) mqtt.send_event(info) if not initial: try: sk = PluginRegistry.getInstance('SessionKeeper') sk.sendSessionNotification() except: # pragma: nocover pass