Beispiel #1
0
    def __init__(self, api_url, api_token, verify_ssl=True):
        self.api_url = api_url
        self.api_token = api_token
        self.zones = []
        self.verify_ssl = verify_ssl
        if not self.verify_ssl:
            logger.warning(
                "__init__@dns_server.py - Disabling SSL Warnings. I hope this was intentional"
            )
            requests.packages.urllib3.disable_warnings(
                category=InsecureRequestWarning)

        payload = jwt.decode(api_token, verify=False)  # do not trust
        if not "dns_server_name" in payload.keys(
        ) or not payload["dns_server_name"]:
            logger.critical(
                f"__init__@api_client.py - No dns_server_name on api token payload: {str(payload)}"
            )
        self.dns_server_name = payload.get("dns_server_name", "")

        if not "http_server_name" in payload.keys(
        ) or not payload["http_server_name"]:
            logger.critical(
                f"__init__@api_client.py - No http_server_name on api token payload: {str(payload)}"
            )
        self.http_server_name = payload.get("http_server_name", "")
Beispiel #2
0
 def get_api_token(self):
     if os.environ.get("API_TOKEN", None):
         return os.environ.get("API_TOKEN")
     if self.option("api_token", None):
         return self.option("api_token")
     logger.critical("api token required")
     self.exit(1)
Beispiel #3
0
    async def run(self):
        # TODO: thread issues?
        verify_ssl = True
        if bool(self.option("no_ssl_verify")):
            verify_ssl = False

        self.api_client = ApiClient(self.get_api_url(),
                                    self.get_api_token(),
                                    verify_ssl=verify_ssl)

        if not self.option("no_api_wait"):
            if not self.api_client.wait_for_up():
                logger.critical(
                    "run@http_server.py - Could not connect to api. quitting")
                self.exit(1)

        if self.option("no_sync"):
            logger.info("run@http_server.py - Skipping syncing api token")
        else:
            self.api_client.sync()

        self.boot()

        self.start_servers()

        try:
            count = 0
            while self.is_alive():
                # zones don't need to be refreshed for http server
                # may want to do something in the future thought
                count = count + 1
                sleep(1)

        except KeyboardInterrupt:
            pass
Beispiel #4
0
 def get_workers(self):
     if self.option("debug", None) or self.option("reload", None):
         logger.critical(
             "get_workers@api_server.py - Cannot use debug or reload with workers. Skipping."
         )
         return None
     return self.option("workers", 5)
Beispiel #5
0
async def show(
        user_repo: UserRepo = Depends(UserRepo()),
        token: TokenPayload = Depends(ScopedTo("profile")),
        user: User = Depends(current_user),
):
    logger.critical("Loading user")
    item = user_repo.set_results(user).data()
    return UserResponse(user=item)
Beispiel #6
0
    async def run(self):
        from boucanpy.db.checks import is_db_up, is_db_setup

        self.db_register()
        db_up = is_db_up()
        if not db_up:
            logger.critical(
                "run@api_server.py - Database not up error. please check logs")
            return self.exit(1)
        return 0
Beispiel #7
0
def token_has_one_required_scopes(token_payload: TokenPayload,
                                  scopes: List[str]):
    token_scopes = token_payload.scopes
    required_scopes = scopes or []
    for required_scope in required_scopes:
        for token_scope in token_scopes:
            if token_scope == required_scope:
                return True
    logger.critical(f"auth token missing at least one scope: {required_scope}")
    return False
Beispiel #8
0
    def make(cls, zone, rr):
        if not getattr(rr, "rtype", None):
            logger.critical(
                f"No rtype found for rr: {str(rr)} - {str(rr.__class__)}")

        # RR's don't have knowledge of domiain so replace "." with zone domain
        if rr.rname == ".":
            zone_rname = zone.domain + "."
        else:
            zone_rname = "." + zone.domain + "."
        new_label_name = str(rr.rname).replace(".", zone_rname)
        logger.debug(
            f"Replacing RR's rname {str(rr.rname)} with {new_label_name}")
        rr.set_rname(new_label_name)
        return cls(zone, rr)
Beispiel #9
0
    def post(self, url: str, data=None, fail=True):
        data = data or {}
        headers = self.get_default_headers()
        logger.info("post@api_client.py - Posting URL: " + str(self.url(url)))

        res = requests.post(self.url(url),
                            json=data,
                            headers=headers,
                            verify=self.verify_ssl)

        if fail:
            if res.status_code != 200:
                logger.critical(f"Error posting API {self.url(url)}: " +
                                str(res.json()))
            res.raise_for_status()
        return res.json()
