예제 #1
0
class NodeFacadeService:
    def __init__(self, interactive=False):
        self.logger = Logger("facade", None)
        if HOST == "":
            self.logger.writeFatal(
                "Unable to start facade due to lack of connectivity")
            sys.exit(1)
        self.running = False
        self.httpServer = None
        self.interface = None
        self.interactive = interactive
        self.registry = None
        self.registry_cleaner = None
        self.node_id = None
        self.mdns = MDNSEngine()
        self.mdnsname_suffix = '_' + str(HOSTNAME) + "_" + str(getpid())
        self.mappings = {
            "device": "ver_dvc",
            "flow": "ver_flw",
            "source": "ver_src",
            "sender": "ver_snd",
            "receiver": "ver_rcv",
            "self": "ver_slf"
        }
        self.mdns_updater = MDNSUpdater(self.mdns,
                                        "_nmos-node._tcp",
                                        "node" + self.mdnsname_suffix,
                                        self.mappings,
                                        PORT,
                                        self.logger,
                                        txt_recs={
                                            "api_ver": "v1.0,v1.1,v1.2",
                                            "api_proto": "http"
                                        })
        self.aggregator = Aggregator(self.logger, self.mdns_updater)

    def sig_handler(self):
        print 'Pressed ctrl+c'
        self.stop()

    def sig_hup_handler(self):
        if getLocalIP() != "":
            global HOST
            HOST = updateHost()
            self.registry.modify_node(href=self.generate_href(),
                                      host=HOST,
                                      api={
                                          "versions": NODE_APIVERSIONS,
                                          "endpoints":
                                          self.generate_endpoints()
                                      },
                                      interfaces=self.list_interfaces())

    def generate_endpoints(self):
        endpoints = []
        if HTTPS_MODE != "enabled":
            endpoints.append({
                "host": HOST,
                "port": 80,  #Everything should go via apache proxy
                "protocol": "http"
            })
        if HTTPS_MODE != "disabled":
            endpoints.append({
                "host": HOST,
                "port": 443,  #Everything should go via apache proxy
                "protocol": "https"
            })
        return endpoints

    def generate_href(self):
        if HTTPS_MODE == "enabled":
            return "https://{}/".format(HOST)
        else:
            return "http://{}/".format(HOST)

    def list_interfaces(self):
        interfaces = {}
        # Initially populate interfaces from known-good location
        net_path = "/sys/class/net/"
        if os.path.exists(net_path):
            for interface_name in os.listdir(net_path):
                if interface_name != "lo":
                    address_path = net_path + interface_name + "/address"
                    if os.path.exists(address_path):
                        address = open(address_path, "r").readline()
                        interfaces[interface_name] = {
                            "name":
                            interface_name,
                            "chassis_id":
                            None,
                            "port_id":
                            address.lower().strip("\n").replace(":", "-")
                        }

        # Attempt to source proper LLDP data for interfaces
        if os.path.exists("/usr/sbin/lldpcli"):
            try:
                chassis_data = json.loads(
                    check_output(
                        ["/usr/sbin/lldpcli", "show", "chassis", "-f",
                         "json"]))
                chassis_id = chassis_data["local-chassis"]['chassis'].values(
                )[0]["id"]["value"]
                if chassis_data["local-chassis"]['chassis'].values(
                )[0]["id"]["type"] == "mac":
                    chassis_id = chassis_id.lower().replace(":", "-")
                interface_data = json.loads(
                    check_output([
                        "/usr/sbin/lldpcli", "show", "statistics", "-f", "json"
                    ]))
                if isinstance(interface_data["lldp"]["interface"], dict):
                    for interface_name in interface_data["lldp"][
                            "interface"].keys():
                        if interface_name in interfaces:
                            # Only correct the Chassis ID. Port ID MUST be a MAC address
                            interfaces[interface_name][
                                "chassis_id"] = chassis_id
                else:
                    for interface_block in interface_data["lldp"]["interface"]:
                        interface_name = interface_block.keys()[0]
                        if interface_name in interfaces:
                            # Only correct the Chassis ID. Port ID MUST be a MAC address
                            interfaces[interface_name][
                                "chassis_id"] = chassis_id
            except Exception:
                pass

        return interfaces.values()

    def start(self):
        if self.running:
            gevent.signal(signal.SIGINT, self.sig_handler)
            gevent.signal(signal.SIGTERM, self.sig_handler)
            gevent.signal(signal.SIGHUP, self.sig_hup_handler)

        self.mdns.start()
        self.node_id = get_node_id()
        node_version = str(ptptime.ptp_detail()[0]) + ":" + str(
            ptptime.ptp_detail()[1])
        node_data = {
            "id":
            self.node_id,
            "label":
            nmoscommonconfig.config.get('node_label', FQDN),
            "description":
            nmoscommonconfig.config.get('node_description',
                                        "Node on {}".format(FQDN)),
            "tags":
            nmoscommonconfig.config.get('node_tags', {}),
            "href":
            self.generate_href(),
            "host":
            HOST,
            "services": [],
            "hostname":
            HOSTNAME,
            "caps": {},
            "version":
            node_version,
            "api": {
                "versions": NODE_APIVERSIONS,
                "endpoints": self.generate_endpoints(),
            },
            "clocks": [
                {
                    "name": "clk0",
                    "ref_type": "internal",
                },
                {
                    "name": "clk1",
                    "ref_type": "ptp",
                    "version": "IEEE1588-2008",
                    "traceable": False,
                    "gmid": "00-00-00-00-00-00-00-00",
                    "locked": False,
                },
                # Extra values will be filled in as needed at point of checking
            ],
            "interfaces":
            self.list_interfaces()
        }
        self.registry = FacadeRegistry(self.mappings.keys(), self.aggregator,
                                       self.mdns_updater, self.node_id,
                                       node_data, self.logger)
        self.registry_cleaner = FacadeRegistryCleaner(self.registry)
        self.registry_cleaner.start()
        self.httpServer = HttpServer(FacadeAPI,
                                     PORT,
                                     '0.0.0.0',
                                     api_args=[self.registry])
        self.httpServer.start()
        while not self.httpServer.started.is_set():
            self.logger.writeInfo('Waiting for httpserver to start...')
            self.httpServer.started.wait()

        if self.httpServer.failed is not None:
            raise self.httpServer.failed

        self.logger.writeInfo("Running on port: {}".format(
            self.httpServer.port))

        try:
            self.logger.writeInfo("Registering as {}...".format(self.node_id))
            self.aggregator.register(
                'node', self.node_id,
                **legalise_resource(node_data, "node", NODE_REGVERSION))
        except Exception as e:
            self.logger.writeWarning("Could not register: {}".format(
                e.__repr__()))

        self.interface = FacadeInterface(self.registry, self.logger)
        self.interface.start()

    def run(self):
        self.running = True
        pidfile = "/tmp/ips-nodefacade.pid"
        file(pidfile, 'w').write(str(getpid()))
        self.start()
        daemon.notify("READY=1")
        while self.running:
            self.registry.update_ptp()
            time.sleep(1)
        os.unlink(pidfile)
        self._cleanup()

    def _cleanup(self):
        try:
            self.logger.writeDebug("cleanup: unregister facade " +
                                   self.node_id)
            self.aggregator.unregister('node', self.node_id)
        except Exception as e:
            self.logger.writeWarning("Could not unregister: {}".format(e))

        if self.mdns:
            try:
                self.mdns.stop()
            except Exception as e:
                self.logger.writeWarning("Could not stop mdns: {}".format(e))

        self.registry_cleaner.stop()
        self.interface.stop()
        self.httpServer.stop()
        self.aggregator.stop()
        self.logger.writeInfo("Stopped main()")

    def stop(self):
        self.running = False
예제 #2
0
class NodeFacadeService:
    def __init__(self, interactive=False):
        self.logger = Logger("facade", None)
        if HOST == "":
            self.logger.writeFatal(
                "Unable to start facade due to lack of connectivity")
            sys.exit(1)
        self.running = False
        self.httpServer = None
        self.interface = None
        self.interactive = interactive
        self.registry = None
        self.registry_cleaner = None
        self.node_id = None
        self.mdns = MDNSEngine()
        self.mappings = {
            "device": "ver_dvc",
            "flow": "ver_flw",
            "source": "ver_src",
            "sender": "ver_snd",
            "receiver": "ver_rcv",
            "self": "ver_slf"
        }
        self.mdns_updater = None
        self.auth_registry = AuthRegistry(app=None, scope=ALLOWED_SCOPE)

        self.protocol = PROTOCOL
        if PROTOCOL == "https":
            self.dns_sd_port = DNS_SD_HTTPS_PORT
        else:
            self.dns_sd_port = DNS_SD_HTTP_PORT
        if ENABLE_P2P:
            self.mdns_updater = MDNSUpdater(self.mdns,
                                            DNS_SD_TYPE,
                                            DNS_SD_NAME,
                                            self.mappings,
                                            self.dns_sd_port,
                                            self.logger,
                                            txt_recs=self._mdns_txt(
                                                NODE_APIVERSIONS,
                                                self.protocol, OAUTH_MODE))

        self.aggregator = Aggregator(self.logger, self.mdns_updater,
                                     self.auth_registry)

    def _mdns_txt(self, versions, protocol, oauth_mode):
        return {
            "api_ver": ",".join(versions),
            "api_proto": protocol,
            "api_auth": str(oauth_mode).lower()
        }

    def sig_handler(self):
        print('Pressed ctrl+c')
        self.stop()

    def sig_hup_handler(self):
        if getLocalIP() != "":
            global HOST
            HOST = updateHost()
            self.registry.modify_node(href=self.generate_href(),
                                      host=HOST,
                                      api={
                                          "versions": NODE_APIVERSIONS,
                                          "endpoints":
                                          self.generate_endpoints()
                                      },
                                      interfaces=self.list_interfaces())

    def generate_endpoints(self):
        endpoints = []
        endpoints.append({
            "host": HOST,
            "port": self.dns_sd_port,  # Everything should go via apache proxy
            "protocol": self.protocol,
            "authorization": OAUTH_MODE
        })
        return endpoints

    def generate_href(self):
        return "{}://{}/".format(PROTOCOL, HOST)

    def list_interfaces(self):
        interfaces = {}
        # Initially populate interfaces from known-good location
        net_path = "/sys/class/net/"
        if os.path.exists(net_path):
            for interface_name in os.listdir(net_path):
                address_path = net_path + interface_name + "/address"
                if os.path.exists(address_path) and interface_name != 'lo':
                    with open(address_path, 'r') as address_file:
                        address = address_file.readline().strip('\n')
                        if address:
                            interfaces[interface_name] = {
                                "name": interface_name,
                                "chassis_id": None,
                                "port_id": address.lower().replace(":", "-")
                            }

        # Attempt to source proper LLDP data for interfaces
        if os.path.exists("/usr/sbin/lldpcli"):
            try:
                chassis_data = json.loads(
                    check_output(
                        ["/usr/sbin/lldpcli", "show", "chassis", "-f",
                         "json"]))
                chassis_id = chassis_data["local-chassis"]['chassis'].values(
                )[0]["id"]["value"]
                if chassis_data["local-chassis"]['chassis'].values(
                )[0]["id"]["type"] == "mac":
                    chassis_id = chassis_id.lower().replace(":", "-")
                interface_data = json.loads(
                    check_output([
                        "/usr/sbin/lldpcli", "show", "statistics", "-f", "json"
                    ]))
                if isinstance(interface_data["lldp"]["interface"], dict):
                    for interface_name in interface_data["lldp"][
                            "interface"].keys():
                        if interface_name in interfaces:
                            # Only correct the Chassis ID. Port ID MUST be a MAC address
                            interfaces[interface_name][
                                "chassis_id"] = chassis_id
                else:
                    for interface_block in interface_data["lldp"]["interface"]:
                        interface_name = interface_block.keys()[0]
                        if interface_name in interfaces:
                            # Only correct the Chassis ID. Port ID MUST be a MAC address
                            interfaces[interface_name][
                                "chassis_id"] = chassis_id
            except Exception:
                pass

        return list(itervalues(interfaces))

    def start(self):
        if self.running:
            gevent.signal_handler(signal.SIGINT, self.sig_handler)
            gevent.signal_handler(signal.SIGTERM, self.sig_handler)
            gevent.signal_handler(signal.SIGHUP, self.sig_hup_handler)

        self.mdns.start()
        self.node_id = get_node_id()
        node_version = str(ptptime.ptp_detail()[0]) + ":" + str(
            ptptime.ptp_detail()[1])
        node_data = {
            "id":
            self.node_id,
            "label":
            _config.get('node_label', FQDN),
            "description":
            _config.get('node_description', "Node on {}".format(FQDN)),
            "tags":
            _config.get('node_tags', {}),
            "href":
            self.generate_href(),
            "host":
            HOST,
            "services": [],
            "hostname":
            HOSTNAME,
            "caps": {},
            "version":
            node_version,
            "api": {
                "versions": NODE_APIVERSIONS,
                "endpoints": self.generate_endpoints(),
            },
            "clocks": [],
            "interfaces":
            self.list_interfaces()
        }
        self.registry = FacadeRegistry(self.mappings.keys(), self.aggregator,
                                       self.mdns_updater, self.node_id,
                                       node_data, self.logger)
        self.registry_cleaner = FacadeRegistryCleaner(self.registry)
        self.registry_cleaner.start()
        self.httpServer = HttpServer(
            FacadeAPI,
            PORT,
            '0.0.0.0',
            api_args=[self.registry, self.auth_registry])
        self.httpServer.start()
        while not self.httpServer.started.is_set():
            self.logger.writeInfo('Waiting for httpserver to start...')
            self.httpServer.started.wait()

        if self.httpServer.failed is not None:
            raise self.httpServer.failed

        self.logger.writeInfo("Running on port: {}".format(
            self.httpServer.port))

        try:
            self.logger.writeInfo("Registering as {}...".format(self.node_id))
            self.aggregator.register(
                'node', self.node_id,
                **translate_api_version(node_data, "node", NODE_REGVERSION))
        except Exception as e:
            self.logger.writeWarning("Could not register: {}".format(
                e.__repr__()))

        self.interface = FacadeInterface(self.registry, self.logger)
        self.interface.start()

    def run(self):
        self.running = True
        pidfile = "/tmp/ips-nodefacade.pid"
        with open(pidfile, 'w') as f:
            f.write(str(getpid()))
        self.start()
        daemon.notify(SYSTEMD_READY)
        while self.running:
            self.registry.update_ptp()
            time.sleep(1)
        os.unlink(pidfile)

    def _cleanup(self):
        try:
            self.logger.writeDebug("cleanup: unregister facade " +
                                   self.node_id)
            self.aggregator.unregister('node', self.node_id)
        except Exception as e:
            self.logger.writeWarning("Could not unregister: {}".format(e))

        if self.mdns:
            try:
                self.mdns.stop()
            except Exception as e:
                self.logger.writeWarning("Could not stop mdns: {}".format(e))

        self.registry_cleaner.stop()
        self.interface.stop()
        self.httpServer.stop()
        self.aggregator.stop()
        self.mdns_updater.stop()
        self.logger.writeInfo("Stopped main()")

    def stop(self):
        self._cleanup()
        self.running = False