110 lines
3.0 KiB
Go
110 lines
3.0 KiB
Go
package bootstrap
|
|
|
|
import (
|
|
"fmt"
|
|
"isle/garage"
|
|
"isle/nebula"
|
|
"net/netip"
|
|
)
|
|
|
|
// NebulaHost describes the nebula configuration of a Host which is relevant for
|
|
// other hosts to know.
|
|
type NebulaHost struct {
|
|
PublicAddr string
|
|
}
|
|
|
|
// GarageHost describes a single garage instance in the GarageHost.
|
|
type GarageHostInstance struct {
|
|
ID string
|
|
RPCPort int
|
|
S3APIPort int
|
|
}
|
|
|
|
// GarageHost describes the garage configuration of a Host which is relevant for
|
|
// other hosts to know.
|
|
type GarageHost struct {
|
|
Instances []GarageHostInstance
|
|
}
|
|
|
|
// HostAssigned are all fields related to a host which were assigned to it by an
|
|
// admin.
|
|
type HostAssigned struct {
|
|
Name nebula.HostName
|
|
PublicCredentials nebula.HostPublicCredentials
|
|
}
|
|
|
|
// HostConfigured are all the fields a host can configure for itself.
|
|
type HostConfigured struct {
|
|
Nebula NebulaHost `json:",omitempty"`
|
|
Garage GarageHost `json:",omitempty"`
|
|
}
|
|
|
|
// AuthenticatedHost wraps all the data about a host which other hosts may know
|
|
// about it, such that those hosts can authenticate that the data is valid and
|
|
// approved by an admin.
|
|
type AuthenticatedHost struct {
|
|
Assigned nebula.Signed[HostAssigned] // signed by CA
|
|
Configured nebula.Signed[HostConfigured] // signed by host
|
|
}
|
|
|
|
// Unwrap attempts to authenticate and unwrap the Host embedded in this
|
|
// instance. nebula.ErrInvalidSignature is returned if any signatures are
|
|
// invalid.
|
|
func (ah AuthenticatedHost) Unwrap(caCreds nebula.CAPublicCredentials) (Host, error) {
|
|
assigned, err := ah.Assigned.Unwrap(caCreds.SigningKey)
|
|
if err != nil {
|
|
return Host{}, fmt.Errorf("unwrapping assigned fields using CA public key: %w", err)
|
|
}
|
|
|
|
configured, err := ah.Configured.Unwrap(assigned.PublicCredentials.SigningKey)
|
|
if err != nil {
|
|
return Host{}, fmt.Errorf("unwrapping configured fields using host public key: %w", err)
|
|
}
|
|
|
|
return Host{assigned, configured}, nil
|
|
}
|
|
|
|
// Host contains all data bout a host which other hosts may know about it.
|
|
//
|
|
// A Host should only be obtained over the network as an AuthenticatedHost, and
|
|
// subsequently Unwrapped.
|
|
type Host struct {
|
|
HostAssigned
|
|
HostConfigured
|
|
}
|
|
|
|
// IP returns the IP address encoded in the Host's nebula certificate, or panics
|
|
// if there is an error.
|
|
//
|
|
// This assumes that the Host and its data has already been verified against the
|
|
// CA signing key.
|
|
func (h Host) IP() netip.Addr {
|
|
cert := h.PublicCredentials.Cert.Unwrap()
|
|
if len(cert.Details.Ips) == 0 {
|
|
panic(fmt.Sprintf("host %q not configured with any ips: %+v", h.Name, h))
|
|
}
|
|
|
|
ip := cert.Details.Ips[0].IP
|
|
addr, ok := netip.AddrFromSlice(ip)
|
|
if !ok {
|
|
panic(fmt.Sprintf("ip %q (%#v) is not valid, somehow", ip, ip))
|
|
}
|
|
|
|
return addr
|
|
}
|
|
|
|
// GarageNodes returns a RemoteNode for each garage instance advertised by this
|
|
// Host.
|
|
func (h Host) GarageNodes() []garage.RemoteNode {
|
|
var nodes []garage.RemoteNode
|
|
for _, instance := range h.Garage.Instances {
|
|
nodes = append(nodes, garage.RemoteNode{
|
|
ID: instance.ID,
|
|
IP: h.IP().String(),
|
|
RPCPort: instance.RPCPort,
|
|
S3APIPort: instance.S3APIPort,
|
|
})
|
|
}
|
|
return nodes
|
|
}
|