Compare commits
No commits in common. "c5e919dc86f84c9eefa308e9fc3660df7c22a75a" and "30c8ca332a9b7988844caacf62e734c5eed3c1fb" have entirely different histories.
c5e919dc86
...
30c8ca332a
@ -42,8 +42,9 @@ func readAdmin(path string) (admin.Admin, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var subCmdAdminCreateBootstrap = subCmd{
|
var subCmdAdminCreateBootstrap = subCmd{
|
||||||
name: "create-bootstrap",
|
name: "create-bootstrap",
|
||||||
descr: "Creates a new bootstrap.json file for a particular host and writes it to stdout",
|
descr: "Creates a new bootstrap.json file for a particular host and writes it to stdout",
|
||||||
|
checkLock: false,
|
||||||
do: func(subCmdCtx subCmdCtx) error {
|
do: func(subCmdCtx subCmdCtx) error {
|
||||||
var (
|
var (
|
||||||
flags = subCmdCtx.flagSet(false)
|
flags = subCmdCtx.flagSet(false)
|
||||||
@ -112,8 +113,9 @@ var subCmdAdminCreateBootstrap = subCmd{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var subCmdAdminCreateNebulaCert = subCmd{
|
var subCmdAdminCreateNebulaCert = subCmd{
|
||||||
name: "create-nebula-cert",
|
name: "create-nebula-cert",
|
||||||
descr: "Creates a signed nebula certificate file and writes it to stdout",
|
descr: "Creates a signed nebula certificate file and writes it to stdout",
|
||||||
|
checkLock: false,
|
||||||
do: func(subCmdCtx subCmdCtx) error {
|
do: func(subCmdCtx subCmdCtx) error {
|
||||||
var (
|
var (
|
||||||
flags = subCmdCtx.flagSet(false)
|
flags = subCmdCtx.flagSet(false)
|
||||||
|
26
go/cmd/entrypoint/bootstrap_util.go
Normal file
26
go/cmd/entrypoint/bootstrap_util.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"isle/bootstrap"
|
||||||
|
)
|
||||||
|
|
||||||
|
func loadHostBootstrap() (bootstrap.Bootstrap, error) {
|
||||||
|
|
||||||
|
stateDirPath := bootstrap.StateDirPath(daemonEnvVars.StateDirPath)
|
||||||
|
|
||||||
|
hostBootstrap, err := bootstrap.FromFile(stateDirPath)
|
||||||
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
|
return bootstrap.Bootstrap{}, fmt.Errorf(
|
||||||
|
"%q not found, has the daemon ever been run?",
|
||||||
|
stateDirPath,
|
||||||
|
)
|
||||||
|
|
||||||
|
} else if err != nil {
|
||||||
|
return bootstrap.Bootstrap{}, fmt.Errorf("loading %q: %w", stateDirPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return hostBootstrap, nil
|
||||||
|
}
|
@ -49,6 +49,12 @@ var subCmdDaemon = subCmd{
|
|||||||
|
|
||||||
logger := subCmdCtx.logger.WithMaxLevel(logLevel.Int())
|
logger := subCmdCtx.logger.WithMaxLevel(logLevel.Int())
|
||||||
|
|
||||||
|
runtimeDirCleanup, err := setupAndLockRuntimeDir(ctx, logger)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("setting up runtime directory: %w", err)
|
||||||
|
}
|
||||||
|
defer runtimeDirCleanup()
|
||||||
|
|
||||||
daemonConfig, err := daemon.LoadConfig(envAppDirPath, *daemonConfigPath)
|
daemonConfig, err := daemon.LoadConfig(envAppDirPath, *daemonConfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("loading daemon config: %w", err)
|
return fmt.Errorf("loading daemon config: %w", err)
|
||||||
|
@ -32,8 +32,9 @@ func initMCConfigDir() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var subCmdGarageMC = subCmd{
|
var subCmdGarageMC = subCmd{
|
||||||
name: "mc",
|
name: "mc",
|
||||||
descr: "Runs the mc (minio-client) binary. The isle garage can be accessed under the `garage` alias",
|
descr: "Runs the mc (minio-client) binary. The isle garage can be accessed under the `garage` alias",
|
||||||
|
checkLock: true,
|
||||||
do: func(subCmdCtx subCmdCtx) error {
|
do: func(subCmdCtx subCmdCtx) error {
|
||||||
|
|
||||||
flags := subCmdCtx.flagSet(true)
|
flags := subCmdCtx.flagSet(true)
|
||||||
@ -115,8 +116,9 @@ var subCmdGarageMC = subCmd{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var subCmdGarageCLI = subCmd{
|
var subCmdGarageCLI = subCmd{
|
||||||
name: "cli",
|
name: "cli",
|
||||||
descr: "Runs the garage binary, automatically configured to point to the garage sub-process of a running isle daemon",
|
descr: "Runs the garage binary, automatically configured to point to the garage sub-process of a running isle daemon",
|
||||||
|
checkLock: true,
|
||||||
do: func(subCmdCtx subCmdCtx) error {
|
do: func(subCmdCtx subCmdCtx) error {
|
||||||
|
|
||||||
var clientParams bootstrap.GarageClientParams
|
var clientParams bootstrap.GarageClientParams
|
||||||
|
@ -46,8 +46,9 @@ var subCmdHostsList = subCmd{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var subCmdHostsDelete = subCmd{
|
var subCmdHostsDelete = subCmd{
|
||||||
name: "delete",
|
name: "delete",
|
||||||
descr: "Deletes a host from the network",
|
descr: "Deletes a host from the network",
|
||||||
|
checkLock: true,
|
||||||
do: func(subCmdCtx subCmdCtx) error {
|
do: func(subCmdCtx subCmdCtx) error {
|
||||||
|
|
||||||
flags := subCmdCtx.flagSet(false)
|
flags := subCmdCtx.flagSet(false)
|
||||||
|
@ -3,7 +3,6 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"isle/jsonutil"
|
"isle/jsonutil"
|
||||||
"isle/nebula"
|
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -17,20 +16,12 @@ var subCmdNebulaShow = subCmd{
|
|||||||
return fmt.Errorf("parsing flags: %w", err)
|
return fmt.Errorf("parsing flags: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hosts, err := subCmdCtx.getHosts()
|
hostBootstrap, err := loadHostBootstrap()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("getting hosts: %w", err)
|
return fmt.Errorf("loading host bootstrap: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var caPublicCreds nebula.CAPublicCredentials
|
caCert := hostBootstrap.CAPublicCredentials.Cert.Unwrap()
|
||||||
err = subCmdCtx.daemonRCPClient.Call(
|
|
||||||
subCmdCtx.ctx, &caPublicCreds, "GetNebulaCAPublicCredentials", nil,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("calling GetNebulaCAPublicCredentials: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
caCert := caPublicCreds.Cert.Unwrap()
|
|
||||||
caCertPEM, err := caCert.MarshalToPEM()
|
caCertPEM, err := caCert.MarshalToPEM()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("marshaling CA cert to PEM: %w", err)
|
return fmt.Errorf("marshaling CA cert to PEM: %w", err)
|
||||||
@ -59,7 +50,7 @@ var subCmdNebulaShow = subCmd{
|
|||||||
SubnetCIDR: subnet.String(),
|
SubnetCIDR: subnet.String(),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, h := range hosts.Hosts {
|
for _, h := range hostBootstrap.Hosts {
|
||||||
if h.Nebula.PublicAddr == "" {
|
if h.Nebula.PublicAddr == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
103
go/cmd/entrypoint/proc_lock.go
Normal file
103
go/cmd/entrypoint/proc_lock.go
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"dev.mediocregopher.com/mediocre-go-lib.git/mctx"
|
||||||
|
"dev.mediocregopher.com/mediocre-go-lib.git/mlog"
|
||||||
|
"github.com/shirou/gopsutil/process"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errDaemonNotRunning = errors.New("no isle daemon process running")
|
||||||
|
|
||||||
|
func lockFilePath() string {
|
||||||
|
return filepath.Join(daemonEnvVars.RuntimeDirPath, "lock")
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeLock() error {
|
||||||
|
|
||||||
|
lockFilePath := lockFilePath()
|
||||||
|
|
||||||
|
lockFile, err := os.OpenFile(
|
||||||
|
lockFilePath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0400,
|
||||||
|
)
|
||||||
|
|
||||||
|
if errors.Is(err, os.ErrExist) {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"lock file %q already exists, if the isle daemon is not already running you can safely delete this file",
|
||||||
|
lockFilePath,
|
||||||
|
)
|
||||||
|
|
||||||
|
} else if err != nil {
|
||||||
|
return fmt.Errorf("opening lockfile %q: %w", lockFilePath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer lockFile.Close()
|
||||||
|
|
||||||
|
if _, err := fmt.Fprintf(lockFile, "%d\n", os.Getpid()); err != nil {
|
||||||
|
return fmt.Errorf("writing pid to %q: %w", lockFilePath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns a cleanup function which will clean up the created runtime directory.
|
||||||
|
func setupAndLockRuntimeDir(ctx context.Context, logger *mlog.Logger) (func(), error) {
|
||||||
|
|
||||||
|
ctx = mctx.Annotate(ctx, "runtimeDirPath", daemonEnvVars.RuntimeDirPath)
|
||||||
|
logger.Info(ctx, "will use runtime directory for temporary state")
|
||||||
|
|
||||||
|
if err := os.MkdirAll(daemonEnvVars.RuntimeDirPath, 0700); err != nil {
|
||||||
|
return nil, fmt.Errorf("creating directory %q: %w", daemonEnvVars.RuntimeDirPath, err)
|
||||||
|
|
||||||
|
} else if err := writeLock(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return func() {
|
||||||
|
logger.Info(ctx, "cleaning up runtime directory")
|
||||||
|
if err := os.RemoveAll(daemonEnvVars.RuntimeDirPath); err != nil {
|
||||||
|
logger.Error(ctx, "removing temporary directory", err)
|
||||||
|
}
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// checks that the lock file exists and that the process which created it also
|
||||||
|
// still exists.
|
||||||
|
func assertLock() error {
|
||||||
|
|
||||||
|
lockFilePath := lockFilePath()
|
||||||
|
|
||||||
|
lockFile, err := os.Open(lockFilePath)
|
||||||
|
|
||||||
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
|
return errDaemonNotRunning
|
||||||
|
|
||||||
|
} else if err != nil {
|
||||||
|
return fmt.Errorf("checking lock file %q: %w", lockFilePath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer lockFile.Close()
|
||||||
|
|
||||||
|
var pid int32
|
||||||
|
|
||||||
|
if _, err := fmt.Fscan(lockFile, &pid); err != nil {
|
||||||
|
return fmt.Errorf("scanning pid from lock file %q: %w", lockFilePath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
procExists, err := process.PidExists(pid)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("checking if process %d exists: %w", pid, err)
|
||||||
|
|
||||||
|
} else if !procExists {
|
||||||
|
return errDaemonNotRunning
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -24,9 +24,10 @@ type subCmdCtx struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type subCmd struct {
|
type subCmd struct {
|
||||||
name string
|
name string
|
||||||
descr string
|
descr string
|
||||||
do func(subCmdCtx) error
|
checkLock bool
|
||||||
|
do func(subCmdCtx) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx subCmdCtx) usagePrefix() string {
|
func (ctx subCmdCtx) usagePrefix() string {
|
||||||
@ -102,6 +103,13 @@ func (ctx subCmdCtx) doSubCmd(subCmds ...subCmd) error {
|
|||||||
printUsageExit(subCmdName)
|
printUsageExit(subCmdName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if subCmd.checkLock {
|
||||||
|
|
||||||
|
if err := assertLock(); err != nil {
|
||||||
|
return fmt.Errorf("checking lock file: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
daemonRCPClient := jsonrpc2.NewUnixHTTPClient(
|
daemonRCPClient := jsonrpc2.NewUnixHTTPClient(
|
||||||
daemon.HTTPSocketPath(), daemonHTTPRPCPath,
|
daemon.HTTPSocketPath(), daemonHTTPRPCPath,
|
||||||
)
|
)
|
||||||
|
@ -49,8 +49,20 @@ type Daemon interface {
|
|||||||
// - ErrAlreadyJoined
|
// - ErrAlreadyJoined
|
||||||
JoinNetwork(context.Context, bootstrap.Bootstrap) error
|
JoinNetwork(context.Context, bootstrap.Bootstrap) error
|
||||||
|
|
||||||
// GetBootstraps returns the currently active Bootstrap.
|
// GetBootstrapHosts returns the hosts stored in the bootstrap.
|
||||||
GetBootstrap(context.Context) (bootstrap.Bootstrap, error)
|
GetBootstrapHosts(
|
||||||
|
ctx context.Context,
|
||||||
|
) (
|
||||||
|
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,
|
// 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.
|
||||||
@ -561,13 +573,31 @@ func (d *daemon) JoinNetwork(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *daemon) GetBootstrap(ctx context.Context) (bootstrap.Bootstrap, error) {
|
func (d *daemon) GetBootstrapHosts(
|
||||||
|
ctx context.Context,
|
||||||
|
) (
|
||||||
|
map[nebula.HostName]bootstrap.Host, error,
|
||||||
|
) {
|
||||||
return withCurrBootstrap(d, func(
|
return withCurrBootstrap(d, func(
|
||||||
currBootstrap bootstrap.Bootstrap,
|
currBootstrap bootstrap.Bootstrap,
|
||||||
) (
|
) (
|
||||||
bootstrap.Bootstrap, error,
|
map[nebula.HostName]bootstrap.Host, error,
|
||||||
) {
|
) {
|
||||||
return currBootstrap, nil
|
return currBootstrap.Hosts, nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *daemon) GetGarageClientParams(
|
||||||
|
ctx context.Context,
|
||||||
|
) (
|
||||||
|
bootstrap.GarageClientParams, error,
|
||||||
|
) {
|
||||||
|
return withCurrBootstrap(d, func(
|
||||||
|
currBootstrap bootstrap.Bootstrap,
|
||||||
|
) (
|
||||||
|
bootstrap.GarageClientParams, error,
|
||||||
|
) {
|
||||||
|
return currBootstrap.GarageClientParams(), nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,12 +73,12 @@ func (r *RPC) GetHosts(
|
|||||||
) (
|
) (
|
||||||
GetHostsResult, error,
|
GetHostsResult, error,
|
||||||
) {
|
) {
|
||||||
b, err := r.daemon.GetBootstrap(ctx)
|
hostsMap, err := r.daemon.GetBootstrapHosts(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return GetHostsResult{}, fmt.Errorf("retrieving bootstrap: %w", err)
|
return GetHostsResult{}, fmt.Errorf("retrieving hosts: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
hosts := maps.Values(b.Hosts)
|
hosts := maps.Values(hostsMap)
|
||||||
slices.SortFunc(hosts, func(a, b bootstrap.Host) int {
|
slices.SortFunc(hosts, func(a, b bootstrap.Host) int {
|
||||||
return cmp.Compare(a.Name, b.Name)
|
return cmp.Compare(a.Name, b.Name)
|
||||||
})
|
})
|
||||||
@ -92,27 +92,5 @@ func (r *RPC) GetGarageClientParams(
|
|||||||
) (
|
) (
|
||||||
bootstrap.GarageClientParams, error,
|
bootstrap.GarageClientParams, error,
|
||||||
) {
|
) {
|
||||||
b, err := r.daemon.GetBootstrap(ctx)
|
return r.daemon.GetGarageClientParams(ctx)
|
||||||
if err != nil {
|
|
||||||
return bootstrap.GarageClientParams{}, fmt.Errorf(
|
|
||||||
"retrieving bootstrap: %w", err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return b.GarageClientParams(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *RPC) GetNebulaCAPublicCredentials(
|
|
||||||
ctx context.Context, req struct{},
|
|
||||||
) (
|
|
||||||
nebula.CAPublicCredentials, error,
|
|
||||||
) {
|
|
||||||
b, err := r.daemon.GetBootstrap(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nebula.CAPublicCredentials{}, fmt.Errorf(
|
|
||||||
"retrieving bootstrap: %w", err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return b.CAPublicCredentials, nil
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user