From 2c4cabbaacdb097589e8f019a8f049a9eb8eb6b5 Mon Sep 17 00:00:00 2001
From: Jacob Salmela <jacob.salmela@hpe.com>
Date: Thu, 28 Dec 2023 06:25:49 -0600
Subject: [PATCH] check all providers, create a map of init commands

Signed-off-by: Jacob Salmela <jacob.salmela@hpe.com>
---
 cmd/session/init.go            | 48 +++++++++++++++-------------------
 cmd/session/session_init.go    | 16 +++++++++---
 internal/domain/domain.go      |  7 +++++
 internal/domain/init.go        | 11 ++++++++
 internal/provider/csm/csm.go   |  8 ++++++
 internal/provider/interface.go |  3 +++
 6 files changed, 62 insertions(+), 31 deletions(-)

diff --git a/cmd/session/init.go b/cmd/session/init.go
index 09fc7c37..f81242b7 100644
--- a/cmd/session/init.go
+++ b/cmd/session/init.go
@@ -30,7 +30,7 @@ import (
 
 	root "github.com/Cray-HPE/cani/cmd"
 	"github.com/Cray-HPE/cani/cmd/taxonomy"
-	"github.com/Cray-HPE/cani/internal/provider/csm"
+	"github.com/Cray-HPE/cani/internal/domain"
 	"github.com/rs/zerolog/log"
 	"github.com/spf13/cobra"
 )
