diff --git a/cmd/micromdm/database.go b/cmd/micromdm/database.go index 983d73d8..09bb800f 100644 --- a/cmd/micromdm/database.go +++ b/cmd/micromdm/database.go @@ -84,25 +84,6 @@ func sqliteInit(conn *sqlite.Conn) error { return err } - var ( - migrations []byte - script = "internal/data/migrations/sqlite/initial_tables.sql" - ) - - // only load and run migrations script if the path exists. - // temporary workaround for tests which will have to be - // replaced once the schema needs to exist for the tests. - if _, err := os.Stat(script); err == nil { - migrations, err = ioutil.ReadFile(script) - if err != nil { - return err - } - } - - if err := sqlitex.ExecScript(conn, string(migrations)); err != nil { - return err - } - return nil } @@ -117,13 +98,6 @@ func setupPostgres(ctx context.Context, f *cliFlags, logger log.Logger) (*postgr return nil, err } - // temporary until migrations are set up - migrations, err := ioutil.ReadFile("internal/data/migrations/postgres/initial_tables.sql") - if _, err := dbpool.Exec(ctx, string(migrations)); err != nil { - dbpool.Close() - return nil, err - } - db := &postgresdb{ userdb: user.NewPostgres(dbpool), sessiondb: session.NewPostgres(dbpool), @@ -133,3 +107,52 @@ func setupPostgres(ctx context.Context, f *cliFlags, logger log.Logger) (*postgr return db, nil } + +func migrate(ctx context.Context, f *cliFlags, logger log.Logger) error { + var err error + switch driver := dbDriver(f.databaseURL); driver { + case "postgres": + dbpool, err := pgxpool.Connect(ctx, f.databaseURL) + if err != nil { + return err + } + log.Info(logger).Log("msg", "connected to db", "backend", driver) + + migrations, err := ioutil.ReadFile("internal/data/migrations/postgres/initial_tables.sql") + if _, err := dbpool.Exec(ctx, string(migrations)); err != nil { + dbpool.Close() + return err + } + return nil + + case "sqlite": + conn, err := sqlite.OpenConn(f.databaseURL, 0) + if err != nil { + return fmt.Errorf("open sqlite dbfile: %s", err) + } + log.Info(logger).Log("msg", "connected to db", "backend", driver) + + var ( + migrations []byte + script = "internal/data/migrations/sqlite/initial_tables.sql" + ) + + // only load and run migrations script if the path exists. + // temporary workaround for tests which will have to be + // replaced once the schema needs to exist for the tests. + if _, err := os.Stat(script); err == nil { + migrations, err = ioutil.ReadFile(script) + if err != nil { + return err + } + } + + if err := sqlitex.ExecScript(conn, string(migrations)); err != nil { + return err + } + default: + err = fmt.Errorf("unsupported database_url value or restricted path %q", f.databaseURL) + } + + return err +} diff --git a/cmd/micromdm/micromdm.go b/cmd/micromdm/micromdm.go index 1b597656..bc8846bc 100644 --- a/cmd/micromdm/micromdm.go +++ b/cmd/micromdm/micromdm.go @@ -78,6 +78,26 @@ func micromdm(args []string, stdin io.Reader, stdout, stderr io.Writer) int { }, } + migrate := &ffcli.Command{ + Name: "migrate", + ShortUsage: "migrate [ ...]", + ShortHelp: "Run database migrations.", + Exec: func(_ context.Context, args []string) error { + logOpts := []log.Option{log.Output(stderr)} + if cli.debug { + logOpts = append(logOpts, log.StartDebug()) + } + + logger = log.New(logOpts...) + err := migrate(ctx, cli, logger) + if err != nil { + return err + } + + return nil + }, + } + // add a help subcommand to make usage more discoverable. helpCmd := &ffcli.Command{ Name: "help", @@ -93,7 +113,7 @@ func micromdm(args []string, stdin io.Reader, stdout, stderr io.Writer) int { ShortUsage: "micromdm [flags] ", FlagSet: rootfs, Options: []ff.Option{ff.WithEnvVarPrefix("MICROMDM"), ff.WithConfigFileParser(ff.PlainParser), ff.WithConfigFileFlag("config")}, - Subcommands: []*ffcli.Command{helpCmd, version}, + Subcommands: []*ffcli.Command{helpCmd, version, migrate}, Exec: func(context.Context, []string) error { logOpts := []log.Option{log.Output(stderr)}