Compare commits

...

11 Commits

Author SHA1 Message Date
amery a910bba406 Merge pull request 'cluster: introduce Machine.Inactive flag' (#38)
Reviewed-on: #38
2023-10-30 20:44:41 +01:00
amery 5ef6d45ef7 Merge pull request 'jpictl: fix cloud.yaml unmarshalling' (#32)
Reviewed-on: #32
2023-10-30 20:43:21 +01:00
amery 99998dc7e8 cluster: mark Machine as Inactive if the "region" file contains "none"
Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-10-30 19:21:08 +00:00
amery 892d849740 cluster: introduce Machine.Inactive flag
if a Machine is Inactive, it won't be included on the DNS
aliases for the zone or it's regions.

v2:
- Machine.Active() renamed to Machine.IsActive()

Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-10-30 19:20:45 +00:00
amery 125a4c0dbe wireguard: implement EndpointAddress.UnmarshalText
Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-10-30 19:13:41 +00:00
amery 7c811d7813 wireguard: implement UnmarshalText for PrivateKey and PublicKey
Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-10-30 19:13:41 +00:00
amery 1580c09746 cluster: add Machine.ReadLines() shortcut
Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-10-30 18:52:28 +00:00
amery a928ab8880 Merge pull request 'jpictl: add flags to control the default scan' (#34)
Reviewed-on: #34
2023-10-30 19:50:14 +01:00
amery 727fd67bc6 jpictl: add --domain/-D and --scan-dir/-d options
Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-10-28 21:22:39 +00:00
amery b8e1b321e5 jpictl: add -S flag to ignore the config file and always scan
Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-10-28 21:22:37 +00:00
amery 0c5429a681 jpictl: move verbosity handling to the log module
Signed-off-by: Alejandro Mery <amery@jpi.io>
2023-10-28 21:22:36 +00:00
10 changed files with 132 additions and 38 deletions
+40 -17
View File
@@ -12,6 +12,14 @@ const (
// DefaultConfigFile is read if -f/--config-file isn't specified. // DefaultConfigFile is read if -f/--config-file isn't specified.
// If it doesn't exist, m/ will be scanned // If it doesn't exist, m/ will be scanned
DefaultConfigFile = "cloud.yaml" DefaultConfigFile = "cloud.yaml"
// DefaultClusterDir is the directory we will scan and write
// unless something else is indicated
DefaultClusterDir = "m"
// DefaultDomain indicates the domain to use unless
// something else is specified
DefaultDomain = "jpi.cloud"
) )
// Config describes the repository // Config describes the repository
@@ -22,27 +30,34 @@ type Config struct {
ConfigFile string ConfigFile string
} }
var forceScan bool
var cfg = &Config{ var cfg = &Config{
Base: "m", Base: DefaultClusterDir,
Domain: "jpi.cloud", Domain: DefaultDomain,
} }
// LoadZones loads all zones and machines in the config directory // LoadZones loads all zones and machines in the config directory
// or file // or file
func (cfg *Config) LoadZones(resolve bool) (*cluster.Cluster, error) { func (cfg *Config) LoadZones(resolve bool) (*cluster.Cluster, error) {
// try config file first var zones *cluster.Cluster
zones, err := cluster.NewFromConfig(cfg.ConfigFile, var err error
cluster.ResolvePublicAddresses(resolve),
cluster.WithLogger(log),
)
switch { if !forceScan {
case err == nil: // try config file first
// file was good zones, err = cluster.NewFromConfig(cfg.ConfigFile,
return zones, nil cluster.ResolvePublicAddresses(resolve),
case !os.IsNotExist(err) || cfg.ConfigFile != DefaultConfigFile: cluster.WithLogger(log),
// file was bad )
return nil, core.Wrap(err, "NewFromConfig(%q)", cfg.ConfigFile)
switch {
case err == nil:
// file was good
return zones, nil
case !os.IsNotExist(err) || cfg.ConfigFile != DefaultConfigFile:
// file was bad
return nil, core.Wrap(err, "NewFromConfig(%q)", cfg.ConfigFile)
}
} }
// default file doesn't exist. scan instead. // default file doesn't exist. scan instead.
@@ -53,7 +68,15 @@ func (cfg *Config) LoadZones(resolve bool) (*cluster.Cluster, error) {
} }
func init() { func init() {
rootCmd.PersistentFlags(). flags := rootCmd.PersistentFlags()
StringVarP(&cfg.ConfigFile, "config-file", "f",
DefaultConfigFile, "config file (JSON or YAML)") flags.StringVarP(&cfg.Base, "scan-dir", "d",
DefaultClusterDir, "directory to scan for cluster data")
flags.StringVarP(&cfg.Domain, "domain", "D",
DefaultDomain, "domain to use for scanned data")
flags.StringVarP(&cfg.ConfigFile, "config-file", "f",
DefaultConfigFile, "config file (JSON or YAML)")
flags.BoolVarP(&forceScan, "force-scan", "S",
false, "ignore config file and scan the directory instead")
} }
+1 -1
View File
@@ -52,7 +52,7 @@ func populateDNSManager(mgr *dns.Manager, m *cluster.Cluster) error {
m.ForEachZone(func(z *cluster.Zone) bool { m.ForEachZone(func(z *cluster.Zone) bool {
z.ForEachMachine(func(p *cluster.Machine) bool { z.ForEachMachine(func(p *cluster.Machine) bool {
err = mgr.AddHost(ctx, z.Name, p.ID, true, p.PublicAddresses...) err = mgr.AddHost(ctx, z.Name, p.ID, p.IsActive(), p.PublicAddresses...)
return err != nil return err != nil
}) })
+21
View File
@@ -3,9 +3,13 @@ package main
import ( import (
"fmt" "fmt"
"darvaza.org/sidecar/pkg/logger/zerolog"
"darvaza.org/slog" "darvaza.org/slog"
"github.com/spf13/cobra"
) )
var log = zerolog.New(nil, slog.Error)
// fatal is a convenience wrapper for slog.Logger.Fatal().Print() // fatal is a convenience wrapper for slog.Logger.Fatal().Print()
func fatal(err error, msg string, args ...any) { func fatal(err error, msg string, args ...any) {
l := log.Fatal() l := log.Fatal()
@@ -19,3 +23,20 @@ func fatal(err error, msg string, args ...any) {
panic("unreachable") panic("unreachable")
} }
var verbosity int
// setVerbosity replaces the global logger using the
// verbosity level specified via -v flags
func setVerbosity(_ *cobra.Command, _ []string) {
desired := int8(slog.Error) + int8(verbosity)
if desired > 6 {
desired = 6
}
log = zerolog.New(nil, slog.LogLevel(desired))
}
func init() {
rootCmd.PersistentFlags().CountVarP(&verbosity, "verbosity", "v",
"increase the verbosity level to Warn, Info or Debug")
}
+1 -18
View File
@@ -2,8 +2,6 @@
package main package main
import ( import (
"darvaza.org/sidecar/pkg/logger/zerolog"
"darvaza.org/slog"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@@ -13,9 +11,7 @@ const (
) )
var ( var (
log = zerolog.New(nil, slog.Error) rootCmd = &cobra.Command{
verbosity int
rootCmd = &cobra.Command{
Use: CmdName, Use: CmdName,
Short: "control tool for jpi.cloud", Short: "control tool for jpi.cloud",
} }
@@ -26,16 +22,3 @@ func main() {
fatal(err, "") fatal(err, "")
} }
} }
func init() {
rootCmd.PersistentFlags().CountVarP(&verbosity, "verbosity", "v",
"increase the verbosity level to Warn, Info or Debug")
}
func setVerbosity(_ *cobra.Command, _ []string) {
desired := int8(slog.Error) + int8(verbosity)
if desired > 6 {
desired = 6
}
log = zerolog.New(nil, slog.LogLevel(desired))
}
+6
View File
@@ -15,6 +15,7 @@ type Machine struct {
ID int ID int
Name string `json:"-" yaml:"-"` Name string `json:"-" yaml:"-"`
Inactive bool `json:"inactive,omitempty" yaml:"inactive,omitempty"`
CephMonitor bool `json:"ceph_monitor,omitempty" yaml:"ceph_monitor,omitempty"` CephMonitor bool `json:"ceph_monitor,omitempty" yaml:"ceph_monitor,omitempty"`
PublicAddresses []netip.Addr `json:"public,omitempty" yaml:"public,omitempty"` PublicAddresses []netip.Addr `json:"public,omitempty" yaml:"public,omitempty"`
Rings []*RingInfo `json:"rings,omitempty" yaml:"rings,omitempty"` Rings []*RingInfo `json:"rings,omitempty" yaml:"rings,omitempty"`
@@ -43,6 +44,11 @@ func (m *Machine) FullName() string {
return strings.Join(name, ".") return strings.Join(name, ".")
} }
// IsActive indicates the machine is to be included in regions' DNS entries
func (m *Machine) IsActive() bool {
return !m.Inactive
}
// IsGateway tells if the Machine is a ring0 gateway // IsGateway tells if the Machine is a ring0 gateway
func (m *Machine) IsGateway() bool { func (m *Machine) IsGateway() bool {
_, ok := m.getRingInfo(0) _, ok := m.getRingInfo(0)
+8
View File
@@ -53,6 +53,14 @@ func (m *Machine) ReadFile(name string, args ...any) ([]byte, error) {
return m.zone.zones.ReadFile(fullName) return m.zone.zones.ReadFile(fullName)
} }
// ReadLines reads a file from the machine's config directory,
// split by lines, trimmed, and accepting `#` to comment lines out.
func (m *Machine) ReadLines(name string, args ...any) ([]string, error) {
fullName := m.getFilename(name, args...)
return m.zone.zones.ReadLines(fullName)
}
// WriteStringFile writes the given content to a file on the machine's config directory // WriteStringFile writes the given content to a file on the machine's config directory
func (m *Machine) WriteStringFile(value string, name string, args ...any) error { func (m *Machine) WriteStringFile(value string, name string, args ...any) error {
fullName := m.getFilename(name, args...) fullName := m.getFilename(name, args...)
+25 -1
View File
@@ -3,6 +3,7 @@ package cluster
import ( import (
"context" "context"
"net/netip" "net/netip"
"os"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@@ -81,7 +82,30 @@ func (m *Machine) scan(_ *ScanOptions) error {
} }
} }
return nil return m.loadInactive()
}
func (m *Machine) loadInactive() error {
data, err := m.ReadLines("region")
switch {
case os.IsNotExist(err):
// no file
return nil
case err != nil:
// read error
return err
default:
// look for "none"
for _, r := range data {
switch r {
case "none":
m.Inactive = true
default:
m.Inactive = false
}
}
return nil
}
} }
// scanWrapUp is called once all machines have been scanned // scanWrapUp is called once all machines have been scanned
+3 -1
View File
@@ -32,7 +32,9 @@ func (r *Region) ForEachMachine(fn func(*Machine) bool) {
var term bool var term bool
z.ForEachMachine(func(p *Machine) bool { z.ForEachMachine(func(p *Machine) bool {
term = fn(p) if p.IsActive() {
term = fn(p)
}
return term return term
}) })
+5
View File
@@ -107,6 +107,11 @@ func (ep EndpointAddress) String() string {
} }
} }
// UnmarshalText loads an endpoint address from text data
func (ep *EndpointAddress) UnmarshalText(b []byte) error {
return ep.FromString(string(b))
}
// FromString sets the EndpointAddress from a given "[host]:port" // FromString sets the EndpointAddress from a given "[host]:port"
func (ep *EndpointAddress) FromString(s string) error { func (ep *EndpointAddress) FromString(s string) error {
host, port, err := core.SplitHostPort(s) host, port, err := core.SplitHostPort(s)
+22
View File
@@ -51,6 +51,28 @@ func (pub PublicKey) String() string {
} }
} }
// UnmarshalText loads the value from base64
func (key *PrivateKey) UnmarshalText(b []byte) error {
v, err := PrivateKeyFromBase64(string(b))
if err != nil {
return err
}
*key = v
return nil
}
// UnmarshalText loads the value from base64
func (pub *PublicKey) UnmarshalText(b []byte) error {
v, err := PublicKeyFromBase64(string(b))
if err != nil {
return err
}
*pub = v
return nil
}
// MarshalJSON encodes the key for JSON, omitting empty. // MarshalJSON encodes the key for JSON, omitting empty.
func (key PrivateKey) MarshalJSON() ([]byte, error) { func (key PrivateKey) MarshalJSON() ([]byte, error) {
return encodeKeyJSON(key.String()) return encodeKeyJSON(key.String())