authelia/internal/commands/root.go

148 lines
4.0 KiB
Go

package commands
import (
"fmt"
"os"
"strings"
"github.com/spf13/cobra"
"github.com/authelia/authelia/v4/internal/logging"
"github.com/authelia/authelia/v4/internal/model"
"github.com/authelia/authelia/v4/internal/utils"
)
// NewRootCmd returns a new Root Cmd.
func NewRootCmd() (cmd *cobra.Command) {
ctx := NewCmdCtx()
version := utils.Version()
cmd = &cobra.Command{
Use: "authelia",
Short: fmt.Sprintf(fmtCmdAutheliaShort, version),
Long: fmt.Sprintf(fmtCmdAutheliaLong, version),
Example: cmdAutheliaExample,
Version: version,
Args: cobra.NoArgs,
PreRunE: ctx.ChainRunE(
ctx.ConfigEnsureExistsRunE,
ctx.ConfigLoadRunE,
ctx.LogConfigure,
ctx.LogProcessCurrentUserRunE,
ctx.ConfigValidateKeysRunE,
ctx.ConfigValidateRunE,
ctx.ConfigValidateLogRunE,
),
RunE: ctx.RootRunE,
DisableAutoGenTag: true,
}
cmd.PersistentFlags().StringSliceP(cmdFlagNameConfig, "c", []string{"configuration.yml"}, "configuration files or directories to load, for more information run 'authelia -h authelia config'")
cmd.PersistentFlags().StringSlice(cmdFlagNameConfigExpFilters, nil, "list of filters to apply to all configuration files, for more information run 'authelia -h authelia filters'")
cmd.AddCommand(
newAccessControlCommand(ctx),
newBuildInfoCmd(ctx),
newCryptoCmd(ctx),
newStorageCmd(ctx),
newValidateConfigCmd(ctx),
newHelpTopic("config", "Help for the config file/directory paths", helpTopicConfig),
newHelpTopic("filters", "help topic for the config filters", helpTopicConfigFilters),
newHelpTopic("time-layouts", "help topic for the various time layouts", helpTopicTimeLayouts),
)
return cmd
}
func (ctx *CmdCtx) RootRunE(_ *cobra.Command, _ []string) (err error) {
ctx.log.Infof("Authelia %s is starting", utils.Version())
if os.Getenv("ENVIRONMENT") == "dev" {
ctx.log.Info("===> Authelia is running in development mode. <===")
}
if err = logging.ConfigureLogger(ctx.config.Log, true); err != nil {
ctx.log.Fatalf("Cannot configure logger: %v", err)
}
warns, errs := ctx.LoadProviders()
if len(warns) != 0 {
for _, err = range warns {
ctx.log.Warn(err)
}
}
if len(errs) != 0 {
for _, err = range errs {
ctx.log.Error(err)
}
ctx.log.Fatalf("Errors occurred provisioning providers.")
}
doStartupChecks(ctx)
ctx.cconfig = nil
servicesRun(ctx)
return nil
}
func doStartupChecks(ctx *CmdCtx) {
var (
failures []string
err error
)
if err = doStartupCheck(ctx, "storage", ctx.providers.StorageProvider, false); err != nil {
ctx.log.Errorf("Failure running the storage provider startup check: %+v", err)
failures = append(failures, "storage")
}
if err = doStartupCheck(ctx, "user", ctx.providers.UserProvider, false); err != nil {
ctx.log.Errorf("Failure running the user provider startup check: %+v", err)
failures = append(failures, "user")
}
if err = doStartupCheck(ctx, "notification", ctx.providers.Notifier, ctx.config.Notifier.DisableStartupCheck); err != nil {
ctx.log.Errorf("Failure running the notification provider startup check: %+v", err)
failures = append(failures, "notification")
}
if !ctx.config.NTP.DisableStartupCheck && !ctx.providers.Authorizer.IsSecondFactorEnabled() {
ctx.log.Debug("The NTP startup check was skipped due to there being no configured 2FA access control rules")
} else if err = doStartupCheck(ctx, "ntp", ctx.providers.NTP, ctx.config.NTP.DisableStartupCheck); err != nil {
ctx.log.Errorf("Failure running the ntp provider startup check: %+v", err)
if !ctx.config.NTP.DisableFailure {
failures = append(failures, "ntp")
}
}
if len(failures) != 0 {
ctx.log.Fatalf("The following providers had fatal failures during startup: %s", strings.Join(failures, ", "))
}
}
func doStartupCheck(ctx *CmdCtx, name string, provider model.StartupCheck, disabled bool) error {
if disabled {
ctx.log.Debugf("%s provider: startup check skipped as it is disabled", name)
return nil
}
if provider == nil {
return fmt.Errorf("unrecognized provider or it is not configured properly")
}
return provider.StartupCheck()
}