Skip to content

Commit

Permalink
Merge branch 'suse-edge:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
dbw7 authored Jan 24, 2025
2 parents e8a5396 + ef4c06b commit 2c9589d
Show file tree
Hide file tree
Showing 33 changed files with 2,490 additions and 132 deletions.
10 changes: 9 additions & 1 deletion RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,23 @@

## General

* Added single-stack IPv6 and dual-stack networking support for Kubernetes

## API

### Image Definition Changes

* Added `kubernetes.network.apiVIP6` field to enable cluster LoadBalancer based on IPv6 address
* Added the `enableExtras` flag to enable the SUSE Linux Extras repository during RPM resolution.

### Image Configuration Directory Changes

## Bug Fixes

* [#594](https://github.com/suse-edge/edge-image-builder/issues/594) - Package install breaks package resolution if packages is already installed on root OS
* [#591](https://github.com/suse-edge/edge-image-builder/issues/591) - Allow additional module registration during package resolution
* [#593](https://github.com/suse-edge/edge-image-builder/issues/593) - OS files script should mount /var
* [#594](https://github.com/suse-edge/edge-image-builder/issues/594) - Package installation breaks package resolution if packages are already installed on root OS
* [#632](https://github.com/suse-edge/edge-image-builder/issues/632) - Create the required Elemental Agent directory structure during Combustion

---

Expand Down
15 changes: 13 additions & 2 deletions docs/building-images.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ operatingSystem:
keymap: us
packages:
noGPGCheck: false
enableExtras: false
packageList:
- pkg1
- pkg2
Expand Down Expand Up @@ -188,6 +189,9 @@ dependencies and download them into the built image. For detailed information on
see the [Installing packages](./installing-packages.md) guide.
* `noGPGCheck` - Defines if GPG validation should be disabled for all additional repositories and side-loaded
RPMs. **Disabling GPG validation is intended for development purposes only.**
* `enableExtras` - Enables the RPM resolution process to pull packages from the SUSE Linux Extras repository.
Defaults to `false` if omitted. **Packages from this repository are unsupported and not intended to be installed on
a production system. Use this flag only if you have a specific reason.**
* `packageList` - Defines a list of packages to install from SUSE's internal RPM repositories or
from additionally provided third-party repositories.
* `additionalRepos` - Defines a list of third-party RPM repositories that will be added to the package manager of
Expand All @@ -214,6 +218,7 @@ kubernetes:
version: v1.30.3+rke2r1
network:
apiVIP: 192.168.122.100
apiVIP6: fd12:3456:789a::21
apiHost: api.cluster01.hosted.on.edge.suse.com
nodes:
- hostname: node1.suse.com
Expand Down Expand Up @@ -260,8 +265,12 @@ kubernetes:
* `version` - Required; Specifies the version of a particular K3s or RKE2 release (e.g.`v1.30.3+k3s1` or `v1.30.3+rke2r1`)
* `network` - Required for multi-node clusters, optional for single-node clusters; Defines the network configuration
for bootstrapping a cluster.
* `apiVIP` - Required for multi-node clusters, optional for single-node clusters; Specifies the IP address which
will serve as the cluster LoadBalancer, backed by MetalLB.
* `apiVIP` - Required for multi-node clusters if not using `apiVIP6`, optional for single-node clusters, can be
specified alongside `apiVIP6` for dual-stack support; Specifies the IPv4 address which will serve as the cluster
LoadBalancer, backed by MetalLB.
* `apiVIP6` - Required for multi-node clusters if not using `apiVIP`, optional for single-node clusters, can be
specified alongside `apiVIP` for dual-stack support; Specifies the IPv6 address which will serve as the cluster
LoadBalancer, backed by MetalLB.
* `apiHost` - Optional; Specifies the domain address for accessing the cluster.
* `nodes` - Required for multi-node clusters; Defines a list of all nodes that form the cluster.
* `hostname` - Required; Indicates the fully qualified domain name (FQDN) to identify the particular node on which
Expand Down Expand Up @@ -465,6 +474,8 @@ defined by the Kubernetes cluster being installed.
* `certs` - Contains certificate files/bundles for TLS verification. Untrusted HTTPS-enabled Helm repositories and
registries must be provided with a certificate file/bundle or require `skipTLSVerify` to be true.

> **_NOTE:_** For dual-stack clusters, a Kubernetes `server.yaml` file is required and it must contain a
> valid dual-stack `service-cidr` and `cluster-cidr` values according to the official [K3s](https://docs.k3s.io/networking/basic-network-options#dual-stack-ipv4--ipv6-networking) and [RKE2](https://docs.rke2.io/networking/basic_network_options#dual-stack-configuration) documentation.
## Elemental

Automatic Elemental registration may be configured for the image. The Elemental registration configuration file,
Expand Down
12 changes: 6 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ require (
github.com/containers/common v0.57.5
github.com/containers/podman/v4 v4.9.5
github.com/google/uuid v1.6.0
github.com/schollz/progressbar/v3 v3.16.1
github.com/stretchr/testify v1.9.0
github.com/schollz/progressbar/v3 v3.18.0
github.com/stretchr/testify v1.10.0
github.com/urfave/cli/v2 v2.27.5
go.uber.org/zap v1.27.0
golang.org/x/sync v0.8.0
golang.org/x/text v0.19.0
golang.org/x/sync v0.10.0
golang.org/x/text v0.21.0
gopkg.in/yaml.v3 v3.0.1
)

Expand Down Expand Up @@ -132,8 +132,8 @@ require (
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/term v0.24.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect
google.golang.org/grpc v1.58.3 // indirect
Expand Down
24 changes: 12 additions & 12 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -854,8 +854,8 @@ github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiBQGYcxhMZ6gUqHn6pYNLypFAvaL3UvgZLR0U4=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/schollz/progressbar/v3 v3.16.1 h1:RnF1neWZFzLCoGx8yp1yF7SDl4AzNDI5y4I0aUJRrZQ=
github.com/schollz/progressbar/v3 v3.16.1/go.mod h1:I2ILR76gz5VXqYMIY/LdLecvMHDPVcQm3W/MSKi1TME=
github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA=
github.com/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec=
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y=
github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI=
Expand Down Expand Up @@ -924,8 +924,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/sylabs/sif/v2 v2.15.0 h1:Nv0tzksFnoQiQ2eUwpAis9nVqEu4c3RcNSxX8P3Cecw=
github.com/sylabs/sif/v2 v2.15.0/go.mod h1:X1H7eaPz6BAxA84POMESXoXfTqgAnLQkujyF/CQFWTc=
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
Expand Down Expand Up @@ -1150,8 +1150,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down Expand Up @@ -1240,16 +1240,16 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand All @@ -1263,8 +1263,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
Expand Down
2 changes: 1 addition & 1 deletion pkg/combustion/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func ComponentHelmCharts(ctx *image.Context) ([]image.HelmChart, []image.HelmRep
var charts []image.HelmChart
var repos []image.HelmRepository

if ctx.ImageDefinition.Kubernetes.Network.APIVIP != "" {
if ctx.ImageDefinition.Kubernetes.Network.APIVIP4 != "" || ctx.ImageDefinition.Kubernetes.Network.APIVIP6 != "" {
metalLBChart := image.HelmChart{
Name: ctx.ArtifactSources.MetalLB.Chart,
RepositoryName: metallbRepositoryName,
Expand Down
85 changes: 71 additions & 14 deletions pkg/combustion/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ const (
k8sAgentConfigFile = "agent.yaml"

k8sInstallScript = "20-k8s-install.sh"
setNodeIPScript = "set-node-ip.sh"
)

var (
Expand All @@ -51,6 +52,9 @@ var (

//go:embed templates/k8s-vip.yaml.tpl
k8sVIPManifest string

//go:embed templates/set-node-ip.sh.tpl
nodeIPScriptTemplate string
)

func (c *Combustion) configureKubernetes(ctx *image.Context) ([]string, error) {
Expand Down Expand Up @@ -87,6 +91,7 @@ func (c *Combustion) configureKubernetes(ctx *image.Context) ([]string, error) {

artefactsPath := kubernetesArtefactsPath(ctx)
if err = os.MkdirAll(artefactsPath, os.ModePerm); err != nil {
log.AuditComponentFailed(k8sComponentName)
return nil, fmt.Errorf("creating kubernetes artefacts path: %w", err)
}

Expand Down Expand Up @@ -145,25 +150,32 @@ func (c *Combustion) configureK3S(ctx *image.Context, cluster *kubernetes.Cluste
return "", fmt.Errorf("configuring kubernetes manifests: %w", err)
}

nodeIPScript, err := createNodeIPScript(ctx, cluster.ServerConfig)
if err != nil {
return "", fmt.Errorf("creating set node IP script: %w", err)
}

templateValues := map[string]any{
"installScript": installScript,
"apiVIP": ctx.ImageDefinition.Kubernetes.Network.APIVIP,
"apiVIP4": ctx.ImageDefinition.Kubernetes.Network.APIVIP4,
"apiVIP6": ctx.ImageDefinition.Kubernetes.Network.APIVIP6,
"apiHost": ctx.ImageDefinition.Kubernetes.Network.APIHost,
"binaryPath": binaryPath,
"imagesPath": imagesPath,
"manifestsPath": manifestsPath,
"configFilePath": prependArtefactPath(k8sDir),
"registryMirrors": prependArtefactPath(filepath.Join(k8sDir, registryMirrorsFileName)),
"setNodeIPScript": nodeIPScript,
}

singleNode := len(ctx.ImageDefinition.Kubernetes.Nodes) < 2
if singleNode {
if ctx.ImageDefinition.Kubernetes.Network.APIVIP == "" {
zap.S().Info("Virtual IP address for k3s cluster is not provided and will not be configured")
if ctx.ImageDefinition.Kubernetes.Network.APIVIP4 == "" && ctx.ImageDefinition.Kubernetes.Network.APIVIP6 == "" {
zap.S().Info("Virtual IP address(es) for k3s cluster not provided and will not be configured")
} else {
log.Audit("WARNING: A Virtual IP address for the k3s cluster has been provided. " +
log.Audit("WARNING: Virtual IP address(es) for the k3s cluster provided. " +
"An external IP address for the Ingress Controller (Traefik) must be manually configured.")
zap.S().Warn("Virtual IP address for k3s cluster is requested and will invalidate Traefik configuration")
zap.S().Warn("Virtual IP address(es) for k3s cluster requested and will invalidate Traefik configuration")
}

templateValues["configFile"] = k8sServerConfigFile
Expand All @@ -172,7 +184,7 @@ func (c *Combustion) configureK3S(ctx *image.Context, cluster *kubernetes.Cluste
}

log.Audit("WARNING: An external IP address for the Ingress Controller (Traefik) must be manually configured in multi-node clusters.")
zap.S().Warn("Virtual IP address for k3s cluster is necessary for multi node clusters and will invalidate Traefik configuration")
zap.S().Warn("Virtual IP address(es) for k3s cluster necessary for multi node clusters and will invalidate Traefik configuration")

templateValues["nodes"] = ctx.ImageDefinition.Kubernetes.Nodes
templateValues["initialiser"] = cluster.InitialiserName
Expand Down Expand Up @@ -240,21 +252,28 @@ func (c *Combustion) configureRKE2(ctx *image.Context, cluster *kubernetes.Clust
return "", fmt.Errorf("configuring kubernetes manifests: %w", err)
}

nodeIPScript, err := createNodeIPScript(ctx, cluster.ServerConfig)
if err != nil {
return "", fmt.Errorf("creating set node IP script: %w", err)
}

templateValues := map[string]any{
"installScript": installScript,
"apiVIP": ctx.ImageDefinition.Kubernetes.Network.APIVIP,
"apiVIP4": ctx.ImageDefinition.Kubernetes.Network.APIVIP4,
"apiVIP6": ctx.ImageDefinition.Kubernetes.Network.APIVIP6,
"apiHost": ctx.ImageDefinition.Kubernetes.Network.APIHost,
"installPath": installPath,
"imagesPath": imagesPath,
"manifestsPath": manifestsPath,
"configFilePath": prependArtefactPath(k8sDir),
"registryMirrors": prependArtefactPath(filepath.Join(k8sDir, registryMirrorsFileName)),
"setNodeIPScript": nodeIPScript,
}

singleNode := len(ctx.ImageDefinition.Kubernetes.Nodes) < 2
if singleNode {
if ctx.ImageDefinition.Kubernetes.Network.APIVIP == "" {
zap.S().Info("Virtual IP address for RKE2 cluster is not provided and will not be configured")
if ctx.ImageDefinition.Kubernetes.Network.APIVIP4 == "" && ctx.ImageDefinition.Kubernetes.Network.APIVIP6 == "" {
zap.S().Info("Virtual IP address(es) for RKE2 cluster not provided and will not be configured")
}

templateValues["configFile"] = k8sServerConfigFile
Expand Down Expand Up @@ -317,16 +336,54 @@ func (c *Combustion) downloadRKE2Artefacts(ctx *image.Context, cluster *kubernet

func kubernetesVIPManifest(k *image.Kubernetes) (string, error) {
manifest := struct {
APIAddress string
RKE2 bool
APIAddress4 string
APIAddress6 string
RKE2 bool
}{
APIAddress: k.Network.APIVIP,
RKE2: strings.Contains(k.Version, image.KubernetesDistroRKE2),
APIAddress4: k.Network.APIVIP4,
APIAddress6: k.Network.APIVIP6,
RKE2: strings.Contains(k.Version, image.KubernetesDistroRKE2),
}

return template.Parse("k8s-vip", k8sVIPManifest, &manifest)
}

func createNodeIPScript(ctx *image.Context, serverConfig map[string]any) (string, error) {
// Setting the Node IP only matters if we're doing dual-stack or single-stack IPv6
if ctx.ImageDefinition.Kubernetes.Network.APIVIP6 == "" {
return "", nil
} else if kubernetes.IsNodeIPSet(serverConfig) {
return "", nil
}

var isIPv4Enabled bool
if ctx.ImageDefinition.Kubernetes.Network.APIVIP4 != "" {
isIPv4Enabled = true
}

manifest := struct {
IPv4Enabled bool
PrioritizeIPv6 bool
RKE2 bool
}{
IPv4Enabled: isIPv4Enabled,
PrioritizeIPv6: kubernetes.IsIPv6Priority(serverConfig),
RKE2: strings.Contains(ctx.ImageDefinition.Kubernetes.Version, image.KubernetesDistroRKE2),
}

data, err := template.Parse("set-node-ip", nodeIPScriptTemplate, &manifest)
if err != nil {
return "", fmt.Errorf("parsing '%s' template: %w", setNodeIPScript, err)
}

nodeIPScript := filepath.Join(ctx.CombustionDir, setNodeIPScript)
if err = os.WriteFile(nodeIPScript, []byte(data), fileio.ExecutablePerms); err != nil {
return "", fmt.Errorf("writing set node IP script: %w", err)
}

return setNodeIPScript, nil
}

func storeKubernetesClusterConfig(cluster *kubernetes.Cluster, destPath string) error {
serverConfig := filepath.Join(destPath, k8sServerConfigFile)
if err := storeKubernetesConfig(cluster.ServerConfig, serverConfig); err != nil {
Expand Down Expand Up @@ -367,7 +424,7 @@ func (c *Combustion) configureManifests(ctx *image.Context) (string, error) {
manifestsPath := localKubernetesManifestsPath()
manifestDestDir := filepath.Join(ctx.ArtefactsDir, manifestsPath)

if ctx.ImageDefinition.Kubernetes.Network.APIVIP != "" {
if ctx.ImageDefinition.Kubernetes.Network.APIVIP4 != "" || ctx.ImageDefinition.Kubernetes.Network.APIVIP6 != "" {
if err := os.MkdirAll(manifestDestDir, os.ModePerm); err != nil {
return "", fmt.Errorf("creating manifests destination dir: %w", err)
}
Expand Down
Loading

0 comments on commit 2c9589d

Please sign in to comment.