def addClient(self, device_uuid): cfg_file = os.path.join(self.__repo_path, "config") config = self._git_get_config(cfg_file) section = 'remote "%s"' % device_uuid if not config.has_section(section): cs = PluginRegistry.getInstance("ClientService") key = self._get_public_key() if not key[1] in [p["data"] for p in cs.clientDispatch(device_uuid, "puppetListKeys").values()]: cs.clientDispatch(device_uuid, "puppetAddKey", [key]) # Update git if needed release = self.__get_client_release(device_uuid) self.gitPush(self.getBaseDir(release)) # Update nodes.pp self.__update_node(device_uuid) # Add git configuration config.add_section(section) # Build push URL for client, it needs to be online try: url = cs.clientDispatch(device_uuid, "puppetGetPushPath") config.set(section, "url", url) with open(cfg_file, "w") as f: config.write(f) except: return False # Reset "P" flag for client cs = PluginRegistry.getInstance("ClientService") cs.systemSetStatus(device_uuid, "-P") return True
def serve(self): """ Start MQTT service for this gosa service provider. """ # Load MQTT and Command registry instances self.client = PluginRegistry.getInstance('MQTTClientHandler') self.client.get_client().add_connection_listener(self._on_connection_change) self.__cr = PluginRegistry.getInstance('ClientCommandRegistry') self.client.set_subscription_callback(self._handle_message)
def serve(self): self.log.info("listening for asterisk events...") amqp = PluginRegistry.getInstance('AMQPHandler') EventConsumer(self.env, amqp.getConnection(), xquery=""" declare namespace f='http://www.gonicus.de/Events'; let $e := ./f:Event return $e/f:AsteriskNotification """, callback=self.process) self.__cr = PluginRegistry.getInstance("CommandRegistry")
def serve(self): """ Start MQTT service for this gosa service provider. """ # Load MQTT and Command registry instances mqtt = PluginRegistry.getInstance('MQTTClientHandler') self.__cr = PluginRegistry.getInstance('ClientCommandRegistry') mqtt.set_subscription_callback(self._handle_message) self.__announce(True) # Send a ping on a regular base timeout = float(self.env.config.get('client.ping-interval', default=600)) sched = PluginRegistry.getInstance("SchedulerService").get_scheduler() sched.add_interval_job(self.__ping, seconds=timeout, start_date=datetime.datetime.now() + datetime.timedelta(seconds=1))
def shutdown(a=None, b=None): """ Function to shut down the client. """ global loop env = Environment.getInstance() env.log.info("GOsa DBUS is shutting down") # Shutdown plugins PluginRegistry.shutdown() if loop: loop.quit() logging.shutdown() exit(0)
def _on_connection_change(self, connected): if connected is True: if self.__last_announce is None or self.__last_announce < (datetime.datetime.now() - datetime.timedelta(minutes=5)): self.__announce(send_client_announce=True, send_user_session=True) # Send a ping on a regular base if self._ping_job is None: timeout = float(self.env.config.get('client.ping-interval', default=600)) sched = PluginRegistry.getInstance("SchedulerService").getScheduler() self._ping_job = sched.add_interval_job(self.__ping, seconds=timeout, start_date=datetime.datetime.now() + datetime.timedelta(seconds=1)) else: if self._ping_job is not None: sched = PluginRegistry.getInstance("SchedulerService").getScheduler() sched.unschedule_job(self._ping_job) self._ping_job = None
def __init__(self): env = Environment.getInstance() self.log = logging.getLogger(__name__) self.log.debug("initializing AMQP handler") self.env = env self.config = env.config # Initialize parser schema_root = etree.XML(PluginRegistry.getEventSchema()) schema = etree.XMLSchema(schema_root) self._parser = objectify.makeparser(schema=schema) # Evaluate username user = self.config.get("amqp.id", default=None) if not user: user = self.env.uuid password = self.config.get("amqp.key") # Load configuration self.url = parseURL(makeAuthURL(self.config.get('amqp.url'), user, password)) self.reconnect = self.config.get('amqp.reconnect', True) self.reconnect_interval = self.config.get('amqp.reconnect_interval', 3) self.reconnect_limit = self.config.get('amqp.reconnect_limit', 0) # Go for it self.start()
def _handleClientAnnounce(self, data): data = data.ClientAnnounce client = data.Id.text self.log.info("client '%s' is joining us" % client) self.systemSetStatus(client, "+O-o") # Assemble network information network = {} for interface in data.NetworkInformation.NetworkDevice: network[interface.Name.text] = { 'IPAddress': interface.IPAddress.text, 'IPv6Address': interface.IPv6Address.text, 'MAC': interface.MAC.text, 'Netmask': interface.Netmask.text, 'Broadcast': interface.Broadcast.text} # Add recieve time to be able to sort out dead nodes t = datetime.datetime.utcnow() info = { 'name': data.Name.text, 'last-seen': t, 'online': True, 'caps': {}, 'network': network } self.__client[data.Id.text] = info # Handle pending "P"repare actions for that client if "P" in self.systemGetStatus(client): try: rm = PluginRegistry.getInstance("RepositoryManager") rm.prepareClient(client) except ValueError: pass
def preUserSession(self, client_id, user_name, skip_config=False): sobj = PluginRegistry.getInstance("SchedulerService") # delay changes, send configuration first if client_id not in self.__user_session: self.__user_session[client_id] = [user_name] elif user_name not in self.__user_session[client_id]: self.__user_session[client_id].append(user_name) if self.env.mode == "proxy": # answer config locally and proceed the write-part of the call to the GOsa backend if self.__current_backend_rpc is None or self.__current_backend_rpc.done() is True: self.log.info("calling preUserSession(%s, %s, skip_config=True) on master backend" % (client_id, user_name)) self.__current_backend_rpc = self.__cr.dispatchRemote(client_id, None, 'preUserSession', client_id, user_name, skip_config=True) if skip_config is False: user_config = self.__collect_user_configuration(client_id, [user_name]) if user_config is not None and user_name in user_config: return user_config[user_name] elif skip_config is True: self.__maintain_user_session(client_id, user_name) else: # normal (non-proxy) mode -> return the config and schedule the user_session maintenance # to prevent it from blocking the config generation sobj.getScheduler().add_date_job(self.__maintain_user_session, datetime.datetime.now() + datetime.timedelta(milliseconds=250), args=(client_id, user_name), tag='_internal', jobstore='ram') user_config = self.__collect_user_configuration(client_id, [user_name]) if user_config is not None and user_name in user_config: return user_config[user_name] return None
def clientDispatch(self, client, method, *arg, **larg): """ Dispatch a method on the client. ========= ================================ Parameter Description ========= ================================ client Device UUID of the client method Method name to call * Method arguments ========= ================================ ``Return:`` varies """ # Bail out if the client is not available if not client in self.__client: raise JSONRPCException("client '%s' not available" % client) # Generate tage queue name queue = '%s.client.%s' % (self.env.domain, client) self.log.debug("got client dispatch: '%s(%s)', sending to %s" % (method, arg, queue)) # client queue -> amqp rpc proxy if not client in self.__proxy: amqp = PluginRegistry.getInstance("AMQPHandler") self.__proxy[client] = AMQPServiceProxy(amqp.url['source'], queue) # Call her to the moon... methodCall = getattr(self.__proxy[client], method) # Do the call res = methodCall(*arg, **larg) return res
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. try: 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, qos=1) except ValueError: pass finally: env.reset_requested = True env.active = False
def commandReceived(self, topic, message): """ Process incoming commands, coming in with session and message information. ================= ========================== Parameter Description ================= ========================== message Received MQTT message ================= ========================== Incoming messages are coming from an :class:`gosa.common.components.mqtt_proxy.MQTTServiceProxy`. The command result is written to the '<domain>.client.<client-uuid>' queue. """ err = None res = None name = None args = None id_ = '' response_topic = "%s/to-backend" % "/".join(topic.split("/")[0:4]) try: req = loads(message) except Exception as e: err = str(e) self.log.error("ServiceRequestNotTranslatable: %s" % err) req = {'id': topic.split("/")[-2]} if err is None: try: id_ = req['id'] name = req['method'] args = req['params'] except KeyError as e: self.log.error("KeyError: %s" % e) err = str(BadServiceRequest(message)) self.log.debug("received call [%s] for %s: %s(%s)" % (id_, topic, name, args)) # Try to execute if err is None: try: res = self.__cr.dispatch(name, *args) except Exception as e: err = str(e) # Write exception to log exc_type, exc_value, exc_traceback = sys.exc_info() self.log.error(traceback.format_exception(exc_type, exc_value, exc_traceback)) self.log.debug("returning call [%s]: %s / %s" % (id_, res, err)) response = dumps({"result": res, "id": id_}) # Get rid of it... mqtt = PluginRegistry.getInstance('MQTTClientHandler') mqtt.send_message(response, topic=response_topic)
def process_IN_CREATE(self, event): self.log.debug("logwatch detected change for '%s'" % event.pathname) if event.pathname.endswith(".yaml"): sleep(1) amqp = PluginRegistry.getInstance("AMQPClientHandler") self.log.debug("puppet logwatch detected change for '%s', producing event" % event.pathname) amqp.sendEvent(self.report_to_event(event.pathname))
def shutdown(a=None, b=None): env = Environment.getInstance() # Function to shut down the client. Do some clean up and close sockets. amqp = PluginRegistry.getInstance("AMQPClientHandler") # Tell others that we're away now e = EventMaker() goodbye = e.Event(e.ClientLeave(e.Id(env.uuid))) amqp.sendEvent(goodbye) # Shutdown plugins PluginRegistry.shutdown() logging.shutdown() exit(0)
def process(self, data): # for some reason we need to convert to string and back cstr = etree.tostring(data, pretty_print = True) dat = etree.fromstring(cstr) event = {} for t in dat[0]: tag = re.sub(r"^\{.*\}(.*)$", r"\1", t.tag) if t.tag == 'From': event[tag] = t.text.split(" ")[0] else: event[tag] = str(t.text) # Resolve numbers with all resolvers, sorted by priority i_from = None i_to = None for mod, info in sorted(self.resolver.iteritems(), key=lambda k: k[1]['priority']): if not i_from: i_from = info['object'].resolve(event['From']) if not i_to: i_to = info['object'].resolve(event['To']) if i_from and i_to: break # Fallback to original number if nothing has been found if not i_from: i_from = {'contact_phone': event['From'], 'contact_name': event['From'], 'company_name': None, 'resource': 'none'} if not i_to: i_to = {'contact_phone': event['To'], 'contact_name': event['To'], 'company_name': None, 'resource': 'none'} # Render messages to_msg = from_msg = "" for mod, info in sorted(self.renderer.iteritems(), key=lambda k: k[1]['priority']): if 'ldap_uid' in i_to and i_to['ldap_uid']: to_msg += info['object'].getHTML(i_from, event) to_msg += "\n\n" if 'ldap_uid' in i_from and i_from['ldap_uid'] and event['Type'] == 'CallEnded': from_msg += info['object'].getHTML(i_to, event) from_msg += "\n\n" # Send from/to messages as needed amqp = PluginRegistry.getInstance('AMQPHandler') if from_msg: self.__cr.dispatch(amqp.url['user'], None, "notifyUser", i_from['ldap_uid'], self.TYPE_MAP[event['Type']], from_msg.strip()) if to_msg: self.__cr.dispatch(amqp.url['user'], None, "notifyUser", i_to['ldap_uid'], self.TYPE_MAP[event['Type']], to_msg.strip())
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. # 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: log.info("sending ClientLeave") mqtt.send_event(goodbye, qos=1) # 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 __open_device(self, device_uuid, read_only=False): device_uuid = self.get_client_uuid(device_uuid) index = PluginRegistry.getInstance("ObjectIndex") res = index.search({'_type': 'Device', 'deviceUUID': device_uuid}, {'dn': 1}) if len(res) != 1: raise ValueError(C.make_error("CLIENT_NOT_FOUND", client=device_uuid, status_code=404)) return ObjectProxy(res[0]['dn'], read_only=read_only, from_db_only=True)
def serve(self): # Add event processor mqtt = self.__get_handler() mqtt.get_client().add_subscription('%s/client/+' % self.env.domain) self.log.debug("subscribing to %s event queue" % '%s/client/+' % self.env.domain) mqtt.set_subscription_callback(self.__eventProcessor) # Get registry - we need it later on self.__cr = PluginRegistry.getInstance("CommandRegistry") # Start maintenance with a delay of 5 seconds timer = Timer(5.0, self.__refresh) timer.start() self.env.threads.append(timer) # Register scheduler task to remove outdated clients sched = PluginRegistry.getInstance('SchedulerService').getScheduler() sched.add_interval_job(self.__gc, minutes=1, tag='_internal', jobstore="ram")
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): # Add event processor mqtt = self.__get_handler() # listen to client topics mqtt.get_client().add_subscription('%s/client/+' % self.env.domain, qos=1) self.log.debug("subscribing to %s event queue on %s" % ('%s/client/+' % self.env.domain, mqtt.host)) mqtt.set_subscription_callback(self.__eventProcessor) # Get registry - we need it later on self.__cr = PluginRegistry.getInstance("CommandRegistry") # Start maintenance when index scan is finished zope.event.subscribers.append(self.__handle_events) # Register scheduler task to remove outdated clients sched = PluginRegistry.getInstance('SchedulerService').getScheduler() sched.add_interval_job(self.__gc, minutes=1, tag='_internal', jobstore="ram") # self.register_listener("configureHostPrinters", self._on_client_caps) self.ppd_proxy = PluginRegistry.getInstance("PPDProxy")
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 __open_device(self, device_uuid): device_uuid = self.get_client_uuid(device_uuid) index = PluginRegistry.getInstance("ObjectIndex") res = index.search({ '_type': 'Device', 'deviceUUID': device_uuid }, {'dn': 1}) if len(res) != 1: raise ValueError( C.make_error("CLIENT_NOT_FOUND", device_uuid, status_code=404)) return ObjectProxy(res[0]['dn'])
def serve(self): # Add event processor amqp = PluginRegistry.getInstance('AMQPHandler') EventConsumer(self.env, amqp.getConnection(), xquery=""" declare namespace f='http://www.gonicus.de/Events'; let $e := ./f:Event return $e/f:ClientAnnounce or $e/f:ClientLeave or $e/f:UserSession """, callback=self.__eventProcessor) # Get registry - we need it later on self.__cr = PluginRegistry.getInstance("CommandRegistry") # Start maintainence timer timer = Timer(10.0, self.__refresh) timer.start() self.env.threads.append(timer)
def sendSessionNotification(self): if self.__notify_backend is True: # 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 serve(self): """ Start AMQP service for this GOsa service provider. """ # Load AMQP and Command registry instances amqp = PluginRegistry.getInstance('AMQPClientHandler') self.__cr = PluginRegistry.getInstance('ClientCommandRegistry') # Add private processor for client queue # pylint: disable=E1101 self.__cmdWorker = AMQPWorker(self.env, connection=amqp.getConnection(), r_address="""%s.client.%s; { create:always, node:{ type:queue, durable:false, x-declare: { exclusive: True, auto-delete: True }, x-bindings:[ { exchange:"amq.direct", queue:"%s.client.%s" } ] } }""" % (self.env.domain, self.env.uuid, self.env.domain, self.env.uuid), workers=self.env.config.get('amqp.command-worker', default=1), callback=self.commandReceived) # Add event processor EventConsumer(self.env, amqp.getConnection(), xquery=""" declare namespace f='http://www.gonicus.de/Events'; let $e := ./f:Event return $e/f:ClientPoll """, callback=self.__handleClientPoll) # Gather interface information self.__announce(True)
def systemGetStatus(self, device_uuid): """ TODO """ index = PluginRegistry.getInstance("ObjectIndex") res = index.search({'_type': 'Device', 'deviceUUID': device_uuid}, {'_uuid': 1}) if len(res) != 1: raise ValueError(C.make_error("CLIENT_NOT_FOUND", device_uuid)) device = ObjectProxy(res[0]['_uuid']) return device.deviceStatus
def __init__(self): super(DebianPreseed, self).__init__() self.env = Environment.getInstance() self.path = self.env.config.get('libinst.path', default="/preseed") try: # Get http service instance self.__http = PluginRegistry.getInstance('HTTPService') # Register ourselves self.__http.register(self.path, self) except: pass
def getDestinationIndicator(self, client_id, uid, cn_query, rotate=True): """ :param client_id: UUID of the client used to find the closest destinationIndicators :param uid: uid of the user :param cn_query: filter for destinationIndicator-cns (e.g. 'lts-% for wildcards) :param rotate: rotate the destinationIndicators (do not use the last one twice in a row) :return: FQDN of the server marked as destinationIndicator """ index = PluginRegistry.getInstance('ObjectIndex') res = index.search({'_type': 'User', 'uid': uid}, {'dn': 1}) if len(res) == 0: raise ValueError(C.make_error("USER_NOT_FOUND", user=uid, status_code=404)) user = ObjectProxy(res[0]['dn']) if rotate is False and user.destinationIndicator is not None: # nothing to rotate, take the stored one return user.destinationIndicator client = self.__open_device(client_id, read_only=True) parent_dn = client.get_adjusted_parent_dn() res = index.search({'_type': 'Device', 'extension': 'GoServer', 'cn': cn_query, '_adjusted_parent_dn': parent_dn}, {'dn': 1}) while len(res) == 0 and len(parent_dn) > len(self.env.base): parent_dn = dn2str(str2dn(parent_dn, flags=ldap.DN_FORMAT_LDAPV3)[1:]) res = index.search({'_type': 'Device', 'cn': cn_query, '_adjusted_parent_dn': parent_dn}, {'dn': 1}) if len(res) > 0: di_pool = sorted([x['dn'] for x in res]) if user.destinationIndicator is None: # nothing to rotate, take the first one user.destinationIndicator = di_pool[0] user.commit() elif rotate is True: if user.destinationIndicator in di_pool: # take the next one from list position = di_pool.index(user.destinationIndicator)+1 if position >= len(di_pool): position = 0 user.destinationIndicator = di_pool[position] user.commit() else: # nothing to rotate, take the first one user.destinationIndicator = di_pool[0] user.commit() return user.destinationIndicator return None
def __maintain_user_session(self, client_id, user_name): # save login time and system<->user references client = self.__open_device(client_id) client.gotoLastUser = user_name self.systemSetStatus(client, "+B") index = PluginRegistry.getInstance("ObjectIndex") res = index.search({"_type": "User", "uid": user_name}, {"dn": 1}) for u in res: user = ObjectProxy(u["dn"]) if not user.is_extended_by("GosaAccount"): user.extend("GosaAccount") user.gotoLastSystemLogin = datetime.datetime.now() user.gotoLastSystem = client.dn user.commit()
def serve(self): # Add event processor mqtt = self.__get_handler() # listen to client topics mqtt.get_client().add_subscription('%s/client/+' % self.env.domain) self.log.debug("subscribing to %s event queue" % '%s/client/+' % self.env.domain) mqtt.set_subscription_callback(self.__eventProcessor) # Get registry - we need it later on self.__cr = PluginRegistry.getInstance("CommandRegistry") # Start maintenance when index scan is finished zope.event.subscribers.append(self.__handle_events) # Register scheduler task to remove outdated clients sched = PluginRegistry.getInstance('SchedulerService').getScheduler() sched.add_interval_job(self.__gc, minutes=1, tag='_internal', jobstore="ram") # self.register_listener("configureHostPrinters", self._on_client_caps) self.ppd_proxy = PluginRegistry.getInstance("PPDProxy")
def __eventProcessor(self, topic, message): if message[0:1] == "{": # RPC response self.log.debug("RPC response received in channel %s: '%s'" % (topic, message)) else: try: data = etree.fromstring(message, PluginRegistry.getEventParser()) eventType = stripNs(data.xpath('/g:Event/*', namespaces={'g': "http://www.gonicus.de/Events"})[0].tag) self.log.debug("'%s' event received from local MQTT broker" % eventType) if hasattr(self, "_handle"+eventType): func = getattr(self, "_handle" + eventType) func(data) else: self.log.debug("unhandled event %s" % eventType) except etree.XMLSyntaxError as e: self.log.error("XML parse error %s on message %s" % (e, message))
def __eventProcessor(self, topic, message): if message[0:1] == "{": # RPC response self.log.debug("RPC response received in channel %s: '%s'" % (topic, message)) else: try: data = etree.fromstring(message, PluginRegistry.getEventParser()) eventType = stripNs(data.xpath('/g:Event/*', namespaces={'g': "http://www.gonicus.de/Events"})[0].tag) self.log.debug("Incoming MQTT event[%s]: '%s'" % (eventType, data)) if hasattr(self, "_handle"+eventType): func = getattr(self, "_handle" + eventType) func(data) else: self.log.debug("unhandled event %s" % eventType) except etree.XMLSyntaxError as e: self.log.error("XML parse error %s on message %s" % (e, message))
def _handleClientAnnounce(self, data): data = data.ClientAnnounce client = data.Id.text self.log.info("client '%s' is joining us" % client) self.systemSetStatus(client, "+O") # Remove remaining proxy values for this client if client in self.__proxy: self.__proxy[client].close() del self.__proxy[client] # Assemble caps caps = {} for method in data.ClientCapabilities.ClientMethod: caps[method.Name.text] = { 'path': method.Path.text, 'sig': method.Signature.text, 'doc': method.Documentation.text} # Assemble network information network = {} for interface in data.NetworkInformation.NetworkDevice: network[interface.Name.text] = { 'IPAddress': interface.IPAddress.text, 'IPv6Address': interface.IPv6Address.text, 'MAC': interface.MAC.text, 'Netmask': interface.Netmask.text, 'Broadcast': interface.Broadcast.text} # Add recieve time to be able to sort out dead nodes t = datetime.datetime.utcnow() info = { 'name': data.Name.text, 'received': time.mktime(t.timetuple()), 'caps': caps, 'network': network } self.__client[data.Id.text] = info # Handle pending "P"repare actions for that client if "P" in self.systemGetStatus(client): try: rm = PluginRegistry.getInstance("RepositoryManager") rm.prepareClient(client) except ValueError: pass
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 systemSetStatus(self, device_uuid, status): """ TODO """ # Write to backend index = PluginRegistry.getInstance("ObjectIndex") res = index.search({'_type': 'Device', 'deviceUUID': device_uuid}, {'_uuid': 1}) if len(res) != 1: raise ValueError(C.make_error("CLIENT_NOT_FOUND", device_uuid)) device = ObjectProxy(res[0]['_uuid']) r = re.compile(r"([+-].)") for stat in r.findall(status): if stat[1] not in mapping: raise ValueError(C.make_error("CLIENT_STATUS_INVALID", device_uuid, status=stat[1])) setattr(device, mapping[stat[1]], stat.startswith("+")) device.commit()
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 mainLoop(env): global loop log = logging.getLogger(__name__) try: # connect to dbus and setup loop dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) get_system_bus() # Instanciate dbus objects PluginRegistry(component='gosa.dbus.module') # Enter main loop loop = GLib.MainLoop() loop.run() except Exception as detail: log.critical("unexpected error in mainLoop") log.exception(detail) log.debug(traceback.format_exc()) finally: shutdown()
def joinClient(self, user, device_uuid, mac, info=None): """ TODO """ index = PluginRegistry.getInstance("ObjectIndex") uuid_check = re.compile( r"^[0-9a-f]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$", re.IGNORECASE) if not uuid_check.match(device_uuid): raise ValueError(C.make_error("CLIENT_UUID_INVALID", device_uuid)) # Handle info, if present more_info = [] if info: # Check string entries for entry in filter( lambda x: x in info, ["serialNumber", "ou", "o", "l", "description"]): if not re.match(r"^[\w\s]+$", info[entry]): raise ValueError( C.make_error("CLIENT_DATA_INVALID", device_uuid, entry=entry, data=info[entry])) more_info.append((entry, info[entry])) # Check desired device type if set if "deviceType" in info: if re.match( r"^(terminal|workstation|server|sipphone|switch|router|printer|scanner)$", info["deviceType"]): more_info.append(("deviceType", info["deviceType"])) else: raise ValueError( C.make_error("CLIENT_TYPE_INVALID", device_uuid, type=info["deviceType"])) # Check owner for presence if "owner" in info: # Take a look at the directory to see if there's such an owner DN res = index.search({'_dn': info["owner"]}, {'_dn': 1}) if len(res) == 0: raise ValueError( C.make_error("CLIENT_OWNER_NOT_FOUND", device_uuid, owner=info["owner"])) more_info.append(("owner", info["owner"])) # Generate random client key h, key, salt = generate_random_key() # Take a look at the directory to see if there's already a joined client with this uuid res = index.search( { '_type': 'Device', 'macAddress': mac, 'extension': 'RegisteredDevice' }, {'dn': 1}) if len(res) > 0: record = ObjectProxy(res[0]['dn']) for ext in ["simpleSecurityObject", "ieee802Device"]: if not record.is_extended_by(ext): record.extend(ext) if record.is_extended_by("ForemanHost") and record.otp is not None: record.otp = None record.userPassword = [ "{SSHA}" + encode(h.digest() + salt).decode() ] for k, value in more_info: setattr(record, k, value) cn = record.deviceUUID record.status_Online = False record.status_Offline = True record.status_InstallationInProgress = False record.commit() self.log.info("UUID '%s' joined as %s" % (device_uuid, record.dn)) else: # While the client is going to be joined, generate a random uuid and an encoded join key cn = str(uuid4()) device_key = encrypt_key(device_uuid.replace("-", ""), cn + key) # Resolve manager res = index.search({'_type': 'User', 'uid': user}, {'dn': 1}) if len(res) != 1: raise GOtoException( C.make_error("USER_NOT_UNIQUE" if res else "UNKNOWN_USER", target=user)) manager = res[0]['dn'] # Create new machine entry dn = ",".join([ self.env.config.get("goto.machine-rdn", default="ou=systems"), self.env.base ]) record = ObjectProxy(dn, "Device") record.extend("RegisteredDevice") record.extend("ieee802Device") record.extend("simpleSecurityObject") record.deviceUUID = cn record.deviceKey = Binary(device_key) record.cn = "mac%s" % mac.replace(":", "") record.manager = manager record.status_Offline = True record.macAddress = mac.encode("ascii", "ignore") record.userPassword = [ "{SSHA}" + encode(h.digest() + salt).decode() ] for k, value in more_info: setattr(record, k, value) record.commit() self.log.info("UUID '%s' joined as %s" % (device_uuid, record.dn)) # make sure the client has the access rights he needs self.applyClientRights(cn) return [key, cn]
def joinClient(self, user, device_uuid, mac, info=None): """ TODO """ index = PluginRegistry.getInstance("ObjectIndex") uuid_check = re.compile(r"^[0-9a-f]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$", re.IGNORECASE) if not uuid_check.match(device_uuid): raise ValueError(C.make_error("CLIENT_UUID_INVALID", device_uuid)) # Handle info, if present more_info = [] if info: # Check string entries for entry in filter(lambda x: x in info, ["serialNumber", "ou", "o", "l", "description"]): if not re.match(r"^[\w\s]+$", info[entry]): raise ValueError(C.make_error("CLIENT_DATA_INVALID", device_uuid, entry=entry, data=info[entry])) more_info.append((entry, info[entry])) # Check desired device type if set if "deviceType" in info: if re.match(r"^(terminal|workstation|server|sipphone|switch|router|printer|scanner)$", info["deviceType"]): more_info.append(("deviceType", info["deviceType"])) else: raise ValueError(C.make_error("CLIENT_TYPE_INVALID", device_uuid, type=info["deviceType"])) # Check owner for presence if "owner" in info: # Take a look at the directory to see if there's such an owner DN res = index.search({'_dn': info["owner"]}, {'_dn': 1}) if len(res) == 0: raise ValueError(C.make_error("CLIENT_OWNER_NOT_FOUND", device_uuid, owner=info["owner"])) more_info.append(("owner", info["owner"])) # Generate random client key random.seed() key = ''.join(random.Random().sample(string.ascii_letters + string.digits, 32)) salt = os.urandom(4) h = hashlib.sha1(key.encode('ascii')) h.update(salt) # Take a look at the directory to see if there's already a joined client with this uuid res = index.search({'_type': 'Device', 'macAddress': mac}, {'_uuid': 1}) if len(res): raise GOtoException(C.make_error("DEVICE_EXISTS", mac)) # While the client is going to be joined, generate a random uuid and an encoded join key cn = str(uuid4()) device_key = self.__encrypt_key(device_uuid.replace("-", ""), cn + key) # Resolve manager res = index.search({'_type': 'User', 'uid': user}, {'dn': 1}) if len(res) != 1: raise GOtoException(C.make_error("USER_NOT_UNIQUE" if res else "UNKNOWN_USER", target=user)) manager = res[0]['dn'] # Create new machine entry # dn = ",".join([self.env.config.get("goto.machine-rdn", default="ou=systems"), self.env.base]) # container = ObjectProxy(dn, "DeviceContainer") # container.commit() dn = ",".join([self.env.config.get("goto.machine-rdn", default="ou=devices,ou=systems"), self.env.base]) record = ObjectProxy(dn, "Device") record.extend("RegisteredDevice") record.extend("ieee802Device") record.extend("simpleSecurityObject") record.deviceUUID = cn record.deviceKey = Binary(device_key) record.cn = cn record.manager = manager record.status_Offline = True record.macAddress = mac.encode("ascii", "ignore") record.userPassword = "******" + encode(h.digest() + salt).decode() for key, value in more_info: setattr(record, key, value) record.commit() self.log.info("UUID '%s' joined as %s" % (device_uuid, record.dn)) return [key, cn] return None
def __collect_user_configuration(self, client_id, users): """ :param client_id: deviceUUID or hostname :param users: list of currently logged in users on the client """ if isinstance(client_id, ObjectProxy): client = client_id else: client = self.__open_device(client_id) group = None index = PluginRegistry.getInstance("ObjectIndex") res = index.search({ "_type": "GroupOfNames", "member": client.dn }, {"dn": 1}) if len(res) > 0: group = ObjectProxy(res[0]["dn"]) config = {} resolution = None if group is not None and group.is_extended_by( "GotoEnvironment") and group.gotoXResolution is not None: resolution = group.gotoXResolution if client.is_extended_by( "GotoEnvironment") and client.gotoXResolution is not None: resolution = client.gotoXResolution release = None if client.is_extended_by("GotoMenu"): release = client.getReleaseName() elif group is not None and group.is_extended_by("ForemanHostGroup"): release = group.getReleaseName() parent_group = group while release is None and parent_group is not None and parent_group.parent_id is not None: res = index.search( { "_type": "GroupOfNames", "extension": "ForemanHostGroup", "foremanGroupId": parent_group.parent_id }, {"dn": 1}) if len(res) == 0: break else: parent_group = ObjectProxy(res[0]["dn"]) release = parent_group.getReleaseName() if release is None: self.log.error( "no release found for client/user combination (%s/%s)" % (client_id, users)) client_menu = None if hasattr(client, "gotoMenu") and client.gotoMenu is not None: client_menu = loads(client.gotoMenu) # collect users DNs query_result = index.search({ "_type": "User", "uid": { "in_": users } }, {"dn": 1}) for entry in query_result: user = ObjectProxy(entry["dn"]) config[user.uid] = {} if release is not None: menus = [] if client_menu is not None: menus.append(client_menu) # get all groups the user is member of which have a menu for the given release query = { '_type': 'GroupOfNames', "member": user.dn, "extension": "GotoMenu", "gotoLsbName": release } for res in index.search(query, {"gotoMenu": 1}): # collect user menus for m in res["gotoMenu"]: menus.append(loads(m)) if len(menus): user_menu = None for menu_entry in menus: if user_menu is None: user_menu = self.get_submenu(menu_entry) else: self.merge_submenu(user_menu, self.get_submenu(menu_entry)) config[user.uid]["menu"] = user_menu # collect printer settings for user, starting with the clients printers settings = self.__collect_printer_settings(group) printer_names = [x["cn"] for x in settings["printers"]] for res in index.search( { '_type': 'GroupOfNames', "member": user.dn, "extension": "GotoEnvironment" }, {"dn": 1}): user_group = ObjectProxy(res["dn"]) if user_group.dn == group.dn: continue s = self.__collect_printer_settings(user_group) if user_group.gotoXResolution is not None: resolution = user_group.gotoXResolution for p in s["printers"]: if p["cn"] not in printer_names: settings["printers"].append(p) printer_names.append(p["cn"]) if s["defaultPrinter"] is not None: settings["defaultPrinter"] = s["defaultPrinter"] # override group environment settings if the client has one s = self.__collect_printer_settings(client) if len(s["printers"]) > 0: settings["printers"] = s["printers"] settings["defaultPrinter"] = s["defaultPrinter"] if user.is_extended_by( "GosaAccount") and user.gosaDefaultPrinter is not None: # check if the users default printer is send to the client found = False for printer_settings in settings["printers"]: if printer_settings["cn"] == user.gosaDefaultPrinter: found = True break def process(res): if len(res) == 0: self.log.warning("users defaultPrinter not found: %s" % user.gosaDefaultPrinter) return None elif len(res) == 1: # add this one to the result set printer = ObjectProxy(res[0]["dn"]) p_conf = {} for attr in self.printer_attributes: p_conf[attr] = getattr(printer, attr) return p_conf return False if found is False: # find the printer and add it to the settings res = index.search( { "_type": "GotoPrinter", "cn": user.gosaDefaultPrinter }, {"dn": 1}) printer_config = process(res) if printer_config is False: # more than 1 printers found by this CN, try to look in the users subtree res = index.search( { "_type": "GotoPrinter", "cn": user.gosaDefaultPrinter, "_adjusted_parent_dn": user.get_adjusted_parent_dn() }, {"dn": 1}) printer_config = process(res) if isinstance(printer_config, dict): settings["printers"].append(printer_config) settings["defaultPrinter"] = user.gosaDefaultPrinter else: self.log.warning("users defaultPrinter not found: %s" % user.gosaDefaultPrinter) else: settings["defaultPrinter"] = user.gosaDefaultPrinter config[user.uid]["printer-setup"] = settings config[user.uid]["resolution"] = None if resolution is not None: config[user.uid]["resolution"] = [ int(x) for x in resolution.split("x") ] # TODO: collect and send login scripts to client return config
def mainLoop(env): global netstate, dr # Enable DBus runner dr = DBusRunner() dr.start() # Do network monitoring nm = Monitor(netactivity) netactivity(nm.is_online()) """ Main event loop which will process all registered threads in a loop. It will run as long env.active is set to True.""" try: log = logging.getLogger(__name__) while True: # Check netstate and wait until we're back online if not netstate: log.info("waiting for network connectivity") while not netstate: time.sleep(1) # Load plugins PluginRegistry(component='gosa.client.module') # Sleep and slice wait = 2 while True: # Threading doesn't seem to work well with python... for p in env.threads: # Bail out if we're active in the meanwhile if not env.active: break p.join(wait) # No break, go to main loop else: continue # Break, leave main loop break # Break, leave main loop if not env.reset_requested: break # Wait for threads to shut down for t in env.threads: if hasattr(t, 'stop'): t.stop() if hasattr(t, 'cancel'): t.cancel() t.join(wait) #TODO: remove me if t.is_alive(): try: t._stop() except: print(str(t.getName()) + ' could not be terminated') # Lets do an environment reset now PluginRegistry.shutdown() # Make us active and loop from the beginning env.reset_requested = False env.active = True if not netstate: log.info("waiting for network connectivity") while not netstate: time.sleep(1) sleep = randint(30, 60) env.log.info( "waiting %s seconds to try an MQTT connection recovery" % sleep) time.sleep(sleep) except Exception as detail: log.critical("unexpected error in mainLoop") log.exception(detail) log.debug(traceback.format_exc()) except KeyboardInterrupt: log.info("console requested shutdown") finally: shutdown()
def __ping(self): e = EventMaker() mqtt = PluginRegistry.getInstance('MQTTClientHandler') info = e.Event(e.ClientPing(e.Id(self.env.uuid))) mqtt.send_event(info)
def commandReceived(self, topic, message): """ Process incoming commands, coming in with session and message information. ================= ========================== Parameter Description ================= ========================== message Received MQTT message ================= ========================== Incoming messages are coming from an :class:`gosa.common.components.mqtt_proxy.MQTTServiceProxy`. The command result is written to the '<domain>.client.<client-uuid>' queue. """ err = None res = None name = None args = None id_ = '' response_topic = "%s/to-backend" % "/".join(topic.split("/")[0:4]) try: req = loads(message) except Exception as e: err = str(e) self.log.error("ServiceRequestNotTranslatable: %s" % err) req = {'id': topic.split("/")[-2]} if err is None: try: id_ = req['id'] name = req['method'] args = req['params'] except KeyError as e: self.log.error("KeyError: %s" % e) err = str(BadServiceRequest(message)) self.log.debug("received call [%s] for %s: %s(%s)" % (id_, topic, name, args)) # Try to execute if err is None: try: res = self.__cr.dispatch(name, *args) except Exception as e: err = str(e) # Write exception to log exc_type, exc_value, exc_traceback = sys.exc_info() self.log.error( traceback.format_exception(exc_type, exc_value, exc_traceback)) self.log.debug("returning call [%s]: %s / %s" % (id_, res, err)) response = dumps({"result": res, "id": id_}) # Get rid of it... mqtt = PluginRegistry.getInstance('MQTTClientHandler') mqtt.send_message(response, topic=response_topic)
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