Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ verify: check-gopath
# Runs our linter to verify that everything is following best practices
# Linter is set to ignore `unused` stuff due to example being incomplete by definition
lint: $(GOLANGCI_LINT)
$(GOLANGCI_LINT) run ./...
$(GOLANGCI_LINT) run ./cmd/... ./pkg/... ./test/...
.PHONY: lint

# Build binaries
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ This project uses [pre-commit](https://pre-commit.io/) for code quality checks.
- **[Database](docs/database.md)** - Schema, migrations, and data model
- **[Deployment](docs/deployment.md)** - Container images, Kubernetes deployment, and configuration
- **[Authentication](docs/authentication.md)** - Development and production auth
- **[Logging](docs/logging.md)** - Structured logging, OpenTelemetry integration, and data masking

### Additional Resources

Expand Down
42 changes: 28 additions & 14 deletions cmd/hyperfleet-api/environments/framework.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package environments

import (
"context"
"fmt"
"os"
"strings"

"github.com/golang/glog"
"github.com/spf13/pflag"

"github.com/openshift-hyperfleet/hyperfleet-api/cmd/hyperfleet-api/environments/registry"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/client/ocm"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/config"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/errors"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/logger"
)

func init() {
Expand Down Expand Up @@ -64,38 +66,46 @@ func (e *Env) AddFlags(flags *pflag.FlagSet) error {
// This should be called after the e.Config has been set appropriately though AddFlags and pasing, done elsewhere
// The environment does NOT handle flag parsing
func (e *Env) Initialize() error {
glog.Infof("Initializing %s environment", e.Name)
ctx := context.Background()
logger.With(ctx, logger.FieldEnvironment, e.Name).Info("Initializing environment")

envImpl, found := environments[e.Name]
if !found {
glog.Fatalf("Unknown runtime environment: %s", e.Name)
logger.With(ctx, logger.FieldEnvironment, e.Name).Error("Unknown runtime environment")
os.Exit(1)
}

if err := envImpl.OverrideConfig(e.Config); err != nil {
glog.Fatalf("Failed to configure ApplicationConfig: %s", err)
logger.WithError(ctx, err).Error("Failed to configure ApplicationConfig")
os.Exit(1)
}

messages := environment.Config.ReadFiles()
if len(messages) != 0 {
glog.Fatalf("unable to read configuration files:\n%s", strings.Join(messages, "\n"))
err := fmt.Errorf("%s", strings.Join(messages, "\n"))
logger.WithError(ctx, err).Error("Unable to read configuration files")
os.Exit(1)
}

// each env will set db explicitly because the DB impl has a `once` init section
if err := envImpl.OverrideDatabase(&e.Database); err != nil {
glog.Fatalf("Failed to configure Database: %s", err)
logger.WithError(ctx, err).Error("Failed to configure Database")
os.Exit(1)
}

err := e.LoadClients()
if err != nil {
return err
}
if err := envImpl.OverrideClients(&e.Clients); err != nil {
glog.Fatalf("Failed to configure Clients: %s", err)
logger.WithError(ctx, err).Error("Failed to configure Clients")
os.Exit(1)
}

e.LoadServices()
if err := envImpl.OverrideServices(&e.Services); err != nil {
glog.Fatalf("Failed to configure Services: %s", err)
logger.WithError(ctx, err).Error("Failed to configure Services")
os.Exit(1)
}

seedErr := e.Seed()
Expand All @@ -104,7 +114,8 @@ func (e *Env) Initialize() error {
}

if err := envImpl.OverrideHandlers(&e.Handlers); err != nil {
glog.Fatalf("Failed to configure Handlers: %s", err)
logger.WithError(ctx, err).Error("Failed to configure Handlers")
os.Exit(1)
}

return nil
Expand All @@ -123,6 +134,7 @@ func (e *Env) LoadServices() {
}

func (e *Env) LoadClients() error {
ctx := context.Background()
var err error

ocmConfig := ocm.Config{
Expand All @@ -136,36 +148,38 @@ func (e *Env) LoadClients() error {

// Create OCM Authz client
if e.Config.OCM.EnableMock {
glog.Infof("Using Mock OCM Authz Client")
logger.Info(ctx, "Using Mock OCM Authz Client")
e.Clients.OCM, err = ocm.NewClientMock(ocmConfig)
} else {
e.Clients.OCM, err = ocm.NewClient(ocmConfig)
}
if err != nil {
glog.Errorf("Unable to create OCM Authz client: %s", err.Error())
logger.WithError(ctx, err).Error("Unable to create OCM Authz client")
return err
}

return nil
}

func (e *Env) Teardown() {
ctx := context.Background()
if e.Database.SessionFactory != nil {
if err := e.Database.SessionFactory.Close(); err != nil {
glog.Errorf("Error closing database session factory: %s", err.Error())
logger.WithError(ctx, err).Error("Error closing database session factory")
}
}
if e.Clients.OCM != nil {
if err := e.Clients.OCM.Close(); err != nil {
glog.Errorf("Error closing OCM client: %v", err)
logger.WithError(ctx, err).Error("Error closing OCM client")
}
}
}

func setConfigDefaults(flags *pflag.FlagSet, defaults map[string]string) error {
ctx := context.Background()
for name, value := range defaults {
if err := flags.Set(name, value); err != nil {
glog.Errorf("Error setting flag %s: %v", name, err)
logger.With(ctx, logger.FieldFlag, name).WithError(err).Error("Error setting flag")
return err
}
}
Expand Down
47 changes: 31 additions & 16 deletions cmd/hyperfleet-api/main.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package main

import (
"flag"
"context"
"log/slog"
"os"

"github.com/golang/glog"
"github.com/spf13/cobra"

"github.com/openshift-hyperfleet/hyperfleet-api/cmd/hyperfleet-api/migrate"
"github.com/openshift-hyperfleet/hyperfleet-api/cmd/hyperfleet-api/servecmd"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/logger"

// Import plugins to trigger their init() functions
// _ "github.com/openshift-hyperfleet/hyperfleet-api/plugins/events" // REMOVED: Events plugin no longer exists
Expand All @@ -20,19 +22,9 @@ import (
// nolint

func main() {
// This is needed to make `glog` believe that the flags have already been parsed, otherwise
// every log messages is prefixed by an error message stating the the flags haven't been
// parsed.
if err := flag.CommandLine.Parse([]string{}); err != nil {
glog.Fatalf("Failed to parse flags: %v", err)
}

//pflag.CommandLine.AddGoFlagSet(flag.CommandLine)

// Always log to stderr by default
if err := flag.Set("logtostderr", "true"); err != nil {
glog.Infof("Unable to set logtostderr to true")
}
// Initialize logger first (before any logging occurs)
initDefaultLogger()
ctx := context.Background()

rootCmd := &cobra.Command{
Use: "hyperfleet",
Expand All @@ -47,6 +39,29 @@ func main() {
rootCmd.AddCommand(migrateCmd, serveCmd)

if err := rootCmd.Execute(); err != nil {
glog.Fatalf("error running command: %v", err)
logger.WithError(ctx, err).Error("Error running command")
os.Exit(1)
}
}

// initDefaultLogger initializes a default logger with INFO level
// This ensures logging works before environment/config is loaded
func initDefaultLogger() {
cfg := &logger.LogConfig{
Level: slog.LevelInfo,
Format: logger.FormatJSON,
Output: os.Stdout,
Component: "hyperfleet-api",
Version: "unknown",
Hostname: getHostname(),
}
logger.InitGlobalLogger(cfg)
}

func getHostname() string {
hostname, err := os.Hostname()
if err != nil {
return "unknown"
}
return hostname
}
29 changes: 24 additions & 5 deletions cmd/hyperfleet-api/migrate/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ package migrate
import (
"context"
"flag"
"os"

"github.com/golang/glog"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/db/db_session"
"github.com/spf13/cobra"

"github.com/openshift-hyperfleet/hyperfleet-api/pkg/config"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/db"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/db/db_session"
"github.com/openshift-hyperfleet/hyperfleet-api/pkg/logger"
)

var dbConfig = config.NewDatabaseConfig()
Expand All @@ -29,13 +30,31 @@ func NewMigrateCommand() *cobra.Command {
}

func runMigrate(_ *cobra.Command, _ []string) {
if err := runMigrateWithError(); err != nil {
os.Exit(1)
}
}

func runMigrateWithError() error {
ctx := context.Background()
err := dbConfig.ReadFiles()
if err != nil {
glog.Fatal(err)
logger.WithError(ctx, err).Error("Fatal error")
return err
}

connection := db_session.NewProdFactory(dbConfig)
if err := db.Migrate(connection.New(context.Background())); err != nil {
glog.Fatal(err)
defer func() {
if closeErr := connection.Close(); closeErr != nil {
logger.WithError(ctx, closeErr).Error("Failed to close database connection")
}
}()

if err := db.Migrate(connection.New(ctx)); err != nil {
logger.WithError(ctx, err).Error("Migration failed")
return err
}

logger.Info(ctx, "Migration completed successfully")
return nil
}
Loading