You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
isle/entrypoint/src/bootstrap/bootstrap.go

105 lines
2.9 KiB

// Package bootstrap deals with the parsing and creation of bootstrap.yml files.
// It also contains some helpers which rely on bootstrap data.
package bootstrap
import (
"isle/admin"
"isle/garage"
"isle/nebula"
"crypto/sha512"
"fmt"
"io"
"os"
"path/filepath"
"sort"
"gopkg.in/yaml.v3"
)
// DataDirPath returns the path within the user's data directory where the
// bootstrap file is stored.
func DataDirPath(dataDirPath string) string {
return filepath.Join(dataDirPath, "bootstrap.yml")
}
// AppDirPath returns the path within the AppDir where an embedded bootstrap
// file might be found.
func AppDirPath(appDirPath string) string {
return filepath.Join(appDirPath, "share/bootstrap.yml")
}
// Bootstrap is used for accessing all information contained within a
// bootstrap.yml file.
type Bootstrap struct {
AdminCreationParams admin.CreationParams `yaml:"admin_creation_params"`
Hosts map[string]Host `yaml:"hosts"`
HostName string `yaml:"hostname"`
Nebula struct {
CAPublicCredentials nebula.CAPublicCredentials `yaml:"ca_public_credentials"`
HostCredentials nebula.HostCredentials `yaml:"host_credentials"`
SignedPublicCredentials string `yaml:"signed_public_credentials"`
} `yaml:"nebula"`
Garage struct {
RPCSecret string `yaml:"rpc_secret"`
AdminToken string `yaml:"admin_token"`
GlobalBucketS3APICredentials garage.S3APICredentials `yaml:"global_bucket_s3_api_credentials"`
} `yaml:"garage"`
}
// FromReader reads a bootstrap.yml file from the given io.Reader.
func FromReader(r io.Reader) (Bootstrap, error) {
var b Bootstrap
err := yaml.NewDecoder(r).Decode(&b)
return b, err
}
// FromFile reads a bootstrap.yml from a file at the given path.
func FromFile(path string) (Bootstrap, error) {
f, err := os.Open(path)
if err != nil {
return Bootstrap{}, fmt.Errorf("opening file: %w", err)
}
defer f.Close()
return FromReader(f)
}
// WriteTo writes the Bootstrap as a new bootstrap.yml to the given io.Writer.
func (b Bootstrap) WriteTo(into io.Writer) error {
return yaml.NewEncoder(into).Encode(b)
}
// ThisHost is a shortcut for b.Hosts[b.HostName], but will panic if the
// HostName isn't found in the Hosts map.
func (b Bootstrap) ThisHost() Host {
host, ok := b.Hosts[b.HostName]
if !ok {
panic(fmt.Sprintf("hostname %q not defined in bootstrap's hosts", b.HostName))
}
return host
}
// Hash returns a deterministic hash of the given hosts map.
func HostsHash(hostsMap map[string]Host) ([]byte, error) {
hosts := make([]Host, 0, len(hostsMap))
for _, host := range hostsMap {
hosts = append(hosts, host)
}
sort.Slice(hosts, func(i, j int) bool { return hosts[i].Name < hosts[j].Name })
h := sha512.New()
if err := yaml.NewEncoder(h).Encode(hosts); err != nil {
return nil, err
}
return h.Sum(nil), nil
}