Beispiel #1
0
 async def merge_graph(self, db: DbAccess) -> GraphUpdate:  # type: ignore
     model = Model.from_kinds([kind async for kind in db.model_db.all()])
     builder = GraphBuilder(model)
     nxt = self.next_action()
     while isinstance(nxt, ReadElement):
         for element in nxt.jsons():
             builder.add_from_json(element)
         log.debug(f"Read {int(BatchSize / 1000)}K elements in process")
         nxt = self.next_action()
     if isinstance(nxt, PoisonPill):
         log.debug("Got poison pill - going to die.")
         shutdown_process(0)
     elif isinstance(nxt, MergeGraph):
         log.debug("Graph read into memory")
         builder.check_complete()
         graphdb = db.get_graph_db(nxt.graph)
         outer_edge_db = db.get_pending_outer_edge_db()
         _, result = await graphdb.merge_graph(builder.graph, model,
                                               nxt.change_id, nxt.is_batch)
         if nxt.task_id and builder.deferred_edges:
             await outer_edge_db.update(
                 PendingDeferredEdges(nxt.task_id, nxt.graph,
                                      builder.deferred_edges))
             log.debug(
                 f"Updated {len(builder.deferred_edges)} pending outer edges for collect task {nxt.task_id}"
             )
         return result
Beispiel #2
0
    def client(args: Namespace) -> StandardDatabase:
        if args.graphdb_type not in "arangodb":
            log.fatal(f"Unknown Graph DB type {args.graphdb_type}")
            shutdown_process(1)

        http_client = ArangoHTTPClient(args.graphdb_request_timeout,
                                       not args.graphdb_no_ssl_verify)
        client = ArangoClient(hosts=args.graphdb_server,
                              http_client=http_client)
        return client.db(args.graphdb_database,
                         username=args.graphdb_username,
                         password=args.graphdb_password)
Beispiel #3
0
def main() -> None:
    """
    Application entrypoint - no arguments are allowed.
    """
    try:
        run(sys.argv[1:])
        log.info("Process finished.")
    except (KeyboardInterrupt, SystemExit):
        log.info("Stopping resoto graph core.")
        shutdown_process(0)
    except Exception as ex:
        print(f"resotocore stopped. Reason {class_fqn(ex)}: {ex}",
              file=sys.stderr)
        shutdown_process(1)
Beispiel #4
0
 def run(self) -> None:
     try:
         # Entrypoint of the new service
         setup_process(self.args, f"merge_update_{self.pid}")
         log.info(f"Import process started: {self.pid}")
         result = asyncio.run(self.setup_and_merge())
         self.write_queue.put(Result(result))
         log.info(f"Update process done: {self.pid} Exit.")
         shutdown_process(0)
     except Exception as ex:
         # not all exceptions can be pickled. Use string representation.
         self.write_queue.put(Result(repr(ex)))
         log.error(f"Update process interrupted. Preemptive Exit. {ex}",
                   exc_info=ex)
         shutdown_process(1)
Beispiel #5
0
    def connect(
        cls,
        args: Namespace,
        timeout: timedelta,
        sleep_time: float = 5,
        verify: Union[str, bool, None] = None
    ) -> Tuple[bool, SystemData, StandardDatabase]:
        deadline = utc() + timeout
        db = cls.client(args, verify)

        def create_database() -> None:
            try:
                # try to access the system database with default credentials.
                # this only works if arango has been started with default settings.
                http_client = ArangoHTTPClient(args.graphdb_request_timeout,
                                               not args.graphdb_no_ssl_verify)
                root_pw = args.graphdb_root_password
                secure_root = not args.graphdb_bootstrap_do_not_secure
                root_db = ArangoClient(
                    hosts=args.graphdb_server,
                    http_client=http_client).db(password=root_pw)
                root_db.echo(
                )  # this call will fail, if we are not allowed to access the system db
                user = args.graphdb_username
                passwd = args.graphdb_password
                database = args.graphdb_database
                change = False
                if not root_db.has_user(user):
                    log.info(
                        "Configured graph db user does not exist. Create it.")
                    root_db.create_user(user, passwd, active=True)
                    change = True
                if not root_db.has_database(database):
                    log.info(
                        "Configured graph db database does not exist. Create it."
                    )
                    root_db.create_database(
                        database,
                        [{
                            "username": user,
                            "password": passwd,
                            "active": True,
                            "extra": {
                                "generated": "resoto"
                            }
                        }],
                    )
                    change = True
                if change and secure_root and root_pw == "" and passwd != "" and passwd not in {
                        "test"
                }:
                    root_db.replace_user("root", passwd, True)
                    log.info(
                        "Database is using an empty password. "
                        "Secure the root account with the provided user password. "
                        "Login to the Resoto database via provided username and password. "
                        "Login to the System database via `root` and provided password!"
                    )
                if not change:
                    log.info(
                        "Not allowed to access database, while user and database exist. Wrong password?"
                    )
            except Exception as ex:
                log.error(
                    "Database or user does not exist or does not have enough permissions. "
                    f"Attempt to create user/database via default system account is not possible. Reason: {ex}. "
                    "You can provide the password of the root user via --graphdb-root-password to setup "
                    "a Resoto user and database automatically.")

        def system_data() -> Tuple[bool, SystemData]:
            def insert_system_data() -> SystemData:
                system = SystemData(uuid_str(), utc(), 1)
                log.info(f"Create new system data entry: {system}")
                db.insert_document("system_data", {
                    "_key": "system",
                    **to_js(system)
                },
                                   overwrite=True)
                return system

            if not db.has_collection("system_data"):
                db.create_collection("system_data")

            sys_js = db.collection("system_data").get("system")
            return (True, insert_system_data()) if not sys_js else (
                False, from_js(sys_js, SystemData))

        while True:
            try:
                db.echo()
                try:
                    db_version = int(db.required_db_version())
                except Exception as ex:
                    log.warning(
                        f"Not able to retrieve version of arangodb. Reason: {ex}. Continue."
                    )
                else:
                    if db_version < 30802:
                        raise RequiredDependencyMissingError(
                            "Need arangodb in version 3.8.2 or later")

                created, sys_data = system_data()
                return created, sys_data, db
            except ArangoServerError as ex:
                if utc() > deadline:
                    log.error("Can not connect to database. Giving up.")
                    shutdown_process(1)
                elif ex.error_code in (11, 1228, 1703):
                    # https://www.arangodb.com/docs/stable/appendix-error-codes.html
                    # This means we can reach the database, but are either not allowed to access it
                    # or the related user and or database could not be found.
                    # We assume the database does not exist and try to create it.
                    create_database()
                else:
                    log.warning(
                        f"Problem accessing the graph database: {ex}. Trying again in 5 seconds."
                    )
                # Retry directly after the first attempt
                sleep(sleep_time)
            except (RequestException, ConnectionError) as ex:
                log.warning(
                    f"Can not access database. Trying again in 5 seconds: {ex}"
                )
                sleep(sleep_time)