* Copyright (c) 2024 Huawei Technologies Co., Ltd.
* openFuyao is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package utils
import (
"context"
"encoding/json"
"github.com/karmada-io/karmada/pkg/generated/clientset/versioned"
"github.com/karmada-io/karmada/pkg/karmadactl/util/apiclient"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/clientcmd/api"
"sigs.k8s.io/controller-runtime/pkg/client"
"openfuyao.com/multi-cluster-service/api/v1beta1"
"openfuyao.com/multi-cluster-service/pkg/zlog"
)
func CreateHostClient() (*kubernetes.Clientset, *api.Config, error) {
config, err := rest.InClusterConfig()
if err != nil {
zlog.LogErrorf("Error Creating Hostcluster restconfig: %v", err)
return nil, nil, err
}
apiConfig := api.NewConfig()
err = restConfig2ApiConfig(config, apiConfig)
if err != nil {
zlog.LogErrorf("Error transferring restconfig to apiconfig: %v", err)
return nil, nil, err
}
clusterClient, err := kubernetes.NewForConfig(config)
if err != nil {
zlog.LogErrorf("Error creating cluster client: %v", err)
return nil, nil, err
}
zlog.LogInfof("Join Hostcluster config. endpoint: %s", config.Host)
return clusterClient, apiConfig, nil
}
func CreateClusterClient(config *api.Config) (*kubernetes.Clientset, error) {
clientConfig := clientcmd.NewNonInteractiveClientConfig(*config, config.CurrentContext,
&clientcmd.ConfigOverrides{}, nil)
restConfig, err := clientConfig.ClientConfig()
if err != nil {
zlog.LogErrorf("Error creating cluster config: %v", err)
return nil, err
}
clusterClient, err := kubernetes.NewForConfig(restConfig)
if err != nil {
zlog.LogErrorf("Error creating cluster client: %v", err)
return nil, err
}
zlog.LogInfof("Join cluster config. endpoint: %s", restConfig.Host)
return clusterClient, nil
}
func CreateClient(path string) (*kubernetes.Clientset, *api.Config, error) {
clientConfig, err := clientcmd.LoadFromFile(path)
if err != nil {
zlog.LogErrorf("Error Creating kubernetes Config : %v", err)
return nil, nil, err
}
config, err := clientcmd.NewNonInteractiveClientConfig(*clientConfig, "",
&clientcmd.ConfigOverrides{}, nil).ClientConfig()
clusterClient, err := kubernetes.NewForConfig(config)
if err != nil {
zlog.LogErrorf("Error creating client from path: %v", err)
return nil, nil, err
}
zlog.LogInfof("Get cluster endpoint: %s", config.Host)
return clusterClient, clientConfig, nil
}
func CreateKarmadaClusterClient() (*kubernetes.Clientset, *versioned.Clientset, error) {
path := KarmadaConfigPath
restConfig, err := apiclient.RestConfig("", path)
if err != nil {
zlog.LogErrorf("Error creating karmada cluster config: %v", err)
return nil, nil, err
}
kClient, err := kubernetes.NewForConfig(restConfig)
if err != nil {
zlog.LogErrorf("Error creating karmada kubernetes client: %v", err)
return nil, nil, err
}
kVersionedClient, err := versioned.NewForConfig(restConfig)
if err != nil {
zlog.LogErrorf("Error creating karmada server client: %v", err)
return nil, nil, err
}
return kClient, kVersionedClient, nil
}
func RetriveKubeconfigClient(mgrClient client.Client, clusterTag string) (*kubernetes.Clientset, error) {
if clusterTag == "host" {
kClient, _, err := CreateHostClient()
if err != nil {
zlog.LogErrorf("Error Creating host cluster client: %v", err)
return nil, err
}
return kClient, nil
}
clusterObj := v1beta1.Cluster{}
if err := mgrClient.Get(context.TODO(), client.ObjectKey{Name: clusterTag}, &clusterObj); err != nil {
zlog.LogErrorf("Error Retrieving cluster object: %v", err)
return nil, err
}
kubeData := clusterObj.Spec.KubeConfig.Raw
var kubeconfig api.Config
err := json.Unmarshal(kubeData, &kubeconfig)
if err != nil {
zlog.LogErrorf("Errorf kubeconfig data unmarshal failed.")
return nil, err
}
kClient, err := CreateClusterClient(&kubeconfig)
if err != nil {
zlog.LogErrorf("Error Creating cluster client from json: %v", err)
return nil, err
}
zlog.LogInfof("Creating cluster success!")
return kClient, nil
}
func restConfig2ApiConfig(restCfg *rest.Config, apiCfg *api.Config) error {
cluster := api.NewCluster()
cluster.Server = restCfg.Host
cluster.CertificateAuthority = restCfg.CAFile
cluster.CertificateAuthorityData = restCfg.CAData
context := api.NewContext()
context.Cluster = "kubernetes"
context.AuthInfo = "kubernetes-admin"
authInfo := api.NewAuthInfo()
authInfo.Token = restCfg.BearerToken
authInfo.ClientCertificateData = restCfg.CertData
authInfo.ClientCertificate = restCfg.CAFile
authInfo.ClientKey = restCfg.KeyFile
authInfo.ClientKeyData = restCfg.KeyData
apiCfg.Clusters["kubernetes"] = cluster
apiCfg.Contexts["kubernetes-admin@kubernetes"] = context
apiCfg.AuthInfos["kubernetes-admin"] = authInfo
apiCfg.CurrentContext = "kubernetes-admin@kubernetes"
return nil
}
func LoadKubeconfigRawData(kubeconfigData json.RawMessage, apiKubeconfig *api.Config) error {
var rawConfig struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Clusters []struct {
Name string `json:"name"`
Cluster api.Cluster `json:"cluster"`
} `json:"clusters"`
Contexts []struct {
Name string `json:"name"`
Context api.Context `json:"context"`
} `json:"contexts"`
CurrentContext string `json:"current-context"`
Preferences api.Preferences `json:"preferences"`
Users []struct {
Name string `json:"name"`
User api.AuthInfo `json:"user"`
} `json:"users"`
}
err := json.Unmarshal(kubeconfigData, &rawConfig)
if err != nil {
zlog.LogErrorf("Error Unmarshal cluster kubeconfig: %v", err)
return err
}
apiKubeconfig.APIVersion = rawConfig.APIVersion
apiKubeconfig.Kind = rawConfig.Kind
apiKubeconfig.CurrentContext = rawConfig.CurrentContext
apiKubeconfig.Preferences = rawConfig.Preferences
apiKubeconfig.Clusters = make(map[string]*api.Cluster)
apiKubeconfig.Contexts = make(map[string]*api.Context)
apiKubeconfig.AuthInfos = make(map[string]*api.AuthInfo)
for _, cluster := range rawConfig.Clusters {
apiKubeconfig.Clusters[cluster.Name] = &cluster.Cluster
}
for _, cluster := range rawConfig.Users {
apiKubeconfig.AuthInfos[cluster.Name] = &cluster.User
}
for _, cluster := range rawConfig.Contexts {
apiKubeconfig.Contexts[cluster.Name] = &cluster.Context
}
return nil
}