@@ -44,10 +44,10 @@ func newRootCmd() *cobra.Command {
4444for testing and development purposes. It currently provides functionality for:
4545
4646 - Creating and managing virtual machines using libvirt
47+ - Creating and managing libvirt networks
4748 - Reserving IP addresses for VMs via DHCP on existing libvirt networks
4849
4950Planned features (not yet implemented):
50- - Network management (create/delete libvirt networks)
5151 - BMC emulator support (sushy-tools, vbmc)
5252 - Image server for provisioning
5353
@@ -88,6 +88,7 @@ func newCreateCmd() *cobra.Command {
8888
8989 cmd .AddCommand (newCreateVMCmd ())
9090 cmd .AddCommand (newCreateBMLCmd ())
91+ cmd .AddCommand (newCreateNetworkCmd ())
9192 return cmd
9293}
9394
@@ -185,8 +186,9 @@ func newCreateBMLCmd() *cobra.Command {
185186 cmd := & cobra.Command {
186187 Use : "bml" ,
187188 Short : "Create a bare metal lab from configuration file" ,
188- Long : `Create a bare metal lab (bml) with all VMs defined in the spec.vms section
189- of the configuration file.
189+ Long : `Create a bare metal lab (bml) with all VMs and networks defined in the spec.vms
190+ and spec.networks sections of the configuration file. Note that network block can
191+ be omitted and VMs can be connected to existing networks as well.
190192
191193Example configuration:
192194 spec:
@@ -197,9 +199,12 @@ Example configuration:
197199 volumes:
198200 - name: "root"
199201 size: 20
200- networks :
202+ networkAttachments :
201203 - network: "baremetal-e2e"
202- macAddress: "00:60:2f:31:81:01"` ,
204+ macAddress: "00:60:2f:31:81:01"
205+ networks:
206+ - name: "baremetal-e2e"
207+ - bridge: "metal3"` ,
203208 RunE : func (_ * cobra.Command , _ []string ) error {
204209 ctx , cancel := contextWithSignal ()
205210 defer cancel ()
@@ -219,6 +224,22 @@ Example configuration:
219224 }
220225 defer func () { _ , _ = conn .Close () }()
221226
227+ // Create networks before VMs
228+ networkManager , err := libvirt .NewNetworkManager (conn )
229+ if err != nil {
230+ return fmt .Errorf ("failed to create Network manager: %w" , err )
231+ }
232+ networks , err := networkManager .CreateNetworks (ctx , cfg .Spec .Networks )
233+ if err != nil {
234+ return err
235+ }
236+ //nolint:forbidigo // CLI output is intentional
237+ fmt .Println ("\n Created networks:" )
238+ for _ , network := range networks {
239+ //nolint:forbidigo // CLI output is intentional
240+ fmt .Printf (" - %s (UUID: %s)\n " , network .Name , network .UUID )
241+ }
242+
222243 vmManager , err := libvirt .NewVMManager (conn , libvirt.VMManagerOptions {
223244 PoolName : cfg .Spec .Pool .Name ,
224245 PoolPath : cfg .Spec .Pool .Path ,
@@ -249,6 +270,63 @@ Example configuration:
249270 return cmd
250271}
251272
273+ func newCreateNetworkCmd () * cobra.Command {
274+ var (
275+ name string
276+ bridge string
277+ address string
278+ netmask string
279+ )
280+
281+ cmd := & cobra.Command {
282+ Use : "network" ,
283+ Short : "Create a network" ,
284+ Long : "Create a new network with the specified configuration." ,
285+ RunE : func (_ * cobra.Command , _ []string ) error {
286+ ctx , cancel := contextWithSignal ()
287+ defer cancel ()
288+
289+ cfg , err := loadConfig ()
290+ if err != nil {
291+ return err
292+ }
293+
294+ conn , err := libvirtgo .NewConnect (cfg .Spec .Libvirt .URI )
295+ if err != nil {
296+ return fmt .Errorf ("failed to connect to libvirt: %w" , err )
297+ }
298+ defer func () { _ , _ = conn .Close () }()
299+
300+ networkManager , err := libvirt .NewNetworkManager (conn )
301+ if err != nil {
302+ return fmt .Errorf ("failed to create Network manager: %w" , err )
303+ }
304+
305+ networkCfg := vbmctlapi.NetworkConfig {
306+ Name : name ,
307+ Bridge : bridge ,
308+ Address : address ,
309+ Netmask : netmask ,
310+ }
311+
312+ network , err := networkManager .CreateNetwork (ctx , networkCfg )
313+ if err != nil {
314+ return err
315+ }
316+ //nolint:forbidigo // CLI output is intentional
317+ fmt .Printf ("Created network: %s (UUID: %s)\n " , network .Name , network .UUID )
318+ return nil
319+ },
320+ }
321+
322+ cmd .Flags ().StringVar (& name , "name" , config .DefaultNetworkName , "name of the network" )
323+ cmd .Flags ().StringVar (& bridge , "bridge" , config .DefaultNetworkBridge , "name of the bridge interface" )
324+ cmd .Flags ().StringVar (& address , "address" , config .DefaultNetworkAddress , "address of bridge" )
325+ cmd .Flags ().StringVar (& netmask , "netmask" , config .DefaultNetworkNetmask , "netmask for network" )
326+
327+ return cmd
328+ }
329+
252330func newDeleteCmd () * cobra.Command {
253331 cmd := & cobra.Command {
254332 Use : "delete" ,
@@ -258,6 +336,7 @@ func newDeleteCmd() *cobra.Command {
258336
259337 cmd .AddCommand (newDeleteVMCmd ())
260338 cmd .AddCommand (newDeleteBMLCmd ())
339+ cmd .AddCommand (newDeleteNetworkCmd ())
261340 return cmd
262341}
263342
@@ -344,8 +423,8 @@ func newDeleteBMLCmd() *cobra.Command {
344423
345424 //nolint:forbidigo // CLI output is intentional
346425 fmt .Printf ("Deleting bare metal lab (%d VMs)...\n " , len (names ))
347-
348- if err := vmManager . DeleteAll ( ctx , names , true ); err != nil {
426+ err = vmManager . DeleteAll ( ctx , names , true )
427+ if err != nil {
349428 return err
350429 }
351430
@@ -356,6 +435,70 @@ func newDeleteBMLCmd() *cobra.Command {
356435 fmt .Printf (" - %s\n " , name )
357436 }
358437
438+ networkManager , err := libvirt .NewNetworkManager (conn )
439+ if err != nil {
440+ return fmt .Errorf ("failed to create Network manager: %w" , err )
441+ }
442+
443+ networks := make ([]string , len (cfg .Spec .Networks ))
444+ for i , network := range cfg .Spec .Networks {
445+ networks [i ] = network .Name
446+ }
447+
448+ //nolint:forbidigo // CLI output is intentional
449+ fmt .Printf ("Deleting networks (%d networks)...\n " , len (networks ))
450+
451+ if err := networkManager .DeleteNetworks (ctx , networks ); err != nil {
452+ return err
453+ }
454+
455+ //nolint:forbidigo // CLI output is intentional
456+ fmt .Println ("Deleted networks:" )
457+ for _ , name := range networks {
458+ //nolint:forbidigo // CLI output is intentional
459+ fmt .Printf (" - %s\n " , name )
460+ }
461+
462+ return nil
463+ },
464+ }
465+
466+ return cmd
467+ }
468+
469+ func newDeleteNetworkCmd () * cobra.Command {
470+ cmd := & cobra.Command {
471+ Use : "network [name]" ,
472+ Short : "Delete a network" ,
473+ Args : cobra .ExactArgs (1 ),
474+ RunE : func (_ * cobra.Command , args []string ) error {
475+ ctx , cancel := contextWithSignal ()
476+ defer cancel ()
477+
478+ name := args [0 ]
479+
480+ cfg , err := loadConfig ()
481+ if err != nil {
482+ return err
483+ }
484+
485+ conn , err := libvirtgo .NewConnect (cfg .Spec .Libvirt .URI )
486+ if err != nil {
487+ return fmt .Errorf ("failed to connect to libvirt: %w" , err )
488+ }
489+ defer func () { _ , _ = conn .Close () }()
490+
491+ networkManager , err := libvirt .NewNetworkManager (conn )
492+ if err != nil {
493+ return fmt .Errorf ("failed to create Network manager: %w" , err )
494+ }
495+
496+ if err := networkManager .DeleteNetwork (ctx , name ); err != nil {
497+ return fmt .Errorf ("failed to delete network: %w" , err )
498+ }
499+
500+ //nolint:forbidigo // CLI output is intentional
501+ fmt .Printf ("Deleted network %s\n " , name )
359502 return nil
360503 },
361504 }
0 commit comments