package services import ( "context" b64 "encoding/base64" "errors" "fmt" clusterApi "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/clients/generated/apis/container/v1beta1" iamv1beta1 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/clients/generated/apis/iam/v1beta1" resourceApi "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/clients/generated/apis/resourcemanager/v1beta1" helmApi "github.com/fluxcd/helm-controller/api/v2" helmRepositoryApi "github.com/fluxcd/source-controller/api/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd/api" "sigs.k8s.io/controller-runtime/pkg/client" "edge-infra.dev/pkg/edge/api/types" "edge-infra.dev/pkg/edge/api/utils" bannerAPI "edge-infra.dev/pkg/edge/apis/banner/v1alpha1" edgeCluster "edge-infra.dev/pkg/edge/apis/cluster/v1alpha1" gkeClusterApi "edge-infra.dev/pkg/edge/apis/gkecluster/v1alpha1" ) func init() { utilruntime.Must(edgeCluster.AddToScheme(scheme.Scheme)) utilruntime.Must(resourceApi.AddToScheme(scheme.Scheme)) utilruntime.Must(helmApi.AddToScheme(scheme.Scheme)) utilruntime.Must(helmRepositoryApi.AddToScheme(scheme.Scheme)) utilruntime.Must(clusterApi.AddToScheme(scheme.Scheme)) utilruntime.Must(apiextensionsv1.AddToScheme(scheme.Scheme)) utilruntime.Must(bannerAPI.AddToScheme(scheme.Scheme)) utilruntime.Must(clusterApi.AddToScheme(scheme.Scheme)) utilruntime.Must(gkeClusterApi.AddToScheme(scheme.Scheme)) utilruntime.Must(iamv1beta1.AddToScheme(scheme.Scheme)) } //go:generate mockgen -destination=../mocks/mock_gke_client.go -package=mocks edge-infra.dev/pkg/edge/api/services GkeClient type GkeClient interface { GetConfigForCluster(ctx context.Context, cluster *types.GkeCluster) (*rest.Config, error) GetRuntimeClient(ctx context.Context, cluster *types.GkeCluster) (client.WithWatch, error) } type gkeClient struct { // configs KubeConfig *rest.Config // clients RuntimeClient client.WithWatch // caches RuntimeClientMap map[string]client.WithWatch } func (gke *gkeClient) GetClientName(cluster *types.GkeCluster) string { return fmt.Sprintf("%s-%s", cluster.Banner, cluster.Name) } func (gke *gkeClient) GetConfigForCluster(ctx context.Context, cluster *types.GkeCluster) (*rest.Config, error) { singleResp := &clusterApi.ContainerCluster{} key := client.ObjectKey{Namespace: cluster.Banner, Name: cluster.Name} if err := gke.RuntimeClient.Get(ctx, key, singleResp); err != nil { return nil, err } return getConfigForCluster(singleResp) } func getConfigForCluster(singleResp *clusterApi.ContainerCluster) (*rest.Config, error) { if singleResp.Spec.MasterAuth == nil || singleResp.Spec.MasterAuth.ClusterCaCertificate == nil { return nil, errors.New("ClusterCaCertificate not ready on kcc container cluster") } if singleResp.Status.Endpoint == nil { return nil, errors.New("host not ready on kcc container cluster") } sDec, err := b64.StdEncoding.DecodeString(*singleResp.Spec.MasterAuth.ClusterCaCertificate) if err != nil { return nil, err } config := &rest.Config{ TLSClientConfig: rest.TLSClientConfig{ CAData: sDec, }, Host: *singleResp.Status.Endpoint, AuthProvider: &api.AuthProviderConfig{ Name: "gcp", }, } return config, nil } func (gke *gkeClient) GetRuntimeClient(ctx context.Context, cluster *types.GkeCluster) (client.WithWatch, error) { if cluster == nil { return gke.RuntimeClient, nil } name := gke.GetClientName(cluster) if client, ok := gke.RuntimeClientMap[name]; ok { return client, nil } cfg, err := gke.GetConfigForCluster(ctx, cluster) if err != nil { return nil, err } runtimeClient, err := client.NewWithWatch(cfg, client.Options{Scheme: scheme.Scheme}) if err != nil { return nil, err } gke.RuntimeClientMap[name] = runtimeClient return runtimeClient, nil } func NewGkeClient(masterconfig string) (*gkeClient, error) { //nolint stupid var err error var config *rest.Config var runtimeClient client.WithWatch if masterconfig != "" { if config, err = utils.GetKubeConfig(masterconfig); err != nil { return nil, err } if runtimeClient, err = client.NewWithWatch(config, client.Options{Scheme: scheme.Scheme}); err != nil { return nil, err } } return &gkeClient{ KubeConfig: config, RuntimeClient: runtimeClient, RuntimeClientMap: map[string]client.WithWatch{}, }, nil }