Files
my-rook-config/pkg/daemon/multus/templates.go
T
2025-03-26 10:41:48 -07:00

293 lines
8.1 KiB
Go

/*
Copyright 2023 The Rook Authors. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package multus
import (
"bytes"
_ "embed"
"fmt"
"strings"
"text/template"
apps "k8s.io/api/apps/v1"
core "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/yaml"
)
var (
//go:embed nginx-pod.yaml
nginxPodTemplate string
//go:embed nginx-config.yaml
nginxConfigTemplate string
//go:embed image-pull-daemonset.yaml
imagePullDaemonSet string
//go:embed host-daemonset.yaml
hostCheckerDaemonSet string
//go:embed client-daemonset.yaml
clientDaemonSet string
)
type webServerTemplateConfig struct {
NetworksAnnotationValue string
NginxImage string
Placement PlacementConfig
}
type imagePullTemplateConfig struct {
NodeType string
NginxImage string
Placement PlacementConfig
}
type hostCheckerTemplateConfig struct {
NodeType string
NginxImage string
PublicNetworkAddress string
Placement PlacementConfig
}
type clientTemplateConfig struct {
NodeType string
ClientType string
ClientID int
NetworksAnnotationValue string
NetworkNamesAndAddresses map[string]string
NginxImage string
Placement PlacementConfig
}
func webServerPodName() string {
return "multus-validation-test-web-server"
}
func imagePullAppLabel() string {
return "app=multus-validation-test-image-pull"
}
func hostCheckerAppLabel() string {
return "app=multus-validation-test-host-checker"
}
func getNodeType(m *metav1.ObjectMeta) string {
return m.GetLabels()["nodeType"]
}
func clientAppLabel() string {
return "app=multus-validation-test-client"
}
const (
ClientTypeOSD = "osd"
ClientTypeNonOSD = "other"
)
type daemonsetAppType string
const (
imagePullDaemonSetAppType = "image pull"
hostCheckerDaemonsetAppType = "host checker"
clientDaemonSetAppType = "client"
)
func (vt *ValidationTest) generateWebServerTemplateConfig(placement PlacementConfig) webServerTemplateConfig {
return webServerTemplateConfig{
NetworksAnnotationValue: vt.generateNetworksAnnotationValue(true, true), // always on both nets
NginxImage: vt.NginxImage,
Placement: placement,
}
}
func (vt *ValidationTest) generateHostCheckerTemplateConfig(
serverPublicAddr string,
nodeType string,
placement PlacementConfig,
) hostCheckerTemplateConfig {
return hostCheckerTemplateConfig{
NodeType: nodeType,
PublicNetworkAddress: serverPublicAddr,
NginxImage: vt.NginxImage,
Placement: placement,
}
}
func (vt *ValidationTest) generateClientTemplateConfig(
attachPublic, attachCluster bool,
serverPublicAddr, serverClusterAddr string,
nodeType, clientType string,
clientID int,
placement PlacementConfig,
) clientTemplateConfig {
netNamesAndAddresses := map[string]string{}
if attachPublic && serverPublicAddr != "" {
netNamesAndAddresses["public"] = serverPublicAddr
}
if attachCluster && serverClusterAddr != "" {
netNamesAndAddresses["cluster"] = serverClusterAddr
}
for name, addr := range netNamesAndAddresses {
if strings.Contains(addr, ":") {
// it's an IPv6 address and needs square brackets around it to support :<port> addition
netNamesAndAddresses[name] = "[" + addr + "]"
}
}
return clientTemplateConfig{
NodeType: nodeType,
ClientType: clientType,
ClientID: clientID,
NetworksAnnotationValue: vt.generateNetworksAnnotationValue(attachPublic, attachCluster),
NetworkNamesAndAddresses: netNamesAndAddresses,
NginxImage: vt.NginxImage,
Placement: placement,
}
}
func (vt *ValidationTest) generateImagePullTemplateConfig(nodeType string, placement PlacementConfig) imagePullTemplateConfig {
return imagePullTemplateConfig{
NodeType: nodeType,
NginxImage: vt.NginxImage,
Placement: placement,
}
}
func (vt *ValidationTest) generateWebServerPod(placement PlacementConfig) (*core.Pod, error) {
t, err := loadTemplate("webServerPod", nginxPodTemplate, vt.generateWebServerTemplateConfig(placement))
if err != nil {
return nil, fmt.Errorf("failed to load web server pod template: %w", err)
}
var p core.Pod
err = yaml.Unmarshal(t, &p)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal web server pod template: %w", err)
}
vt.applyServiceAccountToPodSpec(&p.Spec)
return &p, nil
}
func (vt *ValidationTest) generateWebServerConfigMap() (*core.ConfigMap, error) {
t, err := loadTemplate("webServerConfigMap", nginxConfigTemplate, vt.generateWebServerTemplateConfig(
PlacementConfig{}, // not used for configmap
))
if err != nil {
return nil, fmt.Errorf("failed to load web server configmap template: %w", err)
}
var cm core.ConfigMap
err = yaml.Unmarshal(t, &cm)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal web server configmap template: %w", err)
}
return &cm, nil
}
func (vt *ValidationTest) generateImagePullDaemonSet(nodeType string, placement PlacementConfig) (*apps.DaemonSet, error) {
t, err := loadTemplate("imagePullDaemonSet", imagePullDaemonSet, vt.generateImagePullTemplateConfig(nodeType, placement))
if err != nil {
return nil, fmt.Errorf("failed to load image pull daemonset template: %w", err)
}
var d apps.DaemonSet
err = yaml.Unmarshal(t, &d)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal image pull daemonset template: %w", err)
}
vt.applyServiceAccountToPodSpec(&d.Spec.Template.Spec)
return &d, nil
}
func (vt *ValidationTest) generateHostCheckerDaemonSet(
serverPublicAddr string,
nodeType string,
placement PlacementConfig,
) (*apps.DaemonSet, error) {
t, err := loadTemplate("hostCheckerDaemonSet", hostCheckerDaemonSet, vt.generateHostCheckerTemplateConfig(serverPublicAddr, nodeType, placement))
if err != nil {
return nil, fmt.Errorf("failed to load host checker daemonset template: %w", err)
}
var d apps.DaemonSet
err = yaml.Unmarshal(t, &d)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal host checker daemonset template: %w", err)
}
vt.applyServiceAccountToPodSpec(&d.Spec.Template.Spec)
return &d, nil
}
func (vt *ValidationTest) generateClientDaemonSet(
attachPublic, attachCluster bool,
serverPublicAddr, serverClusterAddr string,
nodeType, clientType string,
clientID int,
placement PlacementConfig,
) (*apps.DaemonSet, error) {
t, err := loadTemplate("clientDaemonSet", clientDaemonSet, vt.generateClientTemplateConfig(attachPublic, attachCluster, serverPublicAddr, serverClusterAddr, nodeType, clientType, clientID, placement))
if err != nil {
return nil, fmt.Errorf("failed to load client daemonset template: %w", err)
}
var d apps.DaemonSet
err = yaml.Unmarshal(t, &d)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal client daemonset template: %w", err)
}
vt.applyServiceAccountToPodSpec(&d.Spec.Template.Spec)
return &d, nil
}
func (vt *ValidationTest) generateNetworksAnnotationValue(public, cluster bool) string {
nets := []string{}
if public && vt.PublicNetwork != "" {
nets = append(nets, vt.PublicNetwork)
}
if cluster && vt.ClusterNetwork != "" {
nets = append(nets, vt.ClusterNetwork)
}
return strings.Join(nets, ",")
}
func (vt *ValidationTest) applyServiceAccountToPodSpec(ps *core.PodSpec) {
if vt.ServiceAccountName != "" {
ps.ServiceAccountName = vt.ServiceAccountName
}
}
func loadTemplate(name, templateFileText string, config interface{}) ([]byte, error) {
var writer bytes.Buffer
t := template.New(name)
t, err := t.Parse(templateFileText)
if err != nil {
return nil, fmt.Errorf("failed to parse template %q: %w", name, err)
}
err = t.Execute(&writer, config)
return writer.Bytes(), err
}