@@ -88,6 +88,7 @@ func newCreateCmd() *cobra.Command {
8888 cmd .AddCommand (newCreateBMLCmd ())
8989 cmd .AddCommand (newCreateNetworkCmd ())
9090 cmd .AddCommand (newCreateImageServerCmd ())
91+ cmd .AddCommand (newCreateBMCEmulatorCmd ())
9192 return cmd
9293}
9394
@@ -210,7 +211,11 @@ Example configuration:
210211 containerPort: 8080
211212 dataDir: "/var/lib/vbmctl/images"
212213 containerDataDir: "/usr/share/nginx/html",
213- containerName: "vbmctl-image-server"` ,
214+ containerName: "vbmctl-image-server"
215+ bmcEmulator:
216+ type: "sushy-tools"
217+ configFile: "vbmc-emulator-file"
218+ image: "bmc-emulator:latest"` ,
214219 RunE : func (_ * cobra.Command , _ []string ) error {
215220 ctx , cancel := contextWithSignal ()
216221 defer cancel ()
@@ -234,6 +239,16 @@ Example configuration:
234239 fmt .Println ("No image server configuration found in the config file." )
235240 }
236241
242+ if cfg .Spec .BMCEmulator != nil {
243+ err = containers .CreateBMCEmulatorInstance (ctx , cfg .Spec .BMCEmulator )
244+ if err != nil {
245+ return err
246+ }
247+ } else {
248+ //nolint:forbidigo // CLI output is intentional
249+ fmt .Println ("No BMC emulator configuration found in the config file." )
250+ }
251+
237252 conn , err := libvirtgo .NewConnect (cfg .Spec .Libvirt .URI )
238253 if err != nil {
239254 return fmt .Errorf ("failed to connect to libvirt: %w" , err )
@@ -420,6 +435,62 @@ func newCreateImageServerCmd() *cobra.Command {
420435 return cmd
421436}
422437
438+ func newCreateBMCEmulatorCmd () * cobra.Command {
439+ var (
440+ emulatorType string
441+ image string
442+ configFile string
443+ )
444+
445+ cmd := & cobra.Command {
446+ Use : "bmc-emulator" ,
447+ Short : "Create a BMC emulator instance" ,
448+ Long : "Create a BMC emulator instance to be used for testing." ,
449+ RunE : func (_ * cobra.Command , _ []string ) error {
450+ ctx , cancel := contextWithSignal ()
451+ defer cancel ()
452+
453+ cfg , err := loadConfig ()
454+ if err != nil {
455+ return err
456+ }
457+
458+ // Resolve effective BMC emulator config: config file values, falling back to defaults.
459+ // Command-line flags take precedence over both.
460+ effective := & vbmctlapi.BMCEmulatorConfig {
461+ Type : config .DefaultBMCEmulatorType ,
462+ Image : config .DefaultBMCEmulatorImage ,
463+ ConfigFile : config .DefaultBMCEmulatorConfigFile ,
464+ }
465+ if cfg .Spec .BMCEmulator != nil {
466+ effective = cfg .Spec .BMCEmulator
467+ }
468+
469+ if emulatorType == "" {
470+ emulatorType = effective .Type
471+ }
472+ if image == "" {
473+ image = effective .Image
474+ }
475+ if configFile == "" {
476+ configFile = effective .ConfigFile
477+ }
478+
479+ return containers .CreateBMCEmulatorInstance (ctx , & vbmctlapi.BMCEmulatorConfig {
480+ Type : emulatorType ,
481+ Image : image ,
482+ ConfigFile : configFile ,
483+ })
484+ },
485+ }
486+
487+ cmd .Flags ().StringVar (& emulatorType , "emulator-type" , "" , "type of the BMC emulator (vbmc or sushy-tools, default is " + config .DefaultBMCEmulatorType + " if not set in config file)" )
488+ cmd .Flags ().StringVar (& image , "image" , "" , "container image to use for the BMC emulator (default is " + config .DefaultBMCEmulatorImage + " if not set in config file)" )
489+ cmd .Flags ().StringVar (& configFile , "config-file" , "" , "configuration file to use for the BMC emulator in case of sushy-tools (default is " + config .DefaultBMCEmulatorConfigFile + " if not set in config file)" )
490+
491+ return cmd
492+ }
493+
423494func newDeleteCmd () * cobra.Command {
424495 cmd := & cobra.Command {
425496 Use : "delete" ,
@@ -431,6 +502,7 @@ func newDeleteCmd() *cobra.Command {
431502 cmd .AddCommand (newDeleteBMLCmd ())
432503 cmd .AddCommand (newDeleteNetworkCmd ())
433504 cmd .AddCommand (newDeleteImageServerCmd ())
505+ cmd .AddCommand (newDeleteBMCEmulatorCmd ())
434506 return cmd
435507}
436508
@@ -565,6 +637,18 @@ func newDeleteBMLCmd() *cobra.Command {
565637 fmt .Println ("No image server configuration found in the config file." )
566638 }
567639
640+ if cfg .Spec .BMCEmulator != nil {
641+ err := containers .DeleteBMCEmulatorInstance (ctx , cfg .Spec .BMCEmulator .Type )
642+ // don't fail the whole command if BMC emulator deletion fails, just log the error
643+ if err != nil {
644+ //nolint:forbidigo // CLI output is intentional
645+ fmt .Printf ("%v\n " , err )
646+ }
647+ } else {
648+ //nolint:forbidigo // CLI output is intentional
649+ fmt .Println ("No BMC emulator configuration found in the config file." )
650+ }
651+
568652 return nil
569653 },
570654 }
@@ -646,8 +730,43 @@ func newDeleteImageServerCmd() *cobra.Command {
646730 return cmd
647731}
648732
733+ func newDeleteBMCEmulatorCmd () * cobra.Command {
734+ var emulatorType string
735+
736+ cmd := & cobra.Command {
737+ Use : "bmc-emulator" ,
738+ Short : "Delete the BMC emulator instance" ,
739+ Long : "Delete the BMC emulator instance used for provisioning." ,
740+ RunE : func (_ * cobra.Command , _ []string ) error {
741+ ctx , cancel := contextWithSignal ()
742+ defer cancel ()
743+
744+ cfg , err := loadConfig ()
745+ if err != nil {
746+ return err
747+ }
748+
749+ // command-line flag takes precedence over config file value
750+ if emulatorType == "" {
751+ if cfg .Spec .BMCEmulator != nil {
752+ emulatorType = cfg .Spec .BMCEmulator .Type
753+ } else {
754+ emulatorType = config .DefaultBMCEmulatorType
755+ }
756+ }
757+
758+ return containers .DeleteBMCEmulatorInstance (ctx , emulatorType )
759+ },
760+ }
761+
762+ cmd .Flags ().StringVar (& emulatorType , "emulator-type" , "" , "type of the BMC emulator container to delete (default is " + config .DefaultBMCEmulatorType + " if not set in config file)" )
763+
764+ return cmd
765+ }
766+
649767func newStatusCmd () * cobra.Command {
650768 var containerName string
769+ var emulatorType string
651770
652771 cmd := & cobra.Command {
653772 Use : "status" ,
@@ -695,9 +814,25 @@ func newStatusCmd() *cobra.Command {
695814 return err
696815 }
697816
817+ // command-line flag takes precedence over config file value
818+ if emulatorType == "" {
819+ if cfg .Spec .BMCEmulator != nil {
820+ emulatorType = cfg .Spec .BMCEmulator .Type
821+ } else {
822+ emulatorType = config .DefaultBMCEmulatorType
823+ }
824+ }
825+ // check if the bmc emulator is present
826+ emulatorInfo , err := containers .GetBMCEmulatorInfo (ctx , emulatorType )
827+ if err != nil {
828+ return err
829+ }
830+
698831 //nolint:forbidigo // CLI output is intentional
699832 fmt .Printf ("Image Server container: %s\n " , containerInfo )
700833 //nolint:forbidigo // CLI output is intentional
834+ fmt .Printf ("BMC Emulator container: %s\n " , emulatorInfo )
835+ //nolint:forbidigo // CLI output is intentional
701836 fmt .Println ("Virtual Machines:" )
702837 //nolint:forbidigo // CLI output is intentional
703838 fmt .Println (" NAME\t \t STATE\t \t MEMORY\t VCPUs" )
@@ -712,6 +847,7 @@ func newStatusCmd() *cobra.Command {
712847 }
713848
714849 cmd .Flags ().StringVar (& containerName , "name" , "" , "name of the image server container (default is " + config .DefaultImageServerContainerName + " if not set in config file)" )
850+ cmd .Flags ().StringVar (& emulatorType , "emulator-type" , "" , "type of the BMC emulator container to check for (default is " + config .DefaultBMCEmulatorType + " if not set in config file)" )
715851
716852 return cmd
717853}
@@ -793,6 +929,14 @@ func newConfigViewCmd() *cobra.Command {
793929 cfg .Spec .ImageServer .ContainerName )
794930 }
795931
932+ if cfg .Spec .BMCEmulator != nil {
933+ //nolint:forbidigo // CLI output is intentional
934+ fmt .Printf ("BMC Emulator:\n Emulator Type: %s\n Config File: %s\n Image: %s\n " ,
935+ cfg .Spec .BMCEmulator .Type ,
936+ cfg .Spec .BMCEmulator .ConfigFile ,
937+ cfg .Spec .BMCEmulator .Image )
938+ }
939+
796940 return nil
797941 },
798942 }
0 commit comments