def test_pass_ip_address(self, mock_popen): self.stdout_mock.write( dedent(""" 10.192.202.23\toctopi.local """).encode("utf-8")) self.stdout_mock.seek(0) mock_popen.return_value.stdout = self.stdout_mock self.stderr_mock.seek(0) mock_popen.return_value.stderr = self.stderr_mock get_avahi_hostname("10.192.202.23") mock_popen.assert_called_with( ["avahi-resolve-address", "10.192.202.23"], stdout=-1, stderr=-1)
def test_err(self, mock_popen, mock_logger): self.stderr_mock.write( dedent(""" Failed to create client object: Daemon not running """).encode("utf-8")) self.stdout_mock.seek(0) mock_popen.return_value.stdout = self.stdout_mock self.stderr_mock.seek(0) mock_popen.return_value.stderr = self.stderr_mock get_avahi_hostname("10.192.202.23") self.assertTrue(mock_logger.call_count, 1) mock_logger.called_with( "avahi-resolve-address error: Failed to create client object: Daemon not running" )
def check_printers(): app.logger.debug("Checking known printers...") for raw_printer in printers.get_printers(): printer = clients.get_printer_instance(raw_printer) if printer.hostname is not None: current_ip = network.get_avahi_address(printer.hostname) if current_ip is not None and current_ip != printer.ip: printer.ip = current_ip printer.update_network_host() else: hostname = network.get_avahi_hostname(printer.ip) if hostname is not None: printer.hostname = hostname printer.update_network_host() printer.is_alive() printers.update_printer( uuid=printer.uuid, name=printer.name, hostname=printer.hostname, ip=printer.ip, port=printer.port, protocol=printer.protocol, client=printer.client_name(), client_props={ "version": printer.client_info.version, "connected": printer.client_info.connected, "access_level": printer.client_info.access_level, "api_key": printer.client_info.api_key, "webcam": printer.webcam(), }, printer_props=printer.get_printer_props(), )
def scan_network(): app.logger.info("Scanning network for printers...") for line in do_arp_scan(settings.get_val("network_interface")): (ip, _) = line hostname = get_avahi_hostname(ip) # it's communicating, let's sniff it for a printer sniff_printer.delay(hostname, ip)
def printer_create(): data = request.json if not data: return abort(400) ip = data.get("ip", None) name = data.get("name", None) if (not ip or not name or re.match( r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:?\d{0,5}$", ip) is None): return abort(400) if printers.get_printer(ip) is not None: return abort(409) hostname = network.get_avahi_hostname(ip) printer = drivers.get_printer_instance({ "hostname": hostname, "ip": ip, "name": name, "client": "octoprint", # TODO make this more generic }) printer.sniff() network_devices.upsert_network_device(ip=ip, retry_after=None, disabled=False) printers.add_printer( name=name, hostname=hostname, ip=ip, client=printer.client_name(), client_props={ "version": printer.client.version, "connected": printer.client.connected, "read_only": printer.client.read_only, }, ) return "", 201
def discover_printers(): if not settings.get_val("network_discovery"): return app.logger.debug("Discovering network printers...") now = datetime.utcnow() to_deactivate = printers.get_printers() to_skip_ip = [ device["ip"] for device in network_devices.get_network_devices() if (device["retry_after"] and device["retry_after"] > now) or device["disabled"] ] for line in do_arp_scan(settings.get_val("network_interface")): (ip, _) = line to_deactivate = [ printer for printer in to_deactivate if printer["ip"] != ip ] if ip in to_skip_ip: continue hostname = get_avahi_hostname(ip) # it's communicating, let's sniff it for a printer sniff_printer.delay(hostname, ip) for printer in to_deactivate: app.logger.debug( "%s (%s) was not encountered on the network, deactivating" % (printer["hostname"], printer["ip"])) printer["client_props"]["connected"] = False printers.update_printer(**printer)
def scan_network(org_uuid, network_interface="wlan0"): app.logger.info("Scanning network %s for printers..." % network_interface) for line in do_arp_scan(network_interface): (ip, _) = line hostname = get_avahi_hostname(ip) # it's communicating, let's sniff it for a printer sniff_printer.delay(org_uuid, hostname, ip)
def test_drop_error_message(self, mock_popen): self.stdout_mock.write( b""" Failed to resolve address '10.192.202.200': Timeout reached """ ) self.stdout_mock.seek(0) mock_popen.return_value.stdout = self.stdout_mock self.assertEqual(get_avahi_hostname("10.192.202.200"), None)
def test_regex(self, mock_popen): self.stdout_mock.write( b""" 10.192.202.23\toctopi.local """ ) self.stdout_mock.seek(0) mock_popen.return_value.stdout = self.stdout_mock result = get_avahi_hostname("10.192.202.23") self.assertEqual(result, "octopi.local")
def test_regex(self, mock_popen): self.stdout_mock.write( dedent(""" 10.192.202.23\toctopi """).encode("utf-8")) self.stdout_mock.seek(0) mock_popen.return_value.stdout = self.stdout_mock self.stderr_mock.seek(0) mock_popen.return_value.stderr = self.stderr_mock result = get_avahi_hostname("10.192.202.23") self.assertEqual(result, "octopi.local")
def check_printer(printer_uuid): app.logger.debug("Checking printer %s" % printer_uuid) raw_printer = printers.get_printer(printer_uuid) # todo: The `get_printer` method should raise an exception instead of returning None if raw_printer is None: app.logger.info( "Printer was deleted after it was scheduled for update.") return raw_client = network_clients.get_network_client( raw_printer["network_client_uuid"]) printer_data = dict(raw_client) printer_data.update(raw_printer) printer = clients.get_printer_instance(printer_data) # websocket printers are not expected to change if printer.protocol in ["http", "https"]: if printer.hostname is not None: current_ip = network.get_avahi_address(printer.hostname) if current_ip is not None and current_ip != printer.ip: printer.ip = current_ip printer.update_network_base() hostname = network.get_avahi_hostname(printer.ip) if hostname is not None and hostname != printer.hostname: printer.hostname = hostname printer.update_network_base() now = datetime.now() if now.minute % 15 == 0 and printer.client_info.connected: printer.sniff() printer.karmen_sniff() else: printer.is_alive() if (printer.client_info.pill_info and printer.client_info.pill_info.get( "update_status", None) is not None): printer.karmen_sniff() if printer.hostname != raw_client.get( "hostname") or printer.ip != raw_client.get("ip"): network_clients.update_network_client( uuid=raw_client["uuid"], hostname=printer.hostname, ip=printer.ip, ) printers.update_printer( uuid=printer.uuid, client_props={ "version": printer.client_info.version, "connected": printer.client_info.connected, "access_level": printer.client_info.access_level, "api_key": printer.client_info.api_key, "webcam": printer.client_info.webcam, "plugins": printer.client_info.plugins, "pill_info": printer.client_info.pill_info, }, )
def check_printer(printer_uuid): app.logger.debug("Checking printer %s" % printer_uuid) raw_printer = printers.get_printer(printer_uuid) raw_client = network_clients.get_network_client( raw_printer["network_client_uuid"]) printer_data = dict(raw_client) printer_data.update(raw_printer) printer = clients.get_printer_instance(printer_data) # websocket printers are not expected to change if printer.protocol in ["http", "https"]: if printer.hostname is not None: current_ip = network.get_avahi_address(printer.hostname) if current_ip is not None and current_ip != printer.ip: printer.ip = current_ip printer.update_network_base() hostname = network.get_avahi_hostname(printer.ip) if hostname is not None and hostname != printer.hostname: printer.hostname = hostname printer.update_network_base() now = datetime.now() if now.minute % 15 == 0 and printer.client_info.connected: printer.sniff() else: printer.is_alive() if printer.hostname != raw_client.get( "hostname") or printer.ip != raw_client.get("ip"): network_clients.update_network_client( uuid=raw_client["uuid"], hostname=printer.hostname, ip=printer.ip, ) printers.update_printer( uuid=printer.uuid, client_props={ "version": printer.client_info.version, "connected": printer.client_info.connected, "access_level": printer.client_info.access_level, "api_key": printer.client_info.api_key, "webcam": printer.client_info.webcam, "plugins": printer.client_info.plugins, }, )
def printer_create(org_uuid): data = request.json if not data: return abort(make_response(jsonify(message="Missing payload"), 400)) uuid = guid.uuid4() ip = data.get("ip", None) port = data.get("port", None) hostname = data.get("hostname", None) name = data.get("name", None) api_key = data.get("api_key", None) protocol = data.get("protocol", "http") path = data.get("path", "") token = data.get("token", None) if token is not None and token != "": if not app.config.get("CLOUD_MODE"): return abort(make_response(jsonify(message="Missing token"), 400)) existing_network_client = network_clients.get_network_client_by_socket_token( token) if existing_network_client: existing_printer = printers.get_printer_by_network_client_uuid( org_uuid, existing_network_client.get("uuid")) if existing_printer is not None: return abort( make_response(jsonify(message="Printer exists"), 409)) path = "" hostname = "" ip = "" protocol = "" port = 0 else: if app.config.get("CLOUD_MODE"): return abort( make_response( jsonify( message= "Cannot add printer without a token in CLOUD_MODE"), 500, )) if ((not ip and not hostname) or not name or protocol not in ["http", "https"] or (hostname and re.match(r"^[0-9a-zA-Z.-]+\.local$", hostname) is None) or (ip and re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", ip) is None) or (port and re.match(r"^\d{0,5}$", str(port)) is None)): return abort( make_response( jsonify( message="Missing some network data about the printer"), 400)) if hostname and not ip: ip = network.get_avahi_address(hostname) if not ip: return abort( make_response( jsonify(message="Cannot resolve %s with mDNS" % hostname), 500)) if ip and not hostname: hostname = network.get_avahi_hostname(ip) existing_network_client = network_clients.get_network_client_by_props( hostname, ip, port, path) if existing_network_client: existing_printer = printers.get_printer_by_network_client_uuid( org_uuid, existing_network_client.get("uuid")) if existing_printer is not None: return abort( make_response(jsonify(message="Printer exists"), 409)) if not existing_network_client: existing_network_client = { "uuid": guid.uuid4(), "hostname": hostname, "client": "octoprint", # TODO make this more generic "protocol": protocol, "ip": ip, "port": port, "path": path, "token": token, } network_clients.add_network_client(**existing_network_client) printer = clients.get_printer_instance({ "uuid": uuid, "network_client_uuid": existing_network_client["uuid"], "organization_uuid": org_uuid, "name": name, "client": existing_network_client["client"], "protocol": existing_network_client["protocol"], "hostname": existing_network_client["hostname"], "ip": existing_network_client["ip"], "port": existing_network_client["port"], "path": existing_network_client["path"], "token": existing_network_client["token"], }) printer.add_api_key(api_key) printer.update_network_base() printer.sniff() printers.add_printer( uuid=uuid, network_client_uuid=existing_network_client["uuid"], organization_uuid=org_uuid, name=name, client=printer.client_name(), client_props={ "version": printer.client_info.version, "connected": printer.client_info.connected, "access_level": printer.client_info.access_level, "api_key": printer.client_info.api_key, "webcam": printer.client_info.webcam, "plugins": printer.client_info.plugins, }, ) # TODO cache webcam, job, status for a small amount of time in this client return jsonify(make_printer_response(printer, ["status", "webcam", "job"])), 201
def printer_create(): data = request.json if not data: return abort(make_response("", 400)) uuid = uuidmodule.uuid4() ip = data.get("ip", None) port = data.get("port", None) hostname = data.get("hostname", None) name = data.get("name", None) api_key = data.get("api_key", None) protocol = data.get("protocol", "http") if ((not ip and not hostname) or not name or protocol not in ["http", "https"] or (hostname and re.match(r"^[0-9a-zA-Z.-]+\.local$", hostname) is None) or (ip and re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$", ip) is None) or (port and re.match(r"^\d{0,5}$", str(port)) is None)): return abort(make_response("", 400)) if hostname and not ip: ip = network.get_avahi_address(hostname) if not ip: return abort( make_response("Cannot resolve %s with mDNS" % hostname, 500)) if ip and not hostname: hostname = network.get_avahi_hostname(ip) if printers.get_printer_by_network_props(hostname, ip, port) is not None: return abort(make_response("", 409)) printer = clients.get_printer_instance({ "uuid": uuid, "hostname": hostname, "ip": ip, "port": port, "name": name, "protocol": protocol, "client": "octoprint", # TODO make this more generic }) printer.add_api_key(api_key) printer.sniff() printers.add_printer( uuid=uuid, name=name, hostname=hostname, ip=ip, port=port, protocol=printer.protocol, client=printer.client_name(), client_props={ "version": printer.client_info.version, "connected": printer.client_info.connected, "access_level": printer.client_info.access_level, "api_key": printer.client_info.api_key, "webcam": printer.webcam(), }, ) # TODO cache webcam, job, status for a small amount of time in client return jsonify(make_printer_response(printer, ["status", "webcam", "job"])), 201