Beispiel #10
0
def token_has_required_scopes(token_payload: TokenPayload, scopes: List[str]):
    token_scopes = token_payload.scopes
    required_scopes = scopes or []
    for required_scope in required_scopes:
        satisfied = False
        for token_scope in token_scopes:
            if token_scope == required_scope:
                satisfied = True
            # probably bad / too generous
            # a:b in a:b:c
            elif token_scope in required_scope:
                satisfied = True
        if not satisfied:
            logger.critical(f"auth token missing scope: {required_scope}")

            return False
    return True
Beispiel #11
0
    def get(self, url: str, params=None, fail=True):
        params = params or {}
        headers = self.get_default_headers()
        logger.info("get@api_client.py - Getting URL: " + str(self.url(url)))

        res = requests.get(self.url(url),
                           headers=headers,
                           params=params,
                           verify=self.verify_ssl)

        if fail:
            if res.status_code != 200:
                logger.critical(
                    f"get@api_client.py - Error getting API {self.url(url)}: "
                    + str(res.json()))
            res.raise_for_status()
        return res.json()
Beispiel #12
0
async def is_broadcast_up():
    seconds = 0
    while True:
        if seconds > 60:
            logger.critical("could not start api. broadcast (queue) not up")
            return False
        logger.debug("checking for broadcast (queue) status")
        try:
            redis = await make_redis()
            await redis.set("up-key", "value")
            val = await redis.get("up-key")
            val = await redis.delete("up-key")
            return True
        except Exception as e:
            logger.critical(
                "broadcast (queue) check not ready after {} seconds: {}".
                format(str(seconds), str(e.__class__.__name__)))
        seconds = seconds + 2
        sleep(2)
Beispiel #13
0
async def broadcast_auth(websocket: WebSocket):
    try:
        await websocket.accept()
    except Exception as e:
        logger.critical(f"[email protected] - Accept Error: {str(type(e))}")
        logger.critical(f"[email protected] - Accept Trace: {str(e)}")
        return 1

    params = parse_qs(urlparse(str(websocket.url)).query)
    token = verify_jwt_token(params["ws_access_token"][0])
    if not token_has_required_scopes(token, []):  # TODO: check scopes later
        raise HTTPException(403, detail="Forbidden")
    user_repo = UserRepo(session())
    user = await current_user(token, user_repo)

    subscriber, channel = await make_subscriber("auth")

    try:
        while await channel.wait_message():
            logger.info("[email protected] - Waiting for message")
            msg = await channel.get(encoding="utf-8")
            logger.info("[email protected] - Received message: " + str(msg))
            data = json.loads(msg)
            logger.info("[email protected] - Sending message: " + str(data))
            await websocket.send_json(data)
    except Exception as e:
        logger.critical(
            f"[email protected] - Receieve/Send: Error: {str(type(e))}"
        )
        logger.critical(f"[email protected] - Receieve/Send: Trace:{str(e)}")
        logger.critical(
            f"[email protected] - Receieve/Send: Not closing or unsubscribing"
        )

        return 1

    logger.info(f"[email protected] - Attempting to unsuscribe")
    await subscriber.unsubscribe("channel:auth")
    logger.info(f"[email protected]: Websocket - Attempting to close socket")
    await websocket.close()
Beispiel #14
0
def is_db_up():
    seconds = 0
    while True:
        if seconds > 60:
            logger.critical("could not start api. database not up")
            return False
        logger.debug("checking for db status")
        try:
            session().execute("SELECT 1")
            return True
        except KeyError as e:
            logger.critical(
                "database has not be registered. please call db_register(db_url)"
            )
            return False
        except Exception as e:
            logger.critical(
                "database check not ready after {} seconds: {}".format(
                    str(seconds), str(e.__class__.__name__)))
        seconds = seconds + 1
        sleep(1)
Beispiel #15
0
def is_db_setup():
    seconds = 0
    while True:
        if seconds > 60:
            logger.critical("could not start api. database not setup")
            return False
        logger.debug("checking for db migrations")
        try:
            session().execute("SELECT * from alembic_version")
            return True
        except KeyError as e:
            logger.critical(
                "database has not be registered. please call db_register(db_url)"
            )
            return False
        except Exception as e:
            logger.critical(
                "database has not been migrated. please run: bdnsctl.py db-setup"
            )
            return False
        seconds = seconds + 1
        sleep(1)
