From 0ada80aa6d8da8e84ab4e6eb6bddbba250eda4d1 Mon Sep 17 00:00:00 2001 From: Bhavin Gandhi Date: Fri, 21 Jun 2024 18:18:17 +0530 Subject: [PATCH] [PLAT-14433] Use correct kubeconfig for edit provider validation Summary: During edit provider, kubeConfigContent is not present in the KubernetesInfo, so we defaulted to using in-cluster credentials instead of using the kubeconfig which provider has. With this change, we will check if kubeConfigContent is present, if not, check kubeConfig and use it. If both are not present we will default to using in-cluster credentials. Also, fixes an edge case where issuer is provided with non-existing namespace. Test Plan: - Removed in-cluster RBAC of YBA pod and then tried to edit an invalid provider. It used the kubeconfig from provider and validated all the parameters. - Tried adding a bogus kubeconfig, it failed as expected. - Also tried to create new provider, it is getting validated as expected. Reviewers: svarshney, rohita.payideti, #yba-api-review! Reviewed By: svarshney Subscribers: yugaware Differential Revision: https://phorge.dev.yugabyte.com/D36051 --- .../KubernetesProviderValidator.java | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/managed/src/main/java/com/yugabyte/yw/models/configs/validators/KubernetesProviderValidator.java b/managed/src/main/java/com/yugabyte/yw/models/configs/validators/KubernetesProviderValidator.java index 6b71fff54527..df874a350fb7 100644 --- a/managed/src/main/java/com/yugabyte/yw/models/configs/validators/KubernetesProviderValidator.java +++ b/managed/src/main/java/com/yugabyte/yw/models/configs/validators/KubernetesProviderValidator.java @@ -130,11 +130,15 @@ private Map> getCloudInfoPerAZ(JsonNode provider, config.putAll(zoneConfig); config.put("zoneCode", zoneCodeNode); - if (!config.containsKey("kubeConfigContent")) { + // New providers have kubeConfigContent and + // during edit we have kubeConfig if the + // kubeconfig is unchanged. + if (!config.containsKey("kubeConfigContent") + && !config.containsKey("kubeConfig")) { log.warn( "No kubeconfig found at any level, using in-cluster credentials"); config.put( - "kubeConfigContent", + "kubeConfig", // TODO: the jsonPath could be different // like $.in-cluster-credentials? Json.newObject().put("jsonPath", "$").put("value", "")); @@ -185,7 +189,7 @@ private void validateZoneLabels( try { regionToZone = KubernetesUtil.computeKubernetesRegionToZoneInfo( - ImmutableMap.of("KUBECONFIG", getStringValue(k8sInfo.get("kubeConfigContent"))), + ImmutableMap.of("KUBECONFIG", getStringValue(getKubeConfigNode(k8sInfo))), kubernetesManagerFactory); } catch (RuntimeException e) { if (e.getMessage().contains("Error from server (Forbidden): nodes")) { @@ -220,7 +224,7 @@ private void validateStorageClass( kubernetesManagerFactory .getManager() .getStorageClass( - ImmutableMap.of("KUBECONFIG", getStringValue(k8sInfo.get("kubeConfigContent"))), + ImmutableMap.of("KUBECONFIG", getStringValue(getKubeConfigNode(k8sInfo))), getStringValue(storageClassNode)); } catch (RuntimeException e) { if (e.getMessage().contains("Error from server (NotFound): storageclasses")) { @@ -259,13 +263,13 @@ private void validateNamespace( kubernetesManagerFactory .getManager() .dbNamespaceExists( - ImmutableMap.of("KUBECONFIG", getStringValue(k8sInfo.get("kubeConfigContent"))), + ImmutableMap.of("KUBECONFIG", getStringValue(getKubeConfigNode(k8sInfo))), getStringValue(namespaceNode)); } catch (RuntimeException e) { if (e.getMessage().contains("error: failed to create secret secrets is forbidden") || e.getMessage().contains("Error from server (Forbidden): secrets is forbidden")) { validationErrors.put( - getJsonPath(k8sInfo.get("kubeConfigContent")), + getJsonPath(getKubeConfigNode(k8sInfo)), "Missing permission to create secrets in " + getStringValue(namespaceNode)); return; } @@ -282,7 +286,7 @@ private void validateCertManagerIssuer( // given preference in KubernetesCommandExecutor. Map config = - ImmutableMap.of("KUBECONFIG", getStringValue(k8sInfo.get("kubeConfigContent"))); + ImmutableMap.of("KUBECONFIG", getStringValue(getKubeConfigNode(k8sInfo))); JsonNode clusterIssuerNode = k8sInfo.get("certManagerClusterIssuer"); if (clusterIssuerNode != null) { @@ -332,6 +336,9 @@ private void validateCertManagerIssuer( validationErrors.put( getJsonPath(issuerNode), "Cluster doesn't have Issuer resource type, ensure cert-manager is installed"); + } else if (e.getMessage().contains("Error from server (NotFound): namespaces")) { + validationErrors.put( + getJsonPath(namespaceNode), "Namespace doesn't exist in the cluster"); } else if (e.getMessage().contains("Error from server (Forbidden): issuers")) { log.warn("Unable to validate cert-manager Issuer: {}", e.getMessage()); } else { @@ -362,4 +369,10 @@ private String getStringValue(JsonNode node) { private String getJsonPath(JsonNode node) { return node.get("jsonPath").asText(); } + + private JsonNode getKubeConfigNode(Map k8sInfo) { + // A new or modified kubeconfig is preferred + // i.e. kubeConfigContent + return k8sInfo.getOrDefault("kubeConfigContent", k8sInfo.get("kubeConfig")); + } }