diff --git a/api/adminmonitor/admin_monitor.go b/api/adminmonitor/admin_monitor.go index e83dd47d5..aeabe0187 100644 --- a/api/adminmonitor/admin_monitor.go +++ b/api/adminmonitor/admin_monitor.go @@ -2,7 +2,6 @@ package adminmonitor import ( "context" - "log" "net/http" "strings" "sync" @@ -11,9 +10,9 @@ import ( httperror "github.com/portainer/libhttp/error" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/dataservices" -) -var logFatalf = log.Fatalf + "github.com/rs/zerolog/log" +) const RedirectReasonAdminInitTimeout string = "AdminInitTimeout" @@ -49,24 +48,28 @@ func (m *Monitor) Start() { m.cancellationFunc = cancellationFunc go func() { - log.Println("[DEBUG] [internal,init] [message: start initialization monitor ]") + log.Debug().Msg("start initialization monitor") + select { case <-time.After(m.timeout): initialized, err := m.WasInitialized() if err != nil { - logFatalf("%s", err) + log.Fatal().Err(err).Msg("") } + if !initialized { - log.Println("[INFO] [internal,init] The Portainer instance timed out for security purposes. To re-enable your Portainer instance, you will need to restart Portainer") + log.Info().Msg("the Portainer instance timed out for security purposes, to re-enable your Portainer instance, you will need to restart Portainer") + m.mu.Lock() defer m.mu.Unlock() + m.adminInitDisabled = true return } case <-cancellationCtx.Done(): - log.Println("[DEBUG] [internal,init] [message: canceling initialization monitor]") + log.Debug().Msg("canceling initialization monitor") case <-m.shutdownCtx.Done(): - log.Println("[DEBUG] [internal,init] [message: shutting down initialization monitor]") + log.Debug().Msg("shutting down initialization monitor") } }() } diff --git a/api/apikey/service_test.go b/api/apikey/service_test.go index a941ffa2a..c8c603b1b 100644 --- a/api/apikey/service_test.go +++ b/api/apikey/service_test.go @@ -2,7 +2,6 @@ package apikey import ( "crypto/sha256" - "log" "strings" "testing" "time" @@ -10,6 +9,8 @@ import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/datastore" "github.com/stretchr/testify/assert" + + "github.com/rs/zerolog/log" ) func Test_SatisfiesAPIKeyServiceInterface(t *testing.T) { @@ -169,8 +170,8 @@ func Test_UpdateAPIKey(t *testing.T) { _, apiKeyGot, err := service.GetDigestUserAndKey(apiKey.Digest) is.NoError(err) - log.Println(apiKey) - log.Println(apiKeyGot) + log.Debug().Msgf("%+v", apiKey) + log.Debug().Msgf("%+v", apiKeyGot) is.Equal(apiKey.LastUsed, apiKeyGot.LastUsed) diff --git a/api/backup/backup.go b/api/backup/backup.go index 9befb7ecc..f14a0582d 100644 --- a/api/backup/backup.go +++ b/api/backup/backup.go @@ -7,13 +7,14 @@ import ( "path/filepath" "time" - "github.com/pkg/errors" "github.com/portainer/portainer/api/archive" "github.com/portainer/portainer/api/crypto" "github.com/portainer/portainer/api/dataservices" "github.com/portainer/portainer/api/filesystem" "github.com/portainer/portainer/api/http/offlinegate" - "github.com/sirupsen/logrus" + + "github.com/pkg/errors" + "github.com/rs/zerolog/log" ) const rwxr__r__ os.FileMode = 0744 @@ -47,9 +48,9 @@ func CreateBackupArchive(password string, gate *offlinegate.OfflineGate, datasto err := datastore.Export(exportFilename) if err != nil { - logrus.WithError(err).Debugf("failed to export to %s", exportFilename) + log.Error().Err(err).Str("filename", exportFilename).Msg("failed to export") } else { - logrus.Debugf("exported to %s", exportFilename) + log.Debug().Str("filename", exportFilename).Msg("file exported") } } diff --git a/api/chisel/service.go b/api/chisel/service.go index d9be54eda..023bc714d 100644 --- a/api/chisel/service.go +++ b/api/chisel/service.go @@ -3,16 +3,17 @@ package chisel import ( "context" "fmt" - "log" "net/http" "sync" "time" - "github.com/dchest/uniuri" - chserver "github.com/jpillora/chisel/server" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/dataservices" "github.com/portainer/portainer/api/http/proxy" + + "github.com/dchest/uniuri" + chserver "github.com/jpillora/chisel/server" + "github.com/rs/zerolog/log" ) const ( @@ -64,7 +65,11 @@ func (service *Service) pingAgent(endpointID portainer.EndpointID) error { // KeepTunnelAlive keeps the tunnel of the given environment for maxAlive duration, or until ctx is done func (service *Service) KeepTunnelAlive(endpointID portainer.EndpointID, ctx context.Context, maxAlive time.Duration) { go func() { - log.Printf("[DEBUG] [chisel,KeepTunnelAlive] [endpoint_id: %d] [message: start for %.0f minutes]\n", endpointID, maxAlive.Minutes()) + log.Debug(). + Int("endpoint_id", int(endpointID)). + Float64("max_alive_minutes", maxAlive.Minutes()). + Msg("start") + maxAliveTicker := time.NewTicker(maxAlive) defer maxAliveTicker.Stop() pingTicker := time.NewTicker(tunnelCleanupInterval) @@ -76,14 +81,25 @@ func (service *Service) KeepTunnelAlive(endpointID portainer.EndpointID, ctx con service.SetTunnelStatusToActive(endpointID) err := service.pingAgent(endpointID) if err != nil { - log.Printf("[DEBUG] [chisel,KeepTunnelAlive] [endpoint_id: %d] [warning: ping agent err=%s]\n", endpointID, err) + log.Debug(). + Int("endpoint_id", int(endpointID)). + Err(err). + Msg("ping agent") } case <-maxAliveTicker.C: - log.Printf("[DEBUG] [chisel,KeepTunnelAlive] [endpoint_id: %d] [message: stop as %.0f minutes timeout]\n", endpointID, maxAlive.Minutes()) + log.Debug(). + Int("endpoint_id", int(endpointID)). + Float64("timeout_minutes", maxAlive.Minutes()). + Msg("tunnel keep alive timeout") + return case <-ctx.Done(): err := ctx.Err() - log.Printf("[DEBUG] [chisel,KeepTunnelAlive] [endpoint_id: %d] [message: stop as err=%s]\n", endpointID, err) + log.Debug(). + Int("endpoint_id", int(endpointID)). + Err(err). + Msg("tunnel stop") + return } } @@ -162,7 +178,10 @@ func (service *Service) retrievePrivateKeySeed() (string, error) { } func (service *Service) startTunnelVerificationLoop() { - log.Printf("[DEBUG] [chisel, monitoring] [check_interval_seconds: %f] [message: starting tunnel management process]", tunnelCleanupInterval.Seconds()) + log.Debug(). + Float64("check_interval_seconds", tunnelCleanupInterval.Seconds()). + Msg("starting tunnel management process") + ticker := time.NewTicker(tunnelCleanupInterval) for { @@ -170,10 +189,12 @@ func (service *Service) startTunnelVerificationLoop() { case <-ticker.C: service.checkTunnels() case <-service.shutdownCtx.Done(): - log.Println("[DEBUG] Shutting down tunnel service") + log.Debug().Msg("shutting down tunnel service") + if err := service.StopTunnelServer(); err != nil { - log.Printf("Stopped tunnel service: %s", err) + log.Debug().Err(err).Msg("stopped tunnel service") } + ticker.Stop() return } @@ -195,22 +216,40 @@ func (service *Service) checkTunnels() { } elapsed := time.Since(tunnel.LastActivity) - log.Printf("[DEBUG] [chisel,monitoring] [endpoint_id: %d] [status: %s] [status_time_seconds: %f] [message: environment tunnel monitoring]", endpointID, tunnel.Status, elapsed.Seconds()) + log.Debug(). + Int("endpoint_id", int(endpointID)). + Str("status", tunnel.Status). + Float64("status_time_seconds", elapsed.Seconds()). + Msg("environment tunnel monitoring") if tunnel.Status == portainer.EdgeAgentManagementRequired && elapsed.Seconds() < requiredTimeout.Seconds() { continue } else if tunnel.Status == portainer.EdgeAgentManagementRequired && elapsed.Seconds() > requiredTimeout.Seconds() { - log.Printf("[DEBUG] [chisel,monitoring] [endpoint_id: %d] [status: %s] [status_time_seconds: %f] [timeout_seconds: %f] [message: REQUIRED state timeout exceeded]", endpointID, tunnel.Status, elapsed.Seconds(), requiredTimeout.Seconds()) + log.Debug(). + Int("endpoint_id", int(endpointID)). + Str("status", tunnel.Status). + Float64("status_time_seconds", elapsed.Seconds()). + Float64("timeout_seconds", requiredTimeout.Seconds()). + Msg("REQUIRED state timeout exceeded") } if tunnel.Status == portainer.EdgeAgentActive && elapsed.Seconds() < activeTimeout.Seconds() { continue } else if tunnel.Status == portainer.EdgeAgentActive && elapsed.Seconds() > activeTimeout.Seconds() { - log.Printf("[DEBUG] [chisel,monitoring] [endpoint_id: %d] [status: %s] [status_time_seconds: %f] [timeout_seconds: %f] [message: ACTIVE state timeout exceeded]", endpointID, tunnel.Status, elapsed.Seconds(), activeTimeout.Seconds()) + log.Debug(). + Int("endpoint_id", int(endpointID)). + Str("status", tunnel.Status). + Float64("status_time_seconds", elapsed.Seconds()). + Float64("timeout_seconds", activeTimeout.Seconds()). + Msg("ACTIVE state timeout exceeded") err := service.snapshotEnvironment(endpointID, tunnel.Port) if err != nil { - log.Printf("[ERROR] [snapshot] Unable to snapshot Edge environment (id: %d): %s", endpointID, err) + log.Error(). + Int("endpoint_id", int(endpointID)).Err( + + err). + Msg("unable to snapshot Edge environment") } } diff --git a/api/cli/cli.go b/api/cli/cli.go index 8e92e1849..83ced70ea 100644 --- a/api/cli/cli.go +++ b/api/cli/cli.go @@ -2,15 +2,14 @@ package cli import ( "errors" - "log" + "os" + "path/filepath" + "strings" "time" portainer "github.com/portainer/portainer/api" - "os" - "path/filepath" - "strings" - + "github.com/rs/zerolog/log" "gopkg.in/alecthomas/kingpin.v2" ) @@ -62,6 +61,7 @@ func (*Service) ParseFlags(version string) (*portainer.CLIFlags, error) { MaxBatchSize: kingpin.Flag("max-batch-size", "Maximum size of a batch").Int(), MaxBatchDelay: kingpin.Flag("max-batch-delay", "Maximum delay before a batch starts").Duration(), SecretKeyName: kingpin.Flag("secret-key-name", "Secret key name for encryption and will be used as /run/secrets/.").Default(defaultSecretKeyName).String(), + LogLevel: kingpin.Flag("log-level", "Set the minimum logging level to show").Default("INFO").Enum("DEBUG", "INFO", "WARN", "ERROR"), } kingpin.Parse() @@ -101,11 +101,11 @@ func (*Service) ValidateFlags(flags *portainer.CLIFlags) error { func displayDeprecationWarnings(flags *portainer.CLIFlags) { if *flags.NoAnalytics { - log.Println("Warning: The --no-analytics flag has been kept to allow migration of instances running a previous version of Portainer with this flag enabled, to version 2.0 where enabling this flag will have no effect.") + log.Warn().Msg("the --no-analytics flag has been kept to allow migration of instances running a previous version of Portainer with this flag enabled, to version 2.0 where enabling this flag will have no effect") } if *flags.SSL { - log.Println("Warning: SSL is enabled by default and there is no need for the --ssl flag. It has been kept to allow migration of instances running a previous version of Portainer with this flag enabled") + log.Warn().Msg("SSL is enabled by default and there is no need for the --ssl flag, it has been kept to allow migration of instances running a previous version of Portainer with this flag enabled") } } diff --git a/api/cmd/portainer/import.go b/api/cmd/portainer/import.go index bb71b111f..7ce53f4a8 100644 --- a/api/cmd/portainer/import.go +++ b/api/cmd/portainer/import.go @@ -1,11 +1,10 @@ package main import ( - "log" - portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/datastore" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) func importFromJson(fileService portainer.FileService, store *datastore.Store) { @@ -13,17 +12,17 @@ func importFromJson(fileService portainer.FileService, store *datastore.Store) { importFile := "/data/import.json" if exists, _ := fileService.FileExists(importFile); exists { if err := store.Import(importFile); err != nil { - logrus.WithError(err).Debugf("Import %s failed", importFile) - + log.Error().Str("filename", importFile).Err(err).Msg("import failed") // TODO: should really rollback on failure, but then we have nothing. } else { - logrus.Printf("Successfully imported %s to new portainer database", importFile) + log.Info().Str("filename", importFile).Msg("successfully imported the file to a new portainer database") } + // TODO: this is bad - its to ensure that any defaults that were broken in import, or migrations get set back to what we want // I also suspect that everything from "Init to Init" is potentially a migration err := store.Init() if err != nil { - log.Fatalf("Failed initializing data store: %v", err) + log.Fatal().Err(err).Msg("failed initializing data store") } } } diff --git a/api/cmd/portainer/log.go b/api/cmd/portainer/log.go index 88de199a2..52cd3ee63 100644 --- a/api/cmd/portainer/log.go +++ b/api/cmd/portainer/log.go @@ -1,20 +1,28 @@ package main import ( - "log" - - "github.com/sirupsen/logrus" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" + "github.com/rs/zerolog/pkgerrors" ) func configureLogger() { - logger := logrus.New() // logger is to implicitly substitute stdlib's log - log.SetOutput(logger.Writer()) + zerolog.ErrorStackFieldName = "stack_trace" + zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack + zerolog.TimeFieldFormat = zerolog.TimeFormatUnix - formatter := &logrus.TextFormatter{DisableTimestamp: false, DisableLevelTruncation: true} - - logger.SetFormatter(formatter) - logrus.SetFormatter(formatter) - - logger.SetLevel(logrus.DebugLevel) - logrus.SetLevel(logrus.DebugLevel) + log.Logger = log.Logger.With().Caller().Stack().Logger() +} + +func setLoggingLevel(level string) { + switch level { + case "ERROR": + zerolog.SetGlobalLevel(zerolog.ErrorLevel) + case "WARN": + zerolog.SetGlobalLevel(zerolog.WarnLevel) + case "INFO": + zerolog.SetGlobalLevel(zerolog.InfoLevel) + case "DEBUG": + zerolog.SetGlobalLevel(zerolog.DebugLevel) + } } diff --git a/api/cmd/portainer/main.go b/api/cmd/portainer/main.go index 6f7f8917d..29e9fffa5 100644 --- a/api/cmd/portainer/main.go +++ b/api/cmd/portainer/main.go @@ -4,15 +4,12 @@ import ( "context" "crypto/sha256" "fmt" - "log" "os" "path" "strconv" "strings" "time" - "github.com/sirupsen/logrus" - "github.com/portainer/libhelm" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/apikey" @@ -45,34 +42,38 @@ import ( "github.com/portainer/portainer/api/oauth" "github.com/portainer/portainer/api/scheduler" "github.com/portainer/portainer/api/stacks" + + "github.com/rs/zerolog/log" ) func initCLI() *portainer.CLIFlags { var cliService portainer.CLIService = &cli.Service{} flags, err := cliService.ParseFlags(portainer.APIVersion) if err != nil { - logrus.Fatalf("Failed parsing flags: %v", err) + log.Fatal().Err(err).Msg("failed parsing flags") } err = cliService.ValidateFlags(flags) if err != nil { - logrus.Fatalf("Failed validating flags:%v", err) + log.Fatal().Err(err).Msg("failed validating flags") } + return flags } func initFileService(dataStorePath string) portainer.FileService { fileService, err := filesystem.NewService(dataStorePath, "") if err != nil { - logrus.Fatalf("Failed creating file service: %v", err) + log.Fatal().Err(err).Msg("failed creating file service") } + return fileService } func initDataStore(flags *portainer.CLIFlags, secretKey []byte, fileService portainer.FileService, shutdownCtx context.Context) dataservices.DataStore { connection, err := database.NewDatabase("boltdb", *flags.Data, secretKey) if err != nil { - logrus.Fatalf("failed creating database connection: %s", err) + log.Fatal().Err(err).Msg("failed creating database connection") } if bconn, ok := connection.(*boltdb.DbConnection); ok { @@ -80,30 +81,31 @@ func initDataStore(flags *portainer.CLIFlags, secretKey []byte, fileService port bconn.MaxBatchDelay = *flags.MaxBatchDelay bconn.InitialMmapSize = *flags.InitialMmapSize } else { - logrus.Fatalf("failed creating database connection: expecting a boltdb database type but a different one was received") + log.Fatal().Msg("failed creating database connection: expecting a boltdb database type but a different one was received") } store := datastore.NewStore(*flags.Data, fileService, connection) isNew, err := store.Open() if err != nil { - logrus.Fatalf("Failed opening store: %v", err) + log.Fatal().Err(err).Msg("failed opening store") } if *flags.Rollback { err := store.Rollback(false) if err != nil { - logrus.Fatalf("Failed rolling back: %v", err) + log.Fatal().Err(err).Msg("failed rolling back") } - logrus.Println("Exiting rollback") + log.Info().Msg("exiting rollback") os.Exit(0) + return nil } // Init sets some defaults - it's basically a migration err = store.Init() if err != nil { - logrus.Fatalf("Failed initializing data store: %v", err) + log.Fatal().Err(err).Msg("failed initializing data store") } if isNew { @@ -112,24 +114,25 @@ func initDataStore(flags *portainer.CLIFlags, secretKey []byte, fileService port err := updateSettingsFromFlags(store, flags) if err != nil { - logrus.Fatalf("Failed updating settings from flags: %v", err) + log.Fatal().Err(err).Msg("failed updating settings from flags") } } else { storedVersion, err := store.VersionService.DBVersion() if err != nil { - logrus.Fatalf("Something Failed during creation of new database: %v", err) + log.Fatal().Err(err).Msg("failure during creation of new database") } + if storedVersion != portainer.DBVersion { err = store.MigrateData() if err != nil { - logrus.Fatalf("Failed migration: %v", err) + log.Fatal().Err(err).Msg("failed migration") } } } err = updateSettingsFromFlags(store, flags) if err != nil { - log.Fatalf("Failed updating settings from flags: %v", err) + log.Fatal().Err(err).Msg("failed updating settings from flags") } // this is for the db restore functionality - needs more tests. @@ -141,19 +144,19 @@ func initDataStore(flags *portainer.CLIFlags, secretKey []byte, fileService port err := store.Export(exportFilename) if err != nil { - logrus.WithError(err).Debugf("Failed to export to %s", exportFilename) + log.Error().Str("filename", exportFilename).Err(err).Msg("failed to export") } else { - logrus.Debugf("exported to %s", exportFilename) + log.Debug().Str("filename", exportFilename).Msg("exported") } - connection.Close() }() + return store } func initComposeStackManager(assetsPath string, configPath string, reverseTunnelService portainer.ReverseTunnelService, proxyManager *proxy.Manager) portainer.ComposeStackManager { composeWrapper, err := exec.NewComposeStackManager(assetsPath, configPath, proxyManager) if err != nil { - logrus.Fatalf("Failed creating compose manager: %v", err) + log.Fatal().Err(err).Msg("failed creating compose manager") } return composeWrapper @@ -187,6 +190,7 @@ func initJWTService(userSessionTimeout string, dataStore dataservices.DataStore) if err != nil { return nil, err } + return jwtService, nil } @@ -341,11 +345,7 @@ func enableFeaturesFromFlags(dataStore dataservices.DataStore, flags *portainer. return fmt.Errorf("feature flag's '%s' value should be true or false", feat.Name) } - if featureState { - logrus.Printf("Feature %v : on", *correspondingFeature) - } else { - logrus.Printf("Feature %v : off", *correspondingFeature) - } + log.Info().Str("feature", string(*correspondingFeature)).Bool("state", featureState).Msg("") settings.FeatureFlagSettings[*correspondingFeature] = featureState } @@ -373,7 +373,7 @@ func generateAndStoreKeyPair(fileService portainer.FileService, signatureService func initKeyPair(fileService portainer.FileService, signatureService portainer.DigitalSignatureService) error { existingKeyPair, err := fileService.KeyPairFilesExist() if err != nil { - logrus.Fatalf("Failed checking for existing key pair: %v", err) + log.Fatal().Err(err).Msg("failed checking for existing key pair") } if existingKeyPair { @@ -443,7 +443,11 @@ func createTLSSecuredEndpoint(flags *portainer.CLIFlags, dataStore dataservices. err := snapshotService.SnapshotEndpoint(endpoint) if err != nil { - logrus.Printf("http error: environment snapshot error (environment=%s, URL=%s) (err=%s)\n", endpoint.Name, endpoint.URL, err) + log.Error(). + Str("endpoint", endpoint.Name). + Str("URL", endpoint.URL). + Err(err). + Msg("environment snapshot error") } return dataStore.Endpoint().Create(endpoint) @@ -488,7 +492,10 @@ func createUnsecuredEndpoint(endpointURL string, dataStore dataservices.DataStor err := snapshotService.SnapshotEndpoint(endpoint) if err != nil { - logrus.Printf("http error: environment snapshot error (environment=%s, URL=%s) (err=%s)\n", endpoint.Name, endpoint.URL, err) + log.Error(). + Str("endpoint", endpoint.Name). + Str("URL", endpoint.URL).Err(err). + Msg("environment snapshot error") } return dataStore.Endpoint().Create(endpoint) @@ -505,7 +512,8 @@ func initEndpoint(flags *portainer.CLIFlags, dataStore dataservices.DataStore, s } if len(endpoints) > 0 { - logrus.Println("Instance already has defined environments. Skipping the environment defined via CLI.") + log.Info().Msg("instance already has defined environments, skipping the environment defined via CLI") + return nil } @@ -519,9 +527,9 @@ func loadEncryptionSecretKey(keyfilename string) []byte { content, err := os.ReadFile(path.Join("/run/secrets", keyfilename)) if err != nil { if os.IsNotExist(err) { - logrus.Printf("Encryption key file `%s` not present", keyfilename) + log.Info().Str("filename", keyfilename).Msg("encryption key file not present") } else { - logrus.Printf("Error reading encryption key file: %v", err) + log.Info().Err(err).Msg("error reading encryption key file") } return nil @@ -538,37 +546,41 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server { fileService := initFileService(*flags.Data) encryptionKey := loadEncryptionSecretKey(*flags.SecretKeyName) if encryptionKey == nil { - logrus.Println("Proceeding without encryption key") + log.Info().Msg("proceeding without encryption key") } dataStore := initDataStore(flags, encryptionKey, fileService, shutdownCtx) if err := dataStore.CheckCurrentEdition(); err != nil { - logrus.Fatal(err) + log.Fatal().Err(err).Msg("") } + instanceID, err := dataStore.Version().InstanceID() if err != nil { - logrus.Fatalf("Failed getting instance id: %v", err) + log.Fatal().Err(err).Msg("failed getting instance id") } apiKeyService := initAPIKeyService(dataStore) settings, err := dataStore.Settings().Settings() if err != nil { - logrus.Fatal(err) + log.Fatal().Err(err).Msg("") } + jwtService, err := initJWTService(settings.UserSessionTimeout, dataStore) if err != nil { - logrus.Fatalf("Failed initializing JWT service: %v", err) + log.Fatal().Err(err).Msg("failed initializing JWT service") } err = enableFeaturesFromFlags(dataStore, flags) if err != nil { - logrus.Fatalf("Failed enabling feature flag: %v", err) + log.Fatal().Err(err).Msg("failed enabling feature flag") } ldapService := initLDAPService() + oauthService := initOAuthService() + gitService := initGitService() openAMTService := openamt.NewService() @@ -579,17 +591,17 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server { sslService, err := initSSLService(*flags.AddrHTTPS, *flags.SSLCert, *flags.SSLKey, fileService, dataStore, shutdownTrigger) if err != nil { - logrus.Fatal(err) + log.Fatal().Err(err).Msg("") } sslSettings, err := sslService.GetSSLSettings() if err != nil { - logrus.Fatalf("Failed to get ssl settings: %s", err) + log.Fatal().Err(err).Msg("failed to get SSL settings") } err = initKeyPair(fileService, digitalSignatureService) if err != nil { - logrus.Fatalf("Failed initializing key pair: %v", err) + log.Fatal().Err(err).Msg("failed initializing key pair") } reverseTunnelService := chisel.NewService(dataStore, shutdownCtx) @@ -599,7 +611,7 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server { snapshotService, err := initSnapshotService(*flags.SnapshotInterval, dataStore, dockerClientFactory, kubernetesClientFactory, shutdownCtx) if err != nil { - logrus.Fatalf("Failed initializing snapshot service: %v", err) + log.Fatal().Err(err).Msg("failed initializing snapshot service") } snapshotService.Start() @@ -620,19 +632,19 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server { swarmStackManager, err := initSwarmStackManager(*flags.Assets, dockerConfigPath, digitalSignatureService, fileService, reverseTunnelService, dataStore) if err != nil { - logrus.Fatalf("Failed initializing swarm stack manager: %v", err) + log.Fatal().Err(err).Msg("failed initializing swarm stack manager") } kubernetesDeployer := initKubernetesDeployer(kubernetesTokenCacheManager, kubernetesClientFactory, dataStore, reverseTunnelService, digitalSignatureService, proxyManager, *flags.Assets) helmPackageManager, err := initHelmPackageManager(*flags.Assets) if err != nil { - logrus.Fatalf("Failed initializing helm package manager: %v", err) + log.Fatal().Err(err).Msg("failed initializing helm package manager") } err = edge.LoadEdgeJobs(dataStore, reverseTunnelService) if err != nil { - logrus.Fatalf("Failed loading edge jobs from database: %v", err) + log.Fatal().Err(err).Msg("failed loading edge jobs from database") } applicationStatus := initStatus(instanceID) @@ -641,24 +653,25 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server { if *flags.DemoEnvironment { err := demoService.Init(dataStore, cryptoService) if err != nil { - log.Fatalf("failed initializing demo environment: %v", err) + log.Fatal().Err(err).Msg("failed initializing demo environment") } } err = initEndpoint(flags, dataStore, snapshotService) if err != nil { - logrus.Fatalf("Failed initializing environment: %v", err) + log.Fatal().Err(err).Msg("failed initializing environment") } adminPasswordHash := "" if *flags.AdminPasswordFile != "" { content, err := fileService.GetFileContent(*flags.AdminPasswordFile, "") if err != nil { - logrus.Fatalf("Failed getting admin password file: %v", err) + log.Fatal().Err(err).Msg("failed getting admin password file") } + adminPasswordHash, err = cryptoService.Hash(strings.TrimSuffix(string(content), "\n")) if err != nil { - logrus.Fatalf("Failed hashing admin password: %v", err) + log.Fatal().Err(err).Msg("failed hashing admin password") } } else if *flags.AdminPassword != "" { adminPasswordHash = *flags.AdminPassword @@ -667,33 +680,34 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server { if adminPasswordHash != "" { users, err := dataStore.User().UsersByRole(portainer.AdministratorRole) if err != nil { - logrus.Fatalf("Failed getting admin user: %v", err) + log.Fatal().Err(err).Msg("failed getting admin user") } if len(users) == 0 { - logrus.Println("Created admin user with the given password.") + log.Info().Msg("created admin user with the given password.") user := &portainer.User{ Username: "admin", Role: portainer.AdministratorRole, Password: adminPasswordHash, } + err := dataStore.User().Create(user) if err != nil { - logrus.Fatalf("Failed creating admin user: %v", err) + log.Fatal().Err(err).Msg("failed creating admin user") } } else { - logrus.Println("Instance already has an administrator user defined. Skipping admin password related flags.") + log.Info().Msg("instance already has an administrator user defined, skipping admin password related flags.") } } err = reverseTunnelService.StartTunnelServer(*flags.TunnelAddr, *flags.TunnelPort, snapshotService) if err != nil { - logrus.Fatalf("Failed starting tunnel server: %v", err) + log.Fatal().Err(err).Msg("failed starting tunnel server") } sslDBSettings, err := dataStore.SSLSettings().Settings() if err != nil { - logrus.Fatalf("Failed to fetch ssl settings from DB") + log.Fatal().Msg("failed to fetch SSL settings from DB") } scheduler := scheduler.NewScheduler(shutdownCtx) @@ -738,22 +752,25 @@ func buildServer(flags *portainer.CLIFlags) portainer.Server { } func main() { + configureLogger() + flags := initCLI() - configureLogger() + setLoggingLevel(*flags.LogLevel) for { server := buildServer(flags) - logrus.WithFields(logrus.Fields{ - "Version": portainer.APIVersion, - "BuildNumber": build.BuildNumber, - "ImageTag": build.ImageTag, - "NodejsVersion": build.NodejsVersion, - "YarnVersion": build.YarnVersion, - "WebpackVersion": build.WebpackVersion, - "GoVersion": build.GoVersion}, - ).Print("[INFO] [cmd,main] Starting Portainer") + log.Info(). + Str("version", portainer.APIVersion). + Str("build_number", build.BuildNumber). + Str("image_tag", build.ImageTag). + Str("nodejs_version", build.NodejsVersion). + Str("yarn_version", build.YarnVersion). + Str("webpack_version", build.WebpackVersion). + Str("go_version", build.GoVersion). + Msg("starting Portainer") + err := server.Start() - logrus.Printf("[INFO] [cmd,main] Http server exited: %v\n", err) + log.Info().Err(err).Msg("HTTP server exited") } } diff --git a/api/database/boltdb/db.go b/api/database/boltdb/db.go index 09054b830..a930c97f0 100644 --- a/api/database/boltdb/db.go +++ b/api/database/boltdb/db.go @@ -11,7 +11,8 @@ import ( "time" dserrors "github.com/portainer/portainer/api/dataservices/errors" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" bolt "go.etcd.io/bbolt" ) @@ -120,7 +121,7 @@ func (connection *DbConnection) NeedsEncryptionMigration() (bool, error) { // Open opens and initializes the BoltDB database. func (connection *DbConnection) Open() error { - logrus.Infof("Loading PortainerDB: %s", connection.GetDatabaseFileName()) + log.Info().Str("filename", connection.GetDatabaseFileName()).Msg("loading PortainerDB") // Now we open the db databasePath := connection.GetDatabaseFilePath() @@ -348,6 +349,7 @@ func (connection *DbConnection) CreateObjectWithSetSequence(bucketName string, i func (connection *DbConnection) GetAll(bucketName string, obj interface{}, append func(o interface{}) (interface{}, error)) error { err := connection.View(func(tx *bolt.Tx) error { bucket := tx.Bucket([]byte(bucketName)) + cursor := bucket.Cursor() for k, v := cursor.First(); k != nil; k, v = cursor.Next() { err := connection.UnmarshalObject(v, obj) @@ -362,6 +364,7 @@ func (connection *DbConnection) GetAll(bucketName string, obj interface{}, appen return nil }) + return err } @@ -411,7 +414,7 @@ func (connection *DbConnection) RestoreMetadata(s map[string]interface{}) error for bucketName, v := range s { id, ok := v.(float64) // JSON ints are unmarshalled to interface as float64. See: https://pkg.go.dev/encoding/json#Decoder.Decode if !ok { - logrus.Errorf("Failed to restore metadata to bucket %s, skipped", bucketName) + log.Error().Str("bucket", bucketName).Msg("failed to restore metadata to bucket, skipped") continue } @@ -420,6 +423,7 @@ func (connection *DbConnection) RestoreMetadata(s map[string]interface{}) error if err != nil { return err } + return bucket.SetSequence(uint64(id)) }) } diff --git a/api/database/boltdb/export.go b/api/database/boltdb/export.go index cd2b7487c..4e7ce763e 100644 --- a/api/database/boltdb/export.go +++ b/api/database/boltdb/export.go @@ -4,7 +4,7 @@ import ( "encoding/json" "time" - "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" bolt "go.etcd.io/bbolt" ) @@ -28,11 +28,11 @@ func backupMetadata(connection *bolt.DB) (map[string]interface{}, error) { // ExportJSON creates a JSON representation from a DbConnection. You can include // the database's metadata or ignore it. Ensure the database is closed before -// using this function +// using this function. // inspired by github.com/konoui/boltdb-exporter (which has no license) // but very much simplified, based on how we use boltdb func (c *DbConnection) ExportJson(databasePath string, metadata bool) ([]byte, error) { - logrus.WithField("databasePath", databasePath).Infof("exportJson") + log.Debug().Str("databasePath", databasePath).Msg("exportJson") connection, err := bolt.Open(databasePath, 0600, &bolt.Options{Timeout: 1 * time.Second, ReadOnly: true}) if err != nil { @@ -44,8 +44,9 @@ func (c *DbConnection) ExportJson(databasePath string, metadata bool) ([]byte, e if metadata { meta, err := backupMetadata(connection) if err != nil { - logrus.WithError(err).Errorf("Failed exporting metadata: %v", err) + log.Error().Err(err).Msg("failed exporting metadata") } + backup["__metadata"] = meta } @@ -59,22 +60,31 @@ func (c *DbConnection) ExportJson(databasePath string, metadata bool) ([]byte, e if v == nil { continue } + var obj interface{} err := c.UnmarshalObject(v, &obj) if err != nil { - logrus.WithError(err).Errorf("Failed to unmarshal (bucket %s): %v", bucketName, string(v)) + log.Error(). + Str("bucket", bucketName). + Str("object", string(v)). + Err(err). + Msg("failed to unmarshal") + obj = v } + if bucketName == "version" { version[string(k)] = string(v) } else { list = append(list, obj) } } + if bucketName == "version" { backup[bucketName] = version return nil } + if len(list) > 0 { if bucketName == "ssl" || bucketName == "settings" || @@ -91,8 +101,10 @@ func (c *DbConnection) ExportJson(databasePath string, metadata bool) ([]byte, e return nil }) + return err }) + if err != nil { return []byte("{}"), err } diff --git a/api/dataservices/apikeyrepository/apikeyrepository.go b/api/dataservices/apikeyrepository/apikeyrepository.go index 1207b3deb..561bde620 100644 --- a/api/dataservices/apikeyrepository/apikeyrepository.go +++ b/api/dataservices/apikeyrepository/apikeyrepository.go @@ -6,7 +6,8 @@ import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/dataservices/errors" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -41,12 +42,14 @@ func (service *Service) GetAPIKeysByUserID(userID portainer.UserID) ([]portainer func(obj interface{}) (interface{}, error) { record, ok := obj.(*portainer.APIKey) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to APIKey object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to APIKey object") return nil, fmt.Errorf("Failed to convert to APIKey object: %s", obj) } + if record.UserID == userID { result = append(result, *record) } + return &portainer.APIKey{}, nil }) @@ -64,18 +67,21 @@ func (service *Service) GetAPIKeyByDigest(digest []byte) (*portainer.APIKey, err func(obj interface{}) (interface{}, error) { key, ok := obj.(*portainer.APIKey) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to APIKey object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to APIKey object") return nil, fmt.Errorf("Failed to convert to APIKey object: %s", obj) } if bytes.Equal(key.Digest, digest) { k = key return nil, stop } + return &portainer.APIKey{}, nil }) + if err == stop { return k, nil } + if err == nil { return nil, errors.ErrObjectNotFound } diff --git a/api/dataservices/customtemplate/customtemplate.go b/api/dataservices/customtemplate/customtemplate.go index 2f27f54ea..15b2b9aa3 100644 --- a/api/dataservices/customtemplate/customtemplate.go +++ b/api/dataservices/customtemplate/customtemplate.go @@ -4,7 +4,8 @@ import ( "fmt" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -44,10 +45,11 @@ func (service *Service) CustomTemplates() ([]portainer.CustomTemplate, error) { //var tag portainer.Tag customTemplate, ok := obj.(*portainer.CustomTemplate) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to CustomTemplate object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to CustomTemplate object") return nil, fmt.Errorf("Failed to convert to CustomTemplate object: %s", obj) } customTemplates = append(customTemplates, *customTemplate) + return &portainer.CustomTemplate{}, nil }) diff --git a/api/dataservices/edgegroup/edgegroup.go b/api/dataservices/edgegroup/edgegroup.go index 3370970fe..22272add8 100644 --- a/api/dataservices/edgegroup/edgegroup.go +++ b/api/dataservices/edgegroup/edgegroup.go @@ -4,7 +4,8 @@ import ( "fmt" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -43,10 +44,11 @@ func (service *Service) EdgeGroups() ([]portainer.EdgeGroup, error) { func(obj interface{}) (interface{}, error) { group, ok := obj.(*portainer.EdgeGroup) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to EdgeGroup object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to EdgeGroup object") return nil, fmt.Errorf("Failed to convert to EdgeGroup object: %s", obj) } groups = append(groups, *group) + return &portainer.EdgeGroup{}, nil }) diff --git a/api/dataservices/edgejob/edgejob.go b/api/dataservices/edgejob/edgejob.go index ab048102d..29f883f1c 100644 --- a/api/dataservices/edgejob/edgejob.go +++ b/api/dataservices/edgejob/edgejob.go @@ -4,7 +4,8 @@ import ( "fmt" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -41,13 +42,14 @@ func (service *Service) EdgeJobs() ([]portainer.EdgeJob, error) { BucketName, &portainer.EdgeJob{}, func(obj interface{}) (interface{}, error) { - //var tag portainer.Tag job, ok := obj.(*portainer.EdgeJob) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to EdgeJob object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to EdgeJob object") return nil, fmt.Errorf("Failed to convert to EdgeJob object: %s", obj) } + edgeJobs = append(edgeJobs, *job) + return &portainer.EdgeJob{}, nil }) diff --git a/api/dataservices/edgestack/edgestack.go b/api/dataservices/edgestack/edgestack.go index 78b7a4f4b..7f45d6146 100644 --- a/api/dataservices/edgestack/edgestack.go +++ b/api/dataservices/edgestack/edgestack.go @@ -4,7 +4,8 @@ import ( "fmt" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -44,10 +45,12 @@ func (service *Service) EdgeStacks() ([]portainer.EdgeStack, error) { //var tag portainer.Tag stack, ok := obj.(*portainer.EdgeStack) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to EdgeStack object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to EdgeStack object") return nil, fmt.Errorf("Failed to convert to EdgeStack object: %s", obj) } + stacks = append(stacks, *stack) + return &portainer.EdgeStack{}, nil }) diff --git a/api/dataservices/endpoint/endpoint.go b/api/dataservices/endpoint/endpoint.go index a8f9294b5..9ecc4ee21 100644 --- a/api/dataservices/endpoint/endpoint.go +++ b/api/dataservices/endpoint/endpoint.go @@ -4,7 +4,8 @@ import ( "fmt" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -68,10 +69,12 @@ func (service *Service) Endpoints() ([]portainer.Endpoint, error) { func(obj interface{}) (interface{}, error) { endpoint, ok := obj.(*portainer.Endpoint) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Endpoint object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Endpoint object") return nil, fmt.Errorf("failed to convert to Endpoint object: %s", obj) } + endpoints = append(endpoints, *endpoint) + return &portainer.Endpoint{}, nil }) diff --git a/api/dataservices/endpointgroup/endpointgroup.go b/api/dataservices/endpointgroup/endpointgroup.go index dc9f57ef0..6b4c4692d 100644 --- a/api/dataservices/endpointgroup/endpointgroup.go +++ b/api/dataservices/endpointgroup/endpointgroup.go @@ -4,7 +4,8 @@ import ( "fmt" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -66,13 +67,14 @@ func (service *Service) EndpointGroups() ([]portainer.EndpointGroup, error) { BucketName, &portainer.EndpointGroup{}, func(obj interface{}) (interface{}, error) { - //var tag portainer.Tag endpointGroup, ok := obj.(*portainer.EndpointGroup) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to EndpointGroup object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to EndpointGroup object") return nil, fmt.Errorf("Failed to convert to EndpointGroup object: %s", obj) } + endpointGroups = append(endpointGroups, *endpointGroup) + return &portainer.EndpointGroup{}, nil }) diff --git a/api/dataservices/endpointrelation/endpointrelation.go b/api/dataservices/endpointrelation/endpointrelation.go index 30e63354b..8dd05be63 100644 --- a/api/dataservices/endpointrelation/endpointrelation.go +++ b/api/dataservices/endpointrelation/endpointrelation.go @@ -4,7 +4,8 @@ import ( "fmt" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -33,7 +34,7 @@ func NewService(connection portainer.Connection) (*Service, error) { }, nil } -//EndpointRelations returns an array of all EndpointRelations +// EndpointRelations returns an array of all EndpointRelations func (service *Service) EndpointRelations() ([]portainer.EndpointRelation, error) { var all = make([]portainer.EndpointRelation, 0) @@ -43,10 +44,12 @@ func (service *Service) EndpointRelations() ([]portainer.EndpointRelation, error func(obj interface{}) (interface{}, error) { r, ok := obj.(*portainer.EndpointRelation) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to EndpointRelation object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to EndpointRelation object") return nil, fmt.Errorf("Failed to convert to EndpointRelation object: %s", obj) } + all = append(all, *r) + return &portainer.EndpointRelation{}, nil }) diff --git a/api/dataservices/extension/extension.go b/api/dataservices/extension/extension.go index 9b501c0f7..6cb4004d7 100644 --- a/api/dataservices/extension/extension.go +++ b/api/dataservices/extension/extension.go @@ -4,7 +4,8 @@ import ( "fmt" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -56,10 +57,12 @@ func (service *Service) Extensions() ([]portainer.Extension, error) { func(obj interface{}) (interface{}, error) { extension, ok := obj.(*portainer.Extension) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Extension object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Extension object") return nil, fmt.Errorf("Failed to convert to Extension object: %s", obj) } + extensions = append(extensions, *extension) + return &portainer.Extension{}, nil }) diff --git a/api/dataservices/fdoprofile/fdoprofile.go b/api/dataservices/fdoprofile/fdoprofile.go index 4cb25e929..918546540 100644 --- a/api/dataservices/fdoprofile/fdoprofile.go +++ b/api/dataservices/fdoprofile/fdoprofile.go @@ -4,7 +4,8 @@ import ( "fmt" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -43,8 +44,9 @@ func (service *Service) FDOProfiles() ([]portainer.FDOProfile, error) { func(obj interface{}) (interface{}, error) { fdoProfile, ok := obj.(*portainer.FDOProfile) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to FDOProfile object") - return nil, fmt.Errorf("failed to convert to FDOProfile object: %s", obj) + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to FDOProfile object") + + return nil, fmt.Errorf("Failed to convert to FDOProfile object: %s", obj) } fdoProfiles = append(fdoProfiles, *fdoProfile) return &portainer.FDOProfile{}, nil diff --git a/api/dataservices/helmuserrepository/helmuserrepository.go b/api/dataservices/helmuserrepository/helmuserrepository.go index 0ae3a3564..375b86151 100644 --- a/api/dataservices/helmuserrepository/helmuserrepository.go +++ b/api/dataservices/helmuserrepository/helmuserrepository.go @@ -4,7 +4,8 @@ import ( "fmt" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -33,7 +34,7 @@ func NewService(connection portainer.Connection) (*Service, error) { }, nil } -//HelmUserRepository returns an array of all HelmUserRepository +// HelmUserRepository returns an array of all HelmUserRepository func (service *Service) HelmUserRepositories() ([]portainer.HelmUserRepository, error) { var repos = make([]portainer.HelmUserRepository, 0) @@ -43,10 +44,12 @@ func (service *Service) HelmUserRepositories() ([]portainer.HelmUserRepository, func(obj interface{}) (interface{}, error) { r, ok := obj.(*portainer.HelmUserRepository) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to HelmUserRepository object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to HelmUserRepository object") return nil, fmt.Errorf("Failed to convert to HelmUserRepository object: %s", obj) } + repos = append(repos, *r) + return &portainer.HelmUserRepository{}, nil }) @@ -63,12 +66,14 @@ func (service *Service) HelmUserRepositoryByUserID(userID portainer.UserID) ([]p func(obj interface{}) (interface{}, error) { record, ok := obj.(*portainer.HelmUserRepository) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to HelmUserRepository object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to HelmUserRepository object") return nil, fmt.Errorf("Failed to convert to HelmUserRepository object: %s", obj) } + if record.UserID == userID { result = append(result, *record) } + return &portainer.HelmUserRepository{}, nil }) diff --git a/api/dataservices/registry/registry.go b/api/dataservices/registry/registry.go index 0fc5e3340..1d1da685c 100644 --- a/api/dataservices/registry/registry.go +++ b/api/dataservices/registry/registry.go @@ -4,7 +4,8 @@ import ( "fmt" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -56,10 +57,12 @@ func (service *Service) Registries() ([]portainer.Registry, error) { func(obj interface{}) (interface{}, error) { registry, ok := obj.(*portainer.Registry) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Registry object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Registry object") return nil, fmt.Errorf("Failed to convert to Registry object: %s", obj) } + registries = append(registries, *registry) + return &portainer.Registry{}, nil }) diff --git a/api/dataservices/resourcecontrol/resourcecontrol.go b/api/dataservices/resourcecontrol/resourcecontrol.go index 3d0486d0f..77deba188 100644 --- a/api/dataservices/resourcecontrol/resourcecontrol.go +++ b/api/dataservices/resourcecontrol/resourcecontrol.go @@ -4,7 +4,8 @@ import ( "fmt" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -58,7 +59,7 @@ func (service *Service) ResourceControlByResourceIDAndType(resourceID string, re func(obj interface{}) (interface{}, error) { rc, ok := obj.(*portainer.ResourceControl) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to ResourceControl object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to ResourceControl object") return nil, fmt.Errorf("Failed to convert to ResourceControl object: %s", obj) } @@ -73,6 +74,7 @@ func (service *Service) ResourceControlByResourceIDAndType(resourceID string, re return nil, stop } } + return &portainer.ResourceControl{}, nil }) if err == stop { @@ -92,10 +94,12 @@ func (service *Service) ResourceControls() ([]portainer.ResourceControl, error) func(obj interface{}) (interface{}, error) { rc, ok := obj.(*portainer.ResourceControl) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to ResourceControl object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to ResourceControl object") return nil, fmt.Errorf("Failed to convert to ResourceControl object: %s", obj) } + rcs = append(rcs, *rc) + return &portainer.ResourceControl{}, nil }) diff --git a/api/dataservices/role/role.go b/api/dataservices/role/role.go index 907004dae..f7754903e 100644 --- a/api/dataservices/role/role.go +++ b/api/dataservices/role/role.go @@ -4,7 +4,8 @@ import ( "fmt" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -56,10 +57,12 @@ func (service *Service) Roles() ([]portainer.Role, error) { func(obj interface{}) (interface{}, error) { set, ok := obj.(*portainer.Role) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Role object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Role object") return nil, fmt.Errorf("Failed to convert to Role object: %s", obj) } + sets = append(sets, *set) + return &portainer.Role{}, nil }) diff --git a/api/dataservices/schedule/schedule.go b/api/dataservices/schedule/schedule.go index d6aac2713..d1cdb800e 100644 --- a/api/dataservices/schedule/schedule.go +++ b/api/dataservices/schedule/schedule.go @@ -4,7 +4,8 @@ import ( "fmt" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -68,10 +69,12 @@ func (service *Service) Schedules() ([]portainer.Schedule, error) { func(obj interface{}) (interface{}, error) { schedule, ok := obj.(*portainer.Schedule) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Schedule object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Schedule object") return nil, fmt.Errorf("Failed to convert to Schedule object: %s", obj) } + schedules = append(schedules, *schedule) + return &portainer.Schedule{}, nil }) @@ -89,12 +92,14 @@ func (service *Service) SchedulesByJobType(jobType portainer.JobType) ([]portain func(obj interface{}) (interface{}, error) { schedule, ok := obj.(*portainer.Schedule) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Schedule object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Schedule object") return nil, fmt.Errorf("Failed to convert to Schedule object: %s", obj) } + if schedule.JobType == jobType { schedules = append(schedules, *schedule) } + return &portainer.Schedule{}, nil }) diff --git a/api/dataservices/stack/stack.go b/api/dataservices/stack/stack.go index 7abd102a0..92ea0dd5e 100644 --- a/api/dataservices/stack/stack.go +++ b/api/dataservices/stack/stack.go @@ -4,10 +4,10 @@ import ( "fmt" "strings" - "github.com/sirupsen/logrus" - portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/dataservices/errors" + + "github.com/rs/zerolog/log" ) const ( @@ -60,13 +60,15 @@ func (service *Service) StackByName(name string) (*portainer.Stack, error) { func(obj interface{}) (interface{}, error) { stack, ok := obj.(*portainer.Stack) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Stack object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Stack object") return nil, fmt.Errorf("Failed to convert to Stack object: %s", obj) } + if stack.Name == name { s = stack return nil, stop } + return &portainer.Stack{}, nil }) if err == stop { @@ -89,12 +91,14 @@ func (service *Service) StacksByName(name string) ([]portainer.Stack, error) { func(obj interface{}) (interface{}, error) { stack, ok := obj.(portainer.Stack) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Stack object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Stack object") return nil, fmt.Errorf("Failed to convert to Stack object: %s", obj) } + if stack.Name == name { stacks = append(stacks, stack) } + return &portainer.Stack{}, nil }) @@ -111,10 +115,12 @@ func (service *Service) Stacks() ([]portainer.Stack, error) { func(obj interface{}) (interface{}, error) { stack, ok := obj.(*portainer.Stack) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Stack object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Stack object") return nil, fmt.Errorf("Failed to convert to Stack object: %s", obj) } + stacks = append(stacks, *stack) + return &portainer.Stack{}, nil }) @@ -156,13 +162,15 @@ func (service *Service) StackByWebhookID(id string) (*portainer.Stack, error) { s, ok = obj.(*portainer.Stack) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Stack object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Stack object") + return &portainer.Stack{}, nil } if s.AutoUpdate != nil && strings.EqualFold(s.AutoUpdate.Webhook, id) { return nil, stop } + return &portainer.Stack{}, nil }) if err == stop { @@ -186,12 +194,14 @@ func (service *Service) RefreshableStacks() ([]portainer.Stack, error) { func(obj interface{}) (interface{}, error) { stack, ok := obj.(*portainer.Stack) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Stack object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Stack object") return nil, fmt.Errorf("Failed to convert to Stack object: %s", obj) } + if stack.AutoUpdate != nil && stack.AutoUpdate.Interval != "" { stacks = append(stacks, *stack) } + return &portainer.Stack{}, nil }) diff --git a/api/dataservices/tag/tag.go b/api/dataservices/tag/tag.go index b62c2eb76..42c289598 100644 --- a/api/dataservices/tag/tag.go +++ b/api/dataservices/tag/tag.go @@ -4,7 +4,8 @@ import ( "fmt" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -43,10 +44,12 @@ func (service *Service) Tags() ([]portainer.Tag, error) { func(obj interface{}) (interface{}, error) { tag, ok := obj.(*portainer.Tag) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Tag object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Tag object") return nil, fmt.Errorf("Failed to convert to Tag object: %s", obj) } + tags = append(tags, *tag) + return &portainer.Tag{}, nil }) diff --git a/api/dataservices/team/team.go b/api/dataservices/team/team.go index 14aa1c131..05b20dd8d 100644 --- a/api/dataservices/team/team.go +++ b/api/dataservices/team/team.go @@ -4,10 +4,10 @@ import ( "fmt" "strings" - "github.com/portainer/portainer/api/dataservices/errors" - "github.com/sirupsen/logrus" - portainer "github.com/portainer/portainer/api" + "github.com/portainer/portainer/api/dataservices/errors" + + "github.com/rs/zerolog/log" ) const ( @@ -60,13 +60,15 @@ func (service *Service) TeamByName(name string) (*portainer.Team, error) { func(obj interface{}) (interface{}, error) { team, ok := obj.(*portainer.Team) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Team object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Team object") return nil, fmt.Errorf("Failed to convert to Team object: %s", obj) } + if strings.EqualFold(team.Name, name) { t = team return nil, stop } + return &portainer.Team{}, nil }) if err == stop { @@ -89,10 +91,12 @@ func (service *Service) Teams() ([]portainer.Team, error) { func(obj interface{}) (interface{}, error) { team, ok := obj.(*portainer.Team) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Team object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Team object") return nil, fmt.Errorf("Failed to convert to Team object: %s", obj) } + teams = append(teams, *team) + return &portainer.Team{}, nil }) diff --git a/api/dataservices/teammembership/teammembership.go b/api/dataservices/teammembership/teammembership.go index d80d95a37..6d8d82208 100644 --- a/api/dataservices/teammembership/teammembership.go +++ b/api/dataservices/teammembership/teammembership.go @@ -4,7 +4,8 @@ import ( "fmt" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -56,10 +57,12 @@ func (service *Service) TeamMemberships() ([]portainer.TeamMembership, error) { func(obj interface{}) (interface{}, error) { membership, ok := obj.(*portainer.TeamMembership) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to TeamMembership object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to TeamMembership object") return nil, fmt.Errorf("Failed to convert to TeamMembership object: %s", obj) } + memberships = append(memberships, *membership) + return &portainer.TeamMembership{}, nil }) @@ -76,12 +79,14 @@ func (service *Service) TeamMembershipsByUserID(userID portainer.UserID) ([]port func(obj interface{}) (interface{}, error) { membership, ok := obj.(*portainer.TeamMembership) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to TeamMembership object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to TeamMembership object") return nil, fmt.Errorf("Failed to convert to TeamMembership object: %s", obj) } + if membership.UserID == userID { memberships = append(memberships, *membership) } + return &portainer.TeamMembership{}, nil }) @@ -98,12 +103,14 @@ func (service *Service) TeamMembershipsByTeamID(teamID portainer.TeamID) ([]port func(obj interface{}) (interface{}, error) { membership, ok := obj.(*portainer.TeamMembership) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to TeamMembership object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to TeamMembership object") return nil, fmt.Errorf("Failed to convert to TeamMembership object: %s", obj) } + if membership.TeamID == teamID { memberships = append(memberships, *membership) } + return &portainer.TeamMembership{}, nil }) @@ -140,13 +147,15 @@ func (service *Service) DeleteTeamMembershipByUserID(userID portainer.UserID) er func(obj interface{}) (id int, ok bool) { membership, ok := obj.(portainer.TeamMembership) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to TeamMembership object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to TeamMembership object") //return fmt.Errorf("Failed to convert to TeamMembership object: %s", obj) return -1, false } + if membership.UserID == userID { return int(membership.ID), true } + return -1, false }) } @@ -158,13 +167,15 @@ func (service *Service) DeleteTeamMembershipByTeamID(teamID portainer.TeamID) er func(obj interface{}) (id int, ok bool) { membership, ok := obj.(portainer.TeamMembership) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to TeamMembership object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to TeamMembership object") //return fmt.Errorf("Failed to convert to TeamMembership object: %s", obj) return -1, false } + if membership.TeamID == teamID { return int(membership.ID), true } + return -1, false }) } diff --git a/api/dataservices/user/user.go b/api/dataservices/user/user.go index e508da851..8a7f7c051 100644 --- a/api/dataservices/user/user.go +++ b/api/dataservices/user/user.go @@ -4,10 +4,10 @@ import ( "fmt" "strings" - "github.com/portainer/portainer/api/dataservices/errors" - "github.com/sirupsen/logrus" - portainer "github.com/portainer/portainer/api" + "github.com/portainer/portainer/api/dataservices/errors" + + "github.com/rs/zerolog/log" ) const ( @@ -59,18 +59,23 @@ func (service *Service) UserByUsername(username string) (*portainer.User, error) func(obj interface{}) (interface{}, error) { user, ok := obj.(*portainer.User) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to User object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to User object") + return nil, fmt.Errorf("Failed to convert to User object: %s", obj) } + if strings.EqualFold(user.Username, username) { u = user return nil, stop } + return &portainer.User{}, nil }) + if err == stop { return u, nil } + if err == nil { return nil, errors.ErrObjectNotFound } @@ -88,10 +93,13 @@ func (service *Service) Users() ([]portainer.User, error) { func(obj interface{}) (interface{}, error) { user, ok := obj.(*portainer.User) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to User object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to User object") + return nil, fmt.Errorf("Failed to convert to User object: %s", obj) } + users = append(users, *user) + return &portainer.User{}, nil }) @@ -108,12 +116,15 @@ func (service *Service) UsersByRole(role portainer.UserRole) ([]portainer.User, func(obj interface{}) (interface{}, error) { user, ok := obj.(*portainer.User) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to User object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to User object") + return nil, fmt.Errorf("Failed to convert to User object: %s", obj) } + if user.Role == role { users = append(users, *user) } + return &portainer.User{}, nil }) diff --git a/api/dataservices/webhook/webhook.go b/api/dataservices/webhook/webhook.go index ae16ec014..1c47c477c 100644 --- a/api/dataservices/webhook/webhook.go +++ b/api/dataservices/webhook/webhook.go @@ -5,7 +5,8 @@ import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/dataservices/errors" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) const ( @@ -34,7 +35,7 @@ func NewService(connection portainer.Connection) (*Service, error) { }, nil } -//Webhooks returns an array of all webhooks +// Webhooks returns an array of all webhooks func (service *Service) Webhooks() ([]portainer.Webhook, error) { var webhooks = make([]portainer.Webhook, 0) @@ -44,10 +45,12 @@ func (service *Service) Webhooks() ([]portainer.Webhook, error) { func(obj interface{}) (interface{}, error) { webhook, ok := obj.(*portainer.Webhook) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Webhook object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Webhook object") return nil, fmt.Errorf("Failed to convert to Webhook object: %s", obj) } + webhooks = append(webhooks, *webhook) + return &portainer.Webhook{}, nil }) @@ -77,18 +80,23 @@ func (service *Service) WebhookByResourceID(ID string) (*portainer.Webhook, erro func(obj interface{}) (interface{}, error) { webhook, ok := obj.(*portainer.Webhook) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Webhook object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Webhook object") + return nil, fmt.Errorf("Failed to convert to Webhook object: %s", obj) } + if webhook.ResourceID == ID { w = webhook return nil, stop } + return &portainer.Webhook{}, nil }) + if err == stop { return w, nil } + if err == nil { return nil, errors.ErrObjectNotFound } @@ -106,18 +114,23 @@ func (service *Service) WebhookByToken(token string) (*portainer.Webhook, error) func(obj interface{}) (interface{}, error) { webhook, ok := obj.(*portainer.Webhook) if !ok { - logrus.WithField("obj", obj).Errorf("Failed to convert to Webhook object") + log.Debug().Str("obj", fmt.Sprintf("%#v", obj)).Msg("failed to convert to Webhook object") + return nil, fmt.Errorf("Failed to convert to Webhook object: %s", obj) } + if webhook.Token == token { w = webhook return nil, stop } + return &portainer.Webhook{}, nil }) + if err == stop { return w, nil } + if err == nil { return nil, errors.ErrObjectNotFound } diff --git a/api/datastore/backup.go b/api/datastore/backup.go index d0d54e3b8..115087678 100644 --- a/api/datastore/backup.go +++ b/api/datastore/backup.go @@ -6,7 +6,7 @@ import ( "path" "time" - plog "github.com/portainer/portainer/api/datastore/log" + "github.com/rs/zerolog/log" ) var backupDefaults = struct { @@ -17,8 +17,6 @@ var backupDefaults = struct { "common", } -var backupLog = plog.NewScopedLog("database, backup") - // // Backup Helpers // @@ -29,7 +27,7 @@ func (store *Store) createBackupFolders() { commonDir := store.commonBackupDir() if exists, _ := store.fileService.FileExists(commonDir); !exists { if err := os.MkdirAll(commonDir, 0700); err != nil { - backupLog.Error("Error while creating common backup folder", err) + log.Error().Err(err).Msg("error while creating common backup folder") } } } @@ -43,11 +41,13 @@ func (store *Store) commonBackupDir() string { } func (store *Store) copyDBFile(from string, to string) error { - backupLog.Info(fmt.Sprintf("Copying db file from %s to %s", from, to)) + log.Info().Str("from", from).Str("to", to).Msg("copying DB file") + err := store.fileService.Copy(from, to, true) if err != nil { - backupLog.Error("Failed", err) + log.Error().Err(err).Msg("failed") } + return err } @@ -99,7 +99,8 @@ func (store *Store) setupOptions(options *BackupOptions) *BackupOptions { // BackupWithOptions backup current database with options func (store *Store) backupWithOptions(options *BackupOptions) (string, error) { - backupLog.Info("creating db backup") + log.Info().Msg("creating DB backup") + store.createBackupFolders() options = store.setupOptions(options) @@ -122,6 +123,7 @@ func (store *Store) backupWithOptions(options *BackupOptions) (string, error) { err, ) } + return options.BackupPath, nil } @@ -135,17 +137,19 @@ func (store *Store) restoreWithOptions(options *BackupOptions) error { // Check if backup file exist before restoring _, err := os.Stat(options.BackupPath) if os.IsNotExist(err) { - backupLog.Error(fmt.Sprintf("Backup file to restore does not exist %s", options.BackupPath), err) + log.Error().Str("path", options.BackupPath).Err(err).Msg("backup file to restore does not exist %s") + return err } err = store.Close() if err != nil { - backupLog.Error("Error while closing store before restore", err) + log.Error().Err(err).Msg("error while closing store before restore") + return err } - backupLog.Info("Restoring db backup") + log.Info().Msg("restoring DB backup") err = store.copyDBFile(options.BackupPath, store.databasePath()) if err != nil { return err @@ -157,20 +161,22 @@ func (store *Store) restoreWithOptions(options *BackupOptions) error { // RemoveWithOptions removes backup database based on supplied options func (store *Store) removeWithOptions(options *BackupOptions) error { - backupLog.Info("Removing db backup") + log.Info().Msg("removing DB backup") options = store.setupOptions(options) _, err := os.Stat(options.BackupPath) if os.IsNotExist(err) { - backupLog.Error(fmt.Sprintf("Backup file to remove does not exist %s", options.BackupPath), err) + log.Error().Str("path", options.BackupPath).Err(err).Msg("backup file to remove does not exist") + return err } - backupLog.Info(fmt.Sprintf("Removing db file at %s", options.BackupPath)) + log.Info().Str("path", options.BackupPath).Msg("removing DB file") err = os.Remove(options.BackupPath) if err != nil { - backupLog.Error("Failed", err) + log.Error().Err(err).Msg("failed") + return err } diff --git a/api/datastore/datastore.go b/api/datastore/datastore.go index b0530937c..fe952e343 100644 --- a/api/datastore/datastore.go +++ b/api/datastore/datastore.go @@ -9,7 +9,8 @@ import ( portainer "github.com/portainer/portainer/api" portainerErrors "github.com/portainer/portainer/api/dataservices/errors" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) func (store *Store) version() (int, error) { @@ -73,7 +74,8 @@ func (store *Store) Open() (newStore bool, err error) { } if version > 0 { - logrus.WithField("version", version).Infof("Opened existing store") + log.Debug().Int("version", version).Msg("opened existing store") + return false, nil } @@ -121,19 +123,21 @@ func (store *Store) encryptDB() error { // The DB is not currently encrypted. First save the encrypted db filename oldFilename := store.connection.GetDatabaseFilePath() - logrus.Infof("Encrypting database") + log.Info().Msg("encrypting database") // export file path for backup exportFilename := path.Join(store.databasePath() + "." + fmt.Sprintf("backup-%d.json", time.Now().Unix())) - logrus.Infof("Exporting database backup to %s", exportFilename) + log.Info().Str("filename", exportFilename).Msg("exporting database backup") + err = store.Export(exportFilename) if err != nil { - logrus.WithError(err).Debugf("Failed to export to %s", exportFilename) + log.Error().Str("filename", exportFilename).Err(err).Msg("failed to export") + return err } - logrus.Infof("Database backup exported") + log.Info().Msg("database backup exported") // Close existing un-encrypted db so that we can delete the file later store.connection.Close() @@ -152,22 +156,23 @@ func (store *Store) encryptDB() error { if err != nil { // Remove the new encrypted file that we failed to import os.Remove(store.connection.GetDatabaseFilePath()) - logrus.Fatal(portainerErrors.ErrDBImportFailed.Error()) + log.Fatal().Err(portainerErrors.ErrDBImportFailed).Msg("") } err = os.Remove(oldFilename) if err != nil { - logrus.Errorf("Failed to remove the un-encrypted db file") + log.Error().Msg("failed to remove the un-encrypted db file") } err = os.Remove(exportFilename) if err != nil { - logrus.Errorf("Failed to remove the json backup file") + log.Error().Msg("failed to remove the json backup file") } // Close db connection store.connection.Close() - logrus.Info("Database successfully encrypted") + log.Info().Msg("database successfully encrypted") + return nil } diff --git a/api/datastore/log/log.go b/api/datastore/log/log.go deleted file mode 100644 index 5deb9a12f..000000000 --- a/api/datastore/log/log.go +++ /dev/null @@ -1,51 +0,0 @@ -package log - -import ( - "fmt" - "log" -) - -const ( - INFO = "INFO" - ERROR = "ERROR" - DEBUG = "DEBUG" - FATAL = "FATAL" -) - -type ScopedLog struct { - scope string -} - -func NewScopedLog(scope string) *ScopedLog { - return &ScopedLog{scope: scope} -} - -func (slog *ScopedLog) print(kind string, message string) { - log.Printf("[%s] [%s] %s", kind, slog.scope, message) -} - -func (slog *ScopedLog) Debug(message string) { - slog.print(DEBUG, fmt.Sprintf("[message: %s]", message)) -} - -func (slog *ScopedLog) Debugf(message string, vars ...interface{}) { - message = fmt.Sprintf(message, vars...) - slog.print(DEBUG, fmt.Sprintf("[message: %s]", message)) -} - -func (slog *ScopedLog) Info(message string) { - slog.print(INFO, fmt.Sprintf("[message: %s]", message)) -} - -func (slog *ScopedLog) Infof(message string, vars ...interface{}) { - message = fmt.Sprintf(message, vars...) - slog.print(INFO, fmt.Sprintf("[message: %s]", message)) -} - -func (slog *ScopedLog) Error(message string, err error) { - slog.print(ERROR, fmt.Sprintf("[message: %s] [error: %s]", message, err)) -} - -func (slog *ScopedLog) NotImplemented(method string) { - log.Fatalf("[%s] [%s] [%s]", FATAL, slog.scope, fmt.Sprintf("%s is not yet implemented", method)) -} diff --git a/api/datastore/migrate_data.go b/api/datastore/migrate_data.go index 9d9bd97a1..3292b8273 100644 --- a/api/datastore/migrate_data.go +++ b/api/datastore/migrate_data.go @@ -4,21 +4,18 @@ import ( "fmt" "runtime/debug" + portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/cli" "github.com/portainer/portainer/api/dataservices/errors" - plog "github.com/portainer/portainer/api/datastore/log" "github.com/portainer/portainer/api/datastore/migrator" "github.com/portainer/portainer/api/internal/authorization" - "github.com/sirupsen/logrus" werrors "github.com/pkg/errors" - portainer "github.com/portainer/portainer/api" + "github.com/rs/zerolog/log" ) const beforePortainerVersionUpgradeBackup = "portainer.db.bak" -var migrateLog = plog.NewScopedLog("database, migrate") - func (store *Store) MigrateData() error { version, err := store.version() if err != nil { @@ -56,20 +53,19 @@ func (store *Store) MigrateData() error { // restore on error err = store.connectionMigrateData(migratorParams) if err != nil { - logrus.Errorf("While DB migration %v. Restoring DB", err) + log.Error().Err(err).Msg("while DB migration, restoring DB") + // Restore options options := BackupOptions{ BackupPath: backupPath, } + err := store.restoreWithOptions(&options) if err != nil { - logrus.Fatalf( - "Failed restoring the backup. portainer database file needs to restored manually by "+ - "replacing %s database file with recent backup %s. Error %v", - store.databasePath(), - options.BackupPath, - err, - ) + log.Fatal(). + Str("database_file", store.databasePath()). + Str("backup", options.BackupPath).Err(err). + Msg("failed restoring the backup, Portainer database file needs to restored manually by replacing the database file with a recent backup") } } @@ -111,10 +107,15 @@ func (store *Store) connectionMigrateData(migratorParams *migrator.MigratorParam } if migrator.Version() < portainer.DBVersion { - migrateLog.Info(fmt.Sprintf("Migrating database from version %v to %v.\n", migrator.Version(), portainer.DBVersion)) + log.Info(). + Int("migrator_version", migrator.Version()). + Int("db_version", portainer.DBVersion). + Msg("migrating database") + err = store.FailSafeMigrate(migrator) if err != nil { - migrateLog.Error("An error occurred during database migration", err) + log.Error().Err(err).Msg("an error occurred during database migration") + return err } } @@ -124,17 +125,19 @@ func (store *Store) connectionMigrateData(migratorParams *migrator.MigratorParam // backupVersion will backup the database or panic if any errors occur func (store *Store) backupVersion(migrator *migrator.Migrator) error { - migrateLog.Info("Backing up database prior to version upgrade...") + log.Info().Msg("backing up database prior to version upgrade") options := getBackupRestoreOptions(store.commonBackupDir()) _, err := store.backupWithOptions(options) if err != nil { - migrateLog.Error("An error occurred during database backup", err) + log.Error().Err(err).Msg("an error occurred during database backup") + removalErr := store.removeWithOptions(options) if removalErr != nil { - migrateLog.Error("An error occurred during store removal prior to backup", err) + log.Error().Err(err).Msg("an error occurred during store removal prior to backup") } + return err } diff --git a/api/datastore/migrate_data_test.go b/api/datastore/migrate_data_test.go index fd3122d3a..9a8e7acfe 100644 --- a/api/datastore/migrate_data_test.go +++ b/api/datastore/migrate_data_test.go @@ -5,15 +5,16 @@ import ( "encoding/json" "fmt" "io" - "log" "os" "path/filepath" "strings" "testing" - "github.com/google/go-cmp/cmp" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/database/boltdb" + + "github.com/google/go-cmp/cmp" + "github.com/rs/zerolog/log" ) // testVersion is a helper which tests current store version against wanted version @@ -157,7 +158,6 @@ func TestMigrateData(t *testing.T) { t.Errorf("Backup file should not exist for dirty database; file=%s", options.BackupPath) } }) - } func Test_getBackupRestoreOptions(t *testing.T) { @@ -168,12 +168,12 @@ func Test_getBackupRestoreOptions(t *testing.T) { wantDir := store.commonBackupDir() if !strings.HasSuffix(options.BackupDir, wantDir) { - log.Fatalf("incorrect backup dir; got=%s, want=%s", options.BackupDir, wantDir) + log.Fatal().Str("got", options.BackupDir).Str("want", wantDir).Msg("incorrect backup dir") } wantFilename := "portainer.db.bak" if options.BackupFileName != wantFilename { - log.Fatalf("incorrect backup file; got=%s, want=%s", options.BackupFileName, wantFilename) + log.Fatal().Str("got", options.BackupFileName).Str("want", wantFilename).Msg("incorrect backup file") } } @@ -186,19 +186,20 @@ func TestRollback(t *testing.T) { _, err := store.backupWithOptions(getBackupRestoreOptions(store.commonBackupDir())) if err != nil { - log.Fatal(err) + log.Fatal().Err(err).Msg("") } // Change the current edition err = store.VersionService.StoreDBVersion(version + 10) if err != nil { - log.Fatal(err) + log.Fatal().Err(err).Msg("") } err = store.Rollback(true) if err != nil { t.Logf("Rollback failed: %s", err) t.Fail() + return } diff --git a/api/datastore/migrator/migrate_ce.go b/api/datastore/migrator/migrate_ce.go index 0114b1e34..07e4d67f7 100644 --- a/api/datastore/migrator/migrate_ce.go +++ b/api/datastore/migrator/migrate_ce.go @@ -5,8 +5,10 @@ import ( "reflect" "runtime" - werrors "github.com/pkg/errors" portainer "github.com/portainer/portainer/api" + + werrors "github.com/pkg/errors" + "github.com/rs/zerolog/log" ) type migration struct { @@ -114,7 +116,7 @@ func (m *Migrator) Migrate() error { // Print the next line only when the version changes if migration.dbversion > lastDbVersion { - migrateLog.Infof("Migrating DB to version %d", migration.dbversion) + log.Info().Int("to_version", migration.dbversion).Msg("migrating DB") } err := migration.migrate() @@ -125,12 +127,14 @@ func (m *Migrator) Migrate() error { lastDbVersion = migration.dbversion } - migrateLog.Infof("Setting DB version to %d", portainer.DBVersion) + log.Info().Int("version", portainer.DBVersion).Msg("setting DB version") + err = m.versionService.StoreDBVersion(portainer.DBVersion) if err != nil { return migrationError(err, "StoreDBVersion") } - migrateLog.Infof("Updated DB version to %d", portainer.DBVersion) + + log.Info().Int("version", portainer.DBVersion).Msg("updated DB version") // reset DB updating status return m.versionService.StoreIsUpdating(false) diff --git a/api/datastore/migrator/migrate_dbversion17.go b/api/datastore/migrator/migrate_dbversion17.go index ee1b563cf..0805ccf4d 100644 --- a/api/datastore/migrator/migrate_dbversion17.go +++ b/api/datastore/migrator/migrate_dbversion17.go @@ -2,10 +2,13 @@ package migrator import ( portainer "github.com/portainer/portainer/api" + + "github.com/rs/zerolog/log" ) func (m *Migrator) updateUsersToDBVersion18() error { - migrateLog.Info("- updating users") + log.Info().Msg("updating users") + legacyUsers, err := m.userService.Users() if err != nil { return err @@ -40,7 +43,8 @@ func (m *Migrator) updateUsersToDBVersion18() error { } func (m *Migrator) updateEndpointsToDBVersion18() error { - migrateLog.Info("- updating endpoints") + log.Info().Msg("updating endpoints") + legacyEndpoints, err := m.endpointService.Endpoints() if err != nil { return err @@ -71,7 +75,8 @@ func (m *Migrator) updateEndpointsToDBVersion18() error { } func (m *Migrator) updateEndpointGroupsToDBVersion18() error { - migrateLog.Info("- updating endpoint groups") + log.Info().Msg("updating endpoint groups") + legacyEndpointGroups, err := m.endpointGroupService.EndpointGroups() if err != nil { return err @@ -102,7 +107,8 @@ func (m *Migrator) updateEndpointGroupsToDBVersion18() error { } func (m *Migrator) updateRegistriesToDBVersion18() error { - migrateLog.Info("- updating registries") + log.Info().Msg("updating registries") + legacyRegistries, err := m.registryService.Registries() if err != nil { return err diff --git a/api/datastore/migrator/migrate_dbversion18.go b/api/datastore/migrator/migrate_dbversion18.go index a3f450289..927069444 100644 --- a/api/datastore/migrator/migrate_dbversion18.go +++ b/api/datastore/migrator/migrate_dbversion18.go @@ -1,9 +1,14 @@ package migrator -import portainer "github.com/portainer/portainer/api" +import ( + portainer "github.com/portainer/portainer/api" + + "github.com/rs/zerolog/log" +) func (m *Migrator) updateSettingsToDBVersion19() error { - migrateLog.Info("- updating settings") + log.Info().Msg("updating settings") + legacySettings, err := m.settingsService.Settings() if err != nil { return err diff --git a/api/datastore/migrator/migrate_dbversion19.go b/api/datastore/migrator/migrate_dbversion19.go index 9782ab336..a69abe65f 100644 --- a/api/datastore/migrator/migrate_dbversion19.go +++ b/api/datastore/migrator/migrate_dbversion19.go @@ -2,12 +2,15 @@ package migrator import ( "strings" + + "github.com/rs/zerolog/log" ) const scheduleScriptExecutionJobType = 1 func (m *Migrator) updateUsersToDBVersion20() error { - migrateLog.Info("- updating user authentication") + log.Info().Msg("updating user authentication") + return m.authorizationService.UpdateUsersAuthorizations() } @@ -23,7 +26,8 @@ func (m *Migrator) updateSettingsToDBVersion20() error { } func (m *Migrator) updateSchedulesToDBVersion20() error { - migrateLog.Info("- updating schedules") + log.Info().Msg("updating schedules") + legacySchedules, err := m.scheduleService.Schedules() if err != nil { return err diff --git a/api/datastore/migrator/migrate_dbversion20.go b/api/datastore/migrator/migrate_dbversion20.go index 54daf6ced..44d237964 100644 --- a/api/datastore/migrator/migrate_dbversion20.go +++ b/api/datastore/migrator/migrate_dbversion20.go @@ -3,10 +3,13 @@ package migrator import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/internal/authorization" + + "github.com/rs/zerolog/log" ) func (m *Migrator) updateResourceControlsToDBVersion22() error { - migrateLog.Info("- updating resource controls") + log.Info().Msg("updating resource controls") + legacyResourceControls, err := m.resourceControlService.ResourceControls() if err != nil { return err @@ -25,7 +28,8 @@ func (m *Migrator) updateResourceControlsToDBVersion22() error { } func (m *Migrator) updateUsersAndRolesToDBVersion22() error { - migrateLog.Info("- updating users and roles") + log.Info().Msg("updating users and roles") + legacyUsers, err := m.userService.Users() if err != nil { return err diff --git a/api/datastore/migrator/migrate_dbversion22.go b/api/datastore/migrator/migrate_dbversion22.go index e1ecf7c67..bcf043c71 100644 --- a/api/datastore/migrator/migrate_dbversion22.go +++ b/api/datastore/migrator/migrate_dbversion22.go @@ -1,9 +1,14 @@ package migrator -import portainer "github.com/portainer/portainer/api" +import ( + portainer "github.com/portainer/portainer/api" + + "github.com/rs/zerolog/log" +) func (m *Migrator) updateTagsToDBVersion23() error { - migrateLog.Info("- Updating tags") + log.Info().Msg("updating tags") + tags, err := m.tagService.Tags() if err != nil { return err @@ -21,7 +26,8 @@ func (m *Migrator) updateTagsToDBVersion23() error { } func (m *Migrator) updateEndpointsAndEndpointGroupsToDBVersion23() error { - migrateLog.Info("- updating endpoints and endpoint groups") + log.Info().Msg("updating endpoints and endpoint groups") + tags, err := m.tagService.Tags() if err != nil { return err @@ -90,5 +96,6 @@ func (m *Migrator) updateEndpointsAndEndpointGroupsToDBVersion23() error { return err } } + return nil } diff --git a/api/datastore/migrator/migrate_dbversion23.go b/api/datastore/migrator/migrate_dbversion23.go index e66c2ceb6..8e3778c34 100644 --- a/api/datastore/migrator/migrate_dbversion23.go +++ b/api/datastore/migrator/migrate_dbversion23.go @@ -1,9 +1,13 @@ package migrator -import portainer "github.com/portainer/portainer/api" +import ( + portainer "github.com/portainer/portainer/api" + + "github.com/rs/zerolog/log" +) func (m *Migrator) updateSettingsToDB24() error { - migrateLog.Info("- updating Settings") + log.Info().Msg("updating Settings") legacySettings, err := m.settingsService.Settings() if err != nil { @@ -18,7 +22,8 @@ func (m *Migrator) updateSettingsToDB24() error { } func (m *Migrator) updateStacksToDB24() error { - migrateLog.Info("- updating stacks") + log.Info().Msg("updating stacks") + stacks, err := m.stackService.Stacks() if err != nil { return err diff --git a/api/datastore/migrator/migrate_dbversion24.go b/api/datastore/migrator/migrate_dbversion24.go index 1ee8c2f6c..724aecbb6 100644 --- a/api/datastore/migrator/migrate_dbversion24.go +++ b/api/datastore/migrator/migrate_dbversion24.go @@ -2,10 +2,12 @@ package migrator import ( portainer "github.com/portainer/portainer/api" + + "github.com/rs/zerolog/log" ) func (m *Migrator) updateSettingsToDB25() error { - migrateLog.Info("- updating settings") + log.Info().Msg("updating settings") legacySettings, err := m.settingsService.Settings() if err != nil { diff --git a/api/datastore/migrator/migrate_dbversion25.go b/api/datastore/migrator/migrate_dbversion25.go index ba4c35b71..dfaaa12f5 100644 --- a/api/datastore/migrator/migrate_dbversion25.go +++ b/api/datastore/migrator/migrate_dbversion25.go @@ -2,10 +2,13 @@ package migrator import ( portainer "github.com/portainer/portainer/api" + + "github.com/rs/zerolog/log" ) func (m *Migrator) updateEndpointSettingsToDB25() error { - migrateLog.Info("- updating endpoint settings") + log.Info().Msg("updating endpoint settings") + settings, err := m.settingsService.Settings() if err != nil { return err diff --git a/api/datastore/migrator/migrate_dbversion26.go b/api/datastore/migrator/migrate_dbversion26.go index 50b6c4b0e..389375876 100644 --- a/api/datastore/migrator/migrate_dbversion26.go +++ b/api/datastore/migrator/migrate_dbversion26.go @@ -4,10 +4,13 @@ import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/dataservices/errors" "github.com/portainer/portainer/api/internal/stackutils" + + "github.com/rs/zerolog/log" ) func (m *Migrator) updateStackResourceControlToDB27() error { - migrateLog.Info("- updating stack resource controls") + log.Info().Msg("updating stack resource controls") + resourceControls, err := m.resourceControlService.ResourceControls() if err != nil { return err diff --git a/api/datastore/migrator/migrate_dbversion29.go b/api/datastore/migrator/migrate_dbversion29.go index f59120b55..8dc167f24 100644 --- a/api/datastore/migrator/migrate_dbversion29.go +++ b/api/datastore/migrator/migrate_dbversion29.go @@ -1,12 +1,11 @@ package migrator -func (m *Migrator) migrateDBVersionToDB30() error { - migrateLog.Info("- updating legacy settings") - if err := m.MigrateSettingsToDB30(); err != nil { - return err - } +import "github.com/rs/zerolog/log" - return nil +func (m *Migrator) migrateDBVersionToDB30() error { + log.Info().Msg("updating legacy settings") + + return m.MigrateSettingsToDB30() } // so setting to false and "", is what would happen without this code diff --git a/api/datastore/migrator/migrate_dbversion31.go b/api/datastore/migrator/migrate_dbversion31.go index 6b89da547..ec826f672 100644 --- a/api/datastore/migrator/migrate_dbversion31.go +++ b/api/datastore/migrator/migrate_dbversion31.go @@ -2,14 +2,14 @@ package migrator import ( "fmt" - "log" - - "github.com/docker/docker/api/types/volume" - "github.com/portainer/portainer/api/dataservices/errors" portainer "github.com/portainer/portainer/api" + "github.com/portainer/portainer/api/dataservices/errors" "github.com/portainer/portainer/api/internal/endpointutils" snapshotutils "github.com/portainer/portainer/api/internal/snapshot" + + "github.com/docker/docker/api/types/volume" + "github.com/rs/zerolog/log" ) func (m *Migrator) migrateDBVersionToDB32() error { @@ -39,7 +39,8 @@ func (m *Migrator) migrateDBVersionToDB32() error { } func (m *Migrator) updateRegistriesToDB32() error { - migrateLog.Info("- updating registries") + log.Info().Msg("updating registries") + registries, err := m.registryService.Registries() if err != nil { return err @@ -82,7 +83,8 @@ func (m *Migrator) updateRegistriesToDB32() error { } func (m *Migrator) updateDockerhubToDB32() error { - migrateLog.Info("- updating dockerhub") + log.Info().Msg("updating dockerhub") + dockerhub, err := m.dockerhubService.DockerHub() if err == errors.ErrObjectNotFound { return nil @@ -171,7 +173,8 @@ func (m *Migrator) updateDockerhubToDB32() error { } func (m *Migrator) updateVolumeResourceControlToDB32() error { - migrateLog.Info("- updating resource controls") + log.Info().Msg("updating resource controls") + endpoints, err := m.endpointService.Endpoints() if err != nil { return fmt.Errorf("failed fetching environments: %w", err) @@ -199,7 +202,7 @@ func (m *Migrator) updateVolumeResourceControlToDB32() error { totalSnapshots := len(endpoint.Snapshots) if totalSnapshots == 0 { - log.Println("[DEBUG] [volume migration] [message: no snapshot found]") + log.Debug().Msg("no snapshot found") continue } @@ -207,13 +210,13 @@ func (m *Migrator) updateVolumeResourceControlToDB32() error { endpointDockerID, err := snapshotutils.FetchDockerID(snapshot) if err != nil { - log.Printf("[WARN] [database,migrator,v31] [message: failed fetching environment docker id] [err: %s]", err) + log.Warn().Err(err).Msg("failed fetching environment docker id") continue } volumesData := snapshot.SnapshotRaw.Volumes if volumesData.Volumes == nil { - log.Println("[DEBUG] [volume migration] [message: no volume data found]") + log.Debug().Msg("no volume data found") continue } @@ -224,17 +227,18 @@ func (m *Migrator) updateVolumeResourceControlToDB32() error { for _, resourceControl := range volumeResourceControls { if newResourceID, ok := toUpdate[resourceControl.ID]; ok { resourceControl.ResourceID = newResourceID + err := m.resourceControlService.UpdateResourceControl(resourceControl.ID, resourceControl) if err != nil { return fmt.Errorf("failed updating resource control %d: %w", resourceControl.ID, err) } - } else { err := m.resourceControlService.DeleteResourceControl(resourceControl.ID) if err != nil { return fmt.Errorf("failed deleting resource control %d: %w", resourceControl.ID, err) } - log.Printf("[DEBUG] [volume migration] [message: legacy resource control(%s) has been deleted]", resourceControl.ResourceID) + + log.Debug().Str("resource_id", resourceControl.ResourceID).Msg("legacy resource control has been deleted") } } @@ -257,21 +261,25 @@ func findResourcesToUpdateForDB32(dockerID string, volumesData volume.VolumeList } func (m *Migrator) kubeconfigExpiryToDB32() error { - migrateLog.Info("- updating kubeconfig expiry") + log.Info().Msg("updating kubeconfig expiry") + settings, err := m.settingsService.Settings() if err != nil { return err } + settings.KubeconfigExpiry = portainer.DefaultKubeconfigExpiry return m.settingsService.UpdateSettings(settings) } func (m *Migrator) helmRepositoryURLToDB32() error { - migrateLog.Info("- setting default helm repository URL") + log.Info().Msg("setting default helm repository URL") + settings, err := m.settingsService.Settings() if err != nil { return err } + settings.HelmRepositoryURL = portainer.DefaultHelmRepositoryURL return m.settingsService.UpdateSettings(settings) } diff --git a/api/datastore/migrator/migrate_dbversion32.go b/api/datastore/migrator/migrate_dbversion32.go index f41bb7a7b..aa52af17f 100644 --- a/api/datastore/migrator/migrate_dbversion32.go +++ b/api/datastore/migrator/migrate_dbversion32.go @@ -2,15 +2,14 @@ package migrator import ( portainer "github.com/portainer/portainer/api" + + "github.com/rs/zerolog/log" ) func (m *Migrator) migrateDBVersionToDB33() error { - migrateLog.Info("- updating settings") - if err := m.migrateSettingsToDB33(); err != nil { - return err - } + log.Info().Msg("updating settings") - return nil + return m.migrateSettingsToDB33() } func (m *Migrator) migrateSettingsToDB33() error { @@ -19,7 +18,8 @@ func (m *Migrator) migrateSettingsToDB33() error { return err } - migrateLog.Info("- setting default kubectl shell image") + log.Info().Msg("setting default kubectl shell image") settings.KubectlShellImage = portainer.DefaultKubectlShellImage + return m.settingsService.UpdateSettings(settings) } diff --git a/api/datastore/migrator/migrate_dbversion33.go b/api/datastore/migrator/migrate_dbversion33.go index ed067dc12..4d28ff6be 100644 --- a/api/datastore/migrator/migrate_dbversion33.go +++ b/api/datastore/migrator/migrate_dbversion33.go @@ -2,16 +2,14 @@ package migrator import ( "github.com/portainer/portainer/api/dataservices" + + "github.com/rs/zerolog/log" ) func (m *Migrator) migrateDBVersionToDB34() error { - migrateLog.Info("- updating stacks") - err := MigrateStackEntryPoint(m.stackService) - if err != nil { - return err - } + log.Info().Msg("updating stacks") - return nil + return MigrateStackEntryPoint(m.stackService) } // MigrateStackEntryPoint exported for testing (blah.) @@ -20,15 +18,18 @@ func MigrateStackEntryPoint(stackService dataservices.StackService) error { if err != nil { return err } + for i := range stacks { stack := &stacks[i] if stack.GitConfig == nil { continue } + stack.GitConfig.ConfigFilePath = stack.EntryPoint if err := stackService.UpdateStack(stack.ID, stack); err != nil { return err } } + return nil } diff --git a/api/datastore/migrator/migrate_dbversion34.go b/api/datastore/migrator/migrate_dbversion34.go index d0ce0d8a6..30371f85e 100644 --- a/api/datastore/migrator/migrate_dbversion34.go +++ b/api/datastore/migrator/migrate_dbversion34.go @@ -1,12 +1,12 @@ package migrator +import "github.com/rs/zerolog/log" + func (m *Migrator) migrateDBVersionToDB35() error { // These should have been migrated already, but due to an earlier bug and a bunch of duplicates, // calling it again will now fix the issue as the function has been repaired. - migrateLog.Info("- updating dockerhub registries") - err := m.updateDockerhubToDB32() - if err != nil { - return err - } - return nil + + log.Info().Msg("updating dockerhub registries") + + return m.updateDockerhubToDB32() } diff --git a/api/datastore/migrator/migrate_dbversion35.go b/api/datastore/migrator/migrate_dbversion35.go index 688cd971e..27ccf757d 100644 --- a/api/datastore/migrator/migrate_dbversion35.go +++ b/api/datastore/migrator/migrate_dbversion35.go @@ -3,15 +3,14 @@ package migrator import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/internal/authorization" + + "github.com/rs/zerolog/log" ) func (m *Migrator) migrateDBVersionToDB36() error { - migrateLog.Info("Updating user authorizations") - if err := m.migrateUsersToDB36(); err != nil { - return err - } + log.Info().Msg("updating user authorizations") - return nil + return m.migrateUsersToDB36() } func (m *Migrator) migrateUsersToDB36() error { diff --git a/api/datastore/migrator/migrate_dbversion40.go b/api/datastore/migrator/migrate_dbversion40.go index e024d43d8..a33e1d206 100644 --- a/api/datastore/migrator/migrate_dbversion40.go +++ b/api/datastore/migrator/migrate_dbversion40.go @@ -1,17 +1,18 @@ package migrator -import "github.com/portainer/portainer/api/internal/endpointutils" +import ( + "github.com/portainer/portainer/api/internal/endpointutils" + + "github.com/rs/zerolog/log" +) func (m *Migrator) migrateDBVersionToDB40() error { - if err := m.trustCurrentEdgeEndpointsDB40(); err != nil { - return err - } - - return nil + return m.trustCurrentEdgeEndpointsDB40() } func (m *Migrator) trustCurrentEdgeEndpointsDB40() error { - migrateLog.Info("- trusting current edge endpoints") + log.Info().Msg("trusting current edge endpoints") + endpoints, err := m.endpointService.Endpoints() if err != nil { return err diff --git a/api/datastore/migrator/migrate_dbversion50.go b/api/datastore/migrator/migrate_dbversion50.go index 680d61b25..8a58f4e66 100644 --- a/api/datastore/migrator/migrate_dbversion50.go +++ b/api/datastore/migrator/migrate_dbversion50.go @@ -2,6 +2,7 @@ package migrator import ( "github.com/pkg/errors" + "github.com/rs/zerolog/log" ) func (m *Migrator) migrateDBVersionToDB50() error { @@ -9,7 +10,8 @@ func (m *Migrator) migrateDBVersionToDB50() error { } func (m *Migrator) migratePasswordLengthSettings() error { - migrateLog.Info("Updating required password length") + log.Info().Msg("updating required password length") + s, err := m.settingsService.Settings() if err != nil { return errors.Wrap(err, "unable to retrieve settings") diff --git a/api/datastore/migrator/migrate_dbversion60.go b/api/datastore/migrator/migrate_dbversion60.go index 227f1262a..dc7bc3f72 100644 --- a/api/datastore/migrator/migrate_dbversion60.go +++ b/api/datastore/migrator/migrate_dbversion60.go @@ -1,17 +1,18 @@ package migrator -import portainer "github.com/portainer/portainer/api" +import ( + portainer "github.com/portainer/portainer/api" + + "github.com/rs/zerolog/log" +) func (m *Migrator) migrateDBVersionToDB60() error { - if err := m.addGpuInputFieldDB60(); err != nil { - return err - } - - return nil + return m.addGpuInputFieldDB60() } func (m *Migrator) addGpuInputFieldDB60() error { - migrateLog.Info("- add gpu input field") + log.Info().Msg("add gpu input field") + endpoints, err := m.endpointService.Endpoints() if err != nil { return err diff --git a/api/datastore/migrator/migrator.go b/api/datastore/migrator/migrator.go index 97836cacb..22431b612 100644 --- a/api/datastore/migrator/migrator.go +++ b/api/datastore/migrator/migrator.go @@ -18,12 +18,9 @@ import ( "github.com/portainer/portainer/api/dataservices/teammembership" "github.com/portainer/portainer/api/dataservices/user" "github.com/portainer/portainer/api/dataservices/version" - plog "github.com/portainer/portainer/api/datastore/log" "github.com/portainer/portainer/api/internal/authorization" ) -var migrateLog = plog.NewScopedLog("database, migrate") - type ( // Migrator defines a service to migrate data after a Portainer version update. Migrator struct { diff --git a/api/datastore/services.go b/api/datastore/services.go index d1bb2693e..2350dac31 100644 --- a/api/datastore/services.go +++ b/api/datastore/services.go @@ -2,6 +2,7 @@ package datastore import ( "encoding/json" + "fmt" "io/ioutil" "strconv" @@ -34,7 +35,8 @@ import ( "github.com/portainer/portainer/api/dataservices/user" "github.com/portainer/portainer/api/dataservices/version" "github.com/portainer/portainer/api/dataservices/webhook" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) // Store defines the implementation of portainer.DataStore using @@ -391,7 +393,7 @@ func (store *Store) Export(filename string) (err error) { if c, err := store.CustomTemplate().CustomTemplates(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Custom Templates") + log.Error().Err(err).Msg("exporting Custom Templates") } } else { backup.CustomTemplate = c @@ -399,7 +401,7 @@ func (store *Store) Export(filename string) (err error) { if e, err := store.EdgeGroup().EdgeGroups(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Edge Groups") + log.Error().Err(err).Msg("exporting Edge Groups") } } else { backup.EdgeGroup = e @@ -407,7 +409,7 @@ func (store *Store) Export(filename string) (err error) { if e, err := store.EdgeJob().EdgeJobs(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Edge Jobs") + log.Error().Err(err).Msg("exporting Edge Jobs") } } else { backup.EdgeJob = e @@ -415,7 +417,7 @@ func (store *Store) Export(filename string) (err error) { if e, err := store.EdgeStack().EdgeStacks(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Edge Stacks") + log.Error().Err(err).Msg("exporting Edge Stacks") } } else { backup.EdgeStack = e @@ -423,7 +425,7 @@ func (store *Store) Export(filename string) (err error) { if e, err := store.Endpoint().Endpoints(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Endpoints") + log.Error().Err(err).Msg("exporting Endpoints") } } else { backup.Endpoint = e @@ -431,7 +433,7 @@ func (store *Store) Export(filename string) (err error) { if e, err := store.EndpointGroup().EndpointGroups(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Endpoint Groups") + log.Error().Err(err).Msg("exporting Endpoint Groups") } } else { backup.EndpointGroup = e @@ -439,7 +441,7 @@ func (store *Store) Export(filename string) (err error) { if r, err := store.EndpointRelation().EndpointRelations(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Endpoint Relations") + log.Error().Err(err).Msg("exporting Endpoint Relations") } } else { backup.EndpointRelation = r @@ -447,7 +449,7 @@ func (store *Store) Export(filename string) (err error) { if r, err := store.ExtensionService.Extensions(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Extensions") + log.Error().Err(err).Msg("exporting Extensions") } } else { backup.Extensions = r @@ -455,7 +457,7 @@ func (store *Store) Export(filename string) (err error) { if r, err := store.HelmUserRepository().HelmUserRepositories(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Helm User Repositories") + log.Error().Err(err).Msg("exporting Helm User Repositories") } } else { backup.HelmUserRepository = r @@ -463,7 +465,7 @@ func (store *Store) Export(filename string) (err error) { if r, err := store.Registry().Registries(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Registries") + log.Error().Err(err).Msg("exporting Registries") } } else { backup.Registry = r @@ -471,7 +473,7 @@ func (store *Store) Export(filename string) (err error) { if c, err := store.ResourceControl().ResourceControls(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Resource Controls") + log.Error().Err(err).Msg("exporting Resource Controls") } } else { backup.ResourceControl = c @@ -479,7 +481,7 @@ func (store *Store) Export(filename string) (err error) { if role, err := store.Role().Roles(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Roles") + log.Error().Err(err).Msg("exporting Roles") } } else { backup.Role = role @@ -487,7 +489,7 @@ func (store *Store) Export(filename string) (err error) { if r, err := store.ScheduleService.Schedules(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Schedules") + log.Error().Err(err).Msg("exporting Schedules") } } else { backup.Schedules = r @@ -495,7 +497,7 @@ func (store *Store) Export(filename string) (err error) { if settings, err := store.Settings().Settings(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Settings") + log.Error().Err(err).Msg("exporting Settings") } } else { backup.Settings = *settings @@ -503,7 +505,7 @@ func (store *Store) Export(filename string) (err error) { if settings, err := store.SSLSettings().Settings(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting SSL Settings") + log.Error().Err(err).Msg("exporting SSL Settings") } } else { backup.SSLSettings = *settings @@ -511,7 +513,7 @@ func (store *Store) Export(filename string) (err error) { if t, err := store.Stack().Stacks(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Stacks") + log.Error().Err(err).Msg("exporting Stacks") } } else { backup.Stack = t @@ -519,7 +521,7 @@ func (store *Store) Export(filename string) (err error) { if t, err := store.Tag().Tags(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Tags") + log.Error().Err(err).Msg("exporting Tags") } } else { backup.Tag = t @@ -527,7 +529,7 @@ func (store *Store) Export(filename string) (err error) { if t, err := store.TeamMembership().TeamMemberships(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Team Memberships") + log.Error().Err(err).Msg("exporting Team Memberships") } } else { backup.TeamMembership = t @@ -535,7 +537,7 @@ func (store *Store) Export(filename string) (err error) { if t, err := store.Team().Teams(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Teams") + log.Error().Err(err).Msg("exporting Teams") } } else { backup.Team = t @@ -543,7 +545,7 @@ func (store *Store) Export(filename string) (err error) { if info, err := store.TunnelServer().Info(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Tunnel Server") + log.Error().Err(err).Msg("exporting Tunnel Server") } } else { backup.TunnelServer = *info @@ -551,7 +553,7 @@ func (store *Store) Export(filename string) (err error) { if users, err := store.User().Users(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Users") + log.Error().Err(err).Msg("exporting Users") } } else { backup.User = users @@ -559,7 +561,7 @@ func (store *Store) Export(filename string) (err error) { if webhooks, err := store.Webhook().Webhooks(); err != nil { if !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting Webhooks") + log.Error().Err(err).Msg("exporting Webhooks") } } else { backup.Webhook = webhooks @@ -567,7 +569,7 @@ func (store *Store) Export(filename string) (err error) { v, err := store.Version().DBVersion() if err != nil && !store.IsErrObjectNotFound(err) { - logrus.WithError(err).Errorf("Exporting DB version") + log.Error().Err(err).Msg("exporting DB version") } instance, _ := store.Version().InstanceID() backup.Version = map[string]string{ @@ -577,7 +579,7 @@ func (store *Store) Export(filename string) (err error) { backup.Metadata, err = store.connection.BackupMetadata() if err != nil { - logrus.WithError(err).Errorf("Exporting Metadata") + log.Error().Err(err).Msg("exporting Metadata") } b, err := json.MarshalIndent(backup, "", " ") @@ -588,7 +590,6 @@ func (store *Store) Export(filename string) (err error) { } func (store *Store) Import(filename string) (err error) { - backup := storeExport{} s, err := ioutil.ReadFile(filename) @@ -604,13 +605,13 @@ func (store *Store) Import(filename string) (err error) { if dbversion, ok := backup.Version["DB_VERSION"]; ok { if v, err := strconv.Atoi(dbversion); err == nil { if err := store.Version().StoreDBVersion(v); err != nil { - logrus.WithError(err).Errorf("DB_VERSION import issue") + log.Error().Err(err).Msg("DB_VERSION import issue") } } } if instanceID, ok := backup.Version["INSTANCE_ID"]; ok { if err := store.Version().StoreInstanceID(instanceID); err != nil { - logrus.WithError(err).Errorf("INSTANCE_ID import issue") + log.Error().Err(err).Msg("INSTANCE_ID import issue") } } @@ -681,7 +682,7 @@ func (store *Store) Import(filename string) (err error) { for _, user := range backup.User { if err := store.User().UpdateUser(user.ID, &user); err != nil { - logrus.WithField("user", user).WithError(err).Errorf("User: Failed to Update Database") + log.Debug().Str("user", fmt.Sprintf("%+v", user)).Err(err).Msg("user: failed to Update Database") } } diff --git a/api/datastore/teststore.go b/api/datastore/teststore.go index 89ed6b27f..8d7d62ce9 100644 --- a/api/datastore/teststore.go +++ b/api/datastore/teststore.go @@ -1,14 +1,14 @@ package datastore import ( - "log" "testing" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/database" + "github.com/portainer/portainer/api/filesystem" "github.com/pkg/errors" - "github.com/portainer/portainer/api/filesystem" + "github.com/rs/zerolog/log" ) var errTempDir = errors.New("can't create a temp dir") @@ -23,7 +23,8 @@ func MustNewTestStore(t *testing.T, init, secure bool) (bool, *Store, func()) { if !errors.Is(err, errTempDir) { teardown() } - log.Fatal(err) + + log.Fatal().Err(err).Msg("") } return newStore, store, teardown @@ -46,12 +47,15 @@ func NewTestStore(t *testing.T, init, secure bool) (bool, *Store, func(), error) if err != nil { panic(err) } + store := NewStore(storePath, fileService, connection) newStore, err := store.Open() if err != nil { return newStore, nil, nil, err } + log.Debug().Msg("opened") + if init { err = store.Init() if err != nil { @@ -59,6 +63,8 @@ func NewTestStore(t *testing.T, init, secure bool) (bool, *Store, func(), error) } } + log.Debug().Msg("initialised") + if newStore { // from MigrateData store.VersionService.StoreDBVersion(portainer.DBVersion) @@ -77,6 +83,6 @@ func NewTestStore(t *testing.T, init, secure bool) (bool, *Store, func(), error) func teardown(store *Store) { err := store.Close() if err != nil { - log.Fatalln(err) + log.Fatal().Err(err).Msg("") } } diff --git a/api/demo/demo.go b/api/demo/demo.go index 330807a64..0135c0e1c 100644 --- a/api/demo/demo.go +++ b/api/demo/demo.go @@ -1,11 +1,11 @@ package demo import ( - "log" - - "github.com/pkg/errors" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/dataservices" + + "github.com/pkg/errors" + "github.com/rs/zerolog/log" ) type EnvironmentDetails struct { @@ -27,7 +27,7 @@ func (service *Service) Details() EnvironmentDetails { } func (service *Service) Init(store dataservices.DataStore, cryptoService portainer.CryptoService) error { - log.Print("[INFO] [main] Starting demo environment") + log.Info().Msg("starting demo environment") isClean, err := isCleanStore(store) if err != nil { diff --git a/api/docker/snapshot.go b/api/docker/snapshot.go index 074cc4726..441a08fad 100644 --- a/api/docker/snapshot.go +++ b/api/docker/snapshot.go @@ -2,15 +2,16 @@ package docker import ( "context" - "log" "strings" "time" + portainer "github.com/portainer/portainer/api" + "github.com/docker/docker/api/types" _container "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/client" - portainer "github.com/portainer/portainer/api" + "github.com/rs/zerolog/log" ) // Snapshotter represents a service used to create environment(endpoint) snapshots @@ -48,44 +49,44 @@ func snapshot(cli *client.Client, endpoint *portainer.Endpoint) (*portainer.Dock err = snapshotInfo(snapshot, cli) if err != nil { - log.Printf("[WARN] [docker,snapshot] [message: unable to snapshot engine information] [environment: %s] [err: %s]", endpoint.Name, err) + log.Warn().Str("environment", endpoint.Name).Err(err).Msg("unable to snapshot engine information") } if snapshot.Swarm { err = snapshotSwarmServices(snapshot, cli) if err != nil { - log.Printf("[WARN] [docker,snapshot] [message: unable to snapshot Swarm services] [environment: %s] [err: %s]", endpoint.Name, err) + log.Warn().Str("environment", endpoint.Name).Err(err).Msg("unable to snapshot Swarm services") } err = snapshotNodes(snapshot, cli) if err != nil { - log.Printf("[WARN] [docker,snapshot] [message: unable to snapshot Swarm nodes] [environment: %s] [err: %s]", endpoint.Name, err) + log.Warn().Str("environment", endpoint.Name).Err(err).Msg("unable to snapshot Swarm nodes") } } err = snapshotContainers(snapshot, cli) if err != nil { - log.Printf("[WARN] [docker,snapshot] [message: unable to snapshot containers] [environment: %s] [err: %s]", endpoint.Name, err) + log.Warn().Str("environment", endpoint.Name).Err(err).Msg("unable to snapshot containers") } err = snapshotImages(snapshot, cli) if err != nil { - log.Printf("[WARN] [docker,snapshot] [message: unable to snapshot images] [environment: %s] [err: %s]", endpoint.Name, err) + log.Warn().Str("environment", endpoint.Name).Err(err).Msg("unable to snapshot images") } err = snapshotVolumes(snapshot, cli) if err != nil { - log.Printf("[WARN] [docker,snapshot] [message: unable to snapshot volumes] [environment: %s] [err: %s]", endpoint.Name, err) + log.Warn().Str("environment", endpoint.Name).Err(err).Msg("unable to snapshot volumes") } err = snapshotNetworks(snapshot, cli) if err != nil { - log.Printf("[WARN] [docker,snapshot] [message: unable to snapshot networks] [environment: %s] [err: %s]", endpoint.Name, err) + log.Warn().Str("environment", endpoint.Name).Err(err).Msg("unable to snapshot networks") } err = snapshotVersion(snapshot, cli) if err != nil { - log.Printf("[WARN] [docker,snapshot] [message: unable to snapshot engine version] [environment: %s] [err: %s]", endpoint.Name, err) + log.Warn().Str("environment", endpoint.Name).Err(err).Msg("unable to snapshot engine version") } snapshot.Time = time.Now().Unix() diff --git a/api/exec/compose_stack_integration_test.go b/api/exec/compose_stack_integration_test.go index 68ff18da8..0d0ddf967 100644 --- a/api/exec/compose_stack_integration_test.go +++ b/api/exec/compose_stack_integration_test.go @@ -3,7 +3,6 @@ package exec import ( "context" "fmt" - "log" "os" "os/exec" "path/filepath" @@ -12,6 +11,8 @@ import ( portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/internal/testhelpers" + + "github.com/rs/zerolog/log" ) const composeFile = `version: "3.9" @@ -77,7 +78,7 @@ func containerExists(containerName string) bool { out, err := cmd.Output() if err != nil { - log.Fatalf("failed to list containers: %s", err) + log.Fatal().Err(err).Msg("failed to list containers") } return strings.Contains(string(out), containerName) diff --git a/api/git/git_test.go b/api/git/git_test.go index b8bd9092c..fe8cae2f3 100644 --- a/api/git/git_test.go +++ b/api/git/git_test.go @@ -6,10 +6,11 @@ import ( "path/filepath" "testing" + "github.com/portainer/portainer/api/archive" + "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/object" "github.com/pkg/errors" - "github.com/portainer/portainer/api/archive" "github.com/stretchr/testify/assert" ) diff --git a/api/go.mod b/api/go.mod index 48671193b..0bbd7d270 100644 --- a/api/go.mod +++ b/api/go.mod @@ -35,7 +35,7 @@ require ( github.com/portainer/docker-compose-wrapper v0.0.0-20220708023447-a69a4ebaa021 github.com/portainer/libcrypto v0.0.0-20220506221303-1f4fb3b30f9a github.com/portainer/libhelm v0.0.0-20210929000907-825e93d62108 - github.com/portainer/libhttp v0.0.0-20211208103139-07a5f798eb3f + github.com/portainer/libhttp v0.0.0-20220916153711-5d61e12f4b0a github.com/rkl-/digest v0.0.0-20180419075440-8316caa4a777 github.com/robfig/cron/v3 v3.0.1 github.com/sirupsen/logrus v1.8.1 @@ -89,6 +89,8 @@ require ( github.com/jpillora/sizestr v1.0.0 // indirect github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect github.com/leodido/go-urn v1.2.1 // indirect + github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.1.2 // indirect github.com/moby/spdystream v0.2.0 // indirect @@ -101,6 +103,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rs/zerolog v1.28.0 // indirect github.com/sergi/go-diff v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce // indirect diff --git a/api/go.sum b/api/go.sum index 11fdd0010..2b26fda2a 100644 --- a/api/go.sum +++ b/api/go.sum @@ -88,6 +88,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -167,6 +168,7 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl github.com/go-playground/validator/v10 v10.10.1 h1:uA0+amWMiglNZKZ9FJRKUAe9U3RX91eVn1JYXMWt7ig= github.com/go-playground/validator/v10 v10.10.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -306,6 +308,10 @@ github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= +github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= @@ -361,6 +367,8 @@ github.com/portainer/libhelm v0.0.0-20210929000907-825e93d62108 h1:5e8KAnDa2G3cE github.com/portainer/libhelm v0.0.0-20210929000907-825e93d62108/go.mod h1:YvYAk7krKTzB+rFwDr0jQ3sQu2BtiXK1AR0sZH7nhJA= github.com/portainer/libhttp v0.0.0-20211208103139-07a5f798eb3f h1:GMIjRVV2LADpJprPG2+8MdRH6XvrFgC7wHm7dFUdOpc= github.com/portainer/libhttp v0.0.0-20211208103139-07a5f798eb3f/go.mod h1:nyQA6IahOruIvENCcBk54aaUvV2WHFdXkvBjIutg+SY= +github.com/portainer/libhttp v0.0.0-20220916153711-5d61e12f4b0a h1:BJ5V4EDNhg3ImYbmXnGS8vrMhq6rzsEneIXyJh0g4dc= +github.com/portainer/libhttp v0.0.0-20220916153711-5d61e12f4b0a/go.mod h1:ckuHnoLA5kLuE5WkvPBXmrw63LUMdSH4aX71QRi9y10= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rkl-/digest v0.0.0-20180419075440-8316caa4a777 h1:rDj3WeO+TiWyxfcydUnKegWAZoR5kQsnW0wzhggdOrw= github.com/rkl-/digest v0.0.0-20180419075440-8316caa4a777/go.mod h1:xRVvTK+cS/dJSvrOufGUQFWfgvE7yXExeng96n8377o= @@ -370,6 +378,9 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.28.0 h1:MirSo27VyNi7RJYP3078AA1+Cyzd2GB66qy3aUHvsWY= +github.com/rs/zerolog v1.28.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= @@ -562,6 +573,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= diff --git a/api/http/client/client.go b/api/http/client/client.go index c789854a4..dcd070375 100644 --- a/api/http/client/client.go +++ b/api/http/client/client.go @@ -6,13 +6,14 @@ import ( "errors" "fmt" "io/ioutil" - "log" "net/http" "net/url" "strings" "time" - "github.com/portainer/portainer/api" + portainer "github.com/portainer/portainer/api" + + "github.com/rs/zerolog/log" ) var errInvalidResponseStatus = errors.New("Invalid response status (expecting 200)") @@ -90,7 +91,8 @@ func Get(url string, timeout int) ([]byte, error) { defer response.Body.Close() if response.StatusCode != http.StatusOK { - log.Printf("[ERROR] [http,client] [message: unexpected status code] [status_code: %d]", response.StatusCode) + log.Error().Int("status_code", response.StatusCode).Msg("unexpected status code") + return nil, errInvalidResponseStatus } diff --git a/api/http/handler/auth/authenticate.go b/api/http/handler/auth/authenticate.go index f68d95cb6..d1c8bbae5 100644 --- a/api/http/handler/auth/authenticate.go +++ b/api/http/handler/auth/authenticate.go @@ -2,17 +2,18 @@ package auth import ( "errors" - "log" "net/http" "strings" - "github.com/asaskevich/govalidator" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" portainer "github.com/portainer/portainer/api" httperrors "github.com/portainer/portainer/api/http/errors" "github.com/portainer/portainer/api/internal/authorization" + + "github.com/asaskevich/govalidator" + "github.com/rs/zerolog/log" ) type authenticatePayload struct { @@ -31,9 +32,11 @@ func (payload *authenticatePayload) Validate(r *http.Request) error { if govalidator.IsNull(payload.Username) { return errors.New("Invalid username") } + if govalidator.IsNull(payload.Password) { return errors.New("Invalid password") } + return nil } @@ -101,6 +104,7 @@ func (handler *Handler) authenticateInternal(w http.ResponseWriter, user *portai } forceChangePassword := !handler.passwordStrengthChecker.Check(password) + return handler.writeToken(w, user, forceChangePassword) } @@ -125,7 +129,7 @@ func (handler *Handler) authenticateLDAP(w http.ResponseWriter, user *portainer. err = handler.addUserIntoTeams(user, ldapSettings) if err != nil { - log.Printf("Warning: unable to automatically add user into teams: %s\n", err.Error()) + log.Warn().Err(err).Msg("unable to automatically add user into teams") } return handler.writeToken(w, user, false) @@ -191,6 +195,7 @@ func teamExists(teamName string, ldapGroups []string) bool { return true } } + return false } @@ -200,6 +205,7 @@ func teamMembershipExists(teamID portainer.TeamID, memberships []portainer.TeamM return true } } + return false } diff --git a/api/http/handler/auth/authenticate_oauth.go b/api/http/handler/auth/authenticate_oauth.go index e296194d3..14863723b 100644 --- a/api/http/handler/auth/authenticate_oauth.go +++ b/api/http/handler/auth/authenticate_oauth.go @@ -2,14 +2,15 @@ package auth import ( "errors" - "log" "net/http" - "github.com/asaskevich/govalidator" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" portainer "github.com/portainer/portainer/api" httperrors "github.com/portainer/portainer/api/http/errors" + + "github.com/asaskevich/govalidator" + "github.com/rs/zerolog/log" ) type oauthPayload struct { @@ -71,7 +72,8 @@ func (handler *Handler) validateOAuth(w http.ResponseWriter, r *http.Request) *h username, err := handler.authenticateOAuth(payload.Code, &settings.OAuthSettings) if err != nil { - log.Printf("[DEBUG] - OAuth authentication error: %s", err) + log.Debug().Err(err).Msg("OAuth authentication error") + return httperror.InternalServerError("Unable to authenticate through OAuth", httperrors.ErrUnauthorized) } diff --git a/api/http/handler/customtemplates/customtemplate_create.go b/api/http/handler/customtemplates/customtemplate_create.go index 66d33cbb9..4929edb65 100644 --- a/api/http/handler/customtemplates/customtemplate_create.go +++ b/api/http/handler/customtemplates/customtemplate_create.go @@ -3,13 +3,11 @@ package customtemplates import ( "encoding/json" "errors" - "log" "net/http" "os" "regexp" "strconv" - "github.com/asaskevich/govalidator" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" @@ -17,6 +15,9 @@ import ( "github.com/portainer/portainer/api/filesystem" "github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/internal/authorization" + + "github.com/asaskevich/govalidator" + "github.com/rs/zerolog/log" ) // @id CustomTemplateCreate @@ -291,16 +292,18 @@ func (handler *Handler) createCustomTemplateFromGitRepository(r *http.Request) ( if err != nil { return nil, err } + isValidProject := true defer func() { if !isValidProject { if err := handler.FileService.RemoveDirectory(projectPath); err != nil { - log.Printf("[WARN] [http,customtemplate,git] [error: %s] [message: unable to remove git repository directory]", err) + log.Warn().Err(err).Msg("unable to remove git repository directory") } } }() entryPath := filesystem.JoinPaths(projectPath, customTemplate.EntryPoint) + exists, err := handler.FileService.FileExists(entryPath) if err != nil || !exists { isValidProject = false diff --git a/api/http/handler/endpoints/endpoint_snapshots.go b/api/http/handler/endpoints/endpoint_snapshots.go index a3bf807f7..5af529a85 100644 --- a/api/http/handler/endpoints/endpoint_snapshots.go +++ b/api/http/handler/endpoints/endpoint_snapshots.go @@ -1,13 +1,14 @@ package endpoints import ( - "log" "net/http" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/response" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/internal/snapshot" + + "github.com/rs/zerolog/log" ) // @id EndpointSnapshots @@ -35,13 +36,23 @@ func (handler *Handler) endpointSnapshots(w http.ResponseWriter, r *http.Request latestEndpointReference, err := handler.DataStore.Endpoint().Endpoint(endpoint.ID) if latestEndpointReference == nil { - log.Printf("background schedule error (environment snapshot). Environment not found inside the database anymore (endpoint=%s, URL=%s) (err=%s)\n", endpoint.Name, endpoint.URL, err) + log.Debug(). + Str("endpoint", endpoint.Name). + Str("URL", endpoint.URL). + Err(err). + Msg("background schedule error (environment snapshot), environment not found inside the database anymore") + continue } endpoint.Status = portainer.EndpointStatusUp if snapshotError != nil { - log.Printf("background schedule error (environment snapshot). Unable to create snapshot (endpoint=%s, URL=%s) (err=%s)\n", endpoint.Name, endpoint.URL, snapshotError) + log.Debug(). + Str("endpoint", endpoint.Name). + Str("URL", endpoint.URL). + Err(snapshotError). + Msg("background schedule error (environment snapshot), unable to create snapshot") + endpoint.Status = portainer.EndpointStatusDown } diff --git a/api/http/handler/helm/helm_show.go b/api/http/handler/helm/helm_show.go index 51ae3133c..a42fb93b9 100644 --- a/api/http/handler/helm/helm_show.go +++ b/api/http/handler/helm/helm_show.go @@ -2,7 +2,6 @@ package helm import ( "fmt" - "log" "net/http" "net/url" @@ -10,6 +9,8 @@ import ( "github.com/portainer/libhelm/options" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" + + "github.com/rs/zerolog/log" ) // @id HelmShow @@ -47,7 +48,7 @@ func (handler *Handler) helmShow(w http.ResponseWriter, r *http.Request) *httper cmd, err := request.RetrieveRouteVariableValue(r, "command") if err != nil { cmd = "all" - log.Printf("[DEBUG] [internal,helm] [message: command not provided, defaulting to %s]", cmd) + log.Debug().Str("default_command", cmd).Msg("command not provided, using default") } showOptions := options.ShowOptions{ diff --git a/api/http/handler/hostmanagement/fdo/configure.go b/api/http/handler/hostmanagement/fdo/configure.go index 918832f68..05cf2221f 100644 --- a/api/http/handler/hostmanagement/fdo/configure.go +++ b/api/http/handler/hostmanagement/fdo/configure.go @@ -7,13 +7,13 @@ import ( "net/url" "strings" - "github.com/fxamacker/cbor/v2" - httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/fxamacker/cbor/v2" + "github.com/rs/zerolog/log" ) const ( @@ -63,7 +63,8 @@ func (payload *deviceConfigurePayload) Validate(r *http.Request) error { func (handler *Handler) fdoConfigureDevice(w http.ResponseWriter, r *http.Request) *httperror.HandlerError { guid, err := request.RetrieveRouteVariableValue(r, "guid") if err != nil { - logrus.WithError(err).Info("fdoConfigureDevice: request.RetrieveRouteVariableValue()") + log.Error().Err(err).Msg("fdoConfigureDevice: request.RetrieveRouteVariableValue()") + return httperror.InternalServerError("fdoConfigureDevice: guid not found", err) } @@ -71,7 +72,8 @@ func (handler *Handler) fdoConfigureDevice(w http.ResponseWriter, r *http.Reques err = request.DecodeAndValidateJSONPayload(r, &payload) if err != nil { - logrus.WithError(err).Error("Invalid request payload") + log.Error().Err(err).Msg("invalid request payload") + return httperror.BadRequest("Invalid request payload", err) } @@ -84,13 +86,15 @@ func (handler *Handler) fdoConfigureDevice(w http.ResponseWriter, r *http.Reques fileContent, err := handler.FileService.GetFileContent(profile.FilePath, "") if err != nil { - logrus.WithError(err).Info("fdoConfigureDevice: GetFileContent") + log.Error().Err(err).Msg("fdoConfigureDevice: GetFileContent") + return httperror.InternalServerError("fdoConfigureDevice: GetFileContent", err) } fdoClient, err := handler.newFDOClient() if err != nil { - logrus.WithError(err).Info("fdoConfigureDevice: newFDOClient()") + log.Error().Err(err).Msg("fdoConfigureDevice: newFDOClient()") + return httperror.InternalServerError("fdoConfigureDevice: newFDOClient()", err) } @@ -102,7 +106,8 @@ func (handler *Handler) fdoConfigureDevice(w http.ResponseWriter, r *http.Reques "var": []string{"active"}, "bytes": []string{"F5"}, // this is "true" in CBOR }, []byte("")); err != nil { - logrus.WithError(err).Info("fdoConfigureDevice: PutDeviceSVIRaw()") + log.Error().Err(err).Msg("fdoConfigureDevice: PutDeviceSVIRaw()") + return httperror.InternalServerError("fdoConfigureDevice: PutDeviceSVIRaw()", err) } @@ -113,7 +118,8 @@ func (handler *Handler) fdoConfigureDevice(w http.ResponseWriter, r *http.Reques "var": []string{"filedesc"}, "filename": []string{"DEVICE_edgeid.txt"}, }, []byte(payload.EdgeID)); err != nil { - logrus.WithError(err).Info("fdoConfigureDevice: PutDeviceSVIRaw(edgeid)") + log.Error().Err(err).Msg("fdoConfigureDevice: PutDeviceSVIRaw(edgeid)") + return httperror.InternalServerError("fdoConfigureDevice: PutDeviceSVIRaw(edgeid)", err) } @@ -125,7 +131,8 @@ func (handler *Handler) fdoConfigureDevice(w http.ResponseWriter, r *http.Reques "var": []string{"filedesc"}, "filename": []string{"DEVICE_edgekey.txt"}, }, []byte(payload.EdgeKey)); err != nil { - logrus.WithError(err).Info("fdoConfigureDevice: PutDeviceSVIRaw(edgekey)") + log.Error().Err(err).Msg("fdoConfigureDevice: PutDeviceSVIRaw(edgekey)") + return httperror.InternalServerError("fdoConfigureDevice: PutDeviceSVIRaw(edgekey)", err) } @@ -137,7 +144,8 @@ func (handler *Handler) fdoConfigureDevice(w http.ResponseWriter, r *http.Reques "var": []string{"filedesc"}, "filename": []string{"DEVICE_name.txt"}, }, []byte(payload.Name)); err != nil { - logrus.WithError(err).Info("fdoConfigureDevice: PutDeviceSVIRaw(name)") + log.Error().Err(err).Msg("fdoConfigureDevice: PutDeviceSVIRaw(name)") + return httperror.InternalServerError("fdoConfigureDevice: PutDeviceSVIRaw(name)", err) } @@ -149,7 +157,8 @@ func (handler *Handler) fdoConfigureDevice(w http.ResponseWriter, r *http.Reques "var": []string{"filedesc"}, "filename": []string{"DEVICE_GUID.txt"}, }, []byte(guid)); err != nil { - logrus.WithError(err).Info("fdoConfigureDevice: PutDeviceSVIRaw()") + log.Error().Err(err).Msg("fdoConfigureDevice: PutDeviceSVIRaw()") + return httperror.InternalServerError("fdoConfigureDevice: PutDeviceSVIRaw()", err) } @@ -160,18 +169,20 @@ func (handler *Handler) fdoConfigureDevice(w http.ResponseWriter, r *http.Reques "var": []string{"filedesc"}, "filename": []string{deploymentScriptName}, }, fileContent); err != nil { - logrus.WithError(err).Info("fdoConfigureDevice: PutDeviceSVIRaw()") + log.Error().Err(err).Msg("fdoConfigureDevice: PutDeviceSVIRaw()") + return httperror.InternalServerError("fdoConfigureDevice: PutDeviceSVIRaw()", err) } b, err := cbor.Marshal([]string{"/bin/sh", deploymentScriptName}) if err != nil { - logrus.WithError(err).Error("failed to marshal string to CBOR") + log.Error().Err(err).Msg("failed to marshal string to CBOR") + return httperror.InternalServerError("fdoConfigureDevice: PutDeviceSVIRaw() failed to encode", err) } cborBytes := strings.ToUpper(hex.EncodeToString(b)) - logrus.WithField("cbor", cborBytes).WithField("string", deploymentScriptName).Info("converted to CBOR") + log.Debug().Str("cbor", cborBytes).Str("string", deploymentScriptName).Msg("converted to CBOR") if err = fdoClient.PutDeviceSVIRaw(url.Values{ "guid": []string{guid}, @@ -180,7 +191,8 @@ func (handler *Handler) fdoConfigureDevice(w http.ResponseWriter, r *http.Reques "var": []string{"exec"}, "bytes": []string{cborBytes}, }, []byte("")); err != nil { - logrus.WithError(err).Info("fdoConfigureDevice: PutDeviceSVIRaw()") + log.Error().Err(err).Msg("fdoConfigureDevice: PutDeviceSVIRaw()") + return httperror.InternalServerError("fdoConfigureDevice: PutDeviceSVIRaw()", err) } diff --git a/api/http/handler/hostmanagement/fdo/fdo.go b/api/http/handler/hostmanagement/fdo/fdo.go index aacae2003..15e035643 100644 --- a/api/http/handler/hostmanagement/fdo/fdo.go +++ b/api/http/handler/hostmanagement/fdo/fdo.go @@ -13,7 +13,8 @@ import ( "github.com/portainer/libhttp/response" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/hostmanagement/fdo" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) type fdoConfigurePayload portainer.FDOConfiguration @@ -88,7 +89,8 @@ func (handler *Handler) fdoConfigure(w http.ResponseWriter, r *http.Request) *ht err := request.DecodeAndValidateJSONPayload(r, &payload) if err != nil { - logrus.WithError(err).Error("Invalid request payload") + log.Error().Err(err).Msg("Invalid request payload") + return httperror.BadRequest("Invalid request payload", err) } @@ -101,6 +103,7 @@ func (handler *Handler) fdoConfigure(w http.ResponseWriter, r *http.Request) *ht if err != nil { return httperror.InternalServerError("Error saving FDO settings", err) } + if len(profiles) == 0 { err = handler.addDefaultProfile() if err != nil { @@ -129,6 +132,7 @@ func (handler *Handler) addDefaultProfile() error { if err != nil { return err } + return nil } diff --git a/api/http/handler/hostmanagement/fdo/list.go b/api/http/handler/hostmanagement/fdo/list.go index ce94bcc6e..4151ff459 100644 --- a/api/http/handler/hostmanagement/fdo/list.go +++ b/api/http/handler/hostmanagement/fdo/list.go @@ -4,9 +4,9 @@ import ( "net/http" httperror "github.com/portainer/libhttp/error" - "github.com/sirupsen/logrus" - "github.com/portainer/libhttp/response" + + "github.com/rs/zerolog/log" ) // @id fdoListAll @@ -24,14 +24,16 @@ import ( func (handler *Handler) fdoListAll(w http.ResponseWriter, r *http.Request) *httperror.HandlerError { fdoClient, err := handler.newFDOClient() if err != nil { - logrus.WithError(err).Info("fdoListAll: newFDOClient()") + log.Error().Err(err).Msg("fdoListAll: newFDOClient()") + return httperror.InternalServerError("fdoRegisterDevice: newFDOClient()", err) } // Get all vouchers guids, err := fdoClient.GetVouchers() if err != nil { - logrus.WithError(err).Info("fdoListAll: GetVouchers()") + log.Error().Err(err).Msg("fdoListAll: GetVouchers()") + return httperror.InternalServerError("fdoListAll: GetVouchers()", err) } diff --git a/api/http/handler/hostmanagement/fdo/register.go b/api/http/handler/hostmanagement/fdo/register.go index ce87c0226..20a1e0773 100644 --- a/api/http/handler/hostmanagement/fdo/register.go +++ b/api/http/handler/hostmanagement/fdo/register.go @@ -6,7 +6,8 @@ import ( httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) type registerDeviceResponse struct { @@ -29,19 +30,22 @@ func (handler *Handler) fdoRegisterDevice(w http.ResponseWriter, r *http.Request // Post a voucher ov, filename, err := request.RetrieveMultiPartFormFile(r, "voucher") if err != nil { - logrus.WithField("filename", filename).WithError(err).Info("fdoRegisterDevice: readVoucher()") + log.Info().Str("filename", filename).Err(err).Msg("fdoRegisterDevice: readVoucher()") + return httperror.InternalServerError("fdoRegisterDevice: read Voucher()", err) } fdoClient, err := handler.newFDOClient() if err != nil { - logrus.WithError(err).Info("fdoRegisterDevice: newFDOClient()") + log.Info().Err(err).Msg("fdoRegisterDevice: newFDOClient()") + return httperror.InternalServerError("fdoRegisterDevice: newFDOClient()", err) } guid, err := fdoClient.PostVoucher(ov) if err != nil { - logrus.WithError(err).Info("fdoRegisterDevice: PostVoucher()") + log.Info().Err(err).Msg("fdoRegisterDevice: PostVoucher()") + return httperror.InternalServerError("fdoRegisterDevice: PostVoucher()", err) } diff --git a/api/http/handler/hostmanagement/openamt/amtconfiguration.go b/api/http/handler/hostmanagement/openamt/amtconfiguration.go index 774814ab1..6ffe5667f 100644 --- a/api/http/handler/hostmanagement/openamt/amtconfiguration.go +++ b/api/http/handler/hostmanagement/openamt/amtconfiguration.go @@ -7,13 +7,13 @@ import ( "net/http" "strings" - "github.com/sirupsen/logrus" - "software.sslmate.com/src/go-pkcs12" - httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" portainer "github.com/portainer/portainer/api" + + "github.com/rs/zerolog/log" + "software.sslmate.com/src/go-pkcs12" ) type openAMTConfigurePayload struct { @@ -73,7 +73,8 @@ func (handler *Handler) openAMTConfigure(w http.ResponseWriter, r *http.Request) var payload openAMTConfigurePayload err := request.DecodeAndValidateJSONPayload(r, &payload) if err != nil { - logrus.WithError(err).Error("Invalid request payload") + log.Error().Err(err).Msg("invalid request payload") + return httperror.BadRequest("Invalid request payload", err) } @@ -142,17 +143,20 @@ func (handler *Handler) enableOpenAMT(configurationPayload openAMTConfigurePaylo err := handler.OpenAMTService.Configure(configuration) if err != nil { - logrus.WithError(err).Error("error configuring OpenAMT server") + log.Error().Err(err).Msg("error configuring OpenAMT server") + return err } err = handler.saveConfiguration(configuration) if err != nil { - logrus.WithError(err).Error("error updating OpenAMT configurations") + log.Error().Err(err).Msg("error updating OpenAMT configurations") + return err } - logrus.Info("OpenAMT successfully enabled") + log.Info().Msg("OpenAMT successfully enabled") + return nil } @@ -186,6 +190,7 @@ func (handler *Handler) disableOpenAMT() error { return err } - logrus.Info("OpenAMT successfully disabled") + log.Info().Msg("OpenAMT successfully disabled") + return nil } diff --git a/api/http/handler/hostmanagement/openamt/amtdevices.go b/api/http/handler/hostmanagement/openamt/amtdevices.go index 68bcdda6f..6df0db2c3 100644 --- a/api/http/handler/hostmanagement/openamt/amtdevices.go +++ b/api/http/handler/hostmanagement/openamt/amtdevices.go @@ -9,7 +9,8 @@ import ( "github.com/portainer/libhttp/response" portainer "github.com/portainer/portainer/api" bolterrors "github.com/portainer/portainer/api/dataservices/errors" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) // @id OpenAMTDevices @@ -67,6 +68,7 @@ func (payload *deviceActionPayload) Validate(r *http.Request) error { if payload.Action == "" { return errors.New("device action must be provided") } + return nil } @@ -93,7 +95,8 @@ func (handler *Handler) deviceAction(w http.ResponseWriter, r *http.Request) *ht var payload deviceActionPayload err = request.DecodeAndValidateJSONPayload(r, &payload) if err != nil { - logrus.WithError(err).Error("Invalid request payload") + log.Error().Err(err).Msg("invalid request payload") + return httperror.BadRequest("Invalid request payload", err) } @@ -104,7 +107,8 @@ func (handler *Handler) deviceAction(w http.ResponseWriter, r *http.Request) *ht err = handler.OpenAMTService.ExecuteDeviceAction(settings.OpenAMTConfiguration, deviceID, payload.Action) if err != nil { - logrus.WithError(err).Error("Error executing device action") + log.Error().Err(err).Msg("error executing device action") + return httperror.BadRequest("Error executing device action", err) } @@ -119,6 +123,7 @@ func (payload *deviceFeaturesPayload) Validate(r *http.Request) error { if payload.Features.UserConsent == "" { return errors.New("device user consent status must be provided") } + return nil } @@ -150,7 +155,8 @@ func (handler *Handler) deviceFeatures(w http.ResponseWriter, r *http.Request) * var payload deviceFeaturesPayload err = request.DecodeAndValidateJSONPayload(r, &payload) if err != nil { - logrus.WithError(err).Error("Invalid request payload") + log.Error().Err(err).Msg("invalid request payload") + return httperror.BadRequest("Invalid request payload", err) } @@ -166,7 +172,8 @@ func (handler *Handler) deviceFeatures(w http.ResponseWriter, r *http.Request) * token, err := handler.OpenAMTService.EnableDeviceFeatures(settings.OpenAMTConfiguration, deviceID, payload.Features) if err != nil { - logrus.WithError(err).Error("Error executing device action") + log.Error().Err(err).Msg("error executing device action") + return httperror.BadRequest("Error executing device action", err) } @@ -174,5 +181,6 @@ func (handler *Handler) deviceFeatures(w http.ResponseWriter, r *http.Request) * Server: settings.OpenAMTConfiguration.MPSServer, Token: token, } + return response.JSON(w, authorizationResponse) } diff --git a/api/http/handler/hostmanagement/openamt/amtrpc.go b/api/http/handler/hostmanagement/openamt/amtrpc.go index b1065cb81..a4922d276 100644 --- a/api/http/handler/hostmanagement/openamt/amtrpc.go +++ b/api/http/handler/hostmanagement/openamt/amtrpc.go @@ -4,24 +4,23 @@ import ( "context" "encoding/json" "fmt" - "github.com/portainer/portainer/api/hostmanagement/openamt" "io/ioutil" - "log" "net/http" "time" - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/api/types/filters" - - "github.com/docker/docker/api/types/network" - "github.com/docker/docker/client" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" portainer "github.com/portainer/portainer/api" bolterrors "github.com/portainer/portainer/api/dataservices/errors" - "github.com/sirupsen/logrus" + "github.com/portainer/portainer/api/hostmanagement/openamt" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/filters" + "github.com/docker/docker/api/types/network" + "github.com/docker/docker/client" + "github.com/rs/zerolog/log" ) type HostInfo struct { @@ -60,7 +59,7 @@ func (handler *Handler) openAMTHostInfo(w http.ResponseWriter, r *http.Request) return httperror.BadRequest("Invalid environment identifier route variable", err) } - logrus.WithField("endpointID", endpointID).Info("OpenAMTHostInfo") + log.Info().Int("endpointID", endpointID).Msg("OpenAMTHostInfo") endpoint, err := handler.DataStore.Endpoint().Endpoint(portainer.EndpointID(endpointID)) if err == bolterrors.ErrObjectNotFound { @@ -121,6 +120,7 @@ func (handler *Handler) PullAndRunContainer(ctx context.Context, endpoint *porta if err != nil { return "Could not run container", err } + return output, nil } @@ -133,18 +133,20 @@ func (handler *Handler) PullAndRunContainer(ctx context.Context, endpoint *porta func pullImage(ctx context.Context, docker *client.Client, imageName string) error { out, err := docker.ImagePull(ctx, imageName, types.ImagePullOptions{}) if err != nil { - logrus.WithError(err).WithField("imageName", imageName).Error("Could not pull image from registry") + log.Error().Str("image_name", imageName).Err(err).Msg("could not pull image from registry") + return err } defer out.Close() outputBytes, err := ioutil.ReadAll(out) if err != nil { - logrus.WithError(err).WithField("imageName", imageName).Error("Could not read image pull output") + log.Error().Str("image_name", imageName).Err(err).Msg("could not read image pull output") + return err } - log.Printf("%s imaged pulled with output:\n%s", imageName, string(outputBytes)) + log.Debug().Str("image_name", imageName).Str("output", string(outputBytes)).Msg("image pulled") return nil } @@ -158,14 +160,24 @@ func runContainer(ctx context.Context, docker *client.Client, imageName, contain opts.Filters.Add("name", containerName) existingContainers, err := docker.ContainerList(ctx, opts) if err != nil { - logrus.WithError(err).WithField("imagename", imageName).WithField("containername", containerName).Error("listing existing container") + log.Error(). + Str("image_name", imageName). + Str("container_name", containerName). + Err(err). + Msg("listing existing container") + return "", err } if len(existingContainers) > 0 { err = docker.ContainerRemove(ctx, existingContainers[0].ID, types.ContainerRemoveOptions{Force: true}) if err != nil { - logrus.WithError(err).WithField("imagename", imageName).WithField("containername", containerName).Error("removing existing container") + log.Error(). + Str("image_name", imageName). + Str("container_name", containerName). + Err(err). + Msg("removing existing container") + return "", err } } @@ -188,50 +200,82 @@ func runContainer(ctx context.Context, docker *client.Client, imageName, contain nil, containerName, ) + if err != nil { - logrus.WithError(err).WithField("imagename", imageName).WithField("containername", containerName).Error("creating container") - return "", err - } - err = docker.ContainerStart(ctx, created.ID, types.ContainerStartOptions{}) - if err != nil { - logrus.WithError(err).WithField("imagename", imageName).WithField("containername", containerName).Error("starting container") + log.Error(). + Str("image_name", imageName). + Str("container_name", containerName). + Err(err). + Msg("creating container") + return "", err } - log.Printf("%s container created and started\n", containerName) + err = docker.ContainerStart(ctx, created.ID, types.ContainerStartOptions{}) + if err != nil { + log.Error(). + Str("image_name", imageName). + Str("container_name", containerName). + Err(err). + Msg("starting container") + + return "", err + } + + log.Debug().Str("container_name", containerName).Msg("container created and started") statusCh, errCh := docker.ContainerWait(ctx, created.ID, container.WaitConditionNotRunning) var statusCode int64 select { case err := <-errCh: if err != nil { - logrus.WithError(err).WithField("imagename", imageName).WithField("containername", containerName).Error("starting container") + log.Error(). + Str("image_name", imageName). + Str("container_name", containerName). + Err(err). + Msg("starting container") + return "", err } case status := <-statusCh: statusCode = status.StatusCode } - logrus.WithField("status", statusCode).Debug("container wait status") + + log.Debug().Int64("status", statusCode).Msg("container wait status") out, err := docker.ContainerLogs(ctx, created.ID, types.ContainerLogsOptions{ShowStdout: true}) if err != nil { - logrus.WithError(err).WithField("imagename", imageName).WithField("containername", containerName).Error("getting container log") + log.Error().Err(err).Str("image_name", imageName).Str("container_name", containerName).Msg("getting container log") + return "", err } err = docker.ContainerRemove(ctx, created.ID, types.ContainerRemoveOptions{}) if err != nil { - logrus.WithError(err).WithField("imagename", imageName).WithField("containername", containerName).Error("removing container") + log.Error(). + Str("image_name", imageName). + Str("container_name", containerName). + Err(err). + Msg("removing container") + return "", err } outputBytes, err := ioutil.ReadAll(out) if err != nil { - logrus.WithError(err).WithField("imagename", imageName).WithField("containername", containerName).Error("read container output") + log.Error(). + Str("image_name", imageName). + Str("container_name", containerName). + Err(err). + Msg("read container output") + return "", err } - log.Printf("%s container finished with output:\n%s", containerName, string(outputBytes)) + log.Debug(). + Str("container_name", containerName). + Str("output", string(outputBytes)). + Msg("container finished with output") return string(outputBytes), nil } @@ -269,6 +313,7 @@ func (handler *Handler) deactivateDevice(endpoint *portainer.Endpoint, settings "-u", fmt.Sprintf("wss://%s/activate", config.MPSServer), "-password", config.MPSPassword, } + _, err := handler.PullAndRunContainer(ctx, endpoint, rpcGoImageName, rpcGoContainerName, cmdLine) if err != nil { return err diff --git a/api/http/handler/stacks/autoupdate.go b/api/http/handler/stacks/autoupdate.go index 9595d7cd6..1b6fbf6db 100644 --- a/api/http/handler/stacks/autoupdate.go +++ b/api/http/handler/stacks/autoupdate.go @@ -1,7 +1,6 @@ package stacks import ( - "log" "time" httperror "github.com/portainer/libhttp/error" @@ -9,6 +8,8 @@ import ( "github.com/portainer/portainer/api/dataservices" "github.com/portainer/portainer/api/scheduler" "github.com/portainer/portainer/api/stacks" + + "github.com/rs/zerolog/log" ) func startAutoupdate(stackID portainer.StackID, interval string, scheduler *scheduler.Scheduler, stackDeployer stacks.StackDeployer, datastore dataservices.DataStore, gitService portainer.GitService) (jobID string, e *httperror.HandlerError) { @@ -30,6 +31,6 @@ func stopAutoupdate(stackID portainer.StackID, jobID string, scheduler scheduler } if err := scheduler.StopJob(jobID); err != nil { - log.Printf("[WARN] could not stop the job for the stack %v", stackID) + log.Warn().Int("stack_id", int(stackID)).Msg("could not stop the job for the stack") } } diff --git a/api/http/handler/stacks/create_compose_stack.go b/api/http/handler/stacks/create_compose_stack.go index 728acf739..d91b358e6 100644 --- a/api/http/handler/stacks/create_compose_stack.go +++ b/api/http/handler/stacks/create_compose_stack.go @@ -2,7 +2,6 @@ package stacks import ( "fmt" - "log" "net/http" "strconv" "time" @@ -16,6 +15,8 @@ import ( gittypes "github.com/portainer/portainer/api/git/types" "github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/internal/stackutils" + + "github.com/rs/zerolog/log" ) type composeStackFromFileContentPayload struct { @@ -44,6 +45,7 @@ func (handler *Handler) checkAndCleanStackDupFromSwarm(w http.ResponseWriter, r if err != nil { return err } + // stop scheduler updates of the stack before removal if stack.AutoUpdate != nil { stopAutoupdate(stack.ID, stack.AutoUpdate.JobID, *handler.Scheduler) @@ -57,16 +59,21 @@ func (handler *Handler) checkAndCleanStackDupFromSwarm(w http.ResponseWriter, r if resourceControl != nil { err = handler.DataStore.ResourceControl().DeleteResourceControl(resourceControl.ID) if err != nil { - log.Printf("[ERROR] [Stack] Unable to remove the associated resource control from the database for stack: [%+v].", stack) + log.Error(). + Str("stack", fmt.Sprintf("%+v", stack)). + Msg("unable to remove the associated resource control from the database for stack") } } if exists, _ := handler.FileService.FileExists(stack.ProjectPath); exists { err = handler.FileService.RemoveDirectory(stack.ProjectPath) if err != nil { - log.Printf("Unable to remove stack files from disk for stack: [%+v].", stack) + log.Warn(). + Str("stack", fmt.Sprintf("%+v", stack)). + Msg("unable to remove stack files from disk for stack") } } + return nil } diff --git a/api/http/handler/stacks/stack_create.go b/api/http/handler/stacks/stack_create.go index 566ed033f..5a4c5cad8 100644 --- a/api/http/handler/stacks/stack_create.go +++ b/api/http/handler/stacks/stack_create.go @@ -1,12 +1,8 @@ package stacks import ( - "log" "net/http" - "github.com/docker/cli/cli/compose/loader" - "github.com/docker/cli/cli/compose/types" - "github.com/pkg/errors" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" @@ -14,6 +10,11 @@ import ( "github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/internal/authorization" "github.com/portainer/portainer/api/internal/stackutils" + + "github.com/docker/cli/cli/compose/loader" + "github.com/docker/cli/cli/compose/types" + "github.com/pkg/errors" + "github.com/rs/zerolog/log" ) func (handler *Handler) cleanUp(stack *portainer.Stack, doCleanUp *bool) error { @@ -23,8 +24,9 @@ func (handler *Handler) cleanUp(stack *portainer.Stack, doCleanUp *bool) error { err := handler.FileService.RemoveDirectory(stack.ProjectPath) if err != nil { - log.Printf("http error: Unable to cleanup stack creation (err=%s)\n", err) + log.Error().Err(err).Msg("unable to cleanup stack creation") } + return nil } diff --git a/api/http/handler/stacks/stack_update.go b/api/http/handler/stacks/stack_update.go index e2fc7eb48..970434aab 100644 --- a/api/http/handler/stacks/stack_update.go +++ b/api/http/handler/stacks/stack_update.go @@ -1,14 +1,10 @@ package stacks import ( - "log" "net/http" "strconv" "time" - "github.com/pkg/errors" - - "github.com/asaskevich/govalidator" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" @@ -16,6 +12,10 @@ import ( httperrors "github.com/portainer/portainer/api/http/errors" "github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/internal/stackutils" + + "github.com/asaskevich/govalidator" + "github.com/pkg/errors" + "github.com/rs/zerolog/log" ) type updateComposeStackPayload struct { @@ -197,7 +197,7 @@ func (handler *Handler) updateComposeStack(r *http.Request, stack *portainer.Sta _, err = handler.FileService.UpdateStoreStackFileFromBytes(stackFolder, stack.EntryPoint, []byte(payload.StackFileContent)) if err != nil { if rollbackErr := handler.FileService.RollbackStackFile(stackFolder, stack.EntryPoint); rollbackErr != nil { - log.Printf("[WARN] [stack,update] [message: rollback stack file error] [err: %s]", rollbackErr) + log.Warn().Err(rollbackErr).Msg("rollback stack file error") } return httperror.InternalServerError("Unable to persist updated Compose file on disk", err) @@ -206,7 +206,7 @@ func (handler *Handler) updateComposeStack(r *http.Request, stack *portainer.Sta config, configErr := handler.createComposeDeployConfig(r, stack, endpoint, payload.PullImage) if configErr != nil { if rollbackErr := handler.FileService.RollbackStackFile(stackFolder, stack.EntryPoint); rollbackErr != nil { - log.Printf("[WARN] [stack,update] [message: rollback stack file error] [err: %s]", rollbackErr) + log.Warn().Err(rollbackErr).Msg("rollback stack file error") } return configErr @@ -215,7 +215,7 @@ func (handler *Handler) updateComposeStack(r *http.Request, stack *portainer.Sta err = handler.deployComposeStack(config, false) if err != nil { if rollbackErr := handler.FileService.RollbackStackFile(stackFolder, stack.EntryPoint); rollbackErr != nil { - log.Printf("[WARN] [stack,update] [message: rollback stack file error] [err: %s]", rollbackErr) + log.Warn().Err(rollbackErr).Msg("rollback stack file error") } return httperror.InternalServerError(err.Error(), err) @@ -248,7 +248,7 @@ func (handler *Handler) updateSwarmStack(r *http.Request, stack *portainer.Stack _, err = handler.FileService.UpdateStoreStackFileFromBytes(stackFolder, stack.EntryPoint, []byte(payload.StackFileContent)) if err != nil { if rollbackErr := handler.FileService.RollbackStackFile(stackFolder, stack.EntryPoint); rollbackErr != nil { - log.Printf("[WARN] [swarm,stack,update] [message: rollback stack file error] [err: %s]", rollbackErr) + log.Warn().Err(rollbackErr).Msg("rollback stack file error") } return httperror.InternalServerError("Unable to persist updated Compose file on disk", err) @@ -257,7 +257,7 @@ func (handler *Handler) updateSwarmStack(r *http.Request, stack *portainer.Stack config, configErr := handler.createSwarmDeployConfig(r, stack, endpoint, payload.Prune, payload.PullImage) if configErr != nil { if rollbackErr := handler.FileService.RollbackStackFile(stackFolder, stack.EntryPoint); rollbackErr != nil { - log.Printf("[WARN] [swarm,stack,update] [message: rollback stack file error] [err: %s]", rollbackErr) + log.Warn().Err(rollbackErr).Msg("rollback stack file error") } return configErr @@ -266,7 +266,7 @@ func (handler *Handler) updateSwarmStack(r *http.Request, stack *portainer.Stack err = handler.deploySwarmStack(config) if err != nil { if rollbackErr := handler.FileService.RollbackStackFile(stackFolder, stack.EntryPoint); rollbackErr != nil { - log.Printf("[WARN] [swarm,stack,update] [message: rollback stack file error] [err: %s]", rollbackErr) + log.Warn().Err(rollbackErr).Msg("rollback stack file error") } return httperror.InternalServerError(err.Error(), err) diff --git a/api/http/handler/stacks/stack_update_git_redeploy.go b/api/http/handler/stacks/stack_update_git_redeploy.go index cb227115d..2ecfe5da2 100644 --- a/api/http/handler/stacks/stack_update_git_redeploy.go +++ b/api/http/handler/stacks/stack_update_git_redeploy.go @@ -2,7 +2,6 @@ package stacks import ( "fmt" - "log" "net/http" "time" @@ -16,6 +15,8 @@ import ( "github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/internal/stackutils" k "github.com/portainer/portainer/api/kubernetes" + + "github.com/rs/zerolog/log" ) type stackGitRedployPayload struct { @@ -156,7 +157,7 @@ func (handler *Handler) stackGitRedeploy(w http.ResponseWriter, r *http.Request) if err != nil { restoreError := filesystem.MoveDirectory(backupProjectPath, stack.ProjectPath) if restoreError != nil { - log.Printf("[WARN] [http,stacks,git] [error: %s] [message: failed restoring backup folder]", restoreError) + log.Warn().Err(restoreError).Msg("failed restoring backup folder") } return httperror.InternalServerError("Unable to clone git repository", err) @@ -165,7 +166,7 @@ func (handler *Handler) stackGitRedeploy(w http.ResponseWriter, r *http.Request) defer func() { err = handler.FileService.RemoveDirectory(backupProjectPath) if err != nil { - log.Printf("[WARN] [http,stacks,git] [error: %s] [message: unable to remove git repository directory]", err) + log.Warn().Err(err).Msg("unable to remove git repository directory") } }() diff --git a/api/http/handler/stacks/update_kubernetes_stack.go b/api/http/handler/stacks/update_kubernetes_stack.go index 28b0eb447..fdbeec69a 100644 --- a/api/http/handler/stacks/update_kubernetes_stack.go +++ b/api/http/handler/stacks/update_kubernetes_stack.go @@ -3,13 +3,10 @@ package stacks import ( "fmt" "io/ioutil" - "log" "net/http" "os" "strconv" - "github.com/asaskevich/govalidator" - "github.com/pkg/errors" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" portainer "github.com/portainer/portainer/api" @@ -17,6 +14,10 @@ import ( gittypes "github.com/portainer/portainer/api/git/types" "github.com/portainer/portainer/api/http/security" k "github.com/portainer/portainer/api/kubernetes" + + "github.com/asaskevich/govalidator" + "github.com/pkg/errors" + "github.com/rs/zerolog/log" ) type kubernetesFileStackUpdatePayload struct { @@ -128,7 +129,7 @@ func (handler *Handler) updateKubernetesStack(r *http.Request, stack *portainer. projectPath, err := handler.FileService.UpdateStoreStackFileFromBytes(stackFolder, stack.EntryPoint, []byte(payload.StackFileContent)) if err != nil { if rollbackErr := handler.FileService.RollbackStackFile(stackFolder, stack.EntryPoint); rollbackErr != nil { - log.Printf("[WARN] [kubernetes,stack,update] [message: rollback stack file error] [err: %s]", rollbackErr) + log.Warn().Err(rollbackErr).Msg("rollback stack file error") } fileType := "Manifest" diff --git a/api/http/handler/stacks/webhook_invoke.go b/api/http/handler/stacks/webhook_invoke.go index ef262e85f..0ac5a1a99 100644 --- a/api/http/handler/stacks/webhook_invoke.go +++ b/api/http/handler/stacks/webhook_invoke.go @@ -3,15 +3,13 @@ package stacks import ( "net/http" - "github.com/gofrs/uuid" - "github.com/sirupsen/logrus" - - "github.com/portainer/libhttp/response" - - "github.com/portainer/portainer/api/stacks" - httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" + "github.com/portainer/libhttp/response" + "github.com/portainer/portainer/api/stacks" + + "github.com/gofrs/uuid" + "github.com/rs/zerolog/log" ) // @id WebhookInvoke @@ -36,6 +34,7 @@ func (handler *Handler) webhookInvoke(w http.ResponseWriter, r *http.Request) *h if handler.DataStore.IsErrObjectNotFound(err) { statusCode = http.StatusNotFound } + return &httperror.HandlerError{StatusCode: statusCode, Message: "Unable to find the stack by webhook ID", Err: err} } @@ -43,7 +42,9 @@ func (handler *Handler) webhookInvoke(w http.ResponseWriter, r *http.Request) *h if _, ok := err.(*stacks.StackAuthorMissingErr); ok { return &httperror.HandlerError{StatusCode: http.StatusConflict, Message: "Autoupdate for the stack isn't available", Err: err} } - logrus.WithError(err).Error("failed to update the stack") + + log.Error().Err(err).Msg("failed to update the stack") + return httperror.InternalServerError("Failed to update the stack", err) } @@ -57,7 +58,6 @@ func retrieveUUIDRouteVariableValue(r *http.Request, name string) (uuid.UUID, er } uid, err := uuid.FromString(webhookID) - if err != nil { return uuid.Nil, err } diff --git a/api/http/handler/status/version.go b/api/http/handler/status/version.go index 27de4277a..44101a385 100644 --- a/api/http/handler/status/version.go +++ b/api/http/handler/status/version.go @@ -5,14 +5,13 @@ import ( "net/http" "strconv" - "github.com/coreos/go-semver/semver" - + "github.com/portainer/libhttp/response" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/build" "github.com/portainer/portainer/api/http/client" - "github.com/portainer/libhttp/response" - log "github.com/sirupsen/logrus" + "github.com/coreos/go-semver/semver" + "github.com/rs/zerolog/log" ) type versionResponse struct { @@ -71,7 +70,8 @@ func (handler *Handler) version(w http.ResponseWriter, r *http.Request) { func getLatestVersion() string { motd, err := client.Get(portainer.VersionCheckURL, 5) if err != nil { - log.WithError(err).Debug("couldn't fetch latest Portainer release version") + log.Debug().Err(err).Msg("couldn't fetch latest Portainer release version") + return "" } @@ -81,7 +81,8 @@ func getLatestVersion() string { err = json.Unmarshal(motd, &data) if err != nil { - log.WithError(err).Debug("couldn't parse latest Portainer version") + log.Debug().Err(err).Msg("couldn't parse latest Portainer version") + return "" } @@ -91,13 +92,15 @@ func getLatestVersion() string { func hasNewerVersion(currentVersion, latestVersion string) bool { currentVersionSemver, err := semver.NewVersion(currentVersion) if err != nil { - log.WithField("version", currentVersion).Debug("current Portainer version isn't a semver") + log.Debug().Str("version", currentVersion).Msg("current Portainer version isn't a semver") + return false } latestVersionSemver, err := semver.NewVersion(latestVersion) if err != nil { - log.WithField("version", latestVersion).Debug("latest Portainer version isn't a semver") + log.Debug().Str("version", latestVersion).Msg("latest Portainer version isn't a semver") + return false } diff --git a/api/http/handler/templates/template_file.go b/api/http/handler/templates/template_file.go index 1f4585dbe..102a76644 100644 --- a/api/http/handler/templates/template_file.go +++ b/api/http/handler/templates/template_file.go @@ -3,7 +3,6 @@ package templates import ( "encoding/json" "errors" - "log" "net/http" "github.com/asaskevich/govalidator" @@ -11,6 +10,8 @@ import ( "github.com/portainer/libhttp/request" "github.com/portainer/libhttp/response" portainer "github.com/portainer/portainer/api" + + "github.com/rs/zerolog/log" ) type filePayload struct { @@ -114,7 +115,8 @@ func (handler *Handler) templateFile(w http.ResponseWriter, r *http.Request) *ht func (handler *Handler) cleanUp(projectPath string) error { err := handler.FileService.RemoveDirectory(projectPath) if err != nil { - log.Printf("http error: Unable to cleanup stack creation (err=%s)\n", err) + log.Debug().Err(err).Msg("HTTP error: unable to cleanup stack creation") } + return nil } diff --git a/api/http/handler/websocket/pod.go b/api/http/handler/websocket/pod.go index 5832e4439..153506126 100644 --- a/api/http/handler/websocket/pod.go +++ b/api/http/handler/websocket/pod.go @@ -3,17 +3,17 @@ package websocket import ( "fmt" "io" - "log" "net/http" "strings" - "github.com/portainer/portainer/api/http/security" - - "github.com/gorilla/websocket" httperror "github.com/portainer/libhttp/error" "github.com/portainer/libhttp/request" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/http/proxy/factory/kubernetes" + "github.com/portainer/portainer/api/http/security" + + "github.com/gorilla/websocket" + "github.com/rs/zerolog/log" ) // @summary Execute a websocket on pod @@ -149,7 +149,8 @@ func (handler *Handler) hijackPodExecStartOperation( // websocket client successfully disconnected if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseNoStatusReceived) { - log.Printf("websocket error: %s \n", err.Error()) + log.Debug().Err(err).Msg("websocket error") + return nil } diff --git a/api/http/offlinegate/offlinegate.go b/api/http/offlinegate/offlinegate.go index e87dbefa7..992d3f199 100644 --- a/api/http/offlinegate/offlinegate.go +++ b/api/http/offlinegate/offlinegate.go @@ -1,12 +1,13 @@ package offlinegate import ( - "log" "net/http" "strings" "time" httperror "github.com/portainer/libhttp/error" + + "github.com/rs/zerolog/log" lock "github.com/viney-shih/go-lock" ) @@ -40,7 +41,7 @@ func (o *OfflineGate) WaitingMiddleware(timeout time.Duration, next http.Handler } if !o.lock.RTryLockWithTimeout(timeout) { - log.Println("error: Timeout waiting for the offline gate to signal") + log.Error().Msg("timeout waiting for the offline gate to signal") httperror.WriteError(w, http.StatusRequestTimeout, "Timeout waiting for the offline gate to signal", http.ErrHandlerTimeout) return } diff --git a/api/http/proxy/factory/agent.go b/api/http/proxy/factory/agent.go index 630c880fc..df74dc3dd 100644 --- a/api/http/proxy/factory/agent.go +++ b/api/http/proxy/factory/agent.go @@ -2,16 +2,17 @@ package factory import ( "fmt" - "log" "net" "net/http" - "github.com/pkg/errors" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/crypto" "github.com/portainer/portainer/api/http/proxy/factory/agent" "github.com/portainer/portainer/api/internal/endpointutils" "github.com/portainer/portainer/api/internal/url" + + "github.com/pkg/errors" + "github.com/rs/zerolog/log" ) // ProxyServer provide an extended proxy with a local server to forward requests @@ -24,7 +25,7 @@ type ProxyServer struct { func (factory *ProxyFactory) NewAgentProxy(endpoint *portainer.Endpoint) (*ProxyServer, error) { urlString := endpoint.URL - if endpointutils.IsEdgeEndpoint((endpoint)) { + if endpointutils.IsEdgeEndpoint(endpoint) { tunnel, err := factory.reverseTunnelService.GetActiveTunnel(endpoint) if err != nil { return nil, errors.Wrap(err, "failed starting tunnel") @@ -77,15 +78,16 @@ func (proxy *ProxyServer) start() error { } proxy.Port = listener.Addr().(*net.TCPAddr).Port + go func() { proxyHost := fmt.Sprintf("127.0.0.1:%d", proxy.Port) - log.Printf("Starting Proxy server on %s...\n", proxyHost) + log.Debug().Str("host", proxyHost).Msg("starting proxy server") err := proxy.server.Serve(listener) - log.Printf("Exiting Proxy server %s\n", proxyHost) + log.Debug().Str("host", proxyHost).Msg("exiting proxy server") if err != nil && err != http.ErrServerClosed { - log.Printf("Proxy server %s exited with an error: %s\n", proxyHost, err) + log.Debug().Str("host", proxyHost).Err(err).Msg("proxy server exited with an error") } }() diff --git a/api/http/proxy/factory/azure/access_control.go b/api/http/proxy/factory/azure/access_control.go index 6c6bcff15..e2ebb41f0 100644 --- a/api/http/proxy/factory/azure/access_control.go +++ b/api/http/proxy/factory/azure/access_control.go @@ -1,12 +1,13 @@ package azure import ( - "log" "net/http" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/internal/authorization" + + "github.com/rs/zerolog/log" ) func (transport *Transport) createAzureRequestContext(request *http.Request) (*azureRequestContext, error) { @@ -65,7 +66,11 @@ func (transport *Transport) createPrivateResourceControl( err := transport.dataStore.ResourceControl().Create(resourceControl) if err != nil { - log.Printf("[ERROR] [http,proxy,azure,transport] [message: unable to persist resource control] [resource: %s] [err: %s]", resourceIdentifier, err) + log.Error(). + Str("resource", resourceIdentifier). + Err(err). + Msg("unable to persist resource control") + return nil, err } @@ -76,6 +81,7 @@ func (transport *Transport) userCanDeleteContainerGroup(request *http.Request, c if context.isAdmin { return true } + resourceIdentifier := request.URL.Path resourceControl := transport.findResourceControl(resourceIdentifier, context) return authorization.UserCanAccessResource(context.userID, context.userTeamIDs, resourceControl) @@ -100,7 +106,7 @@ func (transport *Transport) decorateContainerGroup(containerGroup map[string]int containerGroup = decorateObject(containerGroup, resourceControl) } } else { - log.Printf("[WARN] [http,proxy,azure,decorate] [message: unable to find resource id property in container group]") + log.Warn().Msg("unable to find resource id property in container group") } return containerGroup @@ -137,7 +143,7 @@ func (transport *Transport) removeResourceControl(containerGroup map[string]inte return err } } else { - log.Printf("[WARN] [http,proxy,azure] [message: missign ID in container group]") + log.Debug().Msg("missing ID in container group") } return nil diff --git a/api/http/proxy/factory/docker.go b/api/http/proxy/factory/docker.go index aca8264c8..0b43f59da 100644 --- a/api/http/proxy/factory/docker.go +++ b/api/http/proxy/factory/docker.go @@ -3,7 +3,6 @@ package factory import ( "fmt" "io" - "log" "net/http" "strings" @@ -12,6 +11,8 @@ import ( "github.com/portainer/portainer/api/crypto" "github.com/portainer/portainer/api/http/proxy/factory/docker" "github.com/portainer/portainer/api/internal/url" + + "github.com/rs/zerolog/log" ) func (factory *ProxyFactory) newDockerProxy(endpoint *portainer.Endpoint) (http.Handler, error) { @@ -107,6 +108,6 @@ func (proxy *dockerLocalProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) w.WriteHeader(res.StatusCode) if _, err := io.Copy(w, res.Body); err != nil { - log.Printf("proxy error: %s\n", err) + log.Debug().Err(err).Msg("proxy error") } } diff --git a/api/http/proxy/factory/docker/access_control.go b/api/http/proxy/factory/docker/access_control.go index 1d097ecc1..159435c26 100644 --- a/api/http/proxy/factory/docker/access_control.go +++ b/api/http/proxy/factory/docker/access_control.go @@ -1,16 +1,15 @@ package docker import ( - "log" "net/http" "strings" - "github.com/portainer/portainer/api/internal/stackutils" - + portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/http/proxy/factory/utils" "github.com/portainer/portainer/api/internal/authorization" + "github.com/portainer/portainer/api/internal/stackutils" - portainer "github.com/portainer/portainer/api" + "github.com/rs/zerolog/log" ) const ( @@ -79,7 +78,11 @@ func (transport *Transport) newResourceControlFromPortainerLabels(labelsObject m for _, name := range teamNames { team, err := transport.dataStore.Team().TeamByName(name) if err != nil { - log.Printf("[WARN] [http,proxy,docker] [message: unknown team name in access control label, ignoring access control rule for this team] [name: %s] [resource_id: %s]", name, resourceID) + log.Warn(). + Str("name", name). + Str("resource_id", resourceID). + Msg("unknown team name in access control label, ignoring access control rule for this team") + continue } @@ -89,7 +92,11 @@ func (transport *Transport) newResourceControlFromPortainerLabels(labelsObject m for _, name := range userNames { user, err := transport.dataStore.User().UserByUsername(name) if err != nil { - log.Printf("[WARN] [http,proxy,docker] [message: unknown user name in access control label, ignoring access control rule for this user] [name: %s] [resource_id: %s]", name, resourceID) + log.Warn(). + Str("name", name). + Str("resource_id", resourceID). + Msg("unknown user name in access control label, ignoring access control rule for this user") + continue } @@ -114,7 +121,11 @@ func (transport *Transport) createPrivateResourceControl(resourceIdentifier stri err := transport.dataStore.ResourceControl().Create(resourceControl) if err != nil { - log.Printf("[ERROR] [http,proxy,docker,transport] [message: unable to persist resource control] [resource: %s] [err: %s]", resourceIdentifier, err) + log.Error(). + Str("resource", resourceIdentifier). + Err(err). + Msg("unable to persist resource control") + return nil, err } @@ -148,7 +159,10 @@ func (transport *Transport) getInheritedResourceControlFromServiceOrStack(resour func (transport *Transport) applyAccessControlOnResource(parameters *resourceOperationParameters, responseObject map[string]interface{}, response *http.Response, executor *operationExecutor) error { if responseObject[parameters.resourceIdentifierAttribute] == nil { - log.Printf("[WARN] [message: unable to find resource identifier property in resource object] [identifier_attribute: %s]", parameters.resourceIdentifierAttribute) + log.Warn(). + Str("identifier_attribute", parameters.resourceIdentifierAttribute). + Msg("unable to find resource identifier property in resource object") + return nil } @@ -195,7 +209,10 @@ func (transport *Transport) decorateResourceList(parameters *resourceOperationPa resourceObject := resource.(map[string]interface{}) if resourceObject[parameters.resourceIdentifierAttribute] == nil { - log.Printf("[WARN] [http,proxy,docker,decorate] [message: unable to find resource identifier property in resource list element] [identifier_attribute: %s]", parameters.resourceIdentifierAttribute) + log.Warn(). + Str("identifier_attribute", parameters.resourceIdentifierAttribute). + Msg("unable to find resource identifier property in resource list element") + continue } @@ -232,7 +249,10 @@ func (transport *Transport) filterResourceList(parameters *resourceOperationPara for _, resource := range resourceData { resourceObject := resource.(map[string]interface{}) if resourceObject[parameters.resourceIdentifierAttribute] == nil { - log.Printf("[WARN] [http,proxy,docker,filter] [message: unable to find resource identifier property in resource list element] [identifier_attribute: %s]", parameters.resourceIdentifierAttribute) + log.Warn(). + Str("identifier_attribute", parameters.resourceIdentifierAttribute). + Msg("unable to find resource identifier property in resource list element") + continue } diff --git a/api/http/proxy/factory/docker/build.go b/api/http/proxy/factory/docker/build.go index 5c2da2650..6b5dfa91f 100644 --- a/api/http/proxy/factory/docker/build.go +++ b/api/http/proxy/factory/docker/build.go @@ -5,11 +5,12 @@ import ( "encoding/json" "errors" "io/ioutil" - "log" "mime" "net/http" "github.com/portainer/portainer/api/archive" + + "github.com/rs/zerolog/log" ) const OneMegabyte = 1024768 @@ -78,7 +79,7 @@ func buildOperation(request *http.Request) error { defer f.Close() - log.Printf("[INFO] [http,proxy,docker] [message: upload the file to build image] [filename: %s] [size: %d]", hdr.Filename, hdr.Size) + log.Info().Str("filename", hdr.Filename).Int64("size", hdr.Size).Msg("upload the file to build image") content, err := ioutil.ReadAll(f) if err != nil { diff --git a/api/http/proxy/factory/docker/transport.go b/api/http/proxy/factory/docker/transport.go index c04bb8a4e..439988a96 100644 --- a/api/http/proxy/factory/docker/transport.go +++ b/api/http/proxy/factory/docker/transport.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "io/ioutil" - "log" "net/http" "path" "regexp" @@ -21,6 +20,8 @@ import ( "github.com/portainer/portainer/api/http/proxy/factory/utils" "github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/internal/authorization" + + "github.com/rs/zerolog/log" ) var apiVersionRe = regexp.MustCompile(`(/v[0-9]\.[0-9]*)?`) @@ -422,6 +423,7 @@ func (transport *Transport) proxyImageRequest(request *http.Request) (*http.Resp func (transport *Transport) replaceRegistryAuthenticationHeader(request *http.Request) (*http.Response, error) { transport.decorateRegistryAuthenticationHeader(request) + return transport.decorateGenericResourceCreationOperation(request, serviceObjectIdentifier, portainer.ServiceResourceControl) } @@ -601,7 +603,8 @@ func (transport *Transport) decorateGenericResourceCreationResponse(response *ht } if responseObject[resourceIdentifierAttribute] == nil { - log.Printf("[ERROR] [proxy,docker]") + log.Error().Msg("missing identifier in Docker resource creation response") + return errors.New("missing identifier in Docker resource creation response") } @@ -754,6 +757,7 @@ func (transport *Transport) createOperationContext(request *http.Request) (*rest for _, membership := range teamMemberships { userTeamIDs = append(userTeamIDs, membership.TeamID) } + operationContext.userTeamIDs = userTeamIDs } diff --git a/api/http/proxy/factory/kubernetes/transport.go b/api/http/proxy/factory/kubernetes/transport.go index 1fcc13fd0..3c1471dd6 100644 --- a/api/http/proxy/factory/kubernetes/transport.go +++ b/api/http/proxy/factory/kubernetes/transport.go @@ -6,18 +6,18 @@ import ( "errors" "fmt" "io/ioutil" - "log" "net/http" "path" "regexp" "strconv" "strings" + portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/dataservices" "github.com/portainer/portainer/api/http/security" "github.com/portainer/portainer/api/kubernetes/cli" - portainer "github.com/portainer/portainer/api" + "github.com/rs/zerolog/log" ) type baseTransport struct { @@ -132,7 +132,10 @@ func (transport *baseTransport) getRoundTripToken(request *http.Request, tokenMa } else { token, err = tokenManager.GetUserServiceAccountToken(int(tokenData.ID), transport.endpoint.ID) if err != nil { - log.Printf("Failed retrieving service account token: %v", err) + log.Debug(). + Err(err). + Msg("failed retrieving service account token") + return "", err } } diff --git a/api/http/proxy/factory/utils/response.go b/api/http/proxy/factory/utils/response.go index dc73e5618..a4479b1c0 100644 --- a/api/http/proxy/factory/utils/response.go +++ b/api/http/proxy/factory/utils/response.go @@ -3,10 +3,12 @@ package utils import ( "bytes" "errors" + "fmt" "io/ioutil" - "log" "net/http" "strconv" + + "github.com/rs/zerolog/log" ) // GetResponseAsJSONObject returns the response content as a generic JSON object @@ -34,10 +36,17 @@ func GetResponseAsJSONArray(response *http.Response) ([]interface{}, error) { if responseObject["message"] != nil { return nil, errors.New(responseObject["message"].(string)) } - log.Printf("[ERROR] [http,proxy,response] [message: invalid response format, expecting JSON array] [response: %+v]", responseObject) + + log.Error(). + Str("response", fmt.Sprintf("%+v", responseObject)). + Msg("invalid response format, expecting JSON array") + return nil, errors.New("unable to parse response: expected JSON array, got JSON object") default: - log.Printf("[ERROR] [http,proxy,response] [message: invalid response format, expecting JSON array] [response: %+v]", responseObject) + log.Error(). + Str("response", fmt.Sprintf("%+v", responseObject)). + Msg("invalid response format, expecting JSON array") + return nil, errors.New("unable to parse response: expected JSON array") } } @@ -50,6 +59,7 @@ type errorResponse struct { func WriteAccessDeniedResponse() (*http.Response, error) { response := &http.Response{} err := RewriteResponse(response, errorResponse{Message: "access denied to resource"}, http.StatusForbidden) + return response, err } diff --git a/api/http/security/passwordStrengthCheck.go b/api/http/security/passwordStrengthCheck.go index 695ec1090..d216688ce 100644 --- a/api/http/security/passwordStrengthCheck.go +++ b/api/http/security/passwordStrengthCheck.go @@ -2,7 +2,8 @@ package security import ( portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/rs/zerolog/log" ) type PasswordStrengthChecker interface { @@ -23,7 +24,8 @@ func NewPasswordStrengthChecker(settings settingsService) *passwordStrengthCheck func (c *passwordStrengthChecker) Check(password string) bool { s, err := c.settings.Settings() if err != nil { - logrus.WithError(err).Warn("failed to fetch Portainer settings to validate user password") + log.Warn().Err(err).Msg("failed to fetch Portainer settings to validate user password") + return true } diff --git a/api/http/server.go b/api/http/server.go index 46b9d0aad..1a603e584 100644 --- a/api/http/server.go +++ b/api/http/server.go @@ -3,8 +3,6 @@ package http import ( "context" "crypto/tls" - "fmt" - "log" "net/http" "path/filepath" "time" @@ -64,6 +62,8 @@ import ( "github.com/portainer/portainer/api/kubernetes/cli" "github.com/portainer/portainer/api/scheduler" stackdeployer "github.com/portainer/portainer/api/stacks" + + "github.com/rs/zerolog/log" ) // Server implements the portainer.Server interface @@ -319,21 +319,22 @@ func (server *Server) Start() error { handler := adminMonitor.WithRedirect(offlineGate.WaitingMiddleware(time.Minute, server.Handler)) if server.HTTPEnabled { go func() { - log.Printf("[INFO] [http,server] [message: starting HTTP server on port %s]", server.BindAddress) + log.Info().Str("bind_address", server.BindAddress).Msg("starting HTTP server") httpServer := &http.Server{ Addr: server.BindAddress, Handler: handler, } go shutdown(server.ShutdownCtx, httpServer) + err := httpServer.ListenAndServe() if err != nil && err != http.ErrServerClosed { - log.Printf("[ERROR] [message: http server failed] [error: %s]", err) + log.Error().Err(err).Msg("HTTP server failed to start") } }() } - log.Printf("[INFO] [http,server] [message: starting HTTPS server on port %s]", server.BindAddressHTTPS) + log.Info().Str("bind_address", server.BindAddressHTTPS).Msg("starting HTTPS server") httpsServer := &http.Server{ Addr: server.BindAddressHTTPS, Handler: handler, @@ -345,18 +346,21 @@ func (server *Server) Start() error { } go shutdown(server.ShutdownCtx, httpsServer) + return httpsServer.ListenAndServeTLS("", "") } func shutdown(shutdownCtx context.Context, httpServer *http.Server) { <-shutdownCtx.Done() - log.Println("[DEBUG] [http,server] [message: shutting down http server]") + log.Debug().Msg("shutting down the HTTP server") shutdownTimeout, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() err := httpServer.Shutdown(shutdownTimeout) if err != nil { - fmt.Printf("[ERROR] [http,server] [message: failed shutdown http server] [error: %s]", err) + log.Error(). + Err(err). + Msg("failed to shut down the HTTP server") } } diff --git a/api/internal/registryutils/ecr_reg_token.go b/api/internal/registryutils/ecr_reg_token.go index c597c3d73..3e4451044 100644 --- a/api/internal/registryutils/ecr_reg_token.go +++ b/api/internal/registryutils/ecr_reg_token.go @@ -3,11 +3,11 @@ package registryutils import ( "time" - log "github.com/sirupsen/logrus" - portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/aws/ecr" "github.com/portainer/portainer/api/dataservices" + + "github.com/rs/zerolog/log" ) func isRegTokenValid(registry *portainer.Registry) (valid bool) { @@ -37,11 +37,11 @@ func parseRegToken(registry *portainer.Registry) (username, password string, err func EnsureRegTokenValid(dataStore dataservices.DataStore, registry *portainer.Registry) (err error) { if registry.Type == portainer.EcrRegistry { if isRegTokenValid(registry) { - log.Println("[DEBUG] [registry, GetEcrAccessToken] [message: current ECR token is still valid]") + log.Debug().Msg("current ECR token is still valid") } else { err = doGetRegToken(dataStore, registry) if err != nil { - log.Println("[DEBUG] [registry, GetEcrAccessToken] [message: refresh ECR token]") + log.Debug().Msg("refresh ECR token") } } } diff --git a/api/internal/snapshot/snapshot.go b/api/internal/snapshot/snapshot.go index f4572d7cd..4216aa3fb 100644 --- a/api/internal/snapshot/snapshot.go +++ b/api/internal/snapshot/snapshot.go @@ -4,13 +4,14 @@ import ( "context" "crypto/tls" "errors" - "log" "time" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/agent" "github.com/portainer/portainer/api/crypto" "github.com/portainer/portainer/api/dataservices" + + "github.com/rs/zerolog/log" ) // Service repesents a service to manage environment(endpoint) snapshots. @@ -149,7 +150,7 @@ func (service *Service) startSnapshotLoop() { err := service.snapshotEndpoints() if err != nil { - log.Printf("[ERROR] [internal,snapshot] [message: background schedule error (environment snapshot).] [error: %s]", err) + log.Error().Err(err).Msg("background schedule error (environment snapshot)") } for { @@ -157,10 +158,10 @@ func (service *Service) startSnapshotLoop() { case <-ticker.C: err := service.snapshotEndpoints() if err != nil { - log.Printf("[ERROR] [internal,snapshot] [message: background schedule error (environment snapshot).] [error: %s]", err) + log.Error().Err(err).Msg("background schedule error (environment snapshot)") } case <-service.shutdownCtx.Done(): - log.Println("[DEBUG] [internal,snapshot] [message: shutting down snapshotting]") + log.Debug().Msg("shutting down snapshotting") ticker.Stop() return case interval := <-service.snapshotIntervalCh: @@ -184,13 +185,21 @@ func (service *Service) snapshotEndpoints() error { latestEndpointReference, err := service.dataStore.Endpoint().Endpoint(endpoint.ID) if latestEndpointReference == nil { - log.Printf("background schedule error (environment snapshot). Environment not found inside the database anymore (endpoint=%s, URL=%s) (err=%s)\n", endpoint.Name, endpoint.URL, err) + log.Debug(). + Str("endpoint", endpoint.Name). + Str("URL", endpoint.URL).Err(err). + Msg("background schedule error (environment snapshot), environment not found inside the database anymore") + continue } latestEndpointReference.Status = portainer.EndpointStatusUp if snapshotError != nil { - log.Printf("background schedule error (environment snapshot). Unable to create snapshot (endpoint=%s, URL=%s) (err=%s)\n", endpoint.Name, endpoint.URL, snapshotError) + log.Debug(). + Str("endpoint", endpoint.Name). + Str("URL", endpoint.URL).Err(err). + Msg("background schedule error (environment snapshot), unable to create snapshot") + latestEndpointReference.Status = portainer.EndpointStatusDown } @@ -200,7 +209,11 @@ func (service *Service) snapshotEndpoints() error { err = service.dataStore.Endpoint().UpdateEndpoint(latestEndpointReference.ID, latestEndpointReference) if err != nil { - log.Printf("background schedule error (environment snapshot). Unable to update environment (endpoint=%s, URL=%s) (err=%s)\n", endpoint.Name, endpoint.URL, err) + log.Debug(). + Str("endpoint", endpoint.Name). + Str("URL", endpoint.URL).Err(err). + Msg("background schedule error (environment snapshot), unable to update environment") + continue } } diff --git a/api/internal/ssl/ssl.go b/api/internal/ssl/ssl.go index 71fa315c2..419b54ad0 100644 --- a/api/internal/ssl/ssl.go +++ b/api/internal/ssl/ssl.go @@ -3,15 +3,15 @@ package ssl import ( "context" "crypto/tls" - "log" "os" "time" - "github.com/pkg/errors" - "github.com/portainer/libcrypto" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/dataservices" + + "github.com/pkg/errors" + "github.com/rs/zerolog/log" ) // Service represents a service to manage SSL certificates @@ -45,7 +45,7 @@ func (service *Service) Init(host, certPath, keyPath string) error { settings, err := service.GetSSLSettings() if err != nil { - return errors.Wrap(err, "failed fetching ssl settings") + return errors.Wrap(err, "failed fetching SSL settings") } // certificates already exist @@ -77,7 +77,8 @@ func generateSelfSignedCertificates(ip, certPath, keyPath string) error { return errors.New("host can't be empty") } - log.Printf("[INFO] [internal,ssl] [message: no cert files found, generating self signed ssl certificates]") + log.Info().Msg("no cert files found, generating self signed SSL certificates") + return libcrypto.GenerateCertsForHost("localhost", ip, certPath, keyPath, time.Now().AddDate(5, 0, 0)) } diff --git a/api/jwt/jwt.go b/api/jwt/jwt.go index 54a1f03af..ec727e7e1 100644 --- a/api/jwt/jwt.go +++ b/api/jwt/jwt.go @@ -6,11 +6,12 @@ import ( "os" "time" - "github.com/golang-jwt/jwt" - "github.com/gorilla/securecookie" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/dataservices" - log "github.com/sirupsen/logrus" + + "github.com/golang-jwt/jwt" + "github.com/gorilla/securecookie" + "github.com/rs/zerolog/log" ) // scope represents JWT scopes that are supported in JWT claims. @@ -132,6 +133,7 @@ func (service *Service) ParseAndVerifyToken(token string) (*portainer.TokenData, if user.TokenIssueAt > cl.StandardClaims.IssuedAt { return nil, errInvalidJWTToken } + return &portainer.TokenData{ ID: portainer.UserID(cl.UserID), Username: cl.Username, @@ -152,6 +154,7 @@ func parseScope(token string) scope { } } } + return defaultScope } @@ -168,7 +171,7 @@ func (service *Service) generateSignedToken(data *portainer.TokenData, expiresAt if _, ok := os.LookupEnv("DOCKER_EXTENSION"); ok { // Set expiration to 99 years for docker desktop extension. - log.Infof("[message: detected docker desktop extension mode]") + log.Info().Msg("detected docker desktop extension mode") expiresAt = time.Now().Add(time.Hour * 8760 * 99).Unix() } diff --git a/api/kubernetes/cli/pod.go b/api/kubernetes/cli/pod.go index e916ca132..50c921bc2 100644 --- a/api/kubernetes/cli/pod.go +++ b/api/kubernetes/cli/pod.go @@ -3,11 +3,12 @@ package cli import ( "context" "fmt" - "log" "time" - "github.com/pkg/errors" portainer "github.com/portainer/portainer/api" + + "github.com/pkg/errors" + "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -78,11 +79,11 @@ func (kcl *KubeClient) CreateUserShellPod(ctx context.Context, serviceAccountNam go func() { select { case <-time.After(portainer.WebSocketKeepAlive): - log.Println("[DEBUG] [internal,kubernetes/pod] [message: pod removal schedule duration exceeded]") + log.Debug().Msg("pod removal schedule duration exceeded") kcl.cli.CoreV1().Pods(portainerNamespace).Delete(context.TODO(), shellPod.Name, metav1.DeleteOptions{}) case <-ctx.Done(): err := ctx.Err() - log.Printf("[DEBUG] [internal,kubernetes/pod] [message: context error: err=%s ]\n", err) + log.Debug().Err(err).Msg("context error") kcl.cli.CoreV1().Pods(portainerNamespace).Delete(context.TODO(), shellPod.Name, metav1.DeleteOptions{}) } }() @@ -93,7 +94,7 @@ func (kcl *KubeClient) CreateUserShellPod(ctx context.Context, serviceAccountNam // waitForPodStatus will wait until duration d (from now) for a pod to reach defined phase/status. // The pod status will be polled at specified delay until the pod reaches ready state. func (kcl *KubeClient) waitForPodStatus(ctx context.Context, phase v1.PodPhase, pod *v1.Pod) error { - log.Printf("[DEBUG] [internal,kubernetes/pod] [message: waiting for pod ready: pod=%s... ]\n", pod.Name) + log.Debug().Str("pod", pod.Name).Msg("waiting for pod ready") pollDelay := 500 * time.Millisecond for { diff --git a/api/kubernetes/kubeclusteraccess_service.go b/api/kubernetes/kubeclusteraccess_service.go index f2aa6f3d9..0b1e785d5 100644 --- a/api/kubernetes/kubeclusteraccess_service.go +++ b/api/kubernetes/kubeclusteraccess_service.go @@ -6,12 +6,12 @@ import ( "encoding/pem" "fmt" "io/ioutil" - "log" "strings" - "github.com/pkg/errors" portainer "github.com/portainer/portainer/api" - "github.com/sirupsen/logrus" + + "github.com/pkg/errors" + "github.com/rs/zerolog/log" ) // KubeClusterAccessService represents a service that is responsible for centralizing kube cluster access data @@ -45,7 +45,7 @@ var ( func NewKubeClusterAccessService(baseURL, httpsBindAddr, tlsCertPath string) KubeClusterAccessService { certificateAuthorityData, err := getCertificateAuthorityData(tlsCertPath) if err != nil { - log.Printf("[DEBUG] [internal,kubeconfig] [message: %s, generated KubeConfig will be insecure]", err.Error()) + log.Debug().Err(err).Msg("generated KubeConfig will be insecure") } return &kubeClusterAccessService{ @@ -106,7 +106,11 @@ func (service *kubeClusterAccessService) GetData(hostURL string, endpointID port baseURL = fmt.Sprintf("/%s/", strings.Trim(baseURL, "/")) } - logrus.Infof("[kubeconfig] [hostURL: %s, httpsBindAddr: %s, baseURL: %s]", hostURL, service.httpsBindAddr, baseURL) + log.Info(). + Str("host_URL", hostURL). + Str("HTTPS_bind_address", service.httpsBindAddr). + Str("base_URL", baseURL). + Msg("kubeconfig") clusterURL := hostURL + baseURL diff --git a/api/kubernetes/snapshot.go b/api/kubernetes/snapshot.go index e2fbb1d2c..39c4b1b8d 100644 --- a/api/kubernetes/snapshot.go +++ b/api/kubernetes/snapshot.go @@ -2,11 +2,12 @@ package kubernetes import ( "context" - "log" "time" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/kubernetes/cli" + + "github.com/rs/zerolog/log" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" ) @@ -42,12 +43,12 @@ func snapshot(cli *kubernetes.Clientset, endpoint *portainer.Endpoint) (*portain err := snapshotVersion(snapshot, cli) if err != nil { - log.Printf("[WARN] [kubernetes,snapshot] [message: unable to snapshot cluster version] [endpoint: %s] [err: %s]", endpoint.Name, err) + log.Warn().Str("endpoint", endpoint.Name).Err(err).Msg("unable to snapshot cluster version") } err = snapshotNodes(snapshot, cli) if err != nil { - log.Printf("[WARN] [kubernetes,snapshot] [message: unable to snapshot cluster nodes] [endpoint: %s] [err: %s]", endpoint.Name, err) + log.Warn().Str("endpoint", endpoint.Name).Err(err).Msg("unable to snapshot cluster nodes") } snapshot.Time = time.Now().Unix() diff --git a/api/oauth/oauth.go b/api/oauth/oauth.go index 59a5b3b36..3088ca821 100644 --- a/api/oauth/oauth.go +++ b/api/oauth/oauth.go @@ -9,12 +9,12 @@ import ( "net/url" "strings" - "golang.org/x/oauth2" + portainer "github.com/portainer/portainer/api" "github.com/golang-jwt/jwt" "github.com/pkg/errors" - portainer "github.com/portainer/portainer/api" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" + "golang.org/x/oauth2" ) // Service represents a service used to authenticate users against an authorization server @@ -31,18 +31,20 @@ func NewService() *Service { func (*Service) Authenticate(code string, configuration *portainer.OAuthSettings) (string, error) { token, err := getOAuthToken(code, configuration) if err != nil { - log.Debugf("[internal,oauth] [message: failed retrieving oauth token: %v]", err) + log.Debug().Err(err).Msg("failed retrieving oauth token") + return "", err } idToken, err := getIdToken(token) if err != nil { - log.Debugf("[internal,oauth] [message: failed parsing id_token: %v]", err) + log.Debug().Err(err).Msg("failed parsing id_token") } resource, err := getResource(token.AccessToken, configuration) if err != nil { - log.Debugf("[internal,oauth] [message: failed retrieving resource: %v]", err) + log.Debug().Err(err).Msg("failed retrieving resource") + return "", err } @@ -50,9 +52,11 @@ func (*Service) Authenticate(code string, configuration *portainer.OAuthSettings username, err := getUsername(resource, configuration) if err != nil { - log.Debugf("[internal,oauth] [message: failed retrieving username: %v]", err) + log.Debug().Err(err).Msg("failed retrieving username") + return "", err } + return username, nil } @@ -61,6 +65,7 @@ func mergeSecondIntoFirst(base map[string]interface{}, overlap map[string]interf for k, v := range overlap { base[k] = v } + return base } @@ -104,6 +109,7 @@ func getIdToken(token *oauth2.Token) (map[string]interface{}, error) { tokenData[k] = v } } + return tokenData, nil } diff --git a/api/portainer.go b/api/portainer.go index 4b237282d..4cdb2cbb5 100644 --- a/api/portainer.go +++ b/api/portainer.go @@ -128,6 +128,7 @@ type ( MaxBatchSize *int MaxBatchDelay *time.Duration SecretKeyName *string + LogLevel *string } // CustomTemplateVariableDefinition diff --git a/api/scheduler/scheduler.go b/api/scheduler/scheduler.go index bb4ce5461..328e69999 100644 --- a/api/scheduler/scheduler.go +++ b/api/scheduler/scheduler.go @@ -2,14 +2,13 @@ package scheduler import ( "context" - "log" "strconv" "sync" "time" "github.com/pkg/errors" "github.com/robfig/cron/v3" - "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) type Scheduler struct { @@ -43,7 +42,7 @@ func (s *Scheduler) Shutdown() error { return nil } - log.Println("[DEBUG] Stopping scheduler") + log.Debug().Msg("stopping scheduler") ctx := s.crontab.Stop() <-ctx.Done() @@ -87,7 +86,7 @@ func (s *Scheduler) StartJobEvery(duration time.Duration, job func() error) stri j := cron.FuncJob(func() { if err := job(); err != nil { - logrus.Debug("job returned an error") + log.Debug().Msg("job returned an error") cancel() } }) @@ -100,7 +99,7 @@ func (s *Scheduler) StartJobEvery(duration time.Duration, job func() error) stri go func(entryID cron.EntryID) { <-ctx.Done() - logrus.Debug("job cancelled, stopping") + log.Debug().Msg("job cancelled, stopping") s.crontab.Remove(entryID) }(entryID) diff --git a/api/stacks/deploy.go b/api/stacks/deploy.go index fca79c4ef..1bc4a8532 100644 --- a/api/stacks/deploy.go +++ b/api/stacks/deploy.go @@ -5,11 +5,12 @@ import ( "strings" "time" - "github.com/pkg/errors" portainer "github.com/portainer/portainer/api" "github.com/portainer/portainer/api/dataservices" "github.com/portainer/portainer/api/http/security" - log "github.com/sirupsen/logrus" + + "github.com/pkg/errors" + "github.com/rs/zerolog/log" ) type StackAuthorMissingErr struct { @@ -24,8 +25,7 @@ func (e *StackAuthorMissingErr) Error() string { // RedeployWhenChanged pull and redeploy the stack when git repo changed // Stack will always be redeployed if force deployment is set to true func RedeployWhenChanged(stackID portainer.StackID, deployer StackDeployer, datastore dataservices.DataStore, gitService portainer.GitService) error { - logger := log.WithFields(log.Fields{"stackID": stackID}) - logger.Debug("redeploying stack") + log.Debug().Int("stack_id", int(stackID)).Msg("redeploying stack") stack, err := datastore.Stack().Stack(stackID) if err != nil { @@ -43,7 +43,13 @@ func RedeployWhenChanged(stackID portainer.StackID, deployer StackDeployer, data user, err := datastore.User().UserByUsername(author) if err != nil { - logger.WithFields(log.Fields{"author": author, "stack": stack.Name, "endpointID": stack.EndpointID}).Warn("cannot autoupdate a stack, stack author user is missing") + log.Warn(). + Int("stack_id", int(stackID)). + Str("author", author). + Str("stack", stack.Name). + Int("endpoint_id", int(stack.EndpointID)). + Msg("cannot autoupdate a stack, stack author user is missing") + return &StackAuthorMissingErr{int(stack.ID), author} } @@ -99,7 +105,10 @@ func RedeployWhenChanged(stackID portainer.StackID, deployer StackDeployer, data return errors.WithMessagef(err, "failed to deploy a docker compose stack %v", stackID) } case portainer.KubernetesStack: - logger.Debugf("deploying a kube app") + log.Debug(). + Int("stack_id", int(stackID)). + Msg("deploying a kube app") + err := deployer.DeployKubernetesStack(stack, endpoint, user) if err != nil { return errors.WithMessagef(err, "failed to deploy a kubternetes app stack %v", stackID)