Beispiel #16
0
async def broadcast_index(websocket: WebSocket):
    try:
        logger.info("[email protected] - Accepting websockets")
        await websocket.accept()
    except Exception as e:
        logger.critical(f"[email protected] - Accept: Error: {str(type(e))}")
        logger.critical(f"[email protected] - Accept: Trace: {str(e)}")
        logger.critical(
            f"[email protected] - Accept:Not closing or unsubscribing"
        )
        return 1

    try:
        while True:
            logger.info("[email protected] - Receiving json")
            data = await websocket.receive_json()
            logger.info("[email protected] - Received json: " + str(data))
            logger.info(
                "[email protected] - Sending message: "
                + str({"message": "greetings"})
            )
            await websocket.send_json({"message": "greetings"})
    except Exception as e:
        logger.critical(
            f"[email protected] - Receieve/Send: Error: {str(type(e))}"
        )
        logger.critical(
            f"[email protected] - Receieve/Send: Trace: {str(e)}"
        )
        logger.critical(
            f"[email protected] - Receieve/Send: Not closing or unsubscribing"
        )
        return 1

    await websocket.close()
Beispiel #17
0
    async def run(self):
        self.db_register()

        if self.option("target", False) == False:
            self.set_option("target", "dev")

        if self.option("target") == "env":
            logger.info(f"run@db_seed.py - Seeding {self.option('target')}")
            raise NotImplementedError()  # seed based on env vars

        elif self.option("target") == "dev":
            logger.info(f"run@db_seed.py - Seeding {self.option('target')}")
            logger.info("run@db_seed.py - reating superuser")
            super = factory("SuperUserFactory").create(email="*****@*****.**")

            logger.info("run@db_seed.py - Creating normal user")
            norm = factory("UserFactory").create(email="*****@*****.**")

            logger.info("run@db_seed.py - Creating dns_server")

            _dns_server = factory("DnsServerFactory").create(
                name="mydnsserver")

            dns_server = factory("DnsServerFactory").create()

            logger.info("run@db_seed.py - Creating http_server")

            _http_server = factory("HttpServerFactory").create(
                name="myhttpserver")

            http_server = factory("HttpServerFactory").create()

            logger.info("run@db_seed.py - Creating zones")

            zone = factory("ZoneFactory").create(domain="othersite.com",
                                                 ip="127.0.1.1")

            zone2 = factory("ZoneFactory").create(
                domain="friends4life.com",
                ip="127.0.1.1",
                dns_server=dns_server,
                http_server=http_server,
            )

            zone3 = factory("ZoneFactory").create(domain="differentzone.com",
                                                  ip="127.0.1.1")

            logger.info("run@db_seed.py - Creating api_tokens")

            factory("ApiTokenFactory").create(dns_server=dns_server)
            factory("ApiTokenFactory").create(http_server=http_server)
            factory("ApiTokenFactory").create(dns_server=dns_server,
                                              http_server=http_server)

            logger.info("run@db_seed.py - Creating dns_requests")

            for i in range(35):
                factory("DnsRequestFactory").create(dns_server=dns_server,
                                                    zone=zone2)

            for i in range(35):
                factory("DnsRequestFactory").create(dns_server=dns_server,
                                                    zone=zone3)

            logger.info("run@db_seed.py - Creating dns_records")

            for i in range(3):
                factory("DnsRecordFactory").create(zone=zone)

            for i in range(3):
                factory("DnsRecordFactory").create(zone=zone2)

            for i in range(3):
                factory("DnsRecordFactory").create(zone=zone3)

            logger.info("run@db_seed.py - Creating http_requests")

            for i in range(35):
                factory("HttpRequestFactory").create(http_server=http_server,
                                                     zone=zone2)

            for i in range(35):
                factory("HttpRequestFactory").create(http_server=http_server,
                                                     zone=zone3)
        else:
            logger.critical("run@db_seed.py - invalid target set for seeder")
            self.exit(1)
