(ns metabase-enterprise.advanced-config.file.databases (:require [clojure.spec.alpha :as s] [metabase-enterprise.advanced-config.file.interface :as advanced-config.file.i] [metabase.driver.util :as driver.u] [metabase.models.setting :refer [defsetting]] [metabase.util :as u] [metabase.util.log :as log] [metabase.util.quick-task :as quick-task] [toucan2.core :as t2])) | |
Whether to (asynchronously) sync newly created Databases during config-from-file initialization. By default, true, but you can disable this behavior if you want to sync it manually or use SerDes to populate its data model. | (defsetting config-from-file-sync-databases :visibility :internal :type :boolean :default true :audit :getter) |
(s/def :metabase-enterprise.advanced-config.file.databases.config-file-spec/name string?) | |
(s/def :metabase-enterprise.advanced-config.file.databases.config-file-spec/engine string?) | |
(s/def :metabase-enterprise.advanced-config.file.databases.config-file-spec/details map?) | |
(s/def ::config-file-spec
(s/keys :req-un [:metabase-enterprise.advanced-config.file.databases.config-file-spec/engine
:metabase-enterprise.advanced-config.file.databases.config-file-spec/name
:metabase-enterprise.advanced-config.file.databases.config-file-spec/details])) | |
(defmethod advanced-config.file.i/section-spec :databases [_section] (s/spec (s/* ::config-file-spec))) | |
(defn- init-from-config-file!
[database]
(if (contains? database :delete)
;; Databases can be managed as a service by us. When the service is canceled, we need to delete any information
;; Metabase has about them, including any stored credentials. This is a config file flag instead of a CLI command,
;; so we can ensure the database stays deleted even after restoring backups.
(let [magic-request (format "DELETE_WITH_DEPENDENTS:%s" (:name database))]
(log/info (u/format-color :blue "Deleting databases via the config file is an internal feature subject to breaking changes."))
(when (not= magic-request (:delete database))
(throw (ex-info (format "To delete database %s set `delete` to %s" (pr-str (:name database)) (pr-str magic-request))
{:database-name (:name database)})))
(when-let [existing-database-id (t2/select-one-pk :model/Database :engine (:engine database), :name (:name database))]
(log/info (u/format-color :blue "Deleting Database %s %s" (:engine database) (pr-str (:name database))))
(t2/delete! :model/Database existing-database-id)))
(do
;; assert that we are able to connect to this Database. Otherwise, throw an Exception.
(driver.u/can-connect-with-details? (keyword (:engine database)) (:details database) :throw-exceptions)
(if-let [existing-database-id (t2/select-one-pk :model/Database :engine (:engine database), :name (:name database))]
(do
(log/info (u/format-color :blue "Updating Database %s %s" (:engine database) (pr-str (:name database))))
(t2/update! :model/Database existing-database-id database))
(do
(log/info (u/format-color :green "Creating new %s Database %s" (:engine database) (pr-str (:name database))))
(let [db (first (t2/insert-returning-instances! :model/Database database))]
(if (config-from-file-sync-databases)
(let [sync-database! (requiring-resolve 'metabase.sync.core/sync-database!)]
(quick-task/submit-task! (fn [] (sync-database! db))))
(log/info "Sync on database creation when initializing from file is disabled. Skipping sync.")))))))) | |
(defmethod advanced-config.file.i/initialize-section! :databases
[_section-name databases]
(doseq [database databases]
(init-from-config-file! database))) | |