diff --git a/nodes/xrd/mgmt_intf_v6_addr.sh.tmpl b/nodes/xrd/mgmt_intf_v6_addr.sh.tmpl new file mode 100644 index 000000000..ed3347103 --- /dev/null +++ b/nodes/xrd/mgmt_intf_v6_addr.sh.tmpl @@ -0,0 +1,5 @@ +#!/bin/bash + +source /pkg/bin/ztp_helper.sh + +xrapply_string "interface MgmtEth0/RP0/CPU0/0\n no ipv6 address\n{{- if .MgmtIPv6Addr }}ipv6 address {{ .MgmtIPv6Addr }}/{{ .MgmtIPv6PrefixLen }}\n{{- end}}" \ No newline at end of file diff --git a/nodes/xrd/xrd.go b/nodes/xrd/xrd.go index 70798988c..9ce249359 100644 --- a/nodes/xrd/xrd.go +++ b/nodes/xrd/xrd.go @@ -5,6 +5,7 @@ package xrd import ( + "bytes" "context" _ "embed" "fmt" @@ -12,7 +13,10 @@ import ( "path/filepath" "regexp" "strings" + "text/template" + "github.com/hairyhenderson/gomplate/v3" + "github.com/hairyhenderson/gomplate/v3/data" log "github.com/sirupsen/logrus" "github.com/srl-labs/containerlab/netconf" "github.com/srl-labs/containerlab/nodes" @@ -26,8 +30,15 @@ var ( xrdEnv = map[string]string{ "XR_FIRST_BOOT_CONFIG": "/etc/xrd/first-boot.cfg", "XR_MGMT_INTERFACES": "linux:eth0,xr_name=Mg0/RP0/CPU0/0,chksum,snoop_v4,snoop_v6", + "XR_EVERY_BOOT_SCRIPT": "/etc/xrd/mgmt_intf_v6_addr.sh", } + //go:embed mgmt_intf_v6_addr.sh.tmpl + scriptTemplate string + + xrdMgmtScriptTpl, _ = template.New("clab-xrd-mgmt-ipv6-script").Funcs( + gomplate.CreateFuncs(context.Background(), new(data.Data))).Parse(scriptTemplate) + //go:embed xrd.cfg cfgTemplate string ) @@ -61,6 +72,8 @@ func (n *xrd) Init(cfg *types.NodeConfig, opts ...nodes.NodeOption) error { fmt.Sprint(filepath.Join(n.Cfg.LabDir, "first-boot.cfg"), ":/etc/xrd/first-boot.cfg"), // persist data by mounting /xr-storage fmt.Sprint(filepath.Join(n.Cfg.LabDir, "xr-storage"), ":/xr-storage"), + // management IPv6 address script + fmt.Sprint(filepath.Join(n.Cfg.LabDir, "mgmt_intf_v6_addr.sh"), ":/etc/xrd/mgmt_intf_v6_addr.sh"), ) return nil @@ -79,6 +92,27 @@ func (n *xrd) PreDeploy(ctx context.Context, params *nodes.PreDeployParams) erro return n.createXRDFiles(ctx) } +func (n *xrd) PostDeploy(_ context.Context, _ *nodes.PostDeployParams) error { + log.Infof("Running postdeploy actions for Cisco XRd '%s' node", n.Cfg.ShortName) + + // create interface script template + tpl := xrdScriptTmpl{ + MgmtIPv6Addr: n.Cfg.MgmtIPv6Address, + MgmtIPv6PrefixLen: n.Cfg.MgmtIPv6PrefixLength, + } + + // create script from template + buf := new(bytes.Buffer) + err := xrdMgmtScriptTpl.Execute(buf, tpl) + if err != nil { + return err + } + // write it to disk + utils.CreateFile(filepath.Join(n.Cfg.LabDir, "mgmt_intf_v6_addr.sh"), buf.String()) + + return err +} + func (n *xrd) SaveConfig(_ context.Context) error { err := netconf.SaveConfig(n.Cfg.LongName, defaultCredentials.GetUsername(), @@ -101,6 +135,12 @@ func (n *xrd) createXRDFiles(_ context.Context) error { cfg := filepath.Join(n.Cfg.LabDir, "first-boot.cfg") nodeCfg.ResStartupConfig = cfg + // generate script file + if !utils.FileExists(filepath.Join(n.Cfg.LabDir, "mgmt_intf_v6_addr.sh")) { + utils.CreateFile(filepath.Join(n.Cfg.LabDir, "mgmt_intf_v6_addr.sh"), "") + utils.AdjustFileACLs(filepath.Join(n.Cfg.LabDir, "mgmt_intf_v6_addr.sh")) + } + // set mgmt IPv4/IPv6 gateway as it is already known by now // since the container network has been created before we launch nodes // and mgmt gateway can be used in xrd.Cfg template to configure default route for mgmt @@ -152,3 +192,8 @@ func (n *xrd) CheckInterfaceName() error { return nil } + +type xrdScriptTmpl struct { + MgmtIPv6Addr string + MgmtIPv6PrefixLen int +}