Beispiel #18
0
    async def run(self):

        # TODO: thread issues?
        verify_ssl = True
        if bool(self.option("no_ssl_verify")):
            verify_ssl = False

        self.api_client = ApiClient(self.get_api_url(),
                                    self.get_api_token(),
                                    verify_ssl=verify_ssl)

        if not self.api_client.wait_for_up():
            logger.critical(
                "run@dns_server.py - Could not connect to api. quitting")
            self.exit(1)

        if self.option("no_sync"):
            logger.info("run@dns_server.py - Skipping syncing api token")
        else:
            self.api_client.sync()

        self.boot()

        self.start_servers()

        try:
            count = 0
            while self.udp_server.isAlive():
                if count > 0 and count % self.option("refresh_ttl") == 0:
                    if self.api_client.refresh_zones_if_needed():
                        logger.critical(
                            "run@dns_server.py - API Client found new or changed zones. Stopping servers..."
                        )
                        # TODO: figure out why "stop" does not release the address
                        self.stop_servers()

                        sleep(1)

                        stop_count = 0
                        logger.critical(
                            "run@dns_server.py - Waiting for UDP Server to stop..."
                        )
                        while self.udp_server.thread and self.udp_server.isAlive(
                        ):
                            if stop_count > 30:
                                logger.critical(
                                    "run@dns_server.py - UDP Server did not stop while reloading zones"
                                )
                                raise Exception(
                                    "run@dns_server.py - UDP Server threads went rogue during zone reload"
                                )
                            logger.info(
                                "run@dns_server.py - Waiting for DNS Server to stop before reloading zones"
                            )
                            stop_count = stop_count + 1
                            sleep(1)
                        stop_count = 0
                        logger.critical(
                            "run@dns_server.py - Waiting for TCP Server to stop..."
                        )
                        while self.tcp_server.thread and self.tcp_server.isAlive(
                        ):
                            if stop_count > 30:
                                logger.critical(
                                    "run@dns_server.py - TCP Server did not stop while reloading zones"
                                )
                                raise Exception(
                                    "run@dns_server.py - TCP Server threads went rogue during zone reload"
                                )
                            logger.info(
                                "run@dns_server.py - Waiting for DNS Server to stop before reloading zones"
                            )
                            stop_count = stop_count + 1
                            sleep(1)
                        logger.critical(
                            "run@dns_server.py - Rebooting server with fresh zones..."
                        )
                        self.boot()
                        self.start_servers()

                count = count + 1
                sleep(1)
        except KeyboardInterrupt:
            pass
Beispiel #19
0
    async def run(self):
        app = "boucanpy.api.main:api"
        kwargs = self.get_kwargs()

        if self.should_import_check():
            logger.info("run@api_server.py - Performing import check")
            from boucanpy.api.main import api

        logger.critical(
            "run@api_server.py - Starting api server with options: {}".format(
                str(kwargs)))
        from boucanpy.db.checks import is_db_up, is_db_setup

        # alembic just destroys the loggers, it's annoying
        if self.should_db_check():
            logger.info(
                "run@api_server.py - Waiting for database service to be up")
            db_wait_options = self._args_to_dict(self.options)
            await DbWait(db_wait_options).run()

        if self.option("db_setup"):
            logger.critical("run@api_server.py - Running database migration")
            db_setup_options = self._args_to_dict(self.options)
            if self.option("db_seed"):
                db_setup_options["seed"] = True
            await DbSetup(db_setup_options).run()

        if self.should_db_check():
            logger.info(
                "run@api_server.py - Checking if application database is setup and configured"
            )

            db_setup = is_db_setup()
            if not db_setup:
                logger.critical(
                    "run@api_server.py - Database not setup error. please check logs"
                )
                return self.exit(1)

        from boucanpy.broadcast import is_broadcast_up

        if self.should_bcast_check():
            bcast_up = await is_broadcast_up()
            if not bcast_up:
                logger.critical(
                    "run@api_server.py - Broadcast (queue) not up error. please check logs"
                )
                return self.exit(1)

        if self.option("db_seed_env", False):
            self.seed_from_env()

        # taken from uvicorn/main.py:run

        logger.debug("run@api_server.py - Building Uvicorn Config and Server")
        config = UvicornConfig(app,
                               log_config=self.get_uvicorn_logging(),
                               **kwargs)
        server = UvicornServer(config=config)
        if self.option("force_exit"):
            server.force_exit = True

        if isinstance(app, str) and (config.debug or config.reload):
            logger.warning(
                f"run@api_server.py - Running boucanpy api in dev mode...")
            sock = config.bind_socket()
            supervisor = StatReload(config)
            return supervisor.run(server.run, sockets=[sock])
        elif config.workers > 1:
            sock = config.bind_socket()
            supervisor = Multiprocess(config)
            logger.warning(
                f"run@api_server.py - Running boucanpy api in worker mode...")
            return supervisor.run(server.run, sockets=[sock])
        else:
            sockets = None
            logger.warning(
                f"run@api_server.py - Running boucanpy api in standard mode..."
            )
            return await server.serve(sockets=sockets)