From dfe68b89df053ec17dd49100c8717544ba2e74fc Mon Sep 17 00:00:00 2001
From: tithakka <tithakka@redhat.com>
Date: Mon, 28 Aug 2023 16:49:53 -0700
Subject: [PATCH] Dynamically fetched capabilities from AMS instead of hard
 coded list

---
 .../capabilities/account_capability/cmd.go    |   8 +-
 .../organization_capability/cmd.go            |   8 +-
 .../subscription_capability/cmd.go            |   8 +-
 .../capabilities/account_capability/cmd.go    |   8 +-
 .../organization_capability/cmd.go            |   8 +-
 .../subscription_capability/cmd.go            |   8 +-
 pkg/capability/capability.go                  | 105 +++++-------------
 7 files changed, 41 insertions(+), 112 deletions(-)

diff --git a/cmd/ocm-support/create/capabilities/account_capability/cmd.go b/cmd/ocm-support/create/capabilities/account_capability/cmd.go
index 054654e..e7d6422 100644
--- a/cmd/ocm-support/create/capabilities/account_capability/cmd.go
+++ b/cmd/ocm-support/create/capabilities/account_capability/cmd.go
@@ -34,7 +34,7 @@ var CmdCreateAccountCapability = &cobra.Command{
 		}
 		//validates the capability
 		capabilityKey := args[1]
-		err = capability.ValidateCapability(capabilityKey, "account")
+		err = capability.ValidateCapability(capabilityKey, "account", connection)
 		if err != nil {
 			return fmt.Errorf("%v", err)
 		}
