package cmii_operator import ( "bytes" "context" v1 "k8s.io/api/apps/v1" autoscalingv1 "k8s.io/api/autoscaling/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/scheme" restclient "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" "k8s.io/client-go/tools/remotecommand" "strings" "sync" "time" "wdd.io/agent-go/logger" "wdd.io/agent-go/utils" "wdd.io/cmii_operator/image" ) var log = logger.Log type CmiiK8sOperator struct { DevClient *kubernetes.Clientset CoreClient *kubernetes.Clientset CurrentNamespace string CurrentClient *kubernetes.Clientset DevConfig *restclient.Config CoreConfig *restclient.Config CurrentConfig *restclient.Config } const ( dev = "uavcloud-dev" devFlight = "uavcloud-devflight" devOperation = "uavcloud-devoperation" validation = "uavcloud-feature" integration = "uavcloud-test" uat = "uavcloud-uat" demo = "uavcloud-demo" uavms = "uavcloud-uavms" workerThread = 4 ) func (op *CmiiK8sOperator) checkAndBuildCmiiK8sOperator() { if op.DevClient == nil { log.InfoF("[client] - build devFlight k8s operator client !") devConfig, err := clientcmd.RESTConfigFromKubeConfig([]byte(CmiiDevK8sConfig)) if err != nil { msg := "[client] - build devFlight k8s operator error !" log.Error(msg) panic(msg) } op.DevConfig = devConfig op.DevClient, err = kubernetes.NewForConfig(devConfig) if err != nil { panic(err.Error()) } } if op.CoreClient == nil { log.InfoF("[client] - build core k8s operator client !") coreConfig, err := clientcmd.RESTConfigFromKubeConfig([]byte(CmiiCoreK8sConfig)) if err != nil { msg := "[client] - build devFlight k8s operator error !" log.Error(msg) panic(msg) } op.CoreConfig = coreConfig op.CoreClient, err = kubernetes.NewForConfig(coreConfig) if err != nil { panic(err.Error()) } } } func (op *CmiiK8sOperator) changeOperatorEnv(cmiiEnv string) { // ok op.checkAndBuildCmiiK8sOperator() // first key op.CurrentNamespace = "" if strings.Contains(cmiiEnv, "dev") { if strings.Contains(cmiiEnv, "devf") { op.CurrentNamespace = devFlight } else if strings.Contains(cmiiEnv, "devo") { op.CurrentNamespace = devOperation } else { op.CurrentNamespace = dev } } if strings.Contains(cmiiEnv, "int") || strings.Contains(cmiiEnv, "test") { op.CurrentNamespace = integration } if strings.Contains(cmiiEnv, "fe") || strings.Contains(cmiiEnv, "val") { op.CurrentNamespace = validation } if strings.Contains(cmiiEnv, "uat") { op.CurrentNamespace = uat } if strings.Contains(cmiiEnv, "demo") { op.CurrentNamespace = demo } if strings.Contains(cmiiEnv, "uavms") { op.CurrentNamespace = uavms } // key feature if op.CurrentNamespace == "" { op.CurrentNamespace = cmiiEnv } else { if strings.Contains(cmiiEnv, "dev") { op.CurrentClient = op.DevClient op.CurrentConfig = op.DevConfig } else { op.CurrentClient = op.CoreClient op.CurrentConfig = op.CoreConfig } } log.InfoF("[k8s env] - current env is => %s", op.CurrentNamespace) } func (op *CmiiK8sOperator) BuildCurrentClientFromConfig(realClientConfig string) { log.InfoF("[BuildCurrentClientFromConfig] - build real k8s operator client !") realEnvConfig, err := clientcmd.RESTConfigFromKubeConfig([]byte(realClientConfig)) if err != nil { msg := "[BuildCurrentClientFromConfig] - build real k8s operator error !" log.Error(msg) panic(msg) } op.CurrentConfig = realEnvConfig op.CurrentClient, err = kubernetes.NewForConfig(realEnvConfig) if err != nil { panic(err.Error()) } } func (op *CmiiK8sOperator) DeploymentAll(cmiiEnv string) []v1.Deployment { op.changeOperatorEnv(cmiiEnv) client := op.CurrentClient deploymentList, err := client.AppsV1().Deployments(op.CurrentNamespace).List(context.TODO(), metav1.ListOptions{}) if err != nil { log.ErrorF("[DeploymentAll] - list deployment in [%s] [%s] error => %s", cmiiEnv, op.CurrentNamespace, err.Error()) } deployments := deploymentList.Items length := len(deployments) log.InfoF("[DeploymentAll] - deployment in [%s] count is => %d", op.CurrentNamespace, length) results := make([]v1.Deployment, length) ccc := make(chan v1.Deployment, length) var wg sync.WaitGroup //var mutex sync.Mutex worker := workerThread if length <= worker { for i, deployment := range deployments { objectMeta := deployment.ObjectMeta objectMeta.SetAnnotations(nil) objectMeta.SetManagedFields(nil) deployment.ObjectMeta = objectMeta results[i] = deployment } return results } pinch := (length + worker - 1) / worker wg.Add(worker) for splice := 0; splice < worker; splice++ { // 计算每个goroutine处理的切片段 start := splice * pinch end := start + pinch if end > length { end = length } //log.DebugF("[DeploymentAll] - deployment pinch from [%d - %d]", start, end) go func(deploymentList []v1.Deployment, start int, results *[]v1.Deployment) { for _, deployment := range deploymentList { objectMeta := deployment.ObjectMeta objectMeta.SetAnnotations(nil) objectMeta.SetManagedFields(nil) deployment.ObjectMeta = objectMeta ccc <- deployment //i := *results //i[index+start] = deployment } wg.Done() }(deployments[start:end], start, &results) } go func() { wg.Wait() close(ccc) }() wg.Wait() index := 0 for deployment := range ccc { results[index] = deployment index++ } return results[:index] } func (op *CmiiK8sOperator) DeploymentAllInterface(cmiiEnv string) []CmiiDeploymentInterface { op.changeOperatorEnv(cmiiEnv) client := op.CurrentClient deploymentList, err := client.AppsV1().Deployments(op.CurrentNamespace).List(context.TODO(), metav1.ListOptions{}) if err != nil { log.ErrorF("[DeploymentAllInterface] - list deployment in [%s] [%s] error => %s", cmiiEnv, op.CurrentNamespace, err.Error()) } deployments := deploymentList.Items length := len(deployments) results := make([]CmiiDeploymentInterface, length) ccc := make(chan CmiiDeploymentInterface, length) var wg sync.WaitGroup worker := workerThread if length <= worker { for i, deployment := range deployments { objectMeta := deployment.ObjectMeta objectMeta.SetAnnotations(nil) objectMeta.SetManagedFields(nil) deployment.ObjectMeta = objectMeta results[i] = CmiiDeploymentInterface{}.Convert(deployment) } return results } pinch := length / worker wg.Add(worker) for splice := 0; splice < worker; splice++ { go func(deploymentList []v1.Deployment) { defer wg.Done() for _, deployment := range deploymentList { objectMeta := deployment.ObjectMeta objectMeta.SetAnnotations(nil) objectMeta.SetManagedFields(nil) deployment.ObjectMeta = objectMeta ccc <- CmiiDeploymentInterface{}.Convert(deployment) } }(deployments[splice*pinch : utils.MinInt((splice+1)*pinch, length)]) } go func() { wg.Wait() close(ccc) }() index := 0 for deployment := range ccc { results[index] = deployment index++ } return results[:index] } func (op *CmiiK8sOperator) DeploymentFizz(cmiiEnv, appFizz string) (fizzDeployment []v1.Deployment) { deploymentAll := op.DeploymentAll(cmiiEnv) if deploymentAll == nil { log.ErrorF("[DeploymentFizz] - namespace [%s] can not get deployment [%s]", cmiiEnv, appFizz) return nil } for _, deployment := range deploymentAll { if strings.Contains(deployment.Name, appFizz) { fizzDeployment = append(fizzDeployment, deployment) } } return fizzDeployment } func (op *CmiiK8sOperator) DeploymentExist(cmiiEnv, appName string) (exists *v1.Deployment) { op.changeOperatorEnv(cmiiEnv) client := op.CurrentClient deployment, err := client.AppsV1().Deployments(op.CurrentNamespace).Get(context.TODO(), appName, metav1.GetOptions{}) if err != nil { log.ErrorF("[DeploymentExist] - deployments [%s] [%s] not exists ! %s", cmiiEnv, appName, err.Error()) return nil } return deployment } func (op *CmiiK8sOperator) DeploymentOneInterface(cmiiEnv, appName string) (deploy *CmiiDeploymentInterface) { op.changeOperatorEnv(cmiiEnv) client := op.CurrentClient deploymentInterface := CmiiDeploymentInterface{} deployment, err := client.AppsV1().Deployments(op.CurrentNamespace).Get(context.TODO(), appName, metav1.GetOptions{}) if err != nil { log.ErrorF("[DeploymentExist] - deployments [%s] [%s] not exists ! %s", cmiiEnv, appName, err.Error()) return nil } convert := deploymentInterface.Convert(*deployment) return &convert } func (op *CmiiK8sOperator) StatefulSetOneInterface(cmiiEnv, appName string) (deploy *CmiiDeploymentInterface) { op.changeOperatorEnv(cmiiEnv) client := op.CurrentClient deploymentInterface := CmiiDeploymentInterface{} statefulSet, err := client.AppsV1().StatefulSets(op.CurrentNamespace).Get(context.TODO(), appName, metav1.GetOptions{}) if err != nil { log.ErrorF("[StatefulSetOneInterface] - stateful set [%s] [%s] not exists ! %s", cmiiEnv, appName, err.Error()) return nil } convert := deploymentInterface.ConvertFromStatefulSet(*statefulSet) return &convert } func (op *CmiiK8sOperator) DeploymentScale(cmiiEnv, appName string, scaleCount int32) bool { deployment := op.DeploymentOneInterface(cmiiEnv, appName) client := op.CurrentClient log.DebugF("[DeploymentScale] - start to scale [%s] [%s] to %d", deployment.Namespace, deployment.Name, scaleCount) scale := &autoscalingv1.Scale{ ObjectMeta: metav1.ObjectMeta{ Name: deployment.Name, Namespace: deployment.Namespace, }, Spec: autoscalingv1.ScaleSpec{ Replicas: scaleCount, }, } updateScale, err := client.AppsV1().Deployments(deployment.Namespace).UpdateScale( context.TODO(), deployment.Name, scale, metav1.UpdateOptions{}, ) if err != nil { log.ErrorF("[DeploymentScale] - scale error %s", err.Error()) return false } log.InfoF("[DeploymentScale] - scale of [%s] [%s] to %d success !", updateScale.Namespace, updateScale.Name, scaleCount) return true } func (op *CmiiK8sOperator) DeploymentUpdateTag(cmiiEnv, appName, newTag string) bool { if newTag == "" { log.WarnF("[DeploymentUpdateTag] - can not update image tag to null!") return false } deployment := op.DeploymentExist(cmiiEnv, appName) if deployment == nil { return false } containers := deployment.Spec.Template.Spec.Containers if len(containers) == 1 { // only update this kind container := containers[0] oldName := container.Image split := strings.Split(container.Image, ":") if strings.HasPrefix(container.Image, image.CmiiHarborPrefix) { // harbor container.Image = split[0] + ":" + newTag } else if strings.Contains(container.Image, "8033") { // 192.168.6.6:8033/rancher/k8s-dns-sidecar:v1.0.2 container.Image = split[0] + ":" + split[1] + ":" + newTag } log.DebugF("[DeploymentUpdateTag] - update [%s] [%s] from [%s] to [%s]", op.CurrentNamespace, appName, oldName, container.Image) // re assign deployment.Spec.Template.Spec.Containers[0] = container // update _, err := op.CurrentClient.AppsV1().Deployments(deployment.Namespace).Update(context.TODO(), deployment, metav1.UpdateOptions{}) if err != nil { log.ErrorF("[DeploymentUpdateTag] - update [%s] [%s] from [%s] to [%s] error ! %s", op.CurrentNamespace, appName, split[1], container.Image, err.Error()) return false } } else if len(containers) == 2 { log.ErrorF("[DeploymentUpdateTag] - cant update app with 2 containers !") return false } return true } func (op *CmiiK8sOperator) DeploymentRestart(cmiiEnv, appName string) bool { op.changeOperatorEnv(cmiiEnv) result := true deployment := op.DeploymentOneInterface(cmiiEnv, appName) if deployment == nil { log.ErrorF("[DeploymentRestart] - [%s] [%s] not exists !", cmiiEnv, appName) return false } result = op.DeploymentScale(deployment.Namespace, deployment.Name, 0) if !result { return result } time.Sleep(time.Millisecond * 200) result = op.DeploymentScale(deployment.Namespace, deployment.Name, deployment.Replicas) if !result { return result } return result } func (op *CmiiK8sOperator) DeploymentRestartByKill(cmiiEnv, appName string) bool { deployment := op.DeploymentOneInterface(cmiiEnv, appName) if deployment == nil { log.ErrorF("[DeploymentRestart] - [%s] [%s] not exists !", cmiiEnv, appName) return false } podList := op.PodByAppName(deployment.Namespace, deployment.Name) if podList == nil { log.ErrorF("[DeploymentRestart] - [%s] [%s] no pod success !", deployment.Namespace, deployment.Name) return true } for _, podInterface := range podList { if !op.PodDelete(cmiiEnv, podInterface.Name) { log.ErrorF("[DeploymentRestart] - [%s] [%s] delete pod failed !", podInterface.Namespace, podInterface.Name) } else { log.DebugF("[DeploymentRestart] - [%s] [%s] delete pod success !", podInterface.Namespace, podInterface.Name) } } return true } func (op *CmiiK8sOperator) DeploymentNew(cmiiEnv, appName string, waitTimeOut int) bool { op.changeOperatorEnv(cmiiEnv) //op.CurrentClient.AppsV1().Deployments(op.CurrentNamespace).Apply() return true } func (op *CmiiK8sOperator) DeploymentStatusCheck(cmiiEnv, appName string, waitTimeOut int) bool { op.changeOperatorEnv(cmiiEnv) // 设置超时时间和时间间隔 timeout := time.After(time.Duration(waitTimeOut) * time.Second) tick := time.Tick(time.Second) // 监控Pod状态 for { select { case <-timeout: log.ErrorF("[DeploymentStatusCheck] - [%s] [%s] 状态: 失败!", cmiiEnv, appName) return false case <-tick: // check deployment exists deployment := op.DeploymentOneInterface(cmiiEnv, appName) if deployment == nil { log.ErrorF("[DeploymentStatusCheck] - [%s] [%s] not exists !", cmiiEnv, appName) return false } if deployment.AvailableReplicas == deployment.Replicas { log.InfoF("[DeploymentStatusCheck] - [%s] [%s] Available: %d, Total: %d success !", deployment.Namespace, deployment.Name, deployment.AvailableReplicas, deployment.Replicas) return true } log.DebugF("[DeploymentStatusCheck] - [%s] [%s] Available: %d, Total: %d waiting !", deployment.Namespace, deployment.Name, deployment.AvailableReplicas, deployment.Replicas) } } } func (op *CmiiK8sOperator) ReplicaSetExists(cmiiEnv, replicaSetName string) *v1.ReplicaSet { op.changeOperatorEnv(cmiiEnv) client := op.CurrentClient replicaSet, err := client.AppsV1().ReplicaSets(op.CurrentNamespace).Get(context.TODO(), replicaSetName, metav1.GetOptions{}) if err != nil { log.ErrorF("[ReplicaSetExists] - [%s] [%s] not exists !", cmiiEnv, replicaSetName) return nil } return replicaSet } func (op *CmiiK8sOperator) ReplicaSetByAppName(cmiiEnv, appName string) (replicaList []v1.ReplicaSet) { deploy := op.DeploymentExist(cmiiEnv, appName) if deploy == nil { log.ErrorF("[ReplicaSetByAppName] - [%s] [%s] app not exists !", cmiiEnv, appName) return nil } labelSelector := metav1.FormatLabelSelector(deploy.Spec.Selector) //Get the replica sets that belong to the deployment. replicaSets, err := op.CurrentClient.AppsV1().ReplicaSets(op.CurrentNamespace).List(context.TODO(), metav1.ListOptions{ LabelSelector: labelSelector, }) if err != nil { log.ErrorF("[ReplicaSetByAppName] - [%s] [%s] list replicaset error %s", cmiiEnv, appName, err.Error()) return nil } for _, replicaSet := range replicaSets.Items { replicaSet.SetManagedFields(nil) replicaList = append(replicaList, replicaSet) } return replicaList } func (op *CmiiK8sOperator) PodAll(cmiiEnv string) []corev1.Pod { op.changeOperatorEnv(cmiiEnv) client := op.CurrentClient podList, err := client.CoreV1().Pods(op.CurrentNamespace).List(context.TODO(), metav1.ListOptions{}) if err != nil { log.ErrorF("[PodAll] - list c in [%s] [%s] error => %s", cmiiEnv, op.CurrentNamespace, err.Error()) return nil } pods := podList.Items length := len(pods) results := make([]corev1.Pod, length) ccc := make(chan corev1.Pod, length) var wg sync.WaitGroup worker := workerThread if length <= worker { for i, pod := range pods { objectMeta := pod.ObjectMeta objectMeta.SetAnnotations(nil) objectMeta.SetManagedFields(nil) pod.ObjectMeta = objectMeta results[i] = pod } return results } pinch := length / worker wg.Add(worker) for splice := 0; splice < worker; splice++ { go func(podList []corev1.Pod) { defer wg.Done() for _, pod := range podList { objectMeta := pod.ObjectMeta objectMeta.SetAnnotations(nil) objectMeta.SetManagedFields(nil) pod.ObjectMeta = objectMeta ccc <- pod } }(pods[splice*pinch : utils.MinInt((splice+1)*pinch, length)]) } go func() { wg.Wait() close(ccc) }() index := 0 for c := range ccc { results[index] = c index++ } return results[:index] } func (op *CmiiK8sOperator) PodAllInterface(cmiiEnv string) []CmiiPodInterface { op.changeOperatorEnv(cmiiEnv) client := op.CurrentClient podList, err := client.CoreV1().Pods(op.CurrentNamespace).List(context.TODO(), metav1.ListOptions{}) if err != nil { log.ErrorF("[PodAll] - list c in [%s] [%s] error => %s", cmiiEnv, op.CurrentNamespace, err.Error()) return nil } pods := podList.Items length := len(pods) results := make([]CmiiPodInterface, length) ccc := make(chan CmiiPodInterface, length) var wg sync.WaitGroup podInterface := CmiiPodInterface{} worker := workerThread if length <= worker { for i, pod := range pods { objectMeta := pod.ObjectMeta objectMeta.SetAnnotations(nil) objectMeta.SetManagedFields(nil) pod.ObjectMeta = objectMeta results[i] = podInterface.Convert(pod) } return results } pinch := length / worker wg.Add(worker) for splice := 0; splice < worker; splice++ { go func(podList []corev1.Pod) { defer wg.Done() for _, pod := range podList { objectMeta := pod.ObjectMeta objectMeta.SetAnnotations(nil) objectMeta.SetManagedFields(nil) pod.ObjectMeta = objectMeta ccc <- podInterface.Convert(pod) } }(pods[splice*pinch : utils.MinInt((splice+1)*pinch, length)]) } go func() { wg.Wait() close(ccc) }() index := 0 for c := range ccc { results[index] = c index++ } return results[:index] } func (op *CmiiK8sOperator) PodByAppName(cmiiEnv, appName string) (podList []CmiiPodInterface) { deploy := op.DeploymentExist(cmiiEnv, appName) if deploy == nil { log.ErrorF("[PodByAppName] - [%s] [%s] app not exists !", cmiiEnv, appName) return nil } labelSelector := metav1.FormatLabelSelector(deploy.Spec.Selector) //Get the replica sets that belong to the deployment. pods, err := op.CurrentClient.CoreV1().Pods(op.CurrentNamespace).List(context.TODO(), metav1.ListOptions{ LabelSelector: labelSelector, }) if err != nil { log.ErrorF("[PodByAppName] - [%s] [%s] list pods error %s", cmiiEnv, appName, err.Error()) return nil } cmiiPodInterface := CmiiPodInterface{} for _, pod := range pods.Items { pod.SetManagedFields(nil) podInterface := cmiiPodInterface.Convert(pod) podList = append(podList, podInterface) } return podList } func (op *CmiiK8sOperator) PodByNodeName(cmiiEnv, nodeName string) (podList []CmiiPodInterface) { node := op.NodeExists(cmiiEnv, nodeName) if node == nil { return nil } list, err := op.CurrentClient.CoreV1().Pods("").List(context.TODO(), metav1.ListOptions{ FieldSelector: "spec.nodeName=" + nodeName, }) if err != nil { log.ErrorF("[PodByNodeName] - [%s] [%s] list pod error %s !", cmiiEnv, nodeName, err.Error()) return nil } podInterface := CmiiPodInterface{} for _, pod := range list.Items { cmiiPodInterface := podInterface.Convert(pod) podList = append(podList, cmiiPodInterface) } return podList } func (op *CmiiK8sOperator) PodFizz(cmiiEnv, appFizz string) (fizzPod []corev1.Pod) { podAll := op.PodAll(cmiiEnv) if podAll == nil { log.ErrorF("[DeploymentFizz] - no app find in [%s] !", cmiiEnv) return nil } for _, pod := range podAll { if strings.Contains(pod.Name, appFizz) { fizzPod = append(fizzPod, pod) } } return fizzPod } func (op *CmiiK8sOperator) PodDelete(cmiiEnv, podName string) bool { op.changeOperatorEnv(cmiiEnv) client := op.CurrentClient pod, err := client.CoreV1().Pods(op.CurrentNamespace).Get(context.TODO(), podName, metav1.GetOptions{}) if err != nil { log.ErrorF("[PodDelete] - [%s] [%s] not exists", cmiiEnv, podName) return false } // pod exists err = client.CoreV1().Pods(op.CurrentNamespace).Delete(context.TODO(), pod.Name, metav1.DeleteOptions{}) if err != nil { log.ErrorF("[PodDelete] - [%s] [%s] delete error ! %s", cmiiEnv, podName, err.Error()) return false } return true } func (op *CmiiK8sOperator) PodExec(cmiiEnv string, podInterface CmiiPodInterface, commandList []string) (stdout, stderr *bytes.Buffer) { op.changeOperatorEnv(cmiiEnv) client := op.CurrentClient execRequest := client.CoreV1().RESTClient(). Post(). Resource("pods"). Name(podInterface.Name). Namespace(op.CurrentNamespace). SubResource("exec"). VersionedParams(&corev1.PodExecOptions{ Stdin: false, Stdout: true, Stderr: true, TTY: false, Container: podInterface.ContainerName, Command: commandList, }, scheme.ParameterCodec) stdout = &bytes.Buffer{} stderr = &bytes.Buffer{} //log.DebugF("PodExec] - [%s] [%s] exec %s, url %s", cmiiEnv, podInterface.Name, commandList, execRequest.URL()) exec, err := remotecommand.NewSPDYExecutor(op.CurrentConfig, "POST", execRequest.URL()) if err != nil { log.ErrorF("[PodExec] - NewSPDYExecutor error => %s", err.Error()) return stdout, stderr } err = exec.Stream(remotecommand.StreamOptions{ Stdin: nil, Stdout: stdout, Stderr: stderr, Tty: false, TerminalSizeQueue: nil, }) if err != nil { log.ErrorF("[PodExec] - exec.Stream error => %s", err.Error()) } return stdout, stderr } func (op *CmiiK8sOperator) NodeAll(cmiiEnv string) (nodeListR []corev1.Node) { op.changeOperatorEnv(cmiiEnv) client := op.CurrentClient nodeList, err := client.CoreV1().Nodes().List(context.TODO(), metav1.ListOptions{}) if err != nil { log.ErrorF("[NodeAll] - [%s] list all node failed %s", cmiiEnv, err.Error()) return nil } for _, node := range nodeList.Items { node.SetManagedFields(nil) nodeListR = append(nodeListR, node) } return nodeListR } func (op *CmiiK8sOperator) NodeAllInterface(cmiiEnv string) (nodeList []CmiiNodeInterface) { nodeListR := op.NodeAll(cmiiEnv) nodeInterface := CmiiNodeInterface{} for _, node := range nodeListR { nodeList = append(nodeList, nodeInterface.Convert(node)) } return nodeList } func (op *CmiiK8sOperator) NodeExists(cmiiEnv, nodeName string) (node *CmiiNodeInterface) { op.changeOperatorEnv(cmiiEnv) client := op.CurrentClient nodeInterface := CmiiNodeInterface{} nodeList, err := client.CoreV1().Nodes().Get(context.TODO(), nodeName, metav1.GetOptions{}) if err != nil { log.ErrorF("[NodeExists] - [%s] [%s] not exists !", cmiiEnv, nodeName) return nil } convert := nodeInterface.Convert(*nodeList) return &convert }