Migrations infra & working instance-control + commands

This commit is contained in:
2026-05-23 20:53:44 -07:00
parent acdb4840aa
commit 348e1fa857
13 changed files with 262 additions and 62 deletions

View File

@@ -33,6 +33,7 @@
(chicken string)
(chicken port)
(chicken io)
(chicken sort)
postgresql
sql-null
srfi-1
@@ -295,7 +296,9 @@ returning users.user_id;"
(nextcloud . "nextcloud_version")
(ghost . "ghost_version")
(nassella . "nassella_version")
(log-viewer . "log_viewer_version")))
(log-viewer . "log_viewer_version")
(instance-control . "instance_control_version")
))
(define *user-selected-apps-reverse-column-map*
(map (lambda (config)
@@ -493,7 +496,7 @@ returning users.user_id;"
(map-in-order (lambda (d) (string-append "d." (cdr d))) *deployments-column-map*)
", ")
", uac.root_domain, uac.config_enc, uac.instance_id, "
"usa.wg_easy_version, usa.nextcloud_version, usa.log_viewer_version, usa.ghost_version, usa.nassella_version "
"usa.wg_easy_version, usa.nextcloud_version, usa.log_viewer_version, usa.ghost_version, usa.nassella_version, usa.instance_control_version "
"from instances as i "
"join (select instance_id, max(id) as id from deployments group by instance_id) d2 "
"on d2.instance_id = i.instance_id "
@@ -515,6 +518,7 @@ returning users.user_id;"
(ghost_version . ghost)
(nassella_version . nassella)
(log_viewer_version . log-viewer)
(instance_control_version . instance-control)
,@*deployments-reverse-column-map*))))
`(,config . ,(if (sql-null? value)
#f
@@ -553,8 +557,92 @@ returning users.user_id;"
""
(user-decrypt-from-db (alist-ref 'state_backup_enc res) user-key user-iv user-id)))))))
;; (define (instance-config-for-export conn user-id instance-id)
;; (receive (user-key user-iv auth-user-id)
;; (get-decrypted-user-key-and-iv conn user-id)
;; (let ((res (row-alist
;; (query conn
;; "
;; select
;; instances.ssh_key_priv_enc,
;; instances.ssh_key_pub_enc,
;; instances.restic_password_enc,
;; user_service_configs.cloudflare_api_token_enc,
;; user_service_configs.cloudflare_account_id_enc,
;; user_service_configs.cloudflare_zone_id_enc,
;; user_service_configs.digitalocean_api_token_enc,
;; user_service_configs.digitalocean_region,
;; user_service_configs.digitalocean_size,
;; user_service_configs.backblaze_application_key_enc,
;; user_service_configs.backblaze_key_id_enc,
;; user_service_configs.backblaze_bucket_url_enc,
;; user_selected_apps.wg_easy_version,
;; user_selected_apps.nextcloud_version,
;; user_selected_apps.nassella_version,
;; user_selected_apps.log_viewer_version,
;; user_selected_apps.ghost_version,
;; user_app_configs.root_domain,
;; user_apps_configs.config_end
;; from instances
;; join user_service_configs on user_service_configs.user_id = instances.user_id and user_service_configs.instance_id = instances.instance_id
;; join user_selected_apps on user_selected_apps.user_id = instances.user_id and user_selected_apps.instance_id = instances.instance_id
;; join user_app_configs on user_apps_configs.user_id = instances.user_id and user_app_configs.instance_id = instances.instance_id
;; where instances.user_id=$1 and instance.instance_id=$2;"
;; user-id instance-id))))
;; `((state . ,(if (or (sql-null? (alist-ref 'config_enc res))
;; (sql-null? (alist-ref 'state_enc res)))
;; ""
;; (user-decrypt-from-db (alist-ref 'state_enc res) user-key user-iv user-id)))
;; (backup . ,(if (or (sql-null? (alist-ref 'config_enc res))
;; (sql-null? (alist-ref 'state_backup_enc res)))
;; ""
;; (user-decrypt-from-db (alist-ref 'state_backup_enc res) user-key user-iv user-id)))))))
;; TODO can/should this be removed? I don't remember why I put this here
(debug-log (current-error-port))
;; An a-list of migrations. The car is the migration_id in the migrations
;; table and the cdr is name of the file containing sql for the migration.
;; The file name is appended with "-up.sql" and "-down.sql", depending on if
;; an up or down migration should be run.
;;
;; After a migration has been run, it's migration id (the car in the alist) is
;; added to the database so the migration does not get re-run.
;;
;; To create a new migration:
;; add it to the end of this list with the car being one number higher than
;; the previous migration and the cdr being the filename containing sql statements
;; to run (not including a prefix of the ID or the suffic -up.sql or -down.sql).
;; add two sql files in the "migrations" folder, one ending in -up.sql and one ending
;; in -down.sql.
;; So to for a migration called "my-migration" with id "13 create two files in the
;; migrations directory: 13-my-migration-up.sql and 13-my-migration-down.sql
;;
;; The "up" file is called to run the migration and the "down" file is called to
;; "undo" the migration.
(define *migrations*
'((0 . "adding-instance-control-app")))
(define (run-pending-migrations conn)
(let* ((migration-ids (sort (map car *migrations*) <))
(migration-rows (query conn "select migration_id from migrations;"))
(applied-migration-ids (if (> (row-count migration-rows) 0)
(row-values migration-rows)
'())))
(for-each
(lambda (id)
(when (not (member id applied-migration-ids))
(log-to (debug-log) "running migration: ~A" id)
(for-each
(lambda (statement)
(query conn (conc statement ";")))
(string-split (with-input-from-file
(conc "migrations/" id "-" (alist-ref id *migrations*) "-up.sql")
read-string)
";"))
(query conn "insert into migrations(migration_id) values ($1);" id)))
migration-ids)))
(define (db-init)
(with-db/transaction
(lambda (db)
@@ -571,7 +659,18 @@ returning users.user_id;"
(log-to (debug-log) "table creation finished")
(log-to (debug-log) "creating test user")
(create-user db "me@example.com" "username")
(log-to (debug-log) "test user creation finished"))))))
(log-to (debug-log) "test user creation finished")))
;; originally there was no migrations table, so first add it if it doesn't exist
(if (value-at (query db "SELECT EXISTS (SELECT FROM pg_tables WHERE schemaname = 'public' AND tablename = 'migrations');"))
#t
(begin
(log-to (debug-log) "migrations table not found in db. Creating...")
(query db "create table migrations(
id bigserial primary key,
migration_id integer not null unique
);")
(log-to (debug-log) "migrations table creation finished")))
(run-pending-migrations db))))
(define (db-clean)
(with-db/transaction