diff --git a/go/bootstrap/garage.go b/go/bootstrap/garage.go index e09c7ae..921f639 100644 --- a/go/bootstrap/garage.go +++ b/go/bootstrap/garage.go @@ -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, + } } diff --git a/go/bootstrap/garage_global_bucket.go b/go/bootstrap/garage_global_bucket.go index 4cd5b30..548872f 100644 --- a/go/bootstrap/garage_global_bucket.go +++ b/go/bootstrap/garage_global_bucket.go @@ -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 .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 -} diff --git a/go/cmd/entrypoint/garage.go b/go/cmd/entrypoint/garage.go index d8573c8..2ba2a29 100644 --- a/go/cmd/entrypoint/garage.go +++ b/go/cmd/entrypoint/garage.go @@ -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, ) ) diff --git a/go/cmd/entrypoint/hosts.go b/go/cmd/entrypoint/hosts.go index d3183b7..2f84143 100644 --- a/go/cmd/entrypoint/hosts.go +++ b/go/cmd/entrypoint/hosts.go @@ -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) }, } diff --git a/go/daemon/daemon.go b/go/daemon/daemon.go index 8c10de8..7a690bf 100644 --- a/go/daemon/daemon.go +++ b/go/daemon/daemon.go @@ -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() diff --git a/go/daemon/global_bucket.go b/go/daemon/global_bucket.go index da11636..083bad7 100644 --- a/go/daemon/global_bucket.go +++ b/go/daemon/global_bucket.go @@ -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( diff --git a/go/daemon/rpc.go b/go/daemon/rpc.go index a1bf1cf..a8dbaa6 100644 --- a/go/daemon/rpc.go +++ b/go/daemon/rpc.go @@ -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) +}