Review: Needs Fixing

Couple of changes that we discussed, but almost there.

Diff comments:

> diff --git a/charms/focal/autopkgtest-web/webcontrol/db-backup 
> b/charms/focal/autopkgtest-web/webcontrol/db-backup
> index b03100b..3cec134 100755
> --- a/charms/focal/autopkgtest-web/webcontrol/db-backup
> +++ b/charms/focal/autopkgtest-web/webcontrol/db-backup
> @@ -47,40 +52,13 @@ def db_connect() -> sqlite3.Connection:
>  
>  
>  def backup_db(db_con: sqlite3.Connection):
> -    db_backup_con = sqlite3.connect(DB_BACKUP_PATH)
> -    with db_backup_con:
> -        db_con.backup(db_backup_con, pages=1)
> -    db_backup_con.close()
> -
> -
> -def compress_db():
> -    """
> -    use gzip to compress database
> -    """
> -    with open(DB_BACKUP_PATH, "rb") as f_in, gzip.open(
> -        "%s.gz" % DB_BACKUP_PATH, "wb"
> -    ) as f_out:
> -        shutil.copyfileobj(f_in, f_out)
> -
> -
> -def init_swift_con() -> swiftclient.Connection:
> -    """
> -    Establish connection to swift storage
> -    """
> -    swift_creds = {
> -        "authurl": os.environ["OS_AUTH_URL"],
> -        "user": os.environ["OS_USERNAME"],
> -        "key": os.environ["OS_PASSWORD"],
> -        "os_options": {
> -            "region_name": os.environ["OS_REGION_NAME"],
> -            "project_domain_name": os.environ["OS_PROJECT_DOMAIN_NAME"],
> -            "project_name": os.environ["OS_PROJECT_NAME"],
> -            "user_domain_name": os.environ["OS_USER_DOMAIN_NAME"],
> -        },
> -        "auth_version": 3,
> -    }
> -    swift_conn = swiftclient.Connection(**swift_creds)
> -    return swift_conn
> +    zstd = SimpleZstdInterface()

As discussed, no need for this object, with the newly proposed 
SimpleZstdInterface API.

> +    sql_backup = []

As discussed, remove this in-memory list and just chain all the iterators.

> +    for line in db_con.iterdump():
> +        sql_backup.append(line)
> +    compressed_backup = zstd.compress("\n".join(sql_backup).encode())
> +    with open(DB_BACKUP_PATH, "wb") as bkp_file:
> +        bkp_file.write(compressed_backup)
>  
>  
>  def create_container_if_it_doesnt_exist(swift_conn: swiftclient.Connection):
> diff --git a/charms/focal/autopkgtest-web/webcontrol/helpers/utils.py 
> b/charms/focal/autopkgtest-web/webcontrol/helpers/utils.py
> index 89ea672..c57fb63 100644
> --- a/charms/focal/autopkgtest-web/webcontrol/helpers/utils.py
> +++ b/charms/focal/autopkgtest-web/webcontrol/helpers/utils.py
> @@ -18,10 +19,29 @@ import typing
>  from dataclasses import dataclass
>  
>  import distro_info
> +import swiftclient
>  
>  sqlite3.paramstyle = "named"
>  
>  
> +class SimpleZstdInterface:

Proposed user API:
SimpleZstdInterface.compress(data)
SimpleZstdInterface.decompress(data)
Change is: no need to instantiate a SimpleZstdInterface object.

> +    def __init__(self):
> +        self.COMPRESS_COMMAND = ["zstd", "--compress"]

Those should be class attributes, called like this: 
SimpleZstdInterface.COMPRESS_COMMAND

> +        self.DECOMPRESS_COMMAND = ["zstd", "--decompress"]
> +
> +    def zync_command(self, input: bytes, command: typing.List[str]):

This should be private

> +        p = subprocess.run(
> +            command, input=input, capture_output=True, check=True
> +        )
> +        return p.stdout
> +
> +    def compress(self, data: bytes) -> bytes:
> +        return self.zync_command(data, self.COMPRESS_COMMAND)
> +
> +    def decompress(self, data: bytes) -> bytes:
> +        return self.zync_command(data, self.DECOMPRESS_COMMAND)
> +
> +
>  @dataclass
>  class SqliteWriterConfig:
>      writer_exchange_name = "sqlite-write-me.fanout"
> diff --git a/charms/focal/autopkgtest-web/webcontrol/sqlite-writer 
> b/charms/focal/autopkgtest-web/webcontrol/sqlite-writer
> index d0ec23a..d309311 100755
> --- a/charms/focal/autopkgtest-web/webcontrol/sqlite-writer
> +++ b/charms/focal/autopkgtest-web/webcontrol/sqlite-writer
> @@ -109,9 +109,55 @@ def msg_callback(msg, db_con):
>      checkpoint_db_if_necessary(db_con)
>  
>  
> +def restore_db_from_backup(db_con: sqlite3.Connection):
> +    backups_container = "db-backups"
> +    db_con.execute("PRAGMA wal_checkpoint(TRUNCATE);")

Shouldn't this be deferred to after the connection to swift, and avoided if the 
swift connection cannot be made?

> +    logging.info("Connecting to swift")
> +    try:
> +        swift_conn = init_swift_con()
> +    except swiftclient.ClientException as e:
> +        logging.warning(
> +            (
> +                f"Initialising swift connection failed with {e} - "
> +                "continuing without restoring db from backup"
> +            )
> +        )
> +        return
> +    logging.info(
> +        f"Connected to swift! Getting backups from container: 
> {backups_container}"
> +    )
> +    _, objects = swift_conn.get_container(container=backups_container)
> +    latest = objects[-1]
> +    _, compressed_db_dump = swift_conn.get_object(
> +        container=backups_container, obj=latest["name"]
> +    )
> +    zstd = SimpleZstdInterface()
> +    db_dump = zstd.decompress(compressed_db_dump)
> +    logging.info(
> +        (
> +            "Restoring db from swift - "
> +            f"container: {backups_container} - object: {latest['name']}"
> +        )
> +    )
> +    for line in db_dump.splitlines():
> +        try:
> +            db_con.execute(line.decode("utf-8"))
> +        except sqlite3.OperationalError as e:
> +            logging.warning(
> +                f"Running sql command: `{line.decode('utf-8')}` failed with 
> {e}"
> +            )
> +    logging.info("db restored from backup!")
> +
> +
>  def main():
>      logging.basicConfig(level=logging.INFO)
> -    db_con = db_connect()
> +    db_con = init_db(get_db_path())
> +    if is_db_empty(db_con):
> +        logging.info(
> +            "DB is empty, indicating this unit has been recently deployed."
> +        )
> +        logging.info("Restoring database from a swift backup")
> +        restore_db_from_backup(db_con)
>      amqp_con = amqp_connect()
>      status_ch = amqp_con.channel()
>      status_ch.access_request("/complete", active=True, read=True, 
> write=False)


-- 
https://code.launchpad.net/~andersson123/autopkgtest-cloud/+git/autopkgtest-cloud/+merge/472678
Your team Canonical's Ubuntu QA is requested to review the proposed merge of 
~andersson123/autopkgtest-cloud:charm-fixes into autopkgtest-cloud:master.


-- 
Mailing list: https://launchpad.net/~canonical-ubuntu-qa
Post to     : canonical-ubuntu-qa@lists.launchpad.net
Unsubscribe : https://launchpad.net/~canonical-ubuntu-qa
More help   : https://help.launchpad.net/ListHelp

Reply via email to