Skip to content
Open
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
3 changes: 1 addition & 2 deletions internal/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import (
internalConfig "github.com/canonical/microcluster/v3/internal/config"
"github.com/canonical/microcluster/v3/internal/db"
"github.com/canonical/microcluster/v3/internal/endpoints"
internalLog "github.com/canonical/microcluster/v3/internal/log"
"github.com/canonical/microcluster/v3/internal/recover"
internalREST "github.com/canonical/microcluster/v3/internal/rest"
internalClient "github.com/canonical/microcluster/v3/internal/rest/client"
Expand Down Expand Up @@ -153,7 +152,7 @@ func NewDaemon() *Daemon {
// log is a convenience to retrieve the internal logger from the shutdown context.
// We always expect the logger to be present.
func (d *Daemon) log() *slog.Logger {
return d.shutdownCtx.Value(internalLog.CtxLogger).(*slog.Logger) //nolint:revive
return d.shutdownCtx.Value(types.CtxLogger).(*slog.Logger) //nolint:revive
}

// Run initializes the Daemon with the given configuration, starts the database,
Expand Down
4 changes: 1 addition & 3 deletions internal/daemon/daemon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package daemon

import (
"context"
"log/slog"
"path/filepath"
"testing"

Expand All @@ -13,7 +12,6 @@ import (

"github.com/canonical/microcluster/v3/internal/config"
"github.com/canonical/microcluster/v3/internal/endpoints"
"github.com/canonical/microcluster/v3/internal/log"
"github.com/canonical/microcluster/v3/internal/rest/client"
"github.com/canonical/microcluster/v3/internal/sys"
"github.com/canonical/microcluster/v3/internal/trust"
Expand Down Expand Up @@ -189,7 +187,7 @@ func (t *daemonsSuite) Test_UpdateServers() {
for i, test := range tests {
t.T().Logf("%s (case %d)", test.name, i)

ctx := context.WithValue(context.TODO(), log.CtxLogger, slog.Default())
ctx := types.ContextWithLogger(context.TODO())
commonDir := t.T().TempDir()

// Create a temp watcher.
Expand Down
4 changes: 1 addition & 3 deletions internal/db/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"database/sql"
"encoding/json"
"fmt"
"log/slog"
"testing"
"time"

Expand All @@ -14,7 +13,6 @@ import (

"github.com/canonical/microcluster/v3/internal/cluster"
"github.com/canonical/microcluster/v3/internal/db/update"
"github.com/canonical/microcluster/v3/internal/log"
"github.com/canonical/microcluster/v3/internal/sys"
clusterDB "github.com/canonical/microcluster/v3/microcluster/db"
"github.com/canonical/microcluster/v3/microcluster/types"
Expand Down Expand Up @@ -652,7 +650,7 @@ func (s *dbSuite) Test_waitUpgradeSchemaAndAPI() {
func NewTestDB(extensionsExternal []clusterDB.Update) (*DqliteDB, error) {
var err error

ctx := context.WithValue(context.Background(), log.CtxLogger, slog.Default())
ctx := types.ContextWithLogger(context.Background())

db := &DqliteDB{
ctx: ctx,
Expand Down
3 changes: 1 addition & 2 deletions internal/db/dqlite.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import (

"github.com/canonical/microcluster/v3/internal/cluster"
"github.com/canonical/microcluster/v3/internal/db/update"
"github.com/canonical/microcluster/v3/internal/log"
internalClient "github.com/canonical/microcluster/v3/internal/rest/client"
"github.com/canonical/microcluster/v3/internal/sys"
clusterDB "github.com/canonical/microcluster/v3/microcluster/db"
Expand Down Expand Up @@ -109,7 +108,7 @@ func NewDB(ctx context.Context, serverCert func() *shared.CertInfo, clusterCert
// log is a convenience to retrieve the internal logger from the database's context.
// We always expect the logger to be present.
func (db *DqliteDB) log() *slog.Logger {
return db.ctx.Value(log.CtxLogger).(*slog.Logger) //nolint:revive
return db.ctx.Value(types.CtxLogger).(*slog.Logger) //nolint:revive
}

// SetSchema sets schema and API extensions on the DB.
Expand Down
5 changes: 2 additions & 3 deletions internal/db/query/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,15 @@ import (
"context"
"database/sql"
"errors"
"log/slog"
"testing"

_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/canonical/microcluster/v3/internal/db/query"
"github.com/canonical/microcluster/v3/internal/log"
clusterDB "github.com/canonical/microcluster/v3/microcluster/db"
"github.com/canonical/microcluster/v3/microcluster/types"
)

// Any error happening when beginning the transaction will be propagated.
Expand All @@ -36,7 +35,7 @@ func TestTransaction_FunctionError(t *testing.T) {
db := newDB(t)

// Populate the context with the logger as this is required for a failing transaction.
ctx := context.WithValue(context.TODO(), log.CtxLogger, slog.Default())
ctx := types.ContextWithLogger(context.TODO())

err := query.Transaction(ctx, db, func(ctx context.Context, tx *sql.Tx) error {
_, err := tx.Exec("CREATE TABLE test (id INTEGER)")
Expand Down
4 changes: 2 additions & 2 deletions internal/endpoints/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (

"github.com/canonical/lxd/shared"

"github.com/canonical/microcluster/v3/internal/log"
"github.com/canonical/microcluster/v3/microcluster/types"
)

// Endpoints represents all listeners and servers for the microcluster daemon REST API.
Expand All @@ -28,7 +28,7 @@ func NewEndpoints(shutdownCtx context.Context, endpoints map[string]Endpoint) *E
// log is a convenience to retrieve the internal logger from the shutdown context.
// We always expect the logger to be present.
func (e *Endpoints) log() *slog.Logger {
return e.shutdownCtx.Value(log.CtxLogger).(*slog.Logger) //nolint:revive
return e.shutdownCtx.Value(types.CtxLogger).(*slog.Logger) //nolint:revive
}

// Up calls Serve on each of the configured listeners.
Expand Down
4 changes: 2 additions & 2 deletions internal/endpoints/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (

"github.com/canonical/lxd/shared"

"github.com/canonical/microcluster/v3/internal/log"
"github.com/canonical/microcluster/v3/microcluster/types"
)

// Network represents an HTTPS listener and its server.
Expand Down Expand Up @@ -53,7 +53,7 @@ func NewNetwork(ctx context.Context, endpointType EndpointType, server *http.Ser
// log is a convenience to retrieve the internal logger from the network's context.
// We always expect the logger to be present.
func (n *Network) log() *slog.Logger {
return n.ctx.Value(log.CtxLogger).(*slog.Logger) //nolint:revive
return n.ctx.Value(types.CtxLogger).(*slog.Logger) //nolint:revive
}

// Type returns the type of the Endpoint.
Expand Down
4 changes: 2 additions & 2 deletions internal/endpoints/socket.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (

"github.com/canonical/lxd/shared"

"github.com/canonical/microcluster/v3/internal/log"
"github.com/canonical/microcluster/v3/microcluster/types"
)

// Socket represents a unix socket with a given path.
Expand Down Expand Up @@ -50,7 +50,7 @@ func NewSocket(ctx context.Context, server *http.Server, path *url.URL, group st
// log is a convenience to retrieve the internal logger from the socket's context.
// We always expect the logger to be present.
func (s *Socket) log() *slog.Logger {
return s.ctx.Value(log.CtxLogger).(*slog.Logger) //nolint:revive
return s.ctx.Value(types.CtxLogger).(*slog.Logger) //nolint:revive
}

// Type returns the type of the Endpoint.
Expand Down
9 changes: 3 additions & 6 deletions internal/log/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@ import (
"context"
"errors"
"log/slog"
)

type ctxKey string

// CtxLogger is the name of the context value for the central logger.
const CtxLogger ctxKey = "logger"
"github.com/canonical/microcluster/v3/microcluster/types"
)

// LoggerFromContext returns the logger from the given context.
func LoggerFromContext(ctx context.Context) (*slog.Logger, error) {
logger, ok := ctx.Value(CtxLogger).(*slog.Logger)
logger, ok := ctx.Value(types.CtxLogger).(*slog.Logger)
if !ok {
return nil, errors.New("Logger does not exist on context")
}
Expand Down
4 changes: 2 additions & 2 deletions microcluster/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func (m *MicroCluster) Start(ctx context.Context, daemonArgs DaemonArgs) error {
}

// Attach the logger to the parent context.
ctx = context.WithValue(ctx, log.CtxLogger, logger)
ctx = types.ContextWithLogger(ctx, logger)

err := d.Run(ctx, m.FileSystem.StateDir(), daemonArgs)
if err != nil {
Expand Down Expand Up @@ -280,7 +280,7 @@ func (m *MicroCluster) RecoverFromQuorumLoss(members []types.DqliteMember) (stri
// Derive a new context with the central logger attached.
// As we don't have a running daemon at this stage, we cannot use its context.
// Instead we use the logger populated for the app which uses the custom handler if supplied.
ctx := context.WithValue(context.Background(), log.CtxLogger, m.LoggerFromContext(context.Background()))
ctx := types.ContextWithLogger(context.Background(), m.LoggerFromContext(context.Background()))

return recover.RecoverFromQuorumLoss(ctx, m.FileSystem, members)
}
Expand Down
11 changes: 11 additions & 0 deletions microcluster/rest/response/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package response
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"log/slog"
Expand Down Expand Up @@ -118,6 +119,16 @@ func Unavailable(err error) Response {
return &errorResponse{http.StatusServiceUnavailable, err}
}

// Unauthorized returns an unauthorized response (401) with the given error.
func Unauthorized(err error) Response {
return &errorResponse{http.StatusUnauthorized, err}
}

// ErrorResponse returns an error response with the given code and msg.
func ErrorResponse(code int, msg string) Response {
return &errorResponse{code, errors.New(msg)}
}

func (r *errorResponse) Render(w http.ResponseWriter, req *http.Request) error {
buf := &bytes.Buffer{}
resp := api.ResponseRaw{
Expand Down
24 changes: 24 additions & 0 deletions microcluster/types/log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package types

import (
"context"
"log/slog"
)

type CtxKey string

// CtxLogger is the name of the context value for the central logger.
const CtxLogger CtxKey = "logger"

// ContextWithLogger returns a new context with the given logger.
// If no logger is provided, the default logger is used.
func ContextWithLogger(ctx context.Context, logger ...*slog.Logger) context.Context {
var l *slog.Logger
if len(logger) == 0 {
l = slog.Default()
} else {
l = logger[0]
}

return context.WithValue(ctx, CtxLogger, l)
}
Loading