diff --git a/docs/getting-started-with-kamaji.md b/docs/getting-started-with-kamaji.md index 4f1f3d7..1d11e3e 100644 --- a/docs/getting-started-with-kamaji.md +++ b/docs/getting-started-with-kamaji.md @@ -8,13 +8,16 @@ We assume you have installed on your workstation: - [Docker](https://docs.docker.com/engine/install/) - [KinD](https://kind.sigs.k8s.io/) -- [kubectl](https://kubernetes.io/docs/tasks/tools/) -- [kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/) +- [kubectl@v1.25.0](https://kubernetes.io/docs/tasks/tools/) +- [kubeadm@v1.25.0](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/) - [jq](https://stedolan.github.io/jq/) - [openssl](https://www.openssl.org/) - [cfssl](https://github.com/cloudflare/cfssl) - [cfssljson](https://github.com/cloudflare/cfssl) +> Starting from Kamaji v0.0.2, `kubectl` and `kubeadm` need to meet at least minimum version to `v1.25.0`: +> this is required due to the latest changes addressed from the release Kubernetes 1.25 release regarding the `kubelet-config` ConfigMap required for the node join. + ## Setup Kamaji on KinD The instance of Kamaji is made of a single node hosting: diff --git a/internal/kubeadm/addon.go b/internal/kubeadm/addon.go index 2cb6416..9be14bb 100644 --- a/internal/kubeadm/addon.go +++ b/internal/kubeadm/addon.go @@ -5,25 +5,13 @@ package kubeadm import ( "context" - "fmt" - "time" + "io" - "github.com/pkg/errors" - appsv1 "k8s.io/api/apps/v1" - corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" - clientcmdapi "k8s.io/client-go/tools/clientcmd/api/v1" - "k8s.io/component-base/config/v1alpha1" - kubeproxyconfig "k8s.io/kube-proxy/config/v1alpha1" - kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/dns" "k8s.io/kubernetes/cmd/kubeadm/app/phases/addons/proxy" - "k8s.io/kubernetes/cmd/kubeadm/app/util/apiclient" - "k8s.io/utils/pointer" - - "github.com/clastix/kamaji/internal/utilities" ) const ( @@ -41,7 +29,7 @@ func AddCoreDNS(client kubernetes.Interface, config *Configuration) error { config.InitConfiguration.DNS.ImageTag = opts.Tag } - return dns.EnsureDNSAddon(&config.InitConfiguration.ClusterConfiguration, client) + return dns.EnsureDNSAddon(&config.InitConfiguration.ClusterConfiguration, client, io.Discard, false) } func RemoveCoreDNSAddon(ctx context.Context, client kubernetes.Interface) error { @@ -111,26 +99,15 @@ func getCoreDNSConfigMapName(ctx context.Context) (string, error) { return coreDNSName, nil } -func AddKubeProxy(client kubernetes.Interface, config *Configuration) error { - if err := proxy.CreateServiceAccount(client); err != nil { - return errors.Wrap(err, "error when creating kube-proxy service account") - } +func AddKubeProxy(client kubernetes.Interface, config *Configuration) (err error) { + // This is a workaround since the function EnsureProxyAddon is picking repository and tag from the InitConfiguration + // struct, although is counterintuitive + config.InitConfiguration.ClusterConfiguration.CIImageRepository = config.Parameters.KubeProxyOptions.Repository + config.InitConfiguration.KubernetesVersion = config.Parameters.KubeProxyOptions.Tag - if err := createKubeProxyConfigMap(client, config); err != nil { - return err - } + err = proxy.EnsureProxyAddon(&config.InitConfiguration.ClusterConfiguration, &config.InitConfiguration.LocalAPIEndpoint, client, io.Discard, false) - image := fmt.Sprintf("%s/kube-proxy:%s", config.Parameters.KubeProxyOptions.Repository, config.Parameters.KubeProxyOptions.Tag) - - if err := createKubeProxyAddon(client, image); err != nil { - return err - } - - if err := proxy.CreateRBACRules(client); err != nil { - return errors.Wrap(err, "error when creating kube-proxy RBAC rules") - } - - return nil + return } func RemoveKubeProxy(ctx context.Context, client kubernetes.Interface) error { @@ -224,247 +201,3 @@ func getKubeProxyConfigMapName(ctx context.Context) (string, error) { // Implement a method for future approaches return kubeProxyName, nil } - -func createKubeProxyConfigMap(client kubernetes.Interface, config *Configuration) error { - configConf, err := getKubeproxyConfigmapContent(config) - if err != nil { - return err - } - - kubeconfigConf, err := getKubeproxyKubeconfigContent(config) - if err != nil { - return err - } - - configMap := &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: kubeadmconstants.KubeProxyConfigMap, - Namespace: "kube-system", - Labels: map[string]string{ - "app": "kube-proxy", - }, - }, - Data: map[string]string{ - kubeadmconstants.KubeProxyConfigMapKey: string(configConf), - "kubeconfig.conf": string(kubeconfigConf), - }, - } - - return apiclient.CreateOrUpdateConfigMap(client, configMap) -} - -func createKubeProxyAddon(client kubernetes.Interface, image string) error { - daemonSet := &appsv1.DaemonSet{ - ObjectMeta: metav1.ObjectMeta{ - Name: "kube-proxy", - Namespace: "kube-system", - Labels: map[string]string{ - "k8s-app": "kube-proxy", - }, - }, - Spec: appsv1.DaemonSetSpec{ - RevisionHistoryLimit: pointer.Int32(10), - Selector: &metav1.LabelSelector{ - MatchLabels: map[string]string{ - "k8s-app": "kube-proxy", - }, - }, - Template: corev1.PodTemplateSpec{ - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "k8s-app": "kube-proxy", - }, - }, - Spec: corev1.PodSpec{ - Containers: []corev1.Container{ - { - Command: []string{ - "/usr/local/bin/kube-proxy", - "--config=/var/lib/kube-proxy/config.conf", - "--hostname-override=$(NODE_NAME)", - }, - Env: []corev1.EnvVar{ - { - Name: "NODE_NAME", - ValueFrom: &corev1.EnvVarSource{ - FieldRef: &corev1.ObjectFieldSelector{ - APIVersion: "v1", - FieldPath: "spec.nodeName", - }, - }, - }, - }, - Image: image, - ImagePullPolicy: corev1.PullIfNotPresent, - Name: "kube-proxy", - SecurityContext: &corev1.SecurityContext{ - Privileged: pointer.Bool(true), - }, - TerminationMessagePath: "/dev/termination-log", - TerminationMessagePolicy: "File", - VolumeMounts: []corev1.VolumeMount{ - { - MountPath: "/var/lib/kube-proxy", - Name: "kube-proxy", - }, - { - MountPath: "/run/xtables.lock", - Name: "xtables-lock", - }, - { - MountPath: "/lib/modules", - Name: "lib-modules", - ReadOnly: true, - }, - }, - }, - }, - DNSPolicy: corev1.DNSClusterFirst, - HostNetwork: true, - NodeSelector: map[string]string{ - "kubernetes.io/os": "linux", - }, - Tolerations: []corev1.Toleration{ - {Operator: corev1.TolerationOpExists}, - }, - PriorityClassName: "system-node-critical", - RestartPolicy: corev1.RestartPolicyAlways, - SchedulerName: "default-scheduler", - ServiceAccountName: "kube-proxy", - TerminationGracePeriodSeconds: pointer.Int64(30), - Volumes: []corev1.Volume{ - { - Name: "kube-proxy", - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - DefaultMode: pointer.Int32(420), - LocalObjectReference: corev1.LocalObjectReference{ - Name: "kube-proxy", - }, - }, - }, - }, - { - Name: "xtables-lock", - VolumeSource: corev1.VolumeSource{ - HostPath: &corev1.HostPathVolumeSource{ - Path: "/run/xtables.lock", - Type: (*corev1.HostPathType)(pointer.String(string(corev1.HostPathFileOrCreate))), - }, - }, - }, - { - Name: "lib-modules", - VolumeSource: corev1.VolumeSource{ - HostPath: &corev1.HostPathVolumeSource{ - Path: "/lib/modules", - Type: (*corev1.HostPathType)(pointer.String(string(corev1.HostPathUnset))), - }, - }, - }, - }, - }, - }, - }, - } - - return apiclient.CreateOrUpdateDaemonSet(client, daemonSet) -} - -func getKubeproxyConfigmapContent(config *Configuration) ([]byte, error) { - zeroDuration := metav1.Duration{Duration: 0} - oneSecondDuration := metav1.Duration{Duration: time.Second} - - kubeProxyConfiguration := kubeproxyconfig.KubeProxyConfiguration{ - TypeMeta: metav1.TypeMeta{ - Kind: "KubeProxyConfiguration", - APIVersion: "kubeproxy.config.k8s.io/v1alpha1", - }, - BindAddress: "0.0.0.0", - BindAddressHardFail: false, - ClientConnection: v1alpha1.ClientConnectionConfiguration{ - AcceptContentTypes: "", - Burst: 0, - ContentType: "", - Kubeconfig: "/var/lib/kube-proxy/kubeconfig.conf", - QPS: 0, - }, - ClusterCIDR: config.Parameters.TenantControlPlanePodCIDR, - ConfigSyncPeriod: zeroDuration, - Conntrack: kubeproxyconfig.KubeProxyConntrackConfiguration{ - MaxPerCore: pointer.Int32(0), - Min: nil, - TCPCloseWaitTimeout: nil, - TCPEstablishedTimeout: nil, - }, - DetectLocalMode: "", - EnableProfiling: false, - HealthzBindAddress: "", - HostnameOverride: "", - IPTables: kubeproxyconfig.KubeProxyIPTablesConfiguration{ - MasqueradeAll: false, - MasqueradeBit: nil, - MinSyncPeriod: oneSecondDuration, - SyncPeriod: zeroDuration, - }, - IPVS: kubeproxyconfig.KubeProxyIPVSConfiguration{ - ExcludeCIDRs: nil, - MinSyncPeriod: zeroDuration, - Scheduler: "", - StrictARP: false, - SyncPeriod: zeroDuration, - TCPTimeout: zeroDuration, - TCPFinTimeout: zeroDuration, - UDPTimeout: zeroDuration, - }, - MetricsBindAddress: "", - Mode: "iptables", - NodePortAddresses: nil, - OOMScoreAdj: nil, - PortRange: "", - ShowHiddenMetricsForVersion: "", - UDPIdleTimeout: zeroDuration, - Winkernel: kubeproxyconfig.KubeProxyWinkernelConfiguration{ - EnableDSR: false, - NetworkName: "", - SourceVip: "", - }, - } - - return utilities.EncondeToYaml(&kubeProxyConfiguration) -} - -func getKubeproxyKubeconfigContent(config *Configuration) ([]byte, error) { - kubeconfig := clientcmdapi.Config{ - APIVersion: "v1", - Kind: "Config", - Clusters: []clientcmdapi.NamedCluster{ - { - Name: "default", - Cluster: clientcmdapi.Cluster{ - CertificateAuthority: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt", - Server: fmt.Sprintf("https://%s:%d", config.Parameters.TenantControlPlaneAddress, config.Parameters.TenantControlPlanePort), - }, - }, - }, - Contexts: []clientcmdapi.NamedContext{ - { - Context: clientcmdapi.Context{ - Cluster: "default", - Namespace: "default", - AuthInfo: "default", - }, - }, - }, - AuthInfos: []clientcmdapi.NamedAuthInfo{ - { - Name: "default", - AuthInfo: clientcmdapi.AuthInfo{ - TokenFile: "/var/run/secrets/kubernetes.io/serviceaccount/token", - }, - }, - }, - } - - return utilities.EncondeToYaml(&kubeconfig) -} diff --git a/internal/kubeadm/configuration.go b/internal/kubeadm/configuration.go index 1adb914..f5f7dfe 100644 --- a/internal/kubeadm/configuration.go +++ b/internal/kubeadm/configuration.go @@ -4,15 +4,14 @@ package kubeadm import ( - "encoding/json" "fmt" "strings" - "time" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - bootstraptokenv1 "k8s.io/kubernetes/cmd/kubeadm/app/apis/bootstraptoken/v1" kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" + "k8s.io/kubernetes/cmd/kubeadm/app/util/config" + + "github.com/clastix/kamaji/internal/utilities" ) const ( @@ -21,128 +20,103 @@ const ( defaultKeyFile = "/etc/kubernetes/pki/apiserver-etcd-client.key" ) -func CreateKubeadmInitConfiguration(params Parameters) Configuration { - config := kubeadmapi.InitConfiguration{ - ClusterConfiguration: getKubeadmClusterConfiguration(params), - BootstrapTokens: []bootstraptokenv1.BootstrapToken{ - { - Groups: []string{"system:bootstrappers:kubeadm:default-node-token"}, - TTL: &metav1.Duration{Duration: 48 * time.Hour}, - Usages: []string{ - "signing", - "authentication", - }, - }, - }, - LocalAPIEndpoint: kubeadmapi.APIEndpoint{ - AdvertiseAddress: params.TenantControlPlaneAddress, - BindPort: params.TenantControlPlanePort, - }, - NodeRegistration: kubeadmapi.NodeRegistrationOptions{ - CRISocket: "unix:///run/containerd/containerd.sock", - Name: params.TenantControlPlaneName, - }, +func CreateKubeadmInitConfiguration(params Parameters) (*Configuration, error) { + defaultConf, err := config.DefaultedStaticInitConfiguration() + if err != nil { + return nil, err } - return Configuration{InitConfiguration: config} -} + conf := defaultConf + // Due to unmarshaling error when GetKubeadmInitConfigurationFromMap function is issued, + // we have to store the ComponentConfigs to a null value. + conf.ClusterConfiguration.ComponentConfigs = nil -func isHTTPS(url string) bool { - return strings.HasPrefix(url, "https") -} + conf.LocalAPIEndpoint = kubeadmapi.APIEndpoint{ + AdvertiseAddress: params.TenantControlPlaneAddress, + BindPort: params.TenantControlPlanePort, + } + conf.NodeRegistration.Name = params.TenantControlPlaneName -func getKubeadmClusterConfiguration(params Parameters) kubeadmapi.ClusterConfiguration { caFile, certFile, keyFile := "", "", "" - if isHTTPS(params.ETCDs[0]) { + if strings.HasPrefix(params.ETCDs[0], "https") { caFile, certFile, keyFile = defaultCAFile, defaultCertFile, defaultKeyFile } - return kubeadmapi.ClusterConfiguration{ - KubernetesVersion: params.TenantControlPlaneVersion, - ClusterName: params.TenantControlPlaneName, - CertificatesDir: "/etc/kubernetes/pki", - ImageRepository: "k8s.gcr.io", - Networking: kubeadmapi.Networking{ - DNSDomain: "cluster.local", - PodSubnet: params.TenantControlPlanePodCIDR, - ServiceSubnet: params.TenantControlPlaneServiceCIDR, - }, - DNS: kubeadmapi.DNS{ - Type: "CoreDNS", - }, - ControlPlaneEndpoint: params.TenantControlPlaneEndpoint, - Etcd: kubeadmapi.Etcd{ - External: &kubeadmapi.ExternalEtcd{ - Endpoints: params.ETCDs, - CAFile: caFile, - CertFile: certFile, - KeyFile: keyFile, - }, - }, - APIServer: kubeadmapi.APIServer{ - CertSANs: append([]string{ - "127.0.0.1", - "localhost", - params.TenantControlPlaneName, - fmt.Sprintf("%s.%s.svc", params.TenantControlPlaneName, params.TenantControlPlaneNamespace), - fmt.Sprintf("%s.%s.svc.cluster.local", params.TenantControlPlaneName, params.TenantControlPlaneNamespace), - params.TenantControlPlaneAddress, - }, params.TenantControlPlaneCertSANs...), - ControlPlaneComponent: kubeadmapi.ControlPlaneComponent{ - ExtraArgs: map[string]string{ - "etcd-compaction-interval": "0s", - "etcd-prefix": fmt.Sprintf("/%s", params.TenantControlPlaneName), - }, - }, + conf.Etcd = kubeadmapi.Etcd{ + External: &kubeadmapi.ExternalEtcd{ + Endpoints: params.ETCDs, + CAFile: caFile, + CertFile: certFile, + KeyFile: keyFile, }, } + conf.Networking = kubeadmapi.Networking{ + DNSDomain: "cluster.local", + PodSubnet: params.TenantControlPlanePodCIDR, + ServiceSubnet: params.TenantControlPlaneServiceCIDR, + } + conf.KubernetesVersion = params.TenantControlPlaneVersion + conf.ControlPlaneEndpoint = params.TenantControlPlaneEndpoint + conf.APIServer.CertSANs = append([]string{ + "127.0.0.1", + "localhost", + params.TenantControlPlaneName, + fmt.Sprintf("%s.%s.svc", params.TenantControlPlaneName, params.TenantControlPlaneNamespace), + fmt.Sprintf("%s.%s.svc.cluster.local", params.TenantControlPlaneName, params.TenantControlPlaneNamespace), + params.TenantControlPlaneAddress, + }, params.TenantControlPlaneCertSANs...) + conf.APIServer.ControlPlaneComponent.ExtraArgs = map[string]string{ + "etcd-compaction-interval": "0s", + "etcd-prefix": fmt.Sprintf("/%s", params.TenantControlPlaneName), + } + conf.ClusterName = params.TenantControlPlaneName + + return &Configuration{InitConfiguration: *conf}, nil } func GetKubeadmInitConfigurationMap(config Configuration) (map[string]string, error) { - initConfigurationString, err := getJSONStringFromStruct(config.InitConfiguration) + initConfigurationString, err := utilities.EncodeToJSON(&config.InitConfiguration) if err != nil { - return map[string]string{}, err + return nil, err } - clusterConfigurationString, err := getJSONStringFromStruct(config.InitConfiguration.ClusterConfiguration) + clusterConfigurationString, err := utilities.EncodeToJSON(&config.InitConfiguration.ClusterConfiguration) if err != nil { - return map[string]string{}, err + return nil, err } return map[string]string{ - kubeadmconstants.InitConfigurationKind: initConfigurationString, - kubeadmconstants.ClusterConfigurationKind: clusterConfigurationString, + kubeadmconstants.InitConfigurationKind: string(initConfigurationString), + kubeadmconstants.ClusterConfigurationKind: string(clusterConfigurationString), }, nil } -func GetKubeadmInitConfigurationFromMap(config map[string]string) (*Configuration, error) { - initConfigurationString, ok := config[kubeadmconstants.InitConfigurationKind] +func GetKubeadmInitConfigurationFromMap(conf map[string]string) (*Configuration, error) { + initConfigurationString, ok := conf[kubeadmconstants.InitConfigurationKind] if !ok { return nil, fmt.Errorf("%s is not in the map", kubeadmconstants.InitConfigurationKind) } - clusterConfigurationString, ok := config[kubeadmconstants.ClusterConfigurationKind] + clusterConfigurationString, ok := conf[kubeadmconstants.ClusterConfigurationKind] if !ok { return nil, fmt.Errorf("%s is not in the map", kubeadmconstants.ClusterConfigurationKind) } initConfiguration := kubeadmapi.InitConfiguration{} - if err := json.Unmarshal([]byte(initConfigurationString), &initConfiguration); err != nil { + if err := utilities.DecodeFromJSON(initConfigurationString, &initConfiguration); err != nil { return nil, err } - if err := json.Unmarshal([]byte(clusterConfigurationString), &initConfiguration.ClusterConfiguration); err != nil { + if err := utilities.DecodeFromJSON(clusterConfigurationString, &initConfiguration.ClusterConfiguration); err != nil { return nil, err } + // Due to some weird issues with unmarshaling of the ComponentConfigs struct, + // we have to extract the default value and assign it directly. + defaults, err := config.DefaultedStaticInitConfiguration() + if err != nil { + return nil, err + } + initConfiguration.ClusterConfiguration.ComponentConfigs = defaults.ComponentConfigs return &Configuration{InitConfiguration: initConfiguration}, nil } - -func getJSONStringFromStruct(i interface{}) (string, error) { - b, err := json.Marshal(i) - if err != nil { - return "", err - } - - return string(b), nil -} diff --git a/internal/kubeadm/printers/discard.go b/internal/kubeadm/printers/discard.go new file mode 100644 index 0000000..f401b4e --- /dev/null +++ b/internal/kubeadm/printers/discard.go @@ -0,0 +1,38 @@ +// Copyright 2022 Clastix Labs +// SPDX-License-Identifier: Apache-2.0 + +package printers + +import ( + "io" + + "k8s.io/apimachinery/pkg/runtime" +) + +type Discard struct{} + +func (d Discard) PrintObj(obj runtime.Object, writer io.Writer) error { + return nil +} + +func (d Discard) Fprintf(writer io.Writer, format string, args ...interface{}) (n int, err error) { + return +} + +func (d Discard) Fprintln(writer io.Writer, args ...interface{}) (n int, err error) { + return +} + +func (d Discard) Printf(format string, args ...interface{}) (n int, err error) { + return +} + +func (d Discard) Println(args ...interface{}) (n int, err error) { + return +} + +func (d Discard) Flush(writer io.Writer, last bool) { +} + +func (d Discard) Close(writer io.Writer) { +} diff --git a/internal/kubeadm/uploadconfig.go b/internal/kubeadm/uploadconfig.go index 21e053a..cb0e2f7 100644 --- a/internal/kubeadm/uploadconfig.go +++ b/internal/kubeadm/uploadconfig.go @@ -4,13 +4,10 @@ package kubeadm import ( - "fmt" - "github.com/pkg/errors" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - k8sversion "k8s.io/apimachinery/pkg/util/version" "k8s.io/client-go/kubernetes" kubelettypes "k8s.io/kubelet/config/v1beta1" kubeadmconstants "k8s.io/kubernetes/cmd/kubeadm/app/constants" @@ -37,10 +34,7 @@ func UploadKubeletConfig(client kubernetes.Interface, config *Configuration) err return err } - configMapName, err := configMapName(config.Parameters.TenantControlPlaneVersion) - if err != nil { - return err - } + configMapName := kubeadmconstants.KubeletBaseConfigurationConfigMap configMap := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ @@ -56,7 +50,7 @@ func UploadKubeletConfig(client kubernetes.Interface, config *Configuration) err return err } - if err := createConfigMapRBACRules(client, config.Parameters.TenantControlPlaneVersion); err != nil { + if err := createConfigMapRBACRules(client); err != nil { return errors.Wrap(err, "error creating kubelet configuration configmap RBAC rules") } @@ -120,16 +114,8 @@ func getKubeletConfigmapContent(kubeletConfiguration KubeletConfiguration) ([]by return utilities.EncondeToYaml(&kc) } -func createConfigMapRBACRules(client kubernetes.Interface, kubernetesVersion string) error { - configMapName, err := configMapName(kubernetesVersion) - if err != nil { - return err - } - - configMapRBACName, err := configMapRBACName(kubernetesVersion) - if err != nil { - return err - } +func createConfigMapRBACRules(client kubernetes.Interface) error { + configMapRBACName := kubeadmconstants.KubeletBaseConfigMapRole if err := apiclient.CreateOrUpdateRole(client, &rbacv1.Role{ ObjectMeta: metav1.ObjectMeta{ @@ -141,7 +127,7 @@ func createConfigMapRBACRules(client kubernetes.Interface, kubernetesVersion str Verbs: []string{"get"}, APIGroups: []string{""}, Resources: []string{"configmaps"}, - ResourceNames: []string{configMapName}, + ResourceNames: []string{kubeadmconstants.KubeletBaseConfigurationConfigMap}, }, }, }); err != nil { @@ -170,21 +156,3 @@ func createConfigMapRBACRules(client kubernetes.Interface, kubernetesVersion str }, }) } - -func configMapName(kubernetesVersion string) (string, error) { - version, err := k8sversion.ParseSemantic(kubernetesVersion) - if err != nil { - return "", err - } - - return kubeadmconstants.GetKubeletConfigMapName(version, true), nil -} - -func configMapRBACName(kubernetesVersion string) (string, error) { - version, err := k8sversion.ParseSemantic(kubernetesVersion) - if err != nil { - return "", err - } - - return fmt.Sprintf("%s%d.%d", kubeadmconstants.KubeletBaseConfigMapRolePrefix, version.Major(), version.Minor()), nil -} diff --git a/internal/resources/kubeadm_config.go b/internal/resources/kubeadm_config.go index 7979cbb..2befb48 100644 --- a/internal/resources/kubeadm_config.go +++ b/internal/resources/kubeadm_config.go @@ -99,8 +99,11 @@ func (r *KubeadmConfigResource) mutate(tenantControlPlane *kamajiv1alpha1.Tenant CertificatesDir: r.TmpDirectory, } - config := kubeadm.CreateKubeadmInitConfiguration(params) - data, err := kubeadm.GetKubeadmInitConfigurationMap(config) + config, err := kubeadm.CreateKubeadmInitConfiguration(params) + if err != nil { + return err + } + data, err := kubeadm.GetKubeadmInitConfigurationMap(*config) if err != nil { return err } diff --git a/internal/resources/kubeadm_upgrade.go b/internal/resources/kubeadm_upgrade.go index dbbda58..3034ae4 100644 --- a/internal/resources/kubeadm_upgrade.go +++ b/internal/resources/kubeadm_upgrade.go @@ -14,6 +14,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" kamajiv1alpha1 "github.com/clastix/kamaji/api/v1alpha1" + "github.com/clastix/kamaji/internal/kubeadm/printers" kamajiupgrade "github.com/clastix/kamaji/internal/upgrade" "github.com/clastix/kamaji/internal/utilities" ) @@ -71,7 +72,7 @@ func (k *KubernetesUpgrade) CreateOrUpdate(ctx context.Context, tenantControlPla versionGetter := kamajiupgrade.NewKamajiKubeVersionGetter(restClient) - if _, err = upgrade.GetAvailableUpgrades(versionGetter, false, false, true, restClient, ""); err != nil { + if _, err = upgrade.GetAvailableUpgrades(versionGetter, false, false, true, restClient, "", &printers.Discard{}); err != nil { return controllerutil.OperationResultNone, errors.Wrap(err, "cannot retrieve available Upgrades for Kubernetes upgrade plan") } diff --git a/internal/utilities/utilities.go b/internal/utilities/utilities.go index 2a22b0a..3090a2a 100644 --- a/internal/utilities/utilities.go +++ b/internal/utilities/utilities.go @@ -67,6 +67,41 @@ func EncondeToYaml(o runtime.Object) ([]byte, error) { return buf.Bytes(), err } +func DecodeFromJSON(o string, to runtime.Object) (err error) { + scheme := runtime.NewScheme() + + encoder := json.NewSerializerWithOptions(json.SimpleMetaFactory{}, scheme, scheme, json.SerializerOptions{ + Yaml: false, + Pretty: false, + Strict: false, + }) + + if to, _, err = encoder.Decode([]byte(o), nil, to); err != nil { //nolint:ineffassign,staticcheck + return + } + + return +} + +// EncodeToJSON returns the given object in JSON format and the error, respecting the Kubernetes struct tags. +func EncodeToJSON(o runtime.Object) ([]byte, error) { + scheme := runtime.NewScheme() + + encoder := json.NewSerializerWithOptions(json.SimpleMetaFactory{}, scheme, scheme, json.SerializerOptions{ + Yaml: false, + Pretty: false, + Strict: false, + }) + + buf := bytes.NewBuffer([]byte{}) + + if err := encoder.Encode(o, buf); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} + // IsValidIP checks if the given argument is an IP. func IsValidIP(ip string) bool { return net.ParseIP(ip) != nil