@@ -42,10 +42,10 @@ var (
 	ignoreValidationMessage  = "Ignore validation failures. Use this to allow unconventional configurations."
 	forceInit                bool
 
-	ProviderCmd = &cobra.Command{}
+	ProviderInitCmds = map[string]*cobra.Command{}
 	// BootstapCmd is used to start a session with a specific provider and allows the provider to define
 	// how the real init command is defined using their custom business logic
-	BootstrapCmd = &cobra.Command{
+	SessionInitCmd = &cobra.Command{
 		Use:       "init PROVIDER",
 		Short:     taxonomy.InitShort,
 		Long:      taxonomy.InitLong,
@@ -56,38 +56,32 @@ var (
 )
 
 func init() {
-	// init is run once, and this is where the flags get set
-	// since flags vary by provider, create a variable for each
-	var err error
-	for _, provider := range taxonomy.SupportedProviders {
-		switch provider {
-		case taxonomy.CSM:
-			ProviderCmd, err = csm.NewSessionInitCommand()
-		default:
-			log.Debug().Msgf("skipping provider: %s", provider)
-		}
+	// Define the bare minimum needed to determine who the provider for the session will be
+	SessionInitCmd.Flags().BoolVar(&ignoreExternalValidation, "ignore-validation", false, ignoreValidationMessage)
+	SessionInitCmd.Flags().BoolVarP(&forceInit, "force", "f", false, "Overwrite the existing session with a new session")
+
+	for _, p := range domain.GetProviders() {
+		// Create a domain object to interact with the datastore and the provider
+		providerCmd, err := domain.NewSessionInitCommand(p.Slug())
 		if err != nil {
-			log.Error().Msgf("unable to get cmd from provider: %v", err)
+			log.Error().Msgf("unable to get provider init command: %v", err)
 			os.Exit(1)
 		}
-		ProviderCmd.Use = "init"
-	}
+		providerCmd.Use = "init"
 
-	// Define the bare minimum needed to determine who the provider for the session will be
-	BootstrapCmd.Flags().BoolVar(&ignoreExternalValidation, "ignore-validation", false, ignoreValidationMessage)
-	BootstrapCmd.Flags().BoolVarP(&forceInit, "force", "f", false, "Overwrite the existing session with a new session")
+		// all flags should be set in init().  you can set flags after the fact, but it is much easier to work with everything up front
+		// this will set existing variables for each provider
+		err = root.MergeProviderFlags(SessionInitCmd, providerCmd)
+		if err != nil {
+			log.Error().Msgf("unable to get flags from provider: %v", err)
+			os.Exit(1)
+		}
 
-	// all flags should be set in init().  you can set flags after the fact, but it is much easier to work with everything up front
-	// this will set existing variables for each provider
-	err = root.MergeProviderFlags(BootstrapCmd, ProviderCmd)
-	if err != nil {
-		log.Error().Msgf("unable to get flags from provider: %v", err)
-		os.Exit(1)
+		ProviderInitCmds[p.Slug()] = providerCmd
 	}
 
 	// Add session commands to root commands
-	root.SessionCmd.AddCommand(BootstrapCmd)
-	BootstrapCmd.AddCommand(ProviderCmd)
+	root.SessionCmd.AddCommand(SessionInitCmd)
 	root.SessionCmd.AddCommand(SessionApplyCmd)
 	root.SessionCmd.AddCommand(SessionStatusCmd)
 	root.SessionCmd.AddCommand(SessionSummaryCmd)
diff --git a/cmd/session/session_init.go b/cmd/session/session_init.go
index e8b9a3c1..429aebf9 100644
--- a/cmd/session/session_init.go
+++ b/cmd/session/session_init.go
@@ -43,10 +43,18 @@ import (
 )
 
 func initSessionWithProviderCmd(cmd *cobra.Command, args []string) (err error) {
-	// Create a domain object to interact with the datastore and the provider
-	root.D, err = domain.New(cmd, args)
-	if err != nil {
-		return err
+	for _, p := range domain.GetProviders() {
+		// if the provider matches the arg requested, a session can begin
+		if p.Slug() == args[0] {
+			providerInitCmd, exists := ProviderInitCmds[p.Slug()]
+			if exists {
+				// Create a domain object to interact with the datastore and the provider
+				root.D, err = domain.New(providerInitCmd, args)
+				if err != nil {
+					return err
+				}
+			}
+		}
 	}
 
 	// Set the datastore
diff --git a/internal/domain/domain.go b/internal/domain/domain.go
index d0515214..b5d78ea1 100644
--- a/internal/domain/domain.go
+++ b/internal/domain/domain.go
@@ -164,3 +164,10 @@ type UpdatedHardwareResult struct {
 	DatastoreValidationErrors map[uuid.UUID]inventory.ValidateResult // TODO
 	ProviderValidationErrors  map[uuid.UUID]provider.HardwareValidationResult
 }
+
+func GetProviders() []provider.InventoryProvider {
+	supportedProviders := []provider.InventoryProvider{
+		&csm.CSM{},
+	}
+	return supportedProviders
+}
diff --git a/internal/domain/init.go b/internal/domain/init.go
index 4f114cae..ac3237df 100644
--- a/internal/domain/init.go
+++ b/internal/domain/init.go
@@ -31,6 +31,17 @@ import (
 	"github.com/spf13/cobra"
 )
 
+func NewSessionInitCommand(p string) (providerCmd *cobra.Command, err error) {
+	switch p {
+	case "csm":
+		providerCmd, err = csm.NewSessionInitCommand()
+	}
+	if err != nil {
+		return providerCmd, err
+	}
+	return providerCmd, nil
+}
+
 // NewProviderCmd returns the appropriate command to the cmd layer
 func NewProviderCmd(bootstrapCmd *cobra.Command, availableDomains map[string]*Domain) (providerCmd *cobra.Command, err error) {
 	providerCmd = &cobra.Command{}
diff --git a/internal/provider/csm/csm.go b/internal/provider/csm/csm.go
index 871ac1f6..80703102 100644
--- a/internal/provider/csm/csm.go
+++ b/internal/provider/csm/csm.go
@@ -42,6 +42,10 @@ import (
 	sls_client "github.com/Cray-HPE/cani/pkg/sls-client"
 )
 
+const (
+	CsmSlug = "csm"
+)
+
 type CSM struct {
 	// Clients
 	slsClient       *sls_client.APIClient
@@ -163,6 +167,10 @@ func New(cmd *cobra.Command, args []string, hwlib *hardwaretypes.Library, opts i
 	// return csm, nil
 }
 
+func (csm *CSM) Slug() string {
+	return CsmSlug
+}
+
 func (csm *CSM) setupClients() (err error) {
 	// Setup HTTP client and context using csm options
 	httpClient, _, err := csm.newClient()
diff --git a/internal/provider/interface.go b/internal/provider/interface.go
index 4a44b728..c1cda7f7 100644
--- a/internal/provider/interface.go
+++ b/internal/provider/interface.go
@@ -90,6 +90,9 @@ type InventoryProvider interface {
 
 	// Print
 	PrintHardware(cmd *cobra.Command, args []string, filtered map[uuid.UUID]inventory.Hardware) error
+
+	// Provider's name
+	Slug() string
 }
 
 type HardwareValidationResult struct {