cli/third-party/github.com/letsencrypt/boulder/cmd/admin/admin.go
2025-05-30 12:50:20 -04:00

96 lines
2.8 KiB
Go

package main
import (
"context"
"fmt"
"github.com/jmhodges/clock"
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/db"
"github.com/letsencrypt/boulder/features"
bgrpc "github.com/letsencrypt/boulder/grpc"
blog "github.com/letsencrypt/boulder/log"
rapb "github.com/letsencrypt/boulder/ra/proto"
"github.com/letsencrypt/boulder/sa"
sapb "github.com/letsencrypt/boulder/sa/proto"
)
// admin holds all of the external connections necessary to perform admin
// actions on a boulder deployment.
type admin struct {
rac rapb.RegistrationAuthorityClient
sac sapb.StorageAuthorityClient
saroc sapb.StorageAuthorityReadOnlyClient
// TODO: Remove this and only use sac and saroc to interact with the db.
// We cannot have true dry-run safety as long as we have a direct dbMap.
dbMap *db.WrappedMap
// TODO: Remove this when the dbMap is removed and the dryRunSAC and dryRunRAC
// handle all dry-run safety.
dryRun bool
clk clock.Clock
log blog.Logger
}
// newAdmin constructs a new admin object on the heap and returns a pointer to
// it.
func newAdmin(configFile string, dryRun bool) (*admin, error) {
// Unlike most boulder service constructors, this does all of its own config
// parsing and dependency setup. If this is broken out into its own package
// (outside the //cmd/ directory) those pieces of setup should stay behind
// in //cmd/admin/main.go, to match other boulder services.
var c Config
err := cmd.ReadConfigFile(configFile, &c)
if err != nil {
return nil, fmt.Errorf("parsing config file: %w", err)
}
scope, logger, oTelShutdown := cmd.StatsAndLogging(c.Syslog, c.OpenTelemetry, c.Admin.DebugAddr)
defer oTelShutdown(context.Background())
logger.Info(cmd.VersionString())
clk := cmd.Clock()
features.Set(c.Admin.Features)
tlsConfig, err := c.Admin.TLS.Load(scope)
if err != nil {
return nil, fmt.Errorf("loading TLS config: %w", err)
}
var rac rapb.RegistrationAuthorityClient = dryRunRAC{log: logger}
if !dryRun {
raConn, err := bgrpc.ClientSetup(c.Admin.RAService, tlsConfig, scope, clk)
if err != nil {
return nil, fmt.Errorf("creating RA gRPC client: %w", err)
}
rac = rapb.NewRegistrationAuthorityClient(raConn)
}
saConn, err := bgrpc.ClientSetup(c.Admin.SAService, tlsConfig, scope, clk)
if err != nil {
return nil, fmt.Errorf("creating SA gRPC client: %w", err)
}
saroc := sapb.NewStorageAuthorityReadOnlyClient(saConn)
var sac sapb.StorageAuthorityClient = dryRunSAC{log: logger}
if !dryRun {
sac = sapb.NewStorageAuthorityClient(saConn)
}
dbMap, err := sa.InitWrappedDb(c.Admin.DB, nil, logger)
if err != nil {
return nil, fmt.Errorf("creating database connection: %w", err)
}
return &admin{
rac: rac,
sac: sac,
saroc: saroc,
dbMap: dbMap,
dryRun: dryRun,
clk: clk,
log: logger,
}, nil
}