Skip to content

refactor to support multiple providers #150

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions cmd/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,6 @@ import (
"github.com/spf13/cobra"
)

var (
vendor string
name string
u string
)

// AddCmd represents the switch add command
var AddCmd = &cobra.Command{
Use: "add",
Expand Down
26 changes: 9 additions & 17 deletions cmd/blade/add_blade.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,25 +43,17 @@ import (

// AddBladeCmd represents the blade add command
var AddBladeCmd = &cobra.Command{
Use: "blade",
Short: "Add blades to the inventory.",
Long: `Add blades to the inventory.`,
PersistentPreRunE: root.DatastoreExists, // A session must be active to write to a datastore
SilenceUsage: true, // Errors are more important than the usage
Args: validHardware, // Hardware can only be valid if defined in the hardware library
RunE: addBlade, // Add a blade when this sub-command is called
Use: "blade",
Short: "Add blades to the inventory.",
Long: `Add blades to the inventory.`,
PreRunE: validHardware, // Hardware can only be valid if defined in the hardware library
RunE: addBlade, // Add a blade when this sub-command is called
}

// addBlade adds a blade to the inventory
func addBlade(cmd *cobra.Command, args []string) error {
// Create a domain object to interact with the datastore
d, err := domain.New(root.Conf.Session.DomainOptions)
if err != nil {
return err
}

func addBlade(cmd *cobra.Command, args []string) (err error) {
if auto {
recommendations, err := d.Recommend(args[0])
recommendations, err := root.D.Recommend(args[0])
if err != nil {
return err
}
Expand Down Expand Up @@ -95,7 +87,7 @@ func addBlade(cmd *cobra.Command, args []string) error {
}

// Add the blade from the inventory using domain methods
result, err := d.AddBlade(cmd.Context(), args[0], cabinet, chassis, blade)
result, err := root.D.AddBlade(cmd.Context(), args[0], cabinet, chassis, blade)
if errors.Is(err, provider.ErrDataValidationFailure) {
// TODO this validation error print logic could be shared

Expand Down Expand Up @@ -147,7 +139,7 @@ func addBlade(cmd *cobra.Command, args []string) error {
result.Location)
// Add the node to the map
newNodes = append(newNodes, result)
if root.Conf.Session.DomainOptions.Provider == string(inventory.CSMProvider) {
if root.D.Provider == string(inventory.CSMProvider) {
log.Info().Str("status", "SUCCESS").Msgf("%s was successfully staged to be added to the system", hardwaretypes.NodeBlade)
log.Info().Msgf("UUID: %s", result.Hardware.ID)
log.Info().Msgf("Cabinet: %d", cabinet)
Expand Down
9 changes: 1 addition & 8 deletions cmd/blade/list_blade.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import (
"text/tabwriter"

root "github.com/Cray-HPE/cani/cmd"
"github.com/Cray-HPE/cani/internal/domain"
"github.com/Cray-HPE/cani/internal/inventory"
"github.com/Cray-HPE/cani/pkg/hardwaretypes"
"github.com/google/uuid"
Expand All @@ -53,14 +52,8 @@ var ListBladeCmd = &cobra.Command{

// listBlade lists blades in the inventory
func listBlade(cmd *cobra.Command, args []string) error {
// Instantiate a new logic object to interact with the datastore
d, err := domain.New(root.Conf.Session.DomainOptions)
if err != nil {
return err
}

// Get the entire inventory
inv, err := d.List()
inv, err := root.D.List()
if err != nil {
return err
}
Expand Down
8 changes: 1 addition & 7 deletions cmd/blade/remove_blade.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"fmt"

root "github.com/Cray-HPE/cani/cmd"
"github.com/Cray-HPE/cani/internal/domain"
"github.com/google/uuid"
"github.com/spf13/cobra"
)
Expand All @@ -52,13 +51,8 @@ func removeBlade(cmd *cobra.Command, args []string) error {
return fmt.Errorf("Need a UUID to remove: %s", err.Error())
}

d, err := domain.New(root.Conf.Session.DomainOptions)
if err != nil {
return err
}

// Remove the blade from the inventory
err = d.RemoveBlade(u, recursion)
err = root.D.RemoveBlade(u, recursion)
if err != nil {
return err
}
Expand Down
25 changes: 12 additions & 13 deletions cmd/blade/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,29 @@ import (
"os"

root "github.com/Cray-HPE/cani/cmd"
"github.com/Cray-HPE/cani/pkg/hardwaretypes"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
)

// validHardware checks that the hardware type is valid by comparing it against the list of hardware types
func validHardware(cmd *cobra.Command, args []string) error {
library, err := hardwaretypes.NewEmbeddedLibrary(root.Conf.Session.DomainOptions.CustomHardwareTypesDir)
if err != nil {
return err
}

// Get the list of hardware types that are blades
deviceTypes := library.GetDeviceTypesByHardwareType(hardwaretypes.NodeBlade)
func validHardware(cmd *cobra.Command, args []string) (err error) {
log.Debug().Msgf("Validating hardware %+v", root.D)
if cmd.Flags().Changed("list-supported-types") {
cmd.SetOut(os.Stdout)
for _, hw := range deviceTypes {
cmd.Printf("%s\n", hw.Slug)
for _, hw := range root.BladeTypes {
// print additional provider defaults
if root.Verbose {
cmd.Printf("%s\n", hw.Slug)
} else {
cmd.Printf("%s\n", hw.Slug)
}
}
os.Exit(0)
}

if len(args) == 0 {
bladeTypes := []string{}
for _, hw := range deviceTypes {
for _, hw := range root.BladeTypes {
bladeTypes = append(bladeTypes, hw.Slug)
}
return fmt.Errorf("No hardware type provided: Choose from: %s", bladeTypes)
Expand All @@ -63,7 +62,7 @@ func validHardware(cmd *cobra.Command, args []string) error {
// Check that each arg is a valid blade type
for _, arg := range args {
matchFound := false
for _, device := range deviceTypes {
for _, device := range root.BladeTypes {
if arg == device.Slug {
matchFound = true
break
Expand Down
26 changes: 9 additions & 17 deletions cmd/cabinet/add_cabinet.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,25 +42,17 @@ import (

// AddCabinetCmd represents the cabinet add command
var AddCabinetCmd = &cobra.Command{
Use: "cabinet",
Short: "Add cabinets to the inventory.",
Long: `Add cabinets to the inventory.`,
PersistentPreRunE: validFlagCombos, // Also ensures a session is active
Args: validHardware, // Hardware can only be valid if defined in the hardware library
SilenceUsage: true, // Errors are more important than the usage
RunE: addCabinet, // Add a cabinet when this sub-command is called
Use: "cabinet",
Short: "Add cabinets to the inventory.",
Long: `Add cabinets to the inventory.`,
PreRunE: validHardware, // Hardware can only be valid if defined in the hardware library
RunE: addCabinet, // Add a cabinet when this sub-command is called
}

// addCabinet adds a cabinet to the inventory
func addCabinet(cmd *cobra.Command, args []string) error {
// Create a domain object to interact with the datastore
d, err := domain.New(root.Conf.Session.DomainOptions)
if err != nil {
return err
}

func addCabinet(cmd *cobra.Command, args []string) (err error) {
if auto {
recommendations, err := d.Recommend(args[0])
recommendations, err := root.D.Recommend(args[0])
if err != nil {
return err
}
Expand All @@ -86,7 +78,7 @@ func addCabinet(cmd *cobra.Command, args []string) error {
if !auto {
log.Warn().Msgf("Aborted %s add", hardwaretypes.Cabinet)
fmt.Printf("\nAuto-generated values can be overridden by re-running the command with explicit values:\n")
fmt.Printf("\n\tcani alpha add %s %s --vlan-id %d --cabinet %d\n\n", cmd.Name(), args[0], vlanId, cabinetNumber)
fmt.Printf("\n\t%s %s %s %s --vlan-id %d --cabinet %d\n\n", cmd.Root().Name(), cmd.Parent().Name(), cmd.Name(), args[0], vlanId, cabinetNumber)

return nil
}
Expand All @@ -101,7 +93,7 @@ func addCabinet(cmd *cobra.Command, args []string) error {
}

// Add the cabinet to the inventory using domain methods
result, err := d.AddCabinet(cmd.Context(), args[0], cabinetNumber, cabinetMetadata)
result, err := root.D.AddCabinet(cmd.Context(), args[0], cabinetNumber, cabinetMetadata)
if errors.Is(err, provider.ErrDataValidationFailure) {
// TODO the following should probably suggest commands to fix the issue?
log.Error().Msgf("Inventory data validation errors encountered")
Expand Down
9 changes: 1 addition & 8 deletions cmd/cabinet/list_cabinet.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import (
"text/tabwriter"

root "github.com/Cray-HPE/cani/cmd"
"github.com/Cray-HPE/cani/internal/domain"
"github.com/Cray-HPE/cani/internal/inventory"
"github.com/Cray-HPE/cani/internal/provider/csm"
"github.com/Cray-HPE/cani/pkg/hardwaretypes"
Expand All @@ -54,14 +53,8 @@ var ListCabinetCmd = &cobra.Command{

// listCabinet lists cabinets in the inventory
func listCabinet(cmd *cobra.Command, args []string) error {
// Create a domain object to interact with the datastore
d, err := domain.New(root.Conf.Session.DomainOptions)
if err != nil {
return err
}

// Get the entire inventory
inv, err := d.List()
inv, err := root.D.List()
if err != nil {
return err
}
Expand Down
27 changes: 9 additions & 18 deletions cmd/cabinet/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,14 @@ import (
"strings"

root "github.com/Cray-HPE/cani/cmd"
"github.com/Cray-HPE/cani/pkg/hardwaretypes"
"github.com/spf13/cobra"
)

// validHardware checks that the hardware type is valid by comparing it against the list of hardware types
func validHardware(cmd *cobra.Command, args []string) error {
library, err := hardwaretypes.NewEmbeddedLibrary(root.Conf.Session.DomainOptions.CustomHardwareTypesDir)
if err != nil {
return err
}

// Get the list of hardware types that are cabinets
deviceTypes := library.GetDeviceTypesByHardwareType(hardwaretypes.Cabinet)
func validHardware(cmd *cobra.Command, args []string) (err error) {
if cmd.Flags().Changed("list-supported-types") {
cmd.SetOut(os.Stdout)
for _, hw := range deviceTypes {
for _, hw := range root.CabinetTypes {
// print additional provider defaults
if root.Verbose {
cmd.Printf("%s %d %d\n", hw.Slug, hw.ProviderDefaults.CSM.Ordinal, hw.ProviderDefaults.CSM.StartingHmnVlan)
Expand All @@ -60,7 +52,7 @@ func validHardware(cmd *cobra.Command, args []string) error {

if len(args) == 0 {
types := []string{}
for _, hw := range deviceTypes {
for _, hw := range root.CabinetTypes {
types = append(types, hw.Slug)
}
return fmt.Errorf("No hardware type provided: Choose from: %s", strings.Join(types, "\", \""))
Expand All @@ -69,7 +61,7 @@ func validHardware(cmd *cobra.Command, args []string) error {
// Check that each arg is a valid cabinet type
for _, arg := range args {
matchFound := false
for _, device := range deviceTypes {
for _, device := range root.CabinetTypes {
if arg == device.Slug {
matchFound = true
break
Expand All @@ -80,17 +72,16 @@ func validHardware(cmd *cobra.Command, args []string) error {
}
}

err = validFlagCombos(cmd, args)
if err != nil {
return err
}

return nil
}

// validFlagCombos has additional flag logic to account for overiding required flags with the --auto flag
func validFlagCombos(cmd *cobra.Command, args []string) error {
// ensure the session is up and the datastore exists
err := root.DatastoreExists(cmd, args)
if err != nil {
return err
}

cabinetSet := cmd.Flags().Changed("cabinet")
vlanIdSet := cmd.Flags().Changed("vlan-id")
autoSet := cmd.Flags().Changed("auto")
Expand Down
34 changes: 20 additions & 14 deletions cmd/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,39 +41,45 @@ type Config struct {
Session *Session `yaml:"session"`
}

var ConfigDir, CustomDir, Tl string

// InitConfig creates a default config file if one does not exist
func InitConfig(cfg string) (err error) {
// Create the directory if it doesn't exist
configDir := filepath.Dir(cfg)
if _, err := os.Stat(configDir); os.IsNotExist(err) {
err = os.Mkdir(configDir, 0755)
ConfigDir = filepath.Dir(cfg)
if _, err := os.Stat(ConfigDir); os.IsNotExist(err) {
err = os.Mkdir(ConfigDir, 0755)
if err != nil {
return fmt.Errorf("error creating config directory: %s", err)
}
}
tl := filepath.Join(configDir, taxonomy.LogFile)
customDir := fmt.Sprintf("%s/%s", configDir, "hardware-types")
Tl = filepath.Join(ConfigDir, taxonomy.LogFile)
CustomDir = fmt.Sprintf("%s/%s", ConfigDir, "hardware-types")
// Write a default config file if it doesn't exist
if _, err := os.Stat(cfg); os.IsNotExist(err) {
log.Debug().Msg(fmt.Sprintf("%s does not exist, creating default config file", cfg))

// Create a config with default values since one does not exist
// Create a config with a blank object
conf := &Config{
Session: &Session{
DomainOptions: &domain.DomainOpts{
Provider: "csm",
DatastorePath: filepath.Join(configDir, taxonomy.DsFile),
LogFilePath: tl,
CustomHardwareTypesDir: customDir,
},
Domains: map[string]*domain.Domain{},
},
}

// Add the supported providers to the config as a starting default
for _, p := range taxonomy.SupportedProviders {
conf.Session.Domains[p] = &domain.Domain{
// DatastorePath: filepath.Join(ConfigDir, taxonomy.DsFile),
LogFilePath: Tl,
CustomHardwareTypesDir: CustomDir,
Provider: p,
Active: false,
}
}
// Create the config file
WriteConfig(cfg, conf)
}

err = os.MkdirAll(customDir, 0755)
err = os.MkdirAll(CustomDir, 0755)
if err != nil {
return err
}
Expand Down
4 changes: 1 addition & 3 deletions cmd/config/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,5 @@ import "github.com/Cray-HPE/cani/internal/domain"

// Session defines the session configuration and domain options
type Session struct {
DomainOptions *domain.DomainOpts `yaml:"domain_options"`
Domain *domain.Domain `yaml:"domain"`
Active bool `yaml:"active"`
Domains map[string]*domain.Domain `yaml:"domains"`
}
Loading