Skip to content

Commit 4cf43a3

Browse files
committed
refactor: run a script to configure kube-vip
This makes it more consistent with the other preKubeadmCommands
1 parent 2cb6ec5 commit 4cf43a3

File tree

7 files changed

+216
-72
lines changed

7 files changed

+216
-72
lines changed

pkg/handlers/generic/mutation/controlplanevirtualip/inject.go

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,14 @@ func (h *ControlPlaneVirtualIP) Mutate(
134134
selectors.ControlPlane(),
135135
log,
136136
func(obj *controlplanev1.KubeadmControlPlaneTemplate) error {
137-
virtualIPProviderFile, getFileErr := virtualIPProvider.GetFile(
138-
ctx,
139-
controlPlaneEndpointVar,
140-
)
141-
if getFileErr != nil {
142-
return getFileErr
137+
virtualIPProviderFiles, preKubeadmCommands, postKubeadmCommands, generateErr :=
138+
virtualIPProvider.GenerateFilesAndCommands(
139+
ctx,
140+
controlPlaneEndpointVar,
141+
cluster,
142+
)
143+
if generateErr != nil {
144+
return generateErr
143145
}
144146

145147
log.WithValues(
@@ -151,16 +153,9 @@ func (h *ControlPlaneVirtualIP) Mutate(
151153
))
152154
obj.Spec.Template.Spec.KubeadmConfigSpec.Files = append(
153155
obj.Spec.Template.Spec.KubeadmConfigSpec.Files,
154-
*virtualIPProviderFile,
156+
virtualIPProviderFiles...,
155157
)
156158

157-
preKubeadmCommands, postKubeadmCommands, getCommandsErr := virtualIPProvider.GetCommands(
158-
cluster,
159-
)
160-
if getCommandsErr != nil {
161-
return getCommandsErr
162-
}
163-
164159
if len(preKubeadmCommands) > 0 {
165160
log.WithValues(
166161
"patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(),

pkg/handlers/generic/mutation/controlplanevirtualip/inject_test.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import (
2121
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation"
2222
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest"
2323
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/testutils/capitest/request"
24-
virtuialipproviders "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/mutation/controlplanevirtualip/providers"
2524
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/options"
2625
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/test/helpers"
2726
)
@@ -83,14 +82,14 @@ var _ = Describe("Generate ControlPlane virtual IP patches", func() {
8382
Operation: "add",
8483
Path: "/spec/template/spec/kubeadmConfigSpec/preKubeadmCommands",
8584
ValueMatcher: gomega.ContainElements(
86-
virtuialipproviders.KubeVIPPreKubeadmCommands,
85+
"/bin/bash /etc/caren/configure-kube-vip.sh use-super-admin.conf",
8786
),
8887
},
8988
{
9089
Operation: "add",
9190
Path: "/spec/template/spec/kubeadmConfigSpec/postKubeadmCommands",
9291
ValueMatcher: gomega.ContainElements(
93-
virtuialipproviders.KubeVIPPostKubeadmCommands,
92+
"/bin/bash /etc/caren/configure-kube-vip.sh use-admin.conf",
9493
),
9594
},
9695
},
@@ -148,20 +147,28 @@ var _ = Describe("Generate ControlPlane virtual IP patches", func() {
148147
),
149148
gomega.HaveKey("permissions"),
150149
),
150+
gomega.SatisfyAll(
151+
gomega.HaveKey("content"),
152+
gomega.HaveKeyWithValue(
153+
"path",
154+
gomega.ContainSubstring("configure-kube-vip.sh"),
155+
),
156+
gomega.HaveKey("permissions"),
157+
),
151158
),
152159
},
153160
{
154161
Operation: "add",
155162
Path: "/spec/template/spec/kubeadmConfigSpec/preKubeadmCommands",
156163
ValueMatcher: gomega.ContainElements(
157-
virtuialipproviders.KubeVIPPreKubeadmCommands,
164+
"/bin/bash /etc/caren/configure-kube-vip.sh use-super-admin.conf",
158165
),
159166
},
160167
{
161168
Operation: "add",
162169
Path: "/spec/template/spec/kubeadmConfigSpec/postKubeadmCommands",
163170
ValueMatcher: gomega.ContainElements(
164-
virtuialipproviders.KubeVIPPostKubeadmCommands,
171+
"/bin/bash /etc/caren/configure-kube-vip.sh use-admin.conf",
165172
),
166173
},
167174
},

pkg/handlers/generic/mutation/controlplanevirtualip/providers/kubevip.go

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package providers
55

66
import (
77
"context"
8+
_ "embed"
89
"fmt"
910

1011
"github.com/blang/semver/v4"
@@ -14,17 +15,28 @@ import (
1415
"sigs.k8s.io/controller-runtime/pkg/client"
1516

1617
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
18+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/common"
19+
)
20+
21+
const (
22+
kubeVIPFileOwner = "root:root"
23+
kubeVIPFilePath = "/etc/kubernetes/manifests/kube-vip.yaml"
24+
kubeVIPFilePermissions = "0600"
25+
26+
configureKubeVIPScriptPermissions = "0700"
27+
)
28+
29+
var (
30+
configureKubeVIPScriptOnRemote = common.ConfigFilePathOnRemote(
31+
"configure-kube-vip.sh")
32+
33+
configureKubeVIPScriptOnRemotePreKubeadmCommand = "/bin/bash " + configureKubeVIPScriptOnRemote + " use-super-admin.conf"
34+
configureKubeVIPScriptOnRemotePostKubeadmCommand = "/bin/bash " + configureKubeVIPScriptOnRemote + " use-admin.conf"
1735
)
1836

1937
var (
20-
//nolint:lll // for readability prefer to keep the long line
21-
KubeVIPPreKubeadmCommands = []string{`if [ -f /run/kubeadm/kubeadm.yaml ]; then
22-
sed -i 's#path: /etc/kubernetes/admin.conf#path: /etc/kubernetes/super-admin.conf#' /etc/kubernetes/manifests/kube-vip.yaml;
23-
fi`}
24-
//nolint:lll // for readability prefer to keep the long line
25-
KubeVIPPostKubeadmCommands = []string{`if [ -f /run/kubeadm/kubeadm.yaml ]; then
26-
sed -i 's#path: /etc/kubernetes/super-admin.conf#path: /etc/kubernetes/admin.conf#' /etc/kubernetes/manifests/kube-vip.yaml;
27-
fi`}
38+
//go:embed templates/configure-kube-vip.sh
39+
configureKubeVIPScript []byte
2840
)
2941

3042
type kubeVIPFromConfigMapProvider struct {
@@ -50,35 +62,34 @@ func (p *kubeVIPFromConfigMapProvider) Name() string {
5062
return "kube-vip"
5163
}
5264

53-
// GetFile reads the kube-vip template from the ConfigMap
54-
// and returns the content a File, templating the required variables.
55-
func (p *kubeVIPFromConfigMapProvider) GetFile(
65+
// GenerateFilesAndCommands returns files and pre/post kubeadm commands for kube-vip.
66+
// It reads kube-vip template from a ConfigMap and returns the content a File, templating the required variables.
67+
// If required, it also returns a script file and pre/post kubeadm commands to change the kube-vip Pod to use the new
68+
// super-admin.conf file.
69+
func (p *kubeVIPFromConfigMapProvider) GenerateFilesAndCommands(
5670
ctx context.Context,
5771
spec v1alpha1.ControlPlaneEndpointSpec,
58-
) (*bootstrapv1.File, error) {
72+
cluster *clusterv1.Cluster,
73+
) ([]bootstrapv1.File, []string, []string, error) {
5974
data, err := getTemplateFromConfigMap(ctx, p.client, p.configMapKey)
6075
if err != nil {
61-
return nil, fmt.Errorf("failed getting template data: %w", err)
76+
return nil, nil, nil, fmt.Errorf("failed getting template data: %w", err)
6277
}
6378

6479
kubeVIPStaticPod, err := templateValues(spec, data)
6580
if err != nil {
66-
return nil, fmt.Errorf("failed templating static Pod: %w", err)
81+
return nil, nil, nil, fmt.Errorf("failed templating static Pod: %w", err)
6782
}
6883

69-
return &bootstrapv1.File{
70-
Content: kubeVIPStaticPod,
71-
Owner: kubeVIPFileOwner,
72-
Path: kubeVIPFilePath,
73-
Permissions: kubeVIPFilePermissions,
74-
}, nil
75-
}
84+
files := []bootstrapv1.File{
85+
{
86+
Content: kubeVIPStaticPod,
87+
Owner: kubeVIPFileOwner,
88+
Path: kubeVIPFilePath,
89+
Permissions: kubeVIPFilePermissions,
90+
},
91+
}
7692

77-
//
78-
//nolint:gocritic // No need for named return values
79-
func (p *kubeVIPFromConfigMapProvider) GetCommands(
80-
cluster *clusterv1.Cluster,
81-
) ([]string, []string, error) {
8293
// The kube-vip static Pod uses admin.conf on the host to connect to the API server.
8394
// But, starting with Kubernetes 1.29, admin.conf first gets created with no RBAC permissions.
8495
// At the same time, 'kubeadm init' command waits for the API server to be reachable on the kube-vip IP.
@@ -91,13 +102,24 @@ func (p *kubeVIPFromConfigMapProvider) GetCommands(
91102
// See https://github.com/kube-vip/kube-vip/issues/684
92103
needCommands, err := needHackCommands(cluster)
93104
if err != nil {
94-
return nil, nil, fmt.Errorf("failed to determine if kube-vip commands are needed: %w", err)
105+
return nil, nil, nil, fmt.Errorf("failed to determine if kube-vip commands are needed: %w", err)
95106
}
96107
if !needCommands {
97-
return nil, nil, nil
108+
return files, nil, nil, nil
98109
}
99110

100-
return KubeVIPPreKubeadmCommands, KubeVIPPostKubeadmCommands, nil
111+
files = append(
112+
files,
113+
bootstrapv1.File{
114+
Content: string(configureKubeVIPScript),
115+
Path: configureKubeVIPScriptOnRemote,
116+
Permissions: configureKubeVIPScriptPermissions,
117+
},
118+
)
119+
preKubeadmCommands := []string{configureKubeVIPScriptOnRemotePreKubeadmCommand}
120+
postKubeadmCommands := []string{configureKubeVIPScriptOnRemotePostKubeadmCommand}
121+
122+
return files, preKubeadmCommands, postKubeadmCommands, nil
101123
}
102124

103125
type multipleKeysError struct {

pkg/handlers/generic/mutation/controlplanevirtualip/providers/kubevip_test.go

Lines changed: 77 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,69 @@ import (
1111
"github.com/stretchr/testify/require"
1212
corev1 "k8s.io/api/core/v1"
1313
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
15+
bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
1416
"sigs.k8s.io/controller-runtime/pkg/client"
1517
"sigs.k8s.io/controller-runtime/pkg/client/fake"
1618

1719
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
1820
)
1921

20-
func Test_GetFile(t *testing.T) {
22+
func Test_GenerateFilesAndCommands(t *testing.T) {
2123
t.Parallel()
2224

2325
tests := []struct {
24-
name string
25-
controlPlaneEndpointSpec v1alpha1.ControlPlaneEndpointSpec
26-
configMap *corev1.ConfigMap
27-
expectedContent string
28-
expectedErr error
26+
name string
27+
controlPlaneEndpointSpec v1alpha1.ControlPlaneEndpointSpec
28+
cluster *clusterv1.Cluster
29+
configMap *corev1.ConfigMap
30+
expectedFiles []bootstrapv1.File
31+
expectedPreKubeadmCommands []string
32+
expectedPostKubeadmCommands []string
33+
expectedErr error
2934
}{
35+
{
36+
name: "should return templated data with both host and port and pre/post kubeadm hack commands",
37+
controlPlaneEndpointSpec: v1alpha1.ControlPlaneEndpointSpec{
38+
Host: "10.20.100.10",
39+
Port: 6443,
40+
},
41+
configMap: &corev1.ConfigMap{
42+
ObjectMeta: metav1.ObjectMeta{
43+
Name: "default-kube-vip-template",
44+
Namespace: "default",
45+
},
46+
Data: map[string]string{
47+
"data": validKubeVIPTemplate,
48+
},
49+
},
50+
cluster: &clusterv1.Cluster{
51+
Spec: clusterv1.ClusterSpec{
52+
Topology: &clusterv1.Topology{
53+
Version: "v1.29.0",
54+
},
55+
},
56+
},
57+
expectedFiles: []bootstrapv1.File{
58+
{
59+
Content: expectedKubeVIPPod,
60+
Owner: kubeVIPFileOwner,
61+
Path: kubeVIPFilePath,
62+
Permissions: kubeVIPFilePermissions,
63+
},
64+
{
65+
Content: string(configureKubeVIPScript),
66+
Path: configureKubeVIPScriptOnRemote,
67+
Permissions: configureKubeVIPScriptPermissions,
68+
},
69+
},
70+
expectedPreKubeadmCommands: []string{
71+
configureKubeVIPScriptOnRemotePreKubeadmCommand,
72+
},
73+
expectedPostKubeadmCommands: []string{
74+
configureKubeVIPScriptOnRemotePostKubeadmCommand,
75+
},
76+
},
3077
{
3178
name: "should return templated data with both host and port",
3279
controlPlaneEndpointSpec: v1alpha1.ControlPlaneEndpointSpec{
@@ -42,7 +89,21 @@ func Test_GetFile(t *testing.T) {
4289
"data": validKubeVIPTemplate,
4390
},
4491
},
45-
expectedContent: expectedKubeVIPPod,
92+
cluster: &clusterv1.Cluster{
93+
Spec: clusterv1.ClusterSpec{
94+
Topology: &clusterv1.Topology{
95+
Version: "v1.28.0",
96+
},
97+
},
98+
},
99+
expectedFiles: []bootstrapv1.File{
100+
{
101+
Content: expectedKubeVIPPod,
102+
Owner: kubeVIPFileOwner,
103+
Path: kubeVIPFilePath,
104+
Permissions: kubeVIPFilePermissions,
105+
},
106+
},
46107
},
47108
}
48109

@@ -57,12 +118,16 @@ func Test_GetFile(t *testing.T) {
57118
configMapKey: client.ObjectKeyFromObject(tt.configMap),
58119
}
59120

60-
file, err := provider.GetFile(context.TODO(), tt.controlPlaneEndpointSpec)
121+
files, preKubeadmCommands, postKubeadmCommands, err :=
122+
provider.GenerateFilesAndCommands(
123+
context.TODO(),
124+
tt.controlPlaneEndpointSpec,
125+
tt.cluster,
126+
)
61127
require.Equal(t, tt.expectedErr, err)
62-
assert.Equal(t, tt.expectedContent, file.Content)
63-
assert.NotEmpty(t, file.Path)
64-
assert.NotEmpty(t, file.Owner)
65-
assert.NotEmpty(t, file.Permissions)
128+
assert.Equal(t, tt.expectedFiles, files)
129+
assert.Equal(t, tt.expectedPreKubeadmCommands, preKubeadmCommands)
130+
assert.Equal(t, tt.expectedPostKubeadmCommands, postKubeadmCommands)
66131
})
67132
}
68133
}

pkg/handlers/generic/mutation/controlplanevirtualip/providers/providers.go

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,21 @@ import (
1515
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
1616
)
1717

18-
const (
19-
kubeVIPFileOwner = "root:root"
20-
kubeVIPFilePath = "/etc/kubernetes/manifests/kube-vip.yaml"
21-
kubeVIPFilePermissions = "0600"
22-
)
23-
24-
// Provider is an interface for getting the kube-vip static Pod as a file.
18+
// Provider is an interface for getting the virtual IP provider static Pod as a file.
2519
type Provider interface {
2620
Name() string
27-
GetFile(ctx context.Context, spec v1alpha1.ControlPlaneEndpointSpec) (*bootstrapv1.File, error)
28-
GetCommands(cluster *clusterv1.Cluster) ([]string, []string, error)
21+
GenerateFilesAndCommands(
22+
ctx context.Context,
23+
spec v1alpha1.ControlPlaneEndpointSpec,
24+
cluster *clusterv1.Cluster,
25+
) ([]bootstrapv1.File, []string, []string, error)
2926
}
3027

3128
func templateValues(
3229
controlPlaneEndpoint v1alpha1.ControlPlaneEndpointSpec,
3330
text string,
3431
) (string, error) {
35-
kubeVIPTemplate, err := template.New("").Parse(text)
32+
virtualIPTemplate, err := template.New("").Parse(text)
3633
if err != nil {
3734
return "", fmt.Errorf("failed to parse template: %w", err)
3835
}
@@ -46,7 +43,7 @@ func templateValues(
4643
}
4744

4845
var b bytes.Buffer
49-
err = kubeVIPTemplate.Execute(&b, templateInput)
46+
err = virtualIPTemplate.Execute(&b, templateInput)
5047
if err != nil {
5148
return "", fmt.Errorf("failed setting API endpoint configuration in template: %w", err)
5249
}

0 commit comments

Comments
 (0)