package cmd import ( "encoding/json" "fmt" "github.com/OpenCHAMI/magellan/pkg/jaws" "github.com/OpenCHAMI/magellan/pkg/pdu" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) func transformToSMDFormat(inventory *pdu.PDUInventory) []map[string]any { smdRecords := make([]map[string]any, 0) rtsHostname := fmt.Sprintf("%s-rts:8083", inventory.Hostname) pduBank := "B" for _, outlet := range inventory.Outlets { smdID := fmt.Sprintf("%sp1v%s", inventory.Hostname, outlet.ID) odataID := fmt.Sprintf("/redfish/v1/PowerEquipment/RackPDUs/%s/Outlets/%s", pduBank, outlet.ID) redfishURL := fmt.Sprintf("%s%s", rtsHostname, odataID) powerControlTarget := fmt.Sprintf("%s/Actions/Outlet.PowerControl", odataID) record := map[string]any{ "ID": smdID, "Type": "CabinetPDUPowerConnector", "RedfishType": "Outlet", "RedfishSubtype": "Cx", "OdataID": odataID, "RedfishEndpointID": inventory.Hostname, "Enabled": true, "RedfishEndpointFQDN": rtsHostname, "RedfishURL": redfishURL, "ComponentEndpointType": "ComponentEndpointOutlet", "RedfishOutletInfo": map[string]any{ "Name": outlet.Name, // Directly from inventory "Actions": map[string]any{ "#Outlet.PowerControl": map[string]any{ "PowerState@Redfish.AllowableValues": []string{"On", "Off"}, "target": powerControlTarget, }, }, }, } smdRecords = append(smdRecords, record) } return smdRecords } var pduCollectCmd = &cobra.Command{ Use: "collect [hosts...]", Short: "Collect inventory from JAWS-based PDUs", Long: `Connects to one or more PDUs with a JAWS interface to collect hardware inventory.`, Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 { log.Error().Msg("no PDU hosts provided") return } if username == "" || password == "" { log.Error().Msg("--username and --password are required for PDU collection") return } allSmdRecords := make([]map[string]any, 0) for _, host := range args { log.Info().Msgf("Collecting from PDU: %s", host) config := jaws.CrawlerConfig{ URI: host, Username: username, Password: password, Insecure: true, } inventory, err := jaws.CrawlPDU(config) if err != nil { log.Error().Err(err).Msgf("failed to crawl PDU %s", host) continue } smdRecords := transformToSMDFormat(inventory) allSmdRecords = append(allSmdRecords, smdRecords...) } output, err := json.MarshalIndent(allSmdRecords, "", " ") if err != nil { log.Error().Err(err).Msgf("failed to marshal SMD records to JSON") } fmt.Println(string(output)) }, } func init() { PduCmd.AddCommand(pduCollectCmd) pduCollectCmd.Flags().StringVarP(&username, "username", "u", "", "Set the PDU username") pduCollectCmd.Flags().StringVarP(&password, "password", "p", "", "Set the PDU password") }