Skip to content
Snippets Groups Projects
main.go 3.89 KiB
Newer Older
Gabriel Zachmann's avatar
Gabriel Zachmann committed
package main

import (
	"fmt"
	"os"
	"strings"
	"time"

	"github.com/Songmu/prompter"
Gabriel Zachmann's avatar
Gabriel Zachmann committed
	log "github.com/sirupsen/logrus"
Gabriel Zachmann's avatar
Gabriel Zachmann committed
	"github.com/urfave/cli/v2"
Gabriel Zachmann's avatar
Gabriel Zachmann committed
	"golang.org/x/term"

Gabriel Zachmann's avatar
Gabriel Zachmann committed
	"github.com/oidc-mytoken/server/internal/config"
	"github.com/oidc-mytoken/server/internal/db"
Gabriel Zachmann's avatar
Gabriel Zachmann committed
	"github.com/oidc-mytoken/server/internal/model/version"
Gabriel Zachmann's avatar
Gabriel Zachmann committed
	"github.com/oidc-mytoken/server/shared/utils/fileutil"
Gabriel Zachmann's avatar
Gabriel Zachmann committed
)

var configFile string
var force bool

var dbConfig struct {
	config.DBConf
	Hosts cli.StringSlice
}

var app = &cli.App{
	Name:     "mytoken-migratedb",
	Usage:    "Command line client for easy database migration between mytoken versions",
	Version:  version.VERSION(),
	Compiled: time.Time{},
Gabriel Zachmann's avatar
Gabriel Zachmann committed
	Authors: []*cli.Author{
		{
			Name:  "Gabriel Zachmann",
			Email: "gabriel.zachmann@kit.edu",
		},
	},
Gabriel Zachmann's avatar
Gabriel Zachmann committed
	Copyright:              "Karlsruhe Institute of Technology 2020-2021",
	UseShortOptionHandling: true,
	Flags: []cli.Flag{
		&cli.StringFlag{
Gabriel Zachmann's avatar
Gabriel Zachmann committed
			Name: "nodes",
			Aliases: []string{
				"n",
				"s",
				"server",
			},
Gabriel Zachmann's avatar
Gabriel Zachmann committed
			Usage:       "The passed file lists the mytoken nodes / servers (one server per line)",
			EnvVars:     []string{"MYTOKEN_NODES_FILE"},
			TakesFile:   true,
			Placeholder: "FILE",
			Destination: &configFile,
		},
		&cli.BoolFlag{
Gabriel Zachmann's avatar
Gabriel Zachmann committed
			Name:    "force",
			Aliases: []string{"f"},
			Usage: "Force a complete database migration. It is not checked if mytoken servers are " +
				"compatible with the changes.",
Gabriel Zachmann's avatar
Gabriel Zachmann committed
			Destination:      &force,
			HideDefaultValue: true,
		},

		&cli.StringFlag{
			Name:        "db",
			Usage:       "The name of the database",
			EnvVars:     []string{"DB_DATABASE"},
			Value:       "mytoken",
			Destination: &dbConfig.DB,
			Placeholder: "DB",
		},
		&cli.StringFlag{
			Name:        "user",
			Aliases:     []string{"u"},
			Usage:       "The user for connecting to the database (Needs correct privileges)",
			EnvVars:     []string{"DB_USER"},
			Value:       "root",
			Destination: &dbConfig.User,
			Placeholder: "USER",
		},
		&cli.StringFlag{
Gabriel Zachmann's avatar
Gabriel Zachmann committed
			Name:    "password",
			Aliases: []string{"p"},
			Usage:   "The password for connecting to the database",
			EnvVars: []string{
				"DB_ROOT_PASSWORD",
				"DB_ROOT_PW",
			},
Gabriel Zachmann's avatar
Gabriel Zachmann committed
			Destination: &dbConfig.Password,
			Placeholder: "PASSWORD",
		},
		&cli.StringFlag{
Gabriel Zachmann's avatar
Gabriel Zachmann committed
			Name:    "password-file",
			Aliases: []string{"pw-file"},
			Usage:   "Read the password for connecting to the database from this file",
			EnvVars: []string{
				"DB_PASSWORD_FILE",
				"DB_PW_FILE",
			},
Gabriel Zachmann's avatar
Gabriel Zachmann committed
			Destination: &dbConfig.PasswordFile,
			Placeholder: "FILE",
		},
		&cli.StringSliceFlag{
Gabriel Zachmann's avatar
Gabriel Zachmann committed
			Name:    "host",
			Aliases: []string{"hosts"},
			Usage:   "The hostnames of the database nodes",
			EnvVars: []string{
				"DB_HOST",
				"DB_HOSTS",
				"DB_NODES",
			},
Gabriel Zachmann's avatar
Gabriel Zachmann committed
			Value:       cli.NewStringSlice("localhost"),
			Destination: &dbConfig.Hosts,
			Placeholder: "HOST",
Gabriel Zachmann's avatar
Gabriel Zachmann committed
			TakesFile:   true,
Gabriel Zachmann's avatar
Gabriel Zachmann committed
		},
	},
	Action: func(context *cli.Context) error {
		mytokenNodes := []string{}
		if context.Args().Len() > 0 {
			mytokenNodes = context.Args().Slice()
		} else if configFile != "" {
			mytokenNodes = readConfigFile(configFile)
		} else if os.Getenv("MYTOKEN_NODES") != "" {
			mytokenNodes = strings.Split(os.Getenv("MYTOKEN_NODES"), ",")
		} else if !force {
Gabriel Zachmann's avatar
Gabriel Zachmann committed
			return fmt.Errorf("No mytoken servers specified. Please provide mytoken servers or use '-f' to " +
				"force database migration.")
Gabriel Zachmann's avatar
Gabriel Zachmann committed
		}
Gabriel Zachmann's avatar
Gabriel Zachmann committed
		if dbConfig.GetPassword() == "" {
			dbConfig.Password = prompter.Password(fmt.Sprintf("Enter db password for user '%s'", dbConfig.User))
Gabriel Zachmann's avatar
Gabriel Zachmann committed
		dbConfig.ReconnectInterval = 60
		dbConfig.DBConf.Hosts = dbConfig.Hosts.Value()
		db.ConnectConfig(dbConfig.DBConf)
		return migrateDB(mytokenNodes)
Gabriel Zachmann's avatar
Gabriel Zachmann committed
	},
}

func readConfigFile(file string) []string {
	data := string(fileutil.MustReadFile(file))
	return strings.Split(data, "\n")
}

func main() {

	termWidth, _, err := term.GetSize(int(os.Stdout.Fd()))
	if err == nil {
		cli.HelpWrapAt = termWidth
	}

	if err = app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}