@@ -50,11 +50,7 @@ func runCreateAccountCapability(cmd *cobra.Command, argv []string) error {
 	if err != nil {
 		return fmt.Errorf("failed to create OCM connection: %v", err)
 	}
-	capabilityKey, err := capability.GetCapability(key, "account")
-	if err != nil {
-		return fmt.Errorf("failed to get capability: %v", err)
-	}
-	createdCapability, err := account.AddLabel(accountID, capabilityKey, "true", true, connection)
+	createdCapability, err := account.AddLabel(accountID, key, "true", true, connection)
 	if err != nil {
 		return fmt.Errorf("failed to create capability: %v", err)
 	}
diff --git a/cmd/ocm-support/create/capabilities/organization_capability/cmd.go b/cmd/ocm-support/create/capabilities/organization_capability/cmd.go
index b127ef5..d53deb3 100644
--- a/cmd/ocm-support/create/capabilities/organization_capability/cmd.go
+++ b/cmd/ocm-support/create/capabilities/organization_capability/cmd.go
@@ -34,7 +34,7 @@ var CmdCreateOrganizationCapability = &cobra.Command{
 		}
 		//validates the capability
 		capabilityKey := args[1]
-		err = capability.ValidateCapability(capabilityKey, "organization")
+		err = capability.ValidateCapability(capabilityKey, "organization", connection)
 		if err != nil {
 			return fmt.Errorf("%v", err)
 		}
@@ -50,11 +50,7 @@ func runCreateOrganizationCapability(cmd *cobra.Command, argv []string) error {
 	if err != nil {
 		return fmt.Errorf("failed to create OCM connection: %v", err)
 	}
-	capabilityKey, err := capability.GetCapability(key, "organization")
-	if err != nil {
-		return fmt.Errorf("failed to get capability: %v", err)
-	}
-	createdCapability, err := organization.AddLabel(organizationID, capabilityKey, "true", true, connection)
+	createdCapability, err := organization.AddLabel(organizationID, key, "true", true, connection)
 	if err != nil {
 		return fmt.Errorf("failed to create capability: %v", err)
 	}
diff --git a/cmd/ocm-support/create/capabilities/subscription_capability/cmd.go b/cmd/ocm-support/create/capabilities/subscription_capability/cmd.go
index cd7f732..616367f 100644
--- a/cmd/ocm-support/create/capabilities/subscription_capability/cmd.go
+++ b/cmd/ocm-support/create/capabilities/subscription_capability/cmd.go
@@ -34,7 +34,7 @@ var CmdCreateSubscriptionCapability = &cobra.Command{
 		}
 		//validates the capability
 		capabilityKey := args[1]
-		err = capability.ValidateCapability(capabilityKey, "cluster")
+		err = capability.ValidateCapability(capabilityKey, "cluster", connection)
 		if err != nil {
 			return fmt.Errorf("%v", err)
 		}
@@ -50,11 +50,7 @@ func runCreateSubscriptionCapability(cmd *cobra.Command, argv []string) error {
 	if err != nil {
 		return fmt.Errorf("failed to create OCM connection: %v", err)
 	}
-	capabilityKey, err := capability.GetCapability(key, "cluster")
-	if err != nil {
-		return fmt.Errorf("failed to get capability: %v", err)
-	}
-	createdCapability, err := subscription.AddLabel(subscriptionID, capabilityKey, "true", true, connection)
+	createdCapability, err := subscription.AddLabel(subscriptionID, key, "true", true, connection)
 	if err != nil {
 		return fmt.Errorf("failed to create capability: %v", err)
 	}
diff --git a/cmd/ocm-support/delete/capabilities/account_capability/cmd.go b/cmd/ocm-support/delete/capabilities/account_capability/cmd.go
index b104473..9bd17bc 100644
--- a/cmd/ocm-support/delete/capabilities/account_capability/cmd.go
+++ b/cmd/ocm-support/delete/capabilities/account_capability/cmd.go
@@ -32,7 +32,7 @@ var CmdDeleteAccountCapability = &cobra.Command{
 			return fmt.Errorf("%v", err)
 		}
 		//validates the capability
-		err = capability.ValidateCapability(capabilityKey, "account")
+		err = capability.ValidateCapability(capabilityKey, "account", connection)
 		if err != nil {
 			return fmt.Errorf("%v", err)
 		}
@@ -48,11 +48,7 @@ func runDeleteAccountCapability(cmd *cobra.Command, argv []string) error {
 	if err != nil {
 		return fmt.Errorf("failed to create OCM connection: %v", err)
 	}
-	capabilityKey, err := capability.GetCapability(key, "account")
-	if err != nil {
-		return fmt.Errorf("failed to get capability: %v", err)
-	}
-	err = account.DeleteLabel(accountID, capabilityKey, connection)
+	err = account.DeleteLabel(accountID, key, connection)
 	if err != nil {
 		return fmt.Errorf("failed to delete capability: %v", err)
 	}
diff --git a/cmd/ocm-support/delete/capabilities/organization_capability/cmd.go b/cmd/ocm-support/delete/capabilities/organization_capability/cmd.go
index a1a67eb..f44e838 100644
--- a/cmd/ocm-support/delete/capabilities/organization_capability/cmd.go
+++ b/cmd/ocm-support/delete/capabilities/organization_capability/cmd.go
@@ -32,7 +32,7 @@ var CmdDeleteOrganizationCapability = &cobra.Command{
 			return fmt.Errorf("%v", err)
 		}
 		//validates the capability
-		err = capability.ValidateCapability(capabilityKey, "organization")
+		err = capability.ValidateCapability(capabilityKey, "organization", connection)
 		if err != nil {
 			return fmt.Errorf("%v", err)
 		}
@@ -48,11 +48,7 @@ func runDeleteOrganizationCapability(cmd *cobra.Command, argv []string) error {
 	if err != nil {
 		return fmt.Errorf("failed to create OCM connection: %v", err)
 	}
-	capabilityKey, err := capability.GetCapability(key, "organization")
-	if err != nil {
-		return fmt.Errorf("failed to get capability: %v", err)
-	}
-	err = organization.DeleteLabel(orgID, capabilityKey, connection)
+	err = organization.DeleteLabel(orgID, key, connection)
 	if err != nil {
 		return fmt.Errorf("failed to delete capability: %v", err)
 	}
diff --git a/cmd/ocm-support/delete/capabilities/subscription_capability/cmd.go b/cmd/ocm-support/delete/capabilities/subscription_capability/cmd.go
index 35e4f3b..e6013e1 100644
--- a/cmd/ocm-support/delete/capabilities/subscription_capability/cmd.go
+++ b/cmd/ocm-support/delete/capabilities/subscription_capability/cmd.go
@@ -32,7 +32,7 @@ var CmdDeleteSubscriptionCapability = &cobra.Command{
 			return fmt.Errorf("%v", err)
 		}
 		//validates the capability
-		err = capability.ValidateCapability(capabilityKey, "cluster")
+		err = capability.ValidateCapability(capabilityKey, "cluster", connection)
 		if err != nil {
 			return fmt.Errorf("%v", err)
 		}
@@ -48,11 +48,7 @@ func runDeleteSubscriptionCapability(cmd *cobra.Command, argv []string) error {
 	if err != nil {
 		return fmt.Errorf("failed to create OCM connection: %v", err)
 	}
-	capabilityKey, err := capability.GetCapability(key, "cluster")
-	if err != nil {
-		return fmt.Errorf("failed to get capability: %v", err)
-	}
-	err = subscription.DeleteLabel(subscriptionID, capabilityKey, connection)
+	err = subscription.DeleteLabel(subscriptionID, key, connection)
 	if err != nil {
 		return fmt.Errorf("failed to delete capability: %v", err)
 	}
diff --git a/pkg/capability/capability.go b/pkg/capability/capability.go
index 75053d9..58242f0 100644
--- a/pkg/capability/capability.go
+++ b/pkg/capability/capability.go
@@ -1,7 +1,9 @@
 package capability
 
 import (
+	"context"
 	"fmt"
+	sdk "github.com/openshift-online/ocm-sdk-go"
 	"strings"
 
 	v1 "github.com/openshift-online/ocm-sdk-go/accountsmgmt/v1"
@@ -15,64 +17,6 @@ type Capability struct {
 
 type CapabilityList []Capability
 
-// Capabilities must contain 3 sections, separated by "."
-// capability.{type}.{name}
-const CapabilityAggressiveClusterSetup = "capability.account.aggressive_cluster_cleanup"
-const CapabilityCreateMoaClusters = "capability.account.create_moa_clusters"
-const CapabilityManageClusterAdmin = "capability.cluster.manage_cluster_admin"
-const CapabilityOrganizationRegistrationsPerHour = "capability.organization.clusters_registrations_per_hour"
-const CapabilityOrganizationPinClusterToShard = "capability.organization.pin_cluster_to_shard"
-const CapabilityHibernateCluster = "capability.organization.hibernate_cluster"
-const CapabilitySubscribedOcp = "capability.cluster.subscribed_ocp"
-const CapabilitySubscribedOcpMarketplace = "capability.cluster.subscribed_ocp_marketplace"
-const CapabilitySubscribedOsdMarketplace = "capability.cluster.subscribed_osd_marketplace"
-const CapabilityEnableTermsEnforcement = "capability.account.enable_terms_enforcement"
-const CapabilityBareMetalInstallerAdmin = "capability.account.bare_metal_installer_admin"
-const CapabilityReleaseOcpClusters = "capability.cluster.release_ocp_clusters"
-const CapabilityAutoscaleClustersDeprecated = "capability.organization.autoscale_clusters"
-const CapabilityAutoscaleClusters = "capability.cluster.autoscale_clusters"
-const CapabilityOrganizationInstallConfigOverride = "capability.organization.install_config_override"
-const CapabilityOrganizationInstallConfigDefault = "capability.organization.install_config_default"
-const CapabilityOrganizationOverrideOsdTrialLength = "capability.organization.override_osdtrial_length_days"
-const CapabilityOrganizationCreateClusterProxy = "capability.organization.create_cluster_proxy"
-const CapabilityAllowGCPNonCCSPrivateClusters = "capability.organization.create_gcp_non_ccs_cluster"
-const CapabilityAllowInstallEOLVersions = "capability.organization.allow_install_eol_versions"
-const CapabilityAddOnVersionSelect = "capability.organization.addon_version_select"
-const CapabilityOrganizationFipsCluster = "capability.organization.fips_cluster"
-const CapabilityOrganizationOvnCluster = "capability.organization.ovn_cluster"
-const CapabilityOrganizationHyperShift = "capability.organization.hypershift"
-const CapabilityBypassMaxExpiration = "capability.organization.bypass_max_expiration"
-const CapabilityUseRosaPaidAMI = "capability.account.use_rosa_paid_ami"
-
-var availableCapabilities map[string]string = map[string]string{
-	"AggressiveClusterSetup":             CapabilityAggressiveClusterSetup,
-	"CreateMoaClusters":                  CapabilityCreateMoaClusters,
-	"ManageClusterAdmin":                 CapabilityManageClusterAdmin,
-	"OrganizationRegistrationsPerHour":   CapabilityOrganizationRegistrationsPerHour,
-	"OrganizationPinClusterToShard":      CapabilityOrganizationPinClusterToShard,
-	"HibernateCluster":                   CapabilityHibernateCluster,
-	"SubscribedOcp":                      CapabilitySubscribedOcp,
-	"SubscribedOcpMarketplace":           CapabilitySubscribedOcpMarketplace,
-	"SubscribedOsdMarketplace":           CapabilitySubscribedOsdMarketplace,
-	"EnableTermsEnforcement":             CapabilityEnableTermsEnforcement,
-	"BareMetalInstallerAdmin":            CapabilityBareMetalInstallerAdmin,
-	"ReleaseOcpClusters":                 CapabilityReleaseOcpClusters,
-	"AutoscaleClustersDeprecated":        CapabilityAutoscaleClustersDeprecated,
-	"AutoscaleClusters":                  CapabilityAutoscaleClusters,
-	"OrganizationInstallConfigOverride":  CapabilityOrganizationInstallConfigOverride,
-	"OrganizationInstallConfigDefault":   CapabilityOrganizationInstallConfigDefault,
-	"OrganizationOverrideOsdTrialLength": CapabilityOrganizationOverrideOsdTrialLength,
-	"OrganizationCreateClusterProxy":     CapabilityOrganizationCreateClusterProxy,
-	"AllowGCPNonCCSPrivateClusters":      CapabilityAllowGCPNonCCSPrivateClusters,
-	"AllowInstallEOLVersions":            CapabilityAllowInstallEOLVersions,
-	"AddOnVersionSelect":                 CapabilityAddOnVersionSelect,
-	"OrganizationFipsCluster":            CapabilityOrganizationFipsCluster,
-	"OrganizationOvnCluster":             CapabilityOrganizationOvnCluster,
-	"OrganizationHyperShift":             CapabilityOrganizationHyperShift,
-	"BypassMaxExpiration":                CapabilityBypassMaxExpiration,
-	"UseRosaPaidAMI":                     CapabilityUseRosaPaidAMI,
-}
-
 func PresentCapabilities(capabilities []*v1.Capability) CapabilityList {
 	var capabilitiesList []Capability
 	for _, capability := range capabilities {
@@ -86,33 +30,42 @@ func PresentCapabilities(capabilities []*v1.Capability) CapabilityList {
 	return capabilitiesList
 }
 
-func ValidateCapability(capability string, resourceType string) error {
-	val, ok := availableCapabilities[capability]
-	if !ok {
-		capabilities := GetResourceTypeSpecificCapabilities(resourceType)
-		return fmt.Errorf("capability not available for '%s'. Available capabilities are '%v'", resourceType, capabilities)
+func ValidateCapability(capability string, resourceType string, conn *sdk.Connection) error {
+	availableCapabilities, err := GetCapabilities(conn)
+	if err != nil {
+		return err
+	}
+	var availableCapabilityNames []string
+	for _, availableCapability := range availableCapabilities {
+		availableCapabilityNames = append(availableCapabilityNames, availableCapability.Name())
+	}
+	for _, availableCap := range availableCapabilityNames {
+		if availableCap == capability {
+			return nil
+		}
 	}
-	if strings.Split(val, ".")[1] != resourceType {
-		capabilities := GetResourceTypeSpecificCapabilities(resourceType)
-		return fmt.Errorf("capability not available for '%s'. Available capabilities are '%v'", resourceType, capabilities)
+	resourceSpecificCapabilities := GetResourceTypeSpecificCapabilities(resourceType, availableCapabilities)
+	if len(resourceSpecificCapabilities) == 0 {
+		return fmt.Errorf("capability not available for '%s'. Available capabilities are '%v'", resourceType, availableCapabilities)
 	}
-	return nil
+	return fmt.Errorf("capability not available for '%s'. Available capabilities are '%v'", resourceType, resourceSpecificCapabilities)
 }
 
-func GetResourceTypeSpecificCapabilities(resourceType string) []string {
+func GetResourceTypeSpecificCapabilities(resourceType string, availableCapabilities []*v1.Capability) []string {
 	var capabilities []string
-	for key, val := range availableCapabilities {
-		if strings.Split(val, ".")[1] == resourceType {
-			capabilities = append(capabilities, key)
+	for _, val := range availableCapabilities {
+		if strings.Split(val.Value(), ".")[1] == resourceType {
+			capabilities = append(capabilities, val.Name())
 		}
 	}
 	return capabilities
 }
 
-func GetCapability(capability string, resourceType string) (string, error) {
-	if err := ValidateCapability(capability, resourceType); err != nil {
-		return "", err
+func GetCapabilities(conn *sdk.Connection) ([]*v1.Capability, error) {
+	ctx := context.Background()
+	capabilities, err := conn.AccountsMgmt().V1().Capabilities().List().SendContext(ctx)
+	if err != nil {
+		return nil, err
 	}
-	val := availableCapabilities[capability]
-	return val, nil
+	return capabilities.Items().Slice(), nil
 }