Fetch GarageClientParams from daemon

This commit is contained in:
Brian Picciano 2024-07-12 16:03:37 +02:00
parent 736b23429c
commit 30c8ca332a
7 changed files with 83 additions and 97 deletions

View File

@ -4,6 +4,24 @@ import (
"isle/garage"
)
// GarageClientParams contains all the data needed to instantiate garage
// clients.
type GarageClientParams struct {
Peer garage.RemotePeer
GlobalBucketS3APICredentials garage.S3APICredentials
RPCSecret string
}
// GlobalBucketS3APIClient returns an S3 client pre-configured with access to
// the global bucket.
func (p GarageClientParams) GlobalBucketS3APIClient() garage.S3APIClient {
var (
addr = p.Peer.S3APIAddr()
creds = p.GlobalBucketS3APICredentials
)
return garage.NewS3APIClient(addr, creds)
}
// GaragePeers returns a Peer for each known garage instance in the network.
func (b Bootstrap) GaragePeers() []garage.RemotePeer {
@ -52,10 +70,11 @@ func (b Bootstrap) ChooseGaragePeer() garage.RemotePeer {
panic("no garage instances configured")
}
// GlobalBucketS3APIClient returns an S3 client pre-configured with access to
// the global bucket.
func (b Bootstrap) GlobalBucketS3APIClient() garage.S3APIClient {
addr := b.ChooseGaragePeer().S3APIAddr()
creds := b.Garage.GlobalBucketS3APICredentials
return garage.NewS3APIClient(addr, creds)
// GarageClientParams returns a GarageClientParams.
func (b Bootstrap) GarageClientParams() GarageClientParams {
return GarageClientParams{
Peer: b.ChooseGaragePeer(),
GlobalBucketS3APICredentials: b.Garage.GlobalBucketS3APICredentials,
RPCSecret: b.Garage.RPCSecret,
}
}

View File

@ -2,14 +2,9 @@ package bootstrap
import (
"context"
"encoding/json"
"fmt"
"isle/garage"
"isle/nebula"
"path/filepath"
"dev.mediocregopher.com/mediocre-go-lib.git/mctx"
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
"github.com/minio/minio-go/v7"
)
@ -38,63 +33,3 @@ func RemoveGarageBootstrapHost(
minio.RemoveObjectOptions{},
)
}
// GetGarageBootstrapHosts loads the <hostname>.json.signed file for all hosts
// stored in garage.
//
// Deprecated: should use the method off Daemon instead.
func (b Bootstrap) GetGarageBootstrapHosts(
ctx context.Context,
logger *mlog.Logger,
) (
map[nebula.HostName]Host, error,
) {
client := b.GlobalBucketS3APIClient()
hosts := map[nebula.HostName]Host{}
objInfoCh := client.ListObjects(
ctx, garage.GlobalBucket,
minio.ListObjectsOptions{
Prefix: garageGlobalBucketBootstrapHostsDirPath,
Recursive: true,
},
)
for objInfo := range objInfoCh {
ctx := mctx.Annotate(ctx, "objectKey", objInfo.Key)
if objInfo.Err != nil {
return nil, fmt.Errorf("listing objects: %w", objInfo.Err)
}
obj, err := client.GetObject(
ctx, garage.GlobalBucket, objInfo.Key, minio.GetObjectOptions{},
)
if err != nil {
return nil, fmt.Errorf("retrieving object %q: %w", objInfo.Key, err)
}
var authedHost AuthenticatedHost
err = json.NewDecoder(obj).Decode(&authedHost)
obj.Close()
if err != nil {
logger.Warn(ctx, "object contains invalid json", err)
continue
}
host, err := authedHost.Unwrap(b.CAPublicCredentials)
if err != nil {
logger.Warn(ctx, "host could not be authenticated", err)
}
hosts[host.Name] = host
}
return hosts, nil
}

View File

@ -5,6 +5,8 @@ import (
"os"
"path/filepath"
"syscall"
"isle/bootstrap"
)
// minio-client keeps a configuration directory which contains various pieces of
@ -51,19 +53,22 @@ var subCmdGarageMC = subCmd{
return fmt.Errorf("parsing flags: %w", err)
}
hostBootstrap, err := loadHostBootstrap()
var clientParams bootstrap.GarageClientParams
err := subCmdCtx.daemonRCPClient.Call(
subCmdCtx.ctx, &clientParams, "GetGarageClientParams", nil,
)
if err != nil {
return fmt.Errorf("loading host bootstrap: %w", err)
return fmt.Errorf("calling GetGarageClientParams: %w", err)
}
s3APIAddr := hostBootstrap.ChooseGaragePeer().S3APIAddr()
s3APIAddr := clientParams.Peer.S3APIAddr()
if *keyID == "" {
*keyID = hostBootstrap.Garage.GlobalBucketS3APICredentials.ID
*keyID = clientParams.GlobalBucketS3APICredentials.ID
}
if *keySecret == "" {
*keySecret = hostBootstrap.Garage.GlobalBucketS3APICredentials.Secret
*keySecret = clientParams.GlobalBucketS3APICredentials.Secret
}
args := flags.Args()
@ -116,9 +121,12 @@ var subCmdGarageCLI = subCmd{
checkLock: true,
do: func(subCmdCtx subCmdCtx) error {
hostBootstrap, err := loadHostBootstrap()
var clientParams bootstrap.GarageClientParams
err := subCmdCtx.daemonRCPClient.Call(
subCmdCtx.ctx, &clientParams, "GetGarageClientParams", nil,
)
if err != nil {
return fmt.Errorf("loading host bootstrap: %w", err)
return fmt.Errorf("calling GetGarageClientParams: %w", err)
}
var (
@ -126,8 +134,8 @@ var subCmdGarageCLI = subCmd{
args = append([]string{"garage"}, subCmdCtx.args...)
cliEnv = append(
os.Environ(),
"GARAGE_RPC_HOST="+hostBootstrap.ChooseGaragePeer().RPCPeerAddr(),
"GARAGE_RPC_SECRET="+hostBootstrap.Garage.RPCSecret,
"GARAGE_RPC_HOST="+clientParams.Peer.RPCPeerAddr(),
"GARAGE_RPC_SECRET="+clientParams.RPCSecret,
)
)

View File

@ -6,21 +6,9 @@ import (
"isle/bootstrap"
"isle/jsonutil"
"os"
"regexp"
"sort"
)
var hostNameRegexp = regexp.MustCompile(`^[a-z][a-z0-9\-]*$`)
func validateHostName(name string) error {
if !hostNameRegexp.MatchString(name) {
return errors.New("a host's name must start with a letter and only contain letters, numbers, and dashes")
}
return nil
}
var subCmdHostsList = subCmd{
name: "list",
descr: "Lists all hosts in the network, and their IPs",
@ -78,13 +66,18 @@ var subCmdHostsDelete = subCmd{
return errors.New("--hostname is required")
}
hostBootstrap, err := loadHostBootstrap()
var clientParams bootstrap.GarageClientParams
err := subCmdCtx.daemonRCPClient.Call(
subCmdCtx.ctx, &clientParams, "GetGarageClientParams", nil,
)
if err != nil {
return fmt.Errorf("loading host bootstrap: %w", err)
return fmt.Errorf("calling GetGarageClientParams: %w", err)
}
client := hostBootstrap.GlobalBucketS3APIClient()
client := clientParams.GlobalBucketS3APIClient()
// TODO do this within the daemon, along with first checking if the host
// has any assigned network resources.
return bootstrap.RemoveGarageBootstrapHost(subCmdCtx.ctx, client, *hostName)
},
}

View File

@ -56,6 +56,14 @@ type Daemon interface {
map[nebula.HostName]bootstrap.Host, error,
)
// GetGarageClientParams returns a GarageClientParams based on the current
// network topology.
GetGarageClientParams(
ctx context.Context,
) (
bootstrap.GarageClientParams, error,
)
// Shutdown blocks until all resources held or created by the daemon,
// including child processes it has started, have been cleaned up.
//
@ -579,6 +587,20 @@ func (d *daemon) GetBootstrapHosts(
})
}
func (d *daemon) GetGarageClientParams(
ctx context.Context,
) (
bootstrap.GarageClientParams, error,
) {
return withCurrBootstrap(d, func(
currBootstrap bootstrap.Bootstrap,
) (
bootstrap.GarageClientParams, error,
) {
return currBootstrap.GarageClientParams(), nil
})
}
func (d *daemon) Shutdown() error {
d.l.Lock()
defer d.l.Unlock()

View File

@ -66,7 +66,7 @@ func (d *daemon) putGarageBoostrapHost(ctx context.Context) error {
var (
b = d.currBootstrap
host = b.ThisHost()
client = b.GlobalBucketS3APIClient()
client = b.GarageClientParams().GlobalBucketS3APIClient()
)
configured, err := nebula.Sign(
@ -112,7 +112,7 @@ func getGarageBootstrapHosts(
) {
var (
b = currBootstrap
client = b.GlobalBucketS3APIClient()
client = b.GarageClientParams().GlobalBucketS3APIClient()
hosts = map[nebula.HostName]bootstrap.Host{}
objInfoCh = client.ListObjects(

View File

@ -85,3 +85,12 @@ func (r *RPC) GetHosts(
return GetHostsResult{hosts}, nil
}
// GetGarageClientParams passes through to the Daemon method of the same name.
func (r *RPC) GetGarageClientParams(
ctx context.Context, req struct{},
) (
bootstrap.GarageClientParams, error,
) {
return r.daemon.GetGarageClientParams(ctx)
}