265 lines
7.4 KiB
Go
265 lines
7.4 KiB
Go
package tasks
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/client-go/tools/clientcmd"
|
|
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
|
"k8s.io/klog/v2"
|
|
|
|
"github.com/karmada-io/karmada/operator/pkg/certs"
|
|
"github.com/karmada-io/karmada/operator/pkg/constants"
|
|
"github.com/karmada-io/karmada/operator/pkg/util"
|
|
"github.com/karmada-io/karmada/operator/pkg/util/apiclient"
|
|
"github.com/karmada-io/karmada/operator/pkg/workflow"
|
|
)
|
|
|
|
// NewUploadKubeconfigTask init a task to upload karmada kubeconfig and
|
|
// all of karmada certs to secret
|
|
func NewUploadKubeconfigTask() workflow.Task {
|
|
return workflow.Task{
|
|
Name: "upload-config",
|
|
RunSubTasks: true,
|
|
Run: runUploadKubeconfig,
|
|
Tasks: []workflow.Task{
|
|
{
|
|
Name: "UploadAdminKubeconfig",
|
|
Run: runUploadAdminKubeconfig,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func runUploadKubeconfig(r workflow.RunData) error {
|
|
data, ok := r.(InitData)
|
|
if !ok {
|
|
return errors.New("upload-config task invoked with an invalid data struct")
|
|
}
|
|
|
|
klog.V(4).InfoS("[upload-config] Running task", "karmada", klog.KObj(data))
|
|
return nil
|
|
}
|
|
|
|
func runUploadAdminKubeconfig(r workflow.RunData) error {
|
|
data, ok := r.(InitData)
|
|
if !ok {
|
|
return errors.New("UploadAdminKubeconfig task invoked with an invalid data struct")
|
|
}
|
|
|
|
var endpoint string
|
|
switch data.Components().KarmadaAPIServer.ServiceType {
|
|
case corev1.ServiceTypeClusterIP:
|
|
apiserverName := util.KarmadaAPIServerName(data.GetName())
|
|
endpoint = fmt.Sprintf("https://%s.%s.svc.cluster.local:%d", apiserverName, data.GetNamespace(), constants.KarmadaAPIserverListenClientPort)
|
|
|
|
case corev1.ServiceTypeNodePort:
|
|
service, err := apiclient.GetService(data.RemoteClient(), util.KarmadaAPIServerName(data.GetName()), data.GetNamespace())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
nodePort := getNodePortFromAPIServerService(service)
|
|
endpoint = fmt.Sprintf("https://%s:%d", data.ControlplaneAddress(), nodePort)
|
|
}
|
|
|
|
kubeconfig, err := buildKubeConfigFromSpec(data, endpoint)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
configBytes, err := clientcmd.Write(*kubeconfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
err = apiclient.CreateOrUpdateSecret(data.RemoteClient(), &corev1.Secret{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Namespace: data.GetNamespace(),
|
|
Name: util.AdminKubeconfigSercretName(data.GetName()),
|
|
Labels: constants.KarmadaOperatorLabel,
|
|
},
|
|
Data: map[string][]byte{"config": configBytes},
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create secret of kubeconfig, err: %w", err)
|
|
}
|
|
|
|
// store rest config to RunData.
|
|
config, err := clientcmd.RESTConfigFromKubeConfig(configBytes)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
data.SetControlplaneConifg(config)
|
|
|
|
klog.V(2).InfoS("[UploadAdminKubeconfig] Successfully created secret of karmada apiserver kubeconfig", "karmada", klog.KObj(data))
|
|
return nil
|
|
}
|
|
|
|
func getNodePortFromAPIServerService(service *corev1.Service) int32 {
|
|
var nodePort int32
|
|
if service.Spec.Type == corev1.ServiceTypeNodePort {
|
|
for _, port := range service.Spec.Ports {
|
|
if port.Name != "client" {
|
|
continue
|
|
}
|
|
nodePort = port.NodePort
|
|
}
|
|
}
|
|
|
|
return nodePort
|
|
}
|
|
|
|
func buildKubeConfigFromSpec(data InitData, serverURL string) (*clientcmdapi.Config, error) {
|
|
ca := data.GetCert(constants.CaCertAndKeyName)
|
|
if ca == nil {
|
|
return nil, errors.New("unable build karmada admin kubeconfig, CA cert is empty")
|
|
}
|
|
|
|
cc := certs.KarmadaCertClient()
|
|
|
|
if err := mutateCertConfig(data, cc); err != nil {
|
|
return nil, fmt.Errorf("error when mutate cert altNames for %s, err: %w", cc.Name, err)
|
|
}
|
|
client, err := certs.CreateCertAndKeyFilesWithCA(cc, ca.CertData(), ca.KeyData())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to generate karmada apiserver client certificate for kubeconfig, err: %w", err)
|
|
}
|
|
|
|
return util.CreateWithCerts(
|
|
serverURL,
|
|
constants.ClusterName,
|
|
constants.UserName,
|
|
ca.CertData(),
|
|
client.KeyData(),
|
|
client.CertData(),
|
|
), nil
|
|
}
|
|
|
|
// NewUploadCertsTask init a Upload-Certs task
|
|
func NewUploadCertsTask() workflow.Task {
|
|
return workflow.Task{
|
|
Name: "Upload-Certs",
|
|
Run: runUploadCerts,
|
|
RunSubTasks: true,
|
|
Tasks: []workflow.Task{
|
|
{
|
|
Name: "Upload-KarmadaCert",
|
|
Run: runUploadKarmadaCert,
|
|
},
|
|
{
|
|
Name: "Upload-EtcdCert",
|
|
Run: runUploadEtcdCert,
|
|
},
|
|
{
|
|
Name: "Upload-WebHookCert",
|
|
Run: runUploadWebHookCert,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func runUploadCerts(r workflow.RunData) error {
|
|
data, ok := r.(InitData)
|
|
if !ok {
|
|
return errors.New("upload-certs task invoked with an invalid data struct")
|
|
}
|
|
klog.V(4).InfoS("[upload-certs] Running upload-certs task", "karmada", klog.KObj(data))
|
|
|
|
if len(data.CertList()) == 0 {
|
|
return errors.New("there is no certs in store, please reload crets to store")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func runUploadKarmadaCert(r workflow.RunData) error {
|
|
data, ok := r.(InitData)
|
|
if !ok {
|
|
return errors.New("upload-KarmadaCert task invoked with an invalid data struct")
|
|
}
|
|
|
|
certList := data.CertList()
|
|
certsData := make(map[string][]byte, len(certList))
|
|
for _, c := range certList {
|
|
certsData[c.KeyName()] = c.KeyData()
|
|
certsData[c.CertName()] = c.CertData()
|
|
}
|
|
|
|
err := apiclient.CreateOrUpdateSecret(data.RemoteClient(), &corev1.Secret{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: util.KarmadaCertSecretName(data.GetName()),
|
|
Namespace: data.GetNamespace(),
|
|
Labels: constants.KarmadaOperatorLabel,
|
|
},
|
|
Data: certsData,
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to upload karmada cert to secret, err: %w", err)
|
|
}
|
|
|
|
klog.V(2).InfoS("[upload-KarmadaCert] Successfully uploaded karmada certs to secret", "karmada", klog.KObj(data))
|
|
return nil
|
|
}
|
|
|
|
func runUploadEtcdCert(r workflow.RunData) error {
|
|
data, ok := r.(InitData)
|
|
if !ok {
|
|
return errors.New("upload-etcdCert task invoked with an invalid data struct")
|
|
}
|
|
|
|
ca := data.GetCert(constants.EtcdCaCertAndKeyName)
|
|
server := data.GetCert(constants.EtcdServerCertAndKeyName)
|
|
client := data.GetCert(constants.EtcdClientCertAndKeyName)
|
|
|
|
err := apiclient.CreateOrUpdateSecret(data.RemoteClient(), &corev1.Secret{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Namespace: data.GetNamespace(),
|
|
Name: util.EtcdCertSecretName(data.GetName()),
|
|
Labels: constants.KarmadaOperatorLabel,
|
|
},
|
|
|
|
Data: map[string][]byte{
|
|
ca.CertName(): ca.CertData(),
|
|
ca.KeyName(): ca.KeyData(),
|
|
server.CertName(): server.CertData(),
|
|
server.KeyName(): server.KeyData(),
|
|
client.CertName(): client.CertData(),
|
|
client.KeyName(): client.KeyData(),
|
|
},
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to upload etcd certs to secret, err: %w", err)
|
|
}
|
|
|
|
klog.V(2).InfoS("[upload-etcdCert] Successfully uploaded etcd certs to secret", "karmada", klog.KObj(data))
|
|
return nil
|
|
}
|
|
|
|
func runUploadWebHookCert(r workflow.RunData) error {
|
|
data, ok := r.(InitData)
|
|
if !ok {
|
|
return errors.New("upload-webhookCert task invoked with an invalid data struct")
|
|
}
|
|
|
|
cert := data.GetCert(constants.KarmadaCertAndKeyName)
|
|
err := apiclient.CreateOrUpdateSecret(data.RemoteClient(), &corev1.Secret{
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
Name: util.WebhookCertSecretName(data.GetName()),
|
|
Namespace: data.GetNamespace(),
|
|
Labels: constants.KarmadaOperatorLabel,
|
|
},
|
|
|
|
Data: map[string][]byte{
|
|
"tls.key": cert.KeyData(),
|
|
"tls.crt": cert.CertData(),
|
|
},
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("failed to upload webhook certs to secret, err: %w", err)
|
|
}
|
|
|
|
klog.V(2).InfoS("[upload-webhookCert] Successfully uploaded webhook certs to secret", "karmada", klog.KObj(data))
|
|
return nil
|
|
}
|