engine: resources, modules: virtualization: Add a seeds option

This makes it easier to configure the machine by giving it an automatic
initial setup of an mgmt client.
This commit is contained in:
James Shubin
2025-03-11 00:03:56 -04:00
parent 181aab9c81
commit 219d25b330
2 changed files with 44 additions and 3 deletions

View File

@@ -33,6 +33,7 @@ import (
"bytes" "bytes"
"context" "context"
"fmt" "fmt"
"net/url"
"os" "os"
"os/exec" "os/exec"
"path" "path"
@@ -146,9 +147,13 @@ type VirtBuilderRes struct {
// additional packages to install which are needed to bootstrap mgmt. // additional packages to install which are needed to bootstrap mgmt.
// This defaults to true. // This defaults to true.
// TODO: This does not yet support multi or cross arch. // TODO: This does not yet support multi or cross arch.
// FIXME: This doesn't kick off mgmt runs yet.
Bootstrap bool `lang:"bootstrap" yaml:"bootstrap"` Bootstrap bool `lang:"bootstrap" yaml:"bootstrap"`
// Seeds is a list of default etcd client endpoints to connect to. If
// you specify this, you must also set Bootstrap to true. These should
// likely be http URL's like: http://127.0.0.1:2379 or similar.
Seeds []string `lang:"seeds" yaml:"seeds"`
// LogOutput logs the output of running this command to a file in the // LogOutput logs the output of running this command to a file in the
// special $vardir directory. It defaults to true. Keep in mind that if // special $vardir directory. It defaults to true. Keep in mind that if
// you let virt-builder choose the password randomly, it will be output // you let virt-builder choose the password randomly, it will be output
@@ -305,6 +310,15 @@ func (obj *VirtBuilderRes) Validate() error {
} }
} }
for _, x := range obj.Seeds {
if x == "" {
return fmt.Errorf("empty seed")
}
if _, err := url.Parse(x); err != nil { // it's so rare this fails
return err
}
}
return nil return nil
} }
@@ -501,8 +515,24 @@ func (obj *VirtBuilderRes) CheckApply(ctx context.Context, apply bool) (bool, er
// TODO: bootstrap mgmt based on the deploy method this ran with // TODO: bootstrap mgmt based on the deploy method this ran with
// TODO: --tmp-prefix ? --module-path ? // TODO: --tmp-prefix ? --module-path ?
//args2 := []string{"--firstboot-command", VirtBuilderBinDir+"mgmt", "run", "lang", "?"} // TODO: add an alternate handoff method to run a bolus of code?
//cmdArgs = append(cmdArgs, args2...) if len(obj.Seeds) > 0 {
m := filepath.Join(VirtBuilderBinDir, filepath.Base(p)) // mgmt full path
setupSvc := []string{
m, // mgmt
"setup", // setup command
"svc", // TODO: pull from a const?
"--install",
//"--start", // we're in pre-boot env right now
"--enable", // start on first boot!
fmt.Sprintf("--binary-path=%s", m),
"--no-server", // TODO: hardcode this for now
fmt.Sprintf("--seeds=%s", strings.Join(obj.Seeds, ",")),
}
setupSvcCmd := strings.Join(setupSvc, " ")
args := []string{"--run-command", setupSvcCmd} // cmd must be a single string
cmdArgs = append(cmdArgs, args...)
}
} }
cmd := exec.CommandContext(ctx, cmdName, cmdArgs...) cmd := exec.CommandContext(ctx, cmdName, cmdArgs...)
@@ -644,6 +674,15 @@ func (obj *VirtBuilderRes) Cmp(r engine.Res) error {
return fmt.Errorf("the Bootstrap value differs") return fmt.Errorf("the Bootstrap value differs")
} }
if len(obj.Seeds) != len(res.Seeds) {
return fmt.Errorf("the number of Seeds differs")
}
for i, x := range obj.Seeds {
if seed := res.Seeds[i]; x != seed {
return fmt.Errorf("the seed at index %d differs", i)
}
}
if obj.LogOutput != res.LogOutput { if obj.LogOutput != res.LogOutput {
return fmt.Errorf("the LogOutput value differs") return fmt.Errorf("the LogOutput value differs")
} }

View File

@@ -97,6 +97,7 @@ class vm($name, $config) {
} else { # other distros TODO: add a switch or else if? } else { # other distros TODO: add a switch or else if?
[] []
} }
$seeds = $config->seeds || []
virt:builder "${filename}" { virt:builder "${filename}" {
hostname => $name, hostname => $name,
@@ -115,6 +116,7 @@ class vm($name, $config) {
}, },
], ],
root_password_selector => $root_password_selector, root_password_selector => $root_password_selector,
seeds => $seeds,
# make sure key exists so that's it's available for injection! # make sure key exists so that's it's available for injection!
Depend => File["/root/.ssh/id_rsa"], Depend => File["/root/.ssh/id_rsa"],