Compare commits
2 Commits
c5e919dc86
...
cc121f0752
Author | SHA1 | Date | |
---|---|---|---|
cc121f0752 | |||
778db848c6 |
@ -1,35 +0,0 @@
|
|||||||
package bootstrap
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"isle/garage"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"github.com/minio/minio-go/v7"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Paths within garage's global bucket.
|
|
||||||
//
|
|
||||||
// TODO this is getting moved into daemon package.
|
|
||||||
const (
|
|
||||||
garageGlobalBucketBootstrapHostsDirPath = "bootstrap/hosts"
|
|
||||||
)
|
|
||||||
|
|
||||||
// RemoveGarageBootstrapHost removes the <hostname>.json.signed for the given
|
|
||||||
// host from garage.
|
|
||||||
//
|
|
||||||
// The given client should be for the global bucket.
|
|
||||||
func RemoveGarageBootstrapHost(
|
|
||||||
ctx context.Context, client garage.S3APIClient, hostName string,
|
|
||||||
) error {
|
|
||||||
|
|
||||||
filePath := filepath.Join(
|
|
||||||
garageGlobalBucketBootstrapHostsDirPath,
|
|
||||||
hostName+".json.signed",
|
|
||||||
)
|
|
||||||
|
|
||||||
return client.RemoveObject(
|
|
||||||
ctx, garage.GlobalBucket, filePath,
|
|
||||||
minio.RemoveObjectOptions{},
|
|
||||||
)
|
|
||||||
}
|
|
@ -4,7 +4,9 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"isle/bootstrap"
|
"isle/bootstrap"
|
||||||
|
"isle/daemon"
|
||||||
"isle/jsonutil"
|
"isle/jsonutil"
|
||||||
|
"isle/nebula"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
@ -45,39 +47,39 @@ var subCmdHostsList = subCmd{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var subCmdHostsDelete = subCmd{
|
var subCmdHostsRemove = subCmd{
|
||||||
name: "delete",
|
name: "remove",
|
||||||
descr: "Deletes a host from the network",
|
descr: "Removes a host from the network",
|
||||||
do: func(subCmdCtx subCmdCtx) error {
|
do: func(subCmdCtx subCmdCtx) error {
|
||||||
|
var (
|
||||||
|
flags = subCmdCtx.flagSet(false)
|
||||||
|
hostName nebula.HostName
|
||||||
|
)
|
||||||
|
|
||||||
flags := subCmdCtx.flagSet(false)
|
hostNameF := flags.VarPF(
|
||||||
|
textUnmarshalerFlag{&hostName},
|
||||||
hostName := flags.StringP(
|
"hostname", "h",
|
||||||
"hostname", "h", "",
|
"Name of the host to remove",
|
||||||
"Name of the host to delete",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if err := flags.Parse(subCmdCtx.args); err != nil {
|
if err := flags.Parse(subCmdCtx.args); err != nil {
|
||||||
return fmt.Errorf("parsing flags: %w", err)
|
return fmt.Errorf("parsing flags: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if *hostName == "" {
|
if !hostNameF.Changed {
|
||||||
return errors.New("--hostname is required")
|
return errors.New("--hostname is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
var clientParams bootstrap.GarageClientParams
|
|
||||||
err := subCmdCtx.daemonRCPClient.Call(
|
err := subCmdCtx.daemonRCPClient.Call(
|
||||||
subCmdCtx.ctx, &clientParams, "GetGarageClientParams", nil,
|
subCmdCtx.ctx, nil, "RemoveHost", daemon.RemoveHostRequest{
|
||||||
|
HostName: hostName,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("calling GetGarageClientParams: %w", err)
|
return fmt.Errorf("calling RemoveHost: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
client := clientParams.GlobalBucketS3APIClient()
|
return nil
|
||||||
|
|
||||||
// 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)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +88,7 @@ var subCmdHosts = subCmd{
|
|||||||
descr: "Sub-commands having to do with configuration of hosts in the network",
|
descr: "Sub-commands having to do with configuration of hosts in the network",
|
||||||
do: func(subCmdCtx subCmdCtx) error {
|
do: func(subCmdCtx subCmdCtx) error {
|
||||||
return subCmdCtx.doSubCmd(
|
return subCmdCtx.doSubCmd(
|
||||||
subCmdHostsDelete,
|
subCmdHostsRemove,
|
||||||
subCmdHostsList,
|
subCmdHostsList,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -52,6 +52,9 @@ type Daemon interface {
|
|||||||
// GetBootstraps returns the currently active Bootstrap.
|
// GetBootstraps returns the currently active Bootstrap.
|
||||||
GetBootstrap(context.Context) (bootstrap.Bootstrap, error)
|
GetBootstrap(context.Context) (bootstrap.Bootstrap, error)
|
||||||
|
|
||||||
|
// RemoveHost removes the host of the given name from the network.
|
||||||
|
RemoveHost(context.Context, nebula.HostName) error
|
||||||
|
|
||||||
// Shutdown blocks until all resources held or created by the daemon,
|
// Shutdown blocks until all resources held or created by the daemon,
|
||||||
// including child processes it has started, have been cleaned up.
|
// including child processes it has started, have been cleaned up.
|
||||||
//
|
//
|
||||||
@ -147,6 +150,10 @@ func NewDaemon(
|
|||||||
bootstrapFilePath = bootstrap.StateDirPath(d.opts.EnvVars.StateDirPath)
|
bootstrapFilePath = bootstrap.StateDirPath(d.opts.EnvVars.StateDirPath)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if err := d.opts.EnvVars.init(); err != nil {
|
||||||
|
return nil, fmt.Errorf("initializing daemon directories: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
currBootstrap, err := bootstrap.FromFile(bootstrapFilePath)
|
currBootstrap, err := bootstrap.FromFile(bootstrapFilePath)
|
||||||
if errors.Is(err, fs.ErrNotExist) {
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
// daemon has never had a network created or joined
|
// daemon has never had a network created or joined
|
||||||
@ -368,7 +375,7 @@ func (d *daemon) postInit(ctx context.Context) bool {
|
|||||||
d.logger,
|
d.logger,
|
||||||
"Updating host info in garage",
|
"Updating host info in garage",
|
||||||
func(ctx context.Context) error {
|
func(ctx context.Context) error {
|
||||||
return d.putGarageBoostrapHost(ctx)
|
return putGarageBoostrapHost(ctx, d.logger, d.currBootstrap)
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
return false
|
return false
|
||||||
@ -571,6 +578,20 @@ func (d *daemon) GetBootstrap(ctx context.Context) (bootstrap.Bootstrap, error)
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *daemon) RemoveHost(ctx context.Context, hostName nebula.HostName) error {
|
||||||
|
// TODO RemoveHost should publish a certificate revocation for the host
|
||||||
|
// being removed.
|
||||||
|
_, err := withCurrBootstrap(d, func(
|
||||||
|
currBootstrap bootstrap.Bootstrap,
|
||||||
|
) (
|
||||||
|
struct{}, error,
|
||||||
|
) {
|
||||||
|
client := currBootstrap.GarageClientParams().GlobalBucketS3APIClient()
|
||||||
|
return struct{}{}, removeGarageBootstrapHost(ctx, client, hostName)
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (d *daemon) Shutdown() error {
|
func (d *daemon) Shutdown() error {
|
||||||
d.l.Lock()
|
d.l.Lock()
|
||||||
defer d.l.Unlock()
|
defer d.l.Unlock()
|
||||||
|
@ -13,17 +13,62 @@ import (
|
|||||||
"github.com/adrg/xdg"
|
"github.com/adrg/xdg"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DEPRECATED
|
|
||||||
//
|
|
||||||
// EnvVars are variables which are derived based on the environment which the
|
// EnvVars are variables which are derived based on the environment which the
|
||||||
// process is running in.
|
// process is running in.
|
||||||
//
|
|
||||||
// TODO EnvVars should be private to this package.
|
|
||||||
type EnvVars struct {
|
type EnvVars struct {
|
||||||
RuntimeDirPath string
|
RuntimeDirPath string
|
||||||
StateDirPath string
|
StateDirPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e EnvVars) init() error {
|
||||||
|
var errs []error
|
||||||
|
mkDir := func(path string) error {
|
||||||
|
{
|
||||||
|
parentPath := filepath.Dir(path)
|
||||||
|
parentInfo, err := os.Stat(parentPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("checking parent path %q: %w", parentPath, err)
|
||||||
|
} else if !parentInfo.IsDir() {
|
||||||
|
return fmt.Errorf("%q is not a directory", parentPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
info, err := os.Stat(path)
|
||||||
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
|
// fine
|
||||||
|
} else if err != nil {
|
||||||
|
return fmt.Errorf("checking path: %w", err)
|
||||||
|
} else if !info.IsDir() {
|
||||||
|
return fmt.Errorf("path is not a directory")
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Mkdir(path, 0700); err != nil {
|
||||||
|
return fmt.Errorf("creating directory: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := mkDir(e.RuntimeDirPath); err != nil {
|
||||||
|
errs = append(errs, fmt.Errorf(
|
||||||
|
"creating runtime directory %q: %w",
|
||||||
|
e.RuntimeDirPath,
|
||||||
|
err,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := mkDir(e.StateDirPath); err != nil {
|
||||||
|
errs = append(errs, fmt.Errorf(
|
||||||
|
"creating state directory %q: %w",
|
||||||
|
e.StateDirPath,
|
||||||
|
err,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.Join(errs...)
|
||||||
|
}
|
||||||
|
|
||||||
func getDefaultHTTPSocketDirPath() string {
|
func getDefaultHTTPSocketDirPath() string {
|
||||||
path, err := firstExistingDir(
|
path, err := firstExistingDir(
|
||||||
"/run",
|
"/run",
|
||||||
@ -51,8 +96,6 @@ var HTTPSocketPath = sync.OnceValue(func() string {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
// DEPRECATED
|
|
||||||
//
|
|
||||||
// GetEnvVars will return the EnvVars of the current processes, as determined by
|
// GetEnvVars will return the EnvVars of the current processes, as determined by
|
||||||
// the process's environment.
|
// the process's environment.
|
||||||
var GetEnvVars = sync.OnceValue(func() (v EnvVars) {
|
var GetEnvVars = sync.OnceValue(func() (v EnvVars) {
|
||||||
|
@ -62,9 +62,11 @@ func garageInitializeGlobalBucket(
|
|||||||
// putGarageBoostrapHost places the <hostname>.json.signed file for this host
|
// putGarageBoostrapHost places the <hostname>.json.signed file for this host
|
||||||
// into garage so that other hosts are able to see relevant configuration for
|
// into garage so that other hosts are able to see relevant configuration for
|
||||||
// it.
|
// it.
|
||||||
func (d *daemon) putGarageBoostrapHost(ctx context.Context) error {
|
func putGarageBoostrapHost(
|
||||||
|
ctx context.Context, logger *mlog.Logger, currBootstrap bootstrap.Bootstrap,
|
||||||
|
) error {
|
||||||
var (
|
var (
|
||||||
b = d.currBootstrap
|
b = currBootstrap
|
||||||
host = b.ThisHost()
|
host = b.ThisHost()
|
||||||
client = b.GarageClientParams().GlobalBucketS3APIClient()
|
client = b.GarageClientParams().GlobalBucketS3APIClient()
|
||||||
)
|
)
|
||||||
@ -160,3 +162,17 @@ func getGarageBootstrapHosts(
|
|||||||
|
|
||||||
return hosts, nil
|
return hosts, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func removeGarageBootstrapHost(
|
||||||
|
ctx context.Context, client garage.S3APIClient, hostName nebula.HostName,
|
||||||
|
) error {
|
||||||
|
|
||||||
|
filePath := filepath.Join(
|
||||||
|
garageGlobalBucketBootstrapHostsDirPath,
|
||||||
|
string(hostName)+".json.signed",
|
||||||
|
)
|
||||||
|
|
||||||
|
return client.RemoveObject(
|
||||||
|
ctx, garage.GlobalBucket, filePath, minio.RemoveObjectOptions{},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -86,7 +86,8 @@ func (r *RPC) GetHosts(
|
|||||||
return GetHostsResult{hosts}, nil
|
return GetHostsResult{hosts}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGarageClientParams passes through to the Daemon method of the same name.
|
// GetGarageClientParams returns a GarageClientParams which can be used to
|
||||||
|
// interact with garage.
|
||||||
func (r *RPC) GetGarageClientParams(
|
func (r *RPC) GetGarageClientParams(
|
||||||
ctx context.Context, req struct{},
|
ctx context.Context, req struct{},
|
||||||
) (
|
) (
|
||||||
@ -102,6 +103,7 @@ func (r *RPC) GetGarageClientParams(
|
|||||||
return b.GarageClientParams(), nil
|
return b.GarageClientParams(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetNebulaCAPublicCredentials returns the CAPublicCredentials for the network.
|
||||||
func (r *RPC) GetNebulaCAPublicCredentials(
|
func (r *RPC) GetNebulaCAPublicCredentials(
|
||||||
ctx context.Context, req struct{},
|
ctx context.Context, req struct{},
|
||||||
) (
|
) (
|
||||||
@ -116,3 +118,15 @@ func (r *RPC) GetNebulaCAPublicCredentials(
|
|||||||
|
|
||||||
return b.CAPublicCredentials, nil
|
return b.CAPublicCredentials, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoveHostRequest contains the arguments to the RemoveHost method.
|
||||||
|
//
|
||||||
|
// All fields are required.
|
||||||
|
type RemoveHostRequest struct {
|
||||||
|
HostName nebula.HostName
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveHost passes the call through to the Daemon method of the same name.
|
||||||
|
func (r *RPC) RemoveHost(ctx context.Context, req RemoveHostRequest) (struct{}, error) {
|
||||||
|
return struct{}{}, r.daemon.RemoveHost(ctx, req.HostName)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user