f-33: vm: start vms with multiple nic
All checks were successful
Release Pipeline / checksums (push) Successful in 4s
Release Pipeline / release (push) Successful in 11s
Release Pipeline / set-release-target (push) Successful in 2s
Release Pipeline / upload-assets (agent.service, systemd/agent.service) (push) Successful in 4s
Release Pipeline / upload-assets (dnsmasq@.service, systemd/dnsmasq@.service) (push) Successful in 4s
Release Pipeline / upload-assets (metadata@.service, systemd/metadata@.service) (push) Successful in 4s
Release Pipeline / upload-assets (run-dnsmasq-in-netns.sh, scripts/run-dnsmasq-in-netns.sh) (push) Successful in 4s
Release Pipeline / build (agent, amd64, linux) (push) Successful in 0s
Release Pipeline / build (metadata, amd64, linux) (push) Successful in 0s
Release Pipeline / publish (push) Successful in 0s
Release Pipeline / build (push) Successful in 1m36s
All checks were successful
Release Pipeline / checksums (push) Successful in 4s
Release Pipeline / release (push) Successful in 11s
Release Pipeline / set-release-target (push) Successful in 2s
Release Pipeline / upload-assets (agent.service, systemd/agent.service) (push) Successful in 4s
Release Pipeline / upload-assets (dnsmasq@.service, systemd/dnsmasq@.service) (push) Successful in 4s
Release Pipeline / upload-assets (metadata@.service, systemd/metadata@.service) (push) Successful in 4s
Release Pipeline / upload-assets (run-dnsmasq-in-netns.sh, scripts/run-dnsmasq-in-netns.sh) (push) Successful in 4s
Release Pipeline / build (agent, amd64, linux) (push) Successful in 0s
Release Pipeline / build (metadata, amd64, linux) (push) Successful in 0s
Release Pipeline / publish (push) Successful in 0s
Release Pipeline / build (push) Successful in 1m36s
Signed-off-by: GnomeZworc <nicolas.boufidjeline@g3e.fr>
This commit is contained in:
parent
0237acba81
commit
26d5805747
8 changed files with 309 additions and 25 deletions
|
|
@ -10,6 +10,7 @@ import (
|
|||
type Reservation struct {
|
||||
MAC string
|
||||
IP string
|
||||
Tag string // pose set:<Tag> sur l'entrée, pour cibler les options par interface
|
||||
}
|
||||
|
||||
func HostsDir(confDir, name string) string {
|
||||
|
|
@ -39,7 +40,11 @@ func WriteReservations(confDir, name, vmName string, res []Reservation) error {
|
|||
if r.MAC == "" || r.IP == "" {
|
||||
return fmt.Errorf("incomplete reservation for vm %q: mac=%q ip=%q", vmName, r.MAC, r.IP)
|
||||
}
|
||||
fmt.Fprintf(&sb, "%s,%s\n", r.MAC, r.IP)
|
||||
if r.Tag == "" {
|
||||
fmt.Fprintf(&sb, "%s,%s\n", r.MAC, r.IP)
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(&sb, "%s,%s,set:%s\n", r.MAC, r.IP, r.Tag)
|
||||
}
|
||||
|
||||
path := filepath.Join(dir, vmName)
|
||||
|
|
@ -49,6 +54,51 @@ func WriteReservations(confDir, name, vmName string, res []Reservation) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// WriteVMOptions écrit les options DHCP propres à des interfaces de cette VM
|
||||
// sur ce subnet : elles suppriment la route par défaut — option 3 nue — et
|
||||
// réémettent les autres routes.
|
||||
//
|
||||
// Un override de l'option 121 remplace la précédente en entier, il ne s'y
|
||||
// ajoute pas (vérifié sur dnsmasq 2.90) : omettre la route vers le serveur de
|
||||
// métadonnées la ferait disparaître, et la VM ne se provisionnerait pas.
|
||||
func WriteVMOptions(confDir, name, vmName string, tags []string, c Config) error {
|
||||
if len(tags) == 0 {
|
||||
return RemoveVMOptions(confDir, name, vmName)
|
||||
}
|
||||
if c.InterfaceIP == nil {
|
||||
return fmt.Errorf("interface ip is required to build options for vm %q", vmName)
|
||||
}
|
||||
if c.DefaultGateway != nil {
|
||||
return fmt.Errorf("vm options for %q must not carry a default route", vmName)
|
||||
}
|
||||
|
||||
dir := OptsDir(confDir, name)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return fmt.Errorf("create %s: %w", dir, err)
|
||||
}
|
||||
|
||||
routes := strings.Join(classlessRoutes(c), ",")
|
||||
var sb strings.Builder
|
||||
for _, tag := range tags {
|
||||
fmt.Fprintf(&sb, "tag:%s,3\n", tag)
|
||||
fmt.Fprintf(&sb, "tag:%s,121,%s\n", tag, routes)
|
||||
}
|
||||
|
||||
path := filepath.Join(dir, vmName)
|
||||
if err := os.WriteFile(path, []byte(sb.String()), 0644); err != nil {
|
||||
return fmt.Errorf("write %s: %w", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func RemoveVMOptions(confDir, name, vmName string) error {
|
||||
path := filepath.Join(OptsDir(confDir, name), vmName)
|
||||
if err := os.Remove(path); err != nil && !os.IsNotExist(err) {
|
||||
return fmt.Errorf("remove %s: %w", path, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func RemoveReservations(confDir, name, vmName string) error {
|
||||
for _, dir := range []string{HostsDir(confDir, name), OptsDir(confDir, name)} {
|
||||
path := filepath.Join(dir, vmName)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
package dhcp
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -124,3 +126,103 @@ func TestUnitName(t *testing.T) {
|
|||
t.Errorf("unit attendue dnsmasq@%s.service, obtenu %s", subName, got)
|
||||
}
|
||||
}
|
||||
|
||||
// --- options par interface ---
|
||||
|
||||
func TestWriteReservations_WithTags(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
res := []Reservation{
|
||||
{MAC: "00:22:33:00:01:02", IP: "10.1.1.2", Tag: "i-web-0"},
|
||||
{MAC: "00:22:33:00:02:07", IP: "10.1.2.7", Tag: "i-web-1"},
|
||||
}
|
||||
if err := WriteReservations(dir, subName, "i-web", res); err != nil {
|
||||
t.Fatalf("WriteReservations : %v", err)
|
||||
}
|
||||
content, _ := os.ReadFile(filepath.Join(HostsDir(dir, subName), "i-web"))
|
||||
want := "00:22:33:00:01:02,10.1.1.2,set:i-web-0\n00:22:33:00:02:07,10.1.2.7,set:i-web-1\n"
|
||||
if string(content) != want {
|
||||
t.Errorf("attendu %q, obtenu %q", want, content)
|
||||
}
|
||||
}
|
||||
|
||||
func vmOptions(t *testing.T, dir string, tags []string, vpcRoute *net.IPNet) string {
|
||||
t.Helper()
|
||||
if err := WriteVMOptions(dir, subName, "i-web", tags, Config{
|
||||
InterfaceIP: net.ParseIP("10.1.1.1").To4(),
|
||||
VPCRoute: vpcRoute,
|
||||
}); err != nil {
|
||||
t.Fatalf("WriteVMOptions : %v", err)
|
||||
}
|
||||
b, err := os.ReadFile(filepath.Join(OptsDir(dir, subName), "i-web"))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func TestWriteVMOptions_SuppressesDefaultRoute(t *testing.T) {
|
||||
_, vpcNet, _ := net.ParseCIDR("192.168.0.0/16")
|
||||
got := vmOptions(t, t.TempDir(), []string{"i-web-1"}, vpcNet)
|
||||
|
||||
if !strings.Contains(got, "tag:i-web-1,3\n") {
|
||||
t.Errorf("l'option 3 nue doit supprimer la route par défaut :\n%s", got)
|
||||
}
|
||||
if strings.Contains(got, "0.0.0.0/0") {
|
||||
t.Errorf("la route par défaut ne doit pas figurer dans l'override :\n%s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteVMOptions_ReEmitsMetadataRoute(t *testing.T) {
|
||||
_, vpcNet, _ := net.ParseCIDR("192.168.0.0/16")
|
||||
got := vmOptions(t, t.TempDir(), []string{"i-web-1"}, vpcNet)
|
||||
|
||||
if !strings.Contains(got, "169.254.169.254/32,10.1.1.1") {
|
||||
t.Errorf("un override de l'option 121 remplace la précédente en entier : sans la route metadata, la VM ne se provisionne pas\n%s", got)
|
||||
}
|
||||
if !strings.Contains(got, "192.168.0.0/16,10.1.1.1") {
|
||||
t.Errorf("la route VPC doit être réémise elle aussi :\n%s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteVMOptions_BridgeHasNoVPCRoute(t *testing.T) {
|
||||
got := vmOptions(t, t.TempDir(), []string{"i-web-1"}, nil)
|
||||
|
||||
if !strings.Contains(got, "169.254.169.254/32") {
|
||||
t.Errorf("route metadata absente :\n%s", got)
|
||||
}
|
||||
if strings.Contains(got, "192.168") {
|
||||
t.Errorf("aucune route VPC attendue en mode bridge :\n%s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteVMOptions_OneBlockPerTag(t *testing.T) {
|
||||
got := vmOptions(t, t.TempDir(), []string{"i-web-1", "i-web-2"}, nil)
|
||||
|
||||
for _, tag := range []string{"tag:i-web-1,3", "tag:i-web-2,3"} {
|
||||
if !strings.Contains(got, tag) {
|
||||
t.Errorf("%q absent :\n%s", tag, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteVMOptions_NoTagRemovesFile(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
_ = vmOptions(t, dir, []string{"i-web-1"}, nil)
|
||||
|
||||
if err := WriteVMOptions(dir, subName, "i-web", nil, Config{}); err != nil {
|
||||
t.Fatalf("WriteVMOptions : %v", err)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(OptsDir(dir, subName), "i-web")); !os.IsNotExist(err) {
|
||||
t.Error("sans interface non primaire, aucun fichier d'options ne doit subsister")
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteVMOptions_RefusesDefaultGateway(t *testing.T) {
|
||||
err := WriteVMOptions(t.TempDir(), subName, "i-web", []string{"i-web-1"}, Config{
|
||||
InterfaceIP: net.ParseIP("10.1.1.1").To4(),
|
||||
DefaultGateway: net.ParseIP("10.1.1.254").To4(),
|
||||
})
|
||||
if err == nil {
|
||||
t.Error("ces options servent à retirer la route par défaut : en porter une est une incohérence")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue