Skip to content

Commit

Permalink
fixup! versions: add k8s 1.31, remove k8s 1.28
Browse files Browse the repository at this point in the history
kubecmd: add migration from kubeadm.k8s.io/v1beta3 to v1beta4
  • Loading branch information
burgerdev committed Oct 8, 2024
1 parent d4a6487 commit c1e09be
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 32 deletions.
5 changes: 4 additions & 1 deletion internal/constellation/kubecmd/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ go_library(
"@io_k8s_apimachinery//pkg/apis/meta/v1/unstructured",
"@io_k8s_apimachinery//pkg/runtime",
"@io_k8s_apimachinery//pkg/runtime/schema",
"@io_k8s_apimachinery//pkg/runtime/serializer/json",
"@io_k8s_client_go//util/retry",
"@io_k8s_kubernetes//cmd/kubeadm/app/apis/kubeadm/v1beta3",
"@io_k8s_kubernetes//cmd/kubeadm/app/apis/kubeadm",
"@io_k8s_kubernetes//cmd/kubeadm/app/apis/kubeadm/scheme",
"@io_k8s_kubernetes//cmd/kubeadm/app/apis/kubeadm/v1beta4",
"@io_k8s_sigs_yaml//:yaml",
],
)
Expand Down
56 changes: 25 additions & 31 deletions internal/constellation/kubecmd/kubecmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,11 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
k8sjson "k8s.io/apimachinery/pkg/runtime/serializer/json"
"k8s.io/client-go/util/retry"
kubeadmv1beta3 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta3"
"sigs.k8s.io/yaml"
"k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
kubeadmscheme "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/scheme"
kubeadmv1beta4 "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm/v1beta4"
)

// ErrInProgress signals that an upgrade is in progress inside the cluster.
Expand Down Expand Up @@ -234,9 +236,23 @@ func (k *KubeCmd) ApplyJoinConfig(ctx context.Context, newAttestConfig config.At
// ExtendClusterConfigCertSANs extends the ClusterConfig stored under "kube-system/kubeadm-config" with the given SANs.
// Empty strings are ignored, existing SANs are preserved.
func (k *KubeCmd) ExtendClusterConfigCertSANs(ctx context.Context, alternativeNames []string) error {
clusterConfiguration, kubeadmConfig, err := k.getClusterConfiguration(ctx)
if err != nil {
return fmt.Errorf("getting ClusterConfig: %w", err)
var kubeadmConfig *corev1.ConfigMap
if err := k.retryAction(ctx, func(ctx context.Context) error {
var err error
kubeadmConfig, err = k.kubectl.GetConfigMap(ctx, constants.ConstellationNamespace, constants.KubeadmConfigMap)
return err
}); err != nil {
return fmt.Errorf("retrieving current kubeadm-config: %w", err)
}

clusterConfigData, ok := kubeadmConfig.Data[constants.ClusterConfigurationKey]
if !ok {
return errors.New("ClusterConfiguration missing from kubeadm-config")
}

var clusterConfiguration kubeadm.ClusterConfiguration
if err := runtime.DecodeInto(kubeadmscheme.Codecs.UniversalDecoder(), []byte(clusterConfigData), &clusterConfiguration); err != nil {
return fmt.Errorf("decoding cluster configuration data: %w", err)
}

existingSANs := make(map[string]struct{})
Expand Down Expand Up @@ -264,7 +280,10 @@ func (k *KubeCmd) ExtendClusterConfigCertSANs(ctx context.Context, alternativeNa
clusterConfiguration.APIServer.CertSANs = append(clusterConfiguration.APIServer.CertSANs, missingSANs...)
sort.Strings(clusterConfiguration.APIServer.CertSANs)

newConfigYAML, err := yaml.Marshal(clusterConfiguration)
opt := k8sjson.SerializerOptions{Yaml: true}
serializer := k8sjson.NewSerializerWithOptions(k8sjson.DefaultMetaFactory, kubeadmscheme.Scheme, kubeadmscheme.Scheme, opt)
encoder := kubeadmscheme.Codecs.EncoderForVersion(serializer, kubeadmv1beta4.SchemeGroupVersion)
newConfigYAML, err := runtime.Encode(encoder, &clusterConfiguration)
if err != nil {
return fmt.Errorf("marshaling ClusterConfiguration: %w", err)
}
Expand Down Expand Up @@ -316,31 +335,6 @@ func (k *KubeCmd) getConstellationVersion(ctx context.Context) (updatev1alpha1.N
return nodeVersion, nil
}

// getClusterConfiguration fetches the kubeadm-config configmap from the cluster, extracts the config
// and returns both the full configmap and the ClusterConfiguration.
func (k *KubeCmd) getClusterConfiguration(ctx context.Context) (kubeadmv1beta3.ClusterConfiguration, *corev1.ConfigMap, error) {
var existingConf *corev1.ConfigMap
if err := k.retryAction(ctx, func(ctx context.Context) error {
var err error
existingConf, err = k.kubectl.GetConfigMap(ctx, constants.ConstellationNamespace, constants.KubeadmConfigMap)
return err
}); err != nil {
return kubeadmv1beta3.ClusterConfiguration{}, nil, fmt.Errorf("retrieving current kubeadm-config: %w", err)
}

clusterConf, ok := existingConf.Data[constants.ClusterConfigurationKey]
if !ok {
return kubeadmv1beta3.ClusterConfiguration{}, nil, errors.New("ClusterConfiguration missing from kubeadm-config")
}

var existingClusterConfig kubeadmv1beta3.ClusterConfiguration
if err := yaml.Unmarshal([]byte(clusterConf), &existingClusterConfig); err != nil {
return kubeadmv1beta3.ClusterConfiguration{}, nil, fmt.Errorf("unmarshaling ClusterConfiguration: %w", err)
}

return existingClusterConfig, existingConf, nil
}

// applyComponentsCM applies the k8s components ConfigMap to the cluster.
func (k *KubeCmd) applyComponentsCM(ctx context.Context, components *corev1.ConfigMap) error {
if err := k.retryAction(ctx, func(ctx context.Context) error {
Expand Down
124 changes: 124 additions & 0 deletions internal/constellation/kubecmd/kubecmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -676,6 +676,50 @@ func TestRetryAction(t *testing.T) {
}
}

func TestExtendClusterConfigCertSANs(t *testing.T) {
ctx := context.Background()

testCases := map[string]struct {
clusterConfig string
}{
"kubeadmv1beta3.ClusterConfiguration": {
clusterConfig: kubeadmClusterConfigurationV1Beta3,
},
"kubeadmv1beta4.ClusterConfiguration": {
clusterConfig: kubeadmClusterConfigurationV1Beta4,
},
}

for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
require := require.New(t)
assert := assert.New(t)
kubectl := &fakeConfigMapClient{
configMaps: map[string]*corev1.ConfigMap{
constants.KubeadmConfigMap: {Data: map[string]string{"ClusterConfiguration": tc.clusterConfig}},
},
}
cmd := &KubeCmd{
kubectl: kubectl,
log: logger.NewTest(t),
retryInterval: time.Millisecond,
}

err := cmd.ExtendClusterConfigCertSANs(ctx, []string{"example.com"})
require.NoError(err)

cm := kubectl.configMaps["kubeadm-config"]
require.NotNil(cm)
cc := cm.Data["ClusterConfiguration"]
require.NotNil(cc)
// Verify that SAN was added.
assert.Contains(cc, "example.com")
// Verify that config was written in v1beta4, regardless of the version read.
assert.Contains(cc, "kubeadm.k8s.io/v1beta4")
})
}
}

type fakeUnstructuredClient struct {
mock.Mock
}
Expand Down Expand Up @@ -835,3 +879,83 @@ func supportedValidK8sVersions() (res []versions.ValidK8sVersion) {
}
return
}

var kubeadmClusterConfigurationV1Beta3 = `
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
apiServer:
certSANs:
- 127.0.0.1
extraArgs:
kubelet-certificate-authority: /etc/kubernetes/pki/ca.crt
profiling: "false"
extraVolumes:
- hostPath: /var/log/kubernetes/audit/
mountPath: /var/log/kubernetes/audit/
name: audit-log
pathType: DirectoryOrCreate
certificatesDir: /etc/kubernetes/pki
clusterName: test-55bbf58d
controlPlaneEndpoint: 34.149.125.227:6443
controllerManager:
extraArgs:
cloud-provider: external
dns:
disabled: true
encryptionAlgorithm: RSA-2048
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.k8s.io
kubernetesVersion: v1.31.1
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
proxy:
disabled: true
scheduler:
extraArgs:
profiling: "false"
`

var kubeadmClusterConfigurationV1Beta4 = `
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
apiServer:
certSANs:
- 127.0.0.1
extraArgs:
- name: kubelet-certificate-authority
value: /etc/kubernetes/pki/ca.crt
- name: profiling
value: "false"
extraVolumes:
- hostPath: /var/log/kubernetes/audit/
mountPath: /var/log/kubernetes/audit/
name: audit-log
pathType: DirectoryOrCreate
certificatesDir: /etc/kubernetes/pki
clusterName: test-55bbf58d
controlPlaneEndpoint: 34.149.125.227:6443
controllerManager:
extraArgs:
- name: cloud-provider
value: external
dns:
disabled: true
encryptionAlgorithm: RSA-2048
etcd:
local:
dataDir: /var/lib/etcd
imageRepository: registry.k8s.io
kubernetesVersion: v1.31.1
networking:
dnsDomain: cluster.local
serviceSubnet: 10.96.0.0/12
proxy:
disabled: true
scheduler:
extraArgs:
- name: profiling
value: "false"
`

0 comments on commit c1e09be

Please sign in to comment.