github.com/juju/juju@v0.0.0-20240327075706-a90865de2538/container/lxd/network_test.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package lxd_test
     5  
     6  import (
     7  	"errors"
     8  
     9  	lxdapi "github.com/canonical/lxd/shared/api"
    10  	jc "github.com/juju/testing/checkers"
    11  	"go.uber.org/mock/gomock"
    12  	gc "gopkg.in/check.v1"
    13  
    14  	"github.com/juju/juju/container/lxd"
    15  	lxdtesting "github.com/juju/juju/container/lxd/testing"
    16  	corenetwork "github.com/juju/juju/core/network"
    17  	"github.com/juju/juju/network"
    18  )
    19  
    20  type networkSuite struct {
    21  	lxdtesting.BaseSuite
    22  }
    23  
    24  var _ = gc.Suite(&networkSuite{})
    25  
    26  func (s *networkSuite) patch() {
    27  	lxd.PatchGenerateVirtualMACAddress(s)
    28  }
    29  
    30  func defaultProfileWithNIC() *lxdapi.Profile {
    31  	return &lxdapi.Profile{
    32  		Name: "default",
    33  		ProfilePut: lxdapi.ProfilePut{
    34  			Devices: map[string]map[string]string{
    35  				"eth0": {
    36  					"network": network.DefaultLXDBridge,
    37  					"type":    "nic",
    38  				},
    39  			},
    40  		},
    41  	}
    42  }
    43  
    44  func defaultLegacyProfileWithNIC() *lxdapi.Profile {
    45  	return &lxdapi.Profile{
    46  		Name: "default",
    47  		ProfilePut: lxdapi.ProfilePut{
    48  			Devices: map[string]map[string]string{
    49  				"eth0": {
    50  					"parent":  network.DefaultLXDBridge,
    51  					"type":    "nic",
    52  					"nictype": "bridged",
    53  				},
    54  			},
    55  		},
    56  	}
    57  }
    58  
    59  func (s *networkSuite) TestEnsureIPv4NoChange(c *gc.C) {
    60  	ctrl := gomock.NewController(c)
    61  	defer ctrl.Finish()
    62  	cSvr := s.NewMockServerWithExtensions(ctrl, "network")
    63  
    64  	net := &lxdapi.Network{
    65  		NetworkPut: lxdapi.NetworkPut{
    66  			Config: map[string]string{
    67  				"ipv4.address": "10.5.3.1",
    68  			},
    69  		},
    70  	}
    71  	cSvr.EXPECT().GetNetwork("some-net-name").Return(net, lxdtesting.ETag, nil)
    72  
    73  	jujuSvr, err := lxd.NewServer(cSvr)
    74  	c.Assert(err, jc.ErrorIsNil)
    75  
    76  	mod, err := jujuSvr.EnsureIPv4("some-net-name")
    77  	c.Assert(err, jc.ErrorIsNil)
    78  	c.Check(mod, jc.IsFalse)
    79  }
    80  
    81  func (s *networkSuite) TestEnsureIPv4Modified(c *gc.C) {
    82  	ctrl := gomock.NewController(c)
    83  	defer ctrl.Finish()
    84  	cSvr := s.NewMockServerWithExtensions(ctrl, "network")
    85  
    86  	req := lxdapi.NetworkPut{
    87  		Config: map[string]string{
    88  			"ipv4.address": "auto",
    89  			"ipv4.nat":     "true",
    90  		},
    91  	}
    92  	gomock.InOrder(
    93  		cSvr.EXPECT().GetNetwork(network.DefaultLXDBridge).Return(&lxdapi.Network{}, lxdtesting.ETag, nil),
    94  		cSvr.EXPECT().UpdateNetwork(network.DefaultLXDBridge, req, lxdtesting.ETag).Return(nil),
    95  	)
    96  
    97  	jujuSvr, err := lxd.NewServer(cSvr)
    98  	c.Assert(err, jc.ErrorIsNil)
    99  
   100  	mod, err := jujuSvr.EnsureIPv4(network.DefaultLXDBridge)
   101  	c.Assert(err, jc.ErrorIsNil)
   102  	c.Check(mod, jc.IsTrue)
   103  }
   104  
   105  func (s *networkSuite) TestGetNICsFromProfile(c *gc.C) {
   106  	lxd.PatchGenerateVirtualMACAddress(s)
   107  
   108  	ctrl := gomock.NewController(c)
   109  	defer ctrl.Finish()
   110  	cSvr := s.NewMockServer(ctrl)
   111  
   112  	cSvr.EXPECT().GetProfile("default").Return(defaultLegacyProfileWithNIC(), lxdtesting.ETag, nil)
   113  
   114  	jujuSvr, err := lxd.NewServer(cSvr)
   115  	c.Assert(err, jc.ErrorIsNil)
   116  
   117  	nics, err := jujuSvr.GetNICsFromProfile("default")
   118  	c.Assert(err, jc.ErrorIsNil)
   119  
   120  	exp := map[string]map[string]string{
   121  		"eth0": {
   122  			"parent":  network.DefaultLXDBridge,
   123  			"type":    "nic",
   124  			"nictype": "bridged",
   125  			"hwaddr":  "00:16:3e:00:00:00",
   126  		},
   127  	}
   128  
   129  	c.Check(nics, gc.DeepEquals, exp)
   130  }
   131  
   132  func (s *networkSuite) TestVerifyNetworkDevicePresentValid(c *gc.C) {
   133  	ctrl := gomock.NewController(c)
   134  	defer ctrl.Finish()
   135  	cSvr := s.NewMockServerWithExtensions(ctrl, "network")
   136  
   137  	net := &lxdapi.Network{
   138  		Name:    network.DefaultLXDBridge,
   139  		Managed: true,
   140  		Type:    "bridge",
   141  	}
   142  	cSvr.EXPECT().GetNetwork(network.DefaultLXDBridge).Return(net, "", nil)
   143  
   144  	jujuSvr, err := lxd.NewServer(cSvr)
   145  	c.Assert(err, jc.ErrorIsNil)
   146  
   147  	err = jujuSvr.VerifyNetworkDevice(defaultProfileWithNIC(), "")
   148  	c.Assert(err, jc.ErrorIsNil)
   149  }
   150  
   151  func (s *networkSuite) TestVerifyNetworkDevicePresentValidLegacy(c *gc.C) {
   152  	ctrl := gomock.NewController(c)
   153  	defer ctrl.Finish()
   154  	cSvr := s.NewMockServerWithExtensions(ctrl, "network")
   155  
   156  	cSvr.EXPECT().GetNetwork(network.DefaultLXDBridge).Return(&lxdapi.Network{}, "", nil)
   157  
   158  	jujuSvr, err := lxd.NewServer(cSvr)
   159  	c.Assert(err, jc.ErrorIsNil)
   160  
   161  	err = jujuSvr.VerifyNetworkDevice(defaultLegacyProfileWithNIC(), "")
   162  	c.Assert(err, jc.ErrorIsNil)
   163  }
   164  
   165  func (s *networkSuite) TestVerifyNetworkDeviceMultipleNICsOneValid(c *gc.C) {
   166  	ctrl := gomock.NewController(c)
   167  	defer ctrl.Finish()
   168  	cSvr := s.NewMockServerClustered(ctrl, "cluster-1")
   169  
   170  	profile := defaultLegacyProfileWithNIC()
   171  	profile.Devices["eno1"] = profile.Devices["eth0"]
   172  	profile.Devices["eno1"]["parent"] = "valid-net"
   173  
   174  	net := &lxdapi.Network{
   175  		Name:    network.DefaultLXDBridge,
   176  		Managed: true,
   177  		NetworkPut: lxdapi.NetworkPut{
   178  			Config: map[string]string{
   179  				"ipv6.address": "something-not-nothing",
   180  			},
   181  		},
   182  	}
   183  
   184  	// Random map iteration may or may not cause this call to be made.
   185  	cSvr.EXPECT().GetNetwork(network.DefaultLXDBridge).Return(net, "", nil).MaxTimes(1)
   186  	cSvr.EXPECT().GetNetwork("valid-net").Return(&lxdapi.Network{}, "", nil)
   187  
   188  	jujuSvr, err := lxd.NewServer(cSvr)
   189  	c.Assert(err, jc.ErrorIsNil)
   190  
   191  	err = jujuSvr.VerifyNetworkDevice(profile, "")
   192  	c.Assert(err, jc.ErrorIsNil)
   193  
   194  	c.Check(jujuSvr.LocalBridgeName(), gc.Equals, "valid-net")
   195  }
   196  
   197  func (s *networkSuite) TestVerifyNetworkDevicePresentBadNicType(c *gc.C) {
   198  	ctrl := gomock.NewController(c)
   199  	defer ctrl.Finish()
   200  	cSvr := s.NewMockServerWithExtensions(ctrl, "network")
   201  
   202  	profile := defaultLegacyProfileWithNIC()
   203  	profile.Devices["eth0"]["nictype"] = "not-bridge-or-macvlan"
   204  
   205  	net := &lxdapi.Network{
   206  		Name:    network.DefaultLXDBridge,
   207  		Managed: true,
   208  		Type:    "not-bridge-or-macvlan",
   209  	}
   210  	cSvr.EXPECT().GetNetwork(network.DefaultLXDBridge).Return(net, "", nil)
   211  
   212  	jujuSvr, err := lxd.NewServer(cSvr)
   213  	c.Assert(err, jc.ErrorIsNil)
   214  
   215  	err = jujuSvr.VerifyNetworkDevice(profile, "")
   216  	c.Assert(err, gc.ErrorMatches,
   217  		`profile "default": no network device found with nictype "bridged" or "macvlan"\n`+
   218  			`\tthe following devices were checked: eth0\n`+
   219  			`Reconfigure lxd to use a network of type "bridged" or "macvlan".`)
   220  }
   221  
   222  // Juju used to fail when IPv6 was enabled on the lxd network. This test now
   223  // checks regression to make sure that we know longer fail.
   224  func (s *networkSuite) TestVerifyNetworkDeviceIPv6PresentNoFail(c *gc.C) {
   225  	ctrl := gomock.NewController(c)
   226  	defer ctrl.Finish()
   227  	cSvr := s.NewMockServerWithExtensions(ctrl, "network")
   228  
   229  	net := &lxdapi.Network{
   230  		Name:    network.DefaultLXDBridge,
   231  		Managed: true,
   232  		NetworkPut: lxdapi.NetworkPut{
   233  			Config: map[string]string{
   234  				"ipv6.address": "2001:DB8::1",
   235  			},
   236  		},
   237  	}
   238  	cSvr.EXPECT().GetNetwork(network.DefaultLXDBridge).Return(net, "", nil)
   239  
   240  	jujuSvr, err := lxd.NewServer(cSvr)
   241  	c.Assert(err, jc.ErrorIsNil)
   242  
   243  	err = jujuSvr.VerifyNetworkDevice(defaultLegacyProfileWithNIC(), "")
   244  	c.Assert(err, jc.ErrorIsNil)
   245  }
   246  
   247  func (s *networkSuite) TestVerifyNetworkDeviceNotPresentCreated(c *gc.C) {
   248  	s.patch()
   249  
   250  	ctrl := gomock.NewController(c)
   251  	defer ctrl.Finish()
   252  	cSvr := s.NewMockServerWithExtensions(ctrl, "network")
   253  
   254  	netConf := map[string]string{
   255  		"ipv4.address": "auto",
   256  		"ipv4.nat":     "true",
   257  		"ipv6.address": "none",
   258  		"ipv6.nat":     "false",
   259  	}
   260  	netCreateReq := lxdapi.NetworksPost{
   261  		Name:       network.DefaultLXDBridge,
   262  		Type:       "bridge",
   263  		NetworkPut: lxdapi.NetworkPut{Config: netConf},
   264  	}
   265  	newNet := &lxdapi.Network{
   266  		Name:       network.DefaultLXDBridge,
   267  		Type:       "bridge",
   268  		Managed:    true,
   269  		NetworkPut: lxdapi.NetworkPut{Config: netConf},
   270  	}
   271  	gomock.InOrder(
   272  		cSvr.EXPECT().GetNetwork(network.DefaultLXDBridge).Return(nil, "", errors.New("network not found")),
   273  		cSvr.EXPECT().CreateNetwork(netCreateReq).Return(nil),
   274  		cSvr.EXPECT().GetNetwork(network.DefaultLXDBridge).Return(newNet, "", nil),
   275  		cSvr.EXPECT().UpdateProfile("default", defaultLegacyProfileWithNIC().Writable(), lxdtesting.ETag).Return(nil),
   276  	)
   277  
   278  	profile := defaultLegacyProfileWithNIC()
   279  	delete(profile.Devices, "eth0")
   280  
   281  	jujuSvr, err := lxd.NewServer(cSvr)
   282  	c.Assert(err, jc.ErrorIsNil)
   283  
   284  	err = jujuSvr.VerifyNetworkDevice(profile, lxdtesting.ETag)
   285  	c.Assert(err, jc.ErrorIsNil)
   286  }
   287  
   288  func (s *networkSuite) TestVerifyNetworkDeviceNotPresentNoNetAPIError(c *gc.C) {
   289  	s.patch()
   290  
   291  	ctrl := gomock.NewController(c)
   292  	defer ctrl.Finish()
   293  	cSvr := s.NewMockServer(ctrl)
   294  
   295  	jujuSvr, err := lxd.NewServer(cSvr)
   296  	c.Assert(err, jc.ErrorIsNil)
   297  
   298  	profile := defaultLegacyProfileWithNIC()
   299  	delete(profile.Devices, "eth0")
   300  
   301  	err = jujuSvr.VerifyNetworkDevice(profile, lxdtesting.ETag)
   302  	c.Assert(err, gc.ErrorMatches, `profile "default" does not have any devices configured with type "nic"`)
   303  }
   304  
   305  func (s *networkSuite) TestVerifyNetworkDevicePresentNoNetAPIError(c *gc.C) {
   306  	s.patch()
   307  
   308  	ctrl := gomock.NewController(c)
   309  	defer ctrl.Finish()
   310  	cSvr := s.NewMockServer(ctrl)
   311  
   312  	jujuSvr, err := lxd.NewServer(cSvr)
   313  	c.Assert(err, jc.ErrorIsNil)
   314  
   315  	profile := defaultLegacyProfileWithNIC()
   316  
   317  	err = jujuSvr.VerifyNetworkDevice(profile, lxdtesting.ETag)
   318  	c.Assert(err, gc.ErrorMatches, "versions of LXD without network API not supported")
   319  }
   320  
   321  func (s *networkSuite) TestVerifyNetworkDeviceNotPresentCreatedWithUnusedName(c *gc.C) {
   322  	s.patch()
   323  
   324  	ctrl := gomock.NewController(c)
   325  	defer ctrl.Finish()
   326  	cSvr := s.NewMockServerWithExtensions(ctrl, "network")
   327  
   328  	defaultBridge := &lxdapi.Network{
   329  		Name:    network.DefaultLXDBridge,
   330  		Type:    "bridge",
   331  		Managed: true,
   332  		NetworkPut: lxdapi.NetworkPut{
   333  			Config: map[string]string{
   334  				"ipv4.address": "auto",
   335  				"ipv4.nat":     "true",
   336  				"ipv6.address": "none",
   337  				"ipv6.nat":     "false",
   338  			},
   339  		},
   340  	}
   341  	devReq := lxdapi.ProfilePut{
   342  		Devices: map[string]map[string]string{
   343  			"eth0": {},
   344  			"eth1": {},
   345  			// eth2 will be generated as the first unused device name.
   346  			"eth2": {
   347  				"parent":  network.DefaultLXDBridge,
   348  				"type":    "nic",
   349  				"nictype": "bridged",
   350  			},
   351  		},
   352  	}
   353  	gomock.InOrder(
   354  		cSvr.EXPECT().GetNetwork(network.DefaultLXDBridge).Return(defaultBridge, "", nil),
   355  		cSvr.EXPECT().UpdateProfile("default", devReq, lxdtesting.ETag).Return(nil),
   356  	)
   357  
   358  	profile := defaultLegacyProfileWithNIC()
   359  	profile.Devices["eth0"] = map[string]string{}
   360  	profile.Devices["eth1"] = map[string]string{}
   361  
   362  	jujuSvr, err := lxd.NewServer(cSvr)
   363  	c.Assert(err, jc.ErrorIsNil)
   364  
   365  	err = jujuSvr.VerifyNetworkDevice(profile, lxdtesting.ETag)
   366  	c.Assert(err, jc.ErrorIsNil)
   367  }
   368  
   369  func (s *networkSuite) TestVerifyNetworkDeviceNotPresentErrorForCluster(c *gc.C) {
   370  	ctrl := gomock.NewController(c)
   371  	defer ctrl.Finish()
   372  	cSvr := s.NewMockServerClustered(ctrl, "cluster-1")
   373  
   374  	profile := defaultLegacyProfileWithNIC()
   375  	delete(profile.Devices, "eth0")
   376  
   377  	jujuSvr, err := lxd.NewServer(cSvr)
   378  	c.Assert(err, jc.ErrorIsNil)
   379  
   380  	err = jujuSvr.VerifyNetworkDevice(profile, lxdtesting.ETag)
   381  	c.Assert(err, gc.ErrorMatches, `profile "default" does not have any devices configured with type "nic"`)
   382  }
   383  
   384  func (s *networkSuite) TestInterfaceInfoFromDevices(c *gc.C) {
   385  	nics := map[string]map[string]string{
   386  		"eth0": {
   387  			"parent":  network.DefaultLXDBridge,
   388  			"type":    "nic",
   389  			"nictype": "bridged",
   390  			"hwaddr":  "00:16:3e:00:00:00",
   391  		},
   392  		"eno9": {
   393  			"parent":  "br1",
   394  			"type":    "nic",
   395  			"nictype": "macvlan",
   396  			"hwaddr":  "00:16:3e:00:00:3e",
   397  		},
   398  	}
   399  
   400  	info, err := lxd.InterfaceInfoFromDevices(nics)
   401  	c.Assert(err, jc.ErrorIsNil)
   402  
   403  	exp := corenetwork.InterfaceInfos{
   404  		{
   405  			InterfaceName:       "eno9",
   406  			MACAddress:          "00:16:3e:00:00:3e",
   407  			ConfigType:          corenetwork.ConfigDHCP,
   408  			ParentInterfaceName: "br1",
   409  			Origin:              corenetwork.OriginProvider,
   410  		},
   411  		{
   412  			InterfaceName:       "eth0",
   413  			MACAddress:          "00:16:3e:00:00:00",
   414  			ConfigType:          corenetwork.ConfigDHCP,
   415  			ParentInterfaceName: network.DefaultLXDBridge,
   416  			Origin:              corenetwork.OriginProvider,
   417  		},
   418  	}
   419  	c.Check(info, jc.DeepEquals, exp)
   420  }
   421  
   422  func (s *networkSuite) TestEnableHTTPSListener(c *gc.C) {
   423  	ctrl := gomock.NewController(c)
   424  	defer ctrl.Finish()
   425  
   426  	cfg := &lxdapi.Server{}
   427  	cSvr := lxdtesting.NewMockInstanceServer(ctrl)
   428  
   429  	gomock.InOrder(
   430  		cSvr.EXPECT().GetServer().Return(cfg, lxdtesting.ETag, nil).Times(2),
   431  		cSvr.EXPECT().UpdateServer(lxdapi.ServerPut{
   432  			Config: map[string]interface{}{
   433  				"core.https_address": "[::]",
   434  			},
   435  		}, lxdtesting.ETag).Return(nil),
   436  	)
   437  
   438  	jujuSvr, err := lxd.NewServer(cSvr)
   439  	c.Assert(err, jc.ErrorIsNil)
   440  
   441  	err = jujuSvr.EnableHTTPSListener()
   442  	c.Assert(err, jc.ErrorIsNil)
   443  }
   444  
   445  func (s *networkSuite) TestEnableHTTPSListenerWithFallbackToIPv4(c *gc.C) {
   446  	ctrl := gomock.NewController(c)
   447  	defer ctrl.Finish()
   448  
   449  	cfg := &lxdapi.Server{}
   450  	cSvr := lxdtesting.NewMockInstanceServer(ctrl)
   451  
   452  	gomock.InOrder(
   453  		cSvr.EXPECT().GetServer().Return(cfg, lxdtesting.ETag, nil).Times(2),
   454  		cSvr.EXPECT().UpdateServer(lxdapi.ServerPut{
   455  			Config: map[string]interface{}{
   456  				"core.https_address": "[::]",
   457  			},
   458  		}, lxdtesting.ETag).Return(errors.New(lxd.ErrIPV6NotSupported)),
   459  		cSvr.EXPECT().GetServer().Return(cfg, lxdtesting.ETag, nil),
   460  		cSvr.EXPECT().UpdateServer(lxdapi.ServerPut{
   461  			Config: map[string]interface{}{
   462  				"core.https_address": "0.0.0.0",
   463  			},
   464  		}, lxdtesting.ETag).Return(nil),
   465  	)
   466  
   467  	jujuSvr, err := lxd.NewServer(cSvr)
   468  	c.Assert(err, jc.ErrorIsNil)
   469  
   470  	err = jujuSvr.EnableHTTPSListener()
   471  	c.Assert(err, jc.ErrorIsNil)
   472  }
   473  
   474  func (s *networkSuite) TestEnableHTTPSListenerWithErrors(c *gc.C) {
   475  	ctrl := gomock.NewController(c)
   476  	defer ctrl.Finish()
   477  
   478  	cfg := &lxdapi.Server{}
   479  	cSvr := lxdtesting.NewMockInstanceServer(ctrl)
   480  
   481  	cSvr.EXPECT().GetServer().Return(cfg, lxdtesting.ETag, nil)
   482  
   483  	jujuSvr, err := lxd.NewServer(cSvr)
   484  	c.Assert(err, jc.ErrorIsNil)
   485  
   486  	// check on the first request
   487  	cSvr.EXPECT().GetServer().Return(cfg, lxdtesting.ETag, errors.New("bad"))
   488  
   489  	err = jujuSvr.EnableHTTPSListener()
   490  	c.Assert(err, gc.ErrorMatches, "bad")
   491  
   492  	// check on the second request
   493  	gomock.InOrder(
   494  		cSvr.EXPECT().GetServer().Return(cfg, lxdtesting.ETag, nil),
   495  		cSvr.EXPECT().UpdateServer(lxdapi.ServerPut{
   496  			Config: map[string]interface{}{
   497  				"core.https_address": "[::]",
   498  			},
   499  		}, lxdtesting.ETag).Return(errors.New(lxd.ErrIPV6NotSupported)),
   500  		cSvr.EXPECT().GetServer().Return(cfg, lxdtesting.ETag, errors.New("bad")),
   501  	)
   502  
   503  	err = jujuSvr.EnableHTTPSListener()
   504  	c.Assert(err, gc.ErrorMatches, "bad")
   505  
   506  	// check on the third request
   507  	gomock.InOrder(
   508  		cSvr.EXPECT().GetServer().Return(cfg, lxdtesting.ETag, nil),
   509  		cSvr.EXPECT().UpdateServer(lxdapi.ServerPut{
   510  			Config: map[string]interface{}{
   511  				"core.https_address": "[::]",
   512  			},
   513  		}, lxdtesting.ETag).Return(errors.New(lxd.ErrIPV6NotSupported)),
   514  		cSvr.EXPECT().GetServer().Return(cfg, lxdtesting.ETag, nil),
   515  		cSvr.EXPECT().UpdateServer(lxdapi.ServerPut{
   516  			Config: map[string]interface{}{
   517  				"core.https_address": "0.0.0.0",
   518  			},
   519  		}, lxdtesting.ETag).Return(errors.New("bad")),
   520  	)
   521  
   522  	err = jujuSvr.EnableHTTPSListener()
   523  	c.Assert(err, gc.ErrorMatches, "bad")
   524  }
   525  
   526  func (s *networkSuite) TestNewNICDeviceWithoutMACAddressOrMTUGreaterThanZero(c *gc.C) {
   527  	device := lxd.NewNICDevice("eth1", "br-eth1", "", 0)
   528  	expected := map[string]string{
   529  		"name":    "eth1",
   530  		"nictype": "bridged",
   531  		"parent":  "br-eth1",
   532  		"type":    "nic",
   533  	}
   534  	c.Assert(device, gc.DeepEquals, expected)
   535  }
   536  
   537  func (s *networkSuite) TestNewNICDeviceWithMACAddressButNoMTU(c *gc.C) {
   538  	device := lxd.NewNICDevice("eth1", "br-eth1", "aa:bb:cc:dd:ee:f0", 0)
   539  	expected := map[string]string{
   540  		"hwaddr":  "aa:bb:cc:dd:ee:f0",
   541  		"name":    "eth1",
   542  		"nictype": "bridged",
   543  		"parent":  "br-eth1",
   544  		"type":    "nic",
   545  	}
   546  	c.Assert(device, gc.DeepEquals, expected)
   547  }
   548  
   549  func (s *networkSuite) TestNewNICDeviceWithoutMACAddressButMTUGreaterThanZero(c *gc.C) {
   550  	device := lxd.NewNICDevice("eth1", "br-eth1", "", 1492)
   551  	expected := map[string]string{
   552  		"mtu":     "1492",
   553  		"name":    "eth1",
   554  		"nictype": "bridged",
   555  		"parent":  "br-eth1",
   556  		"type":    "nic",
   557  	}
   558  	c.Assert(device, gc.DeepEquals, expected)
   559  }
   560  
   561  func (s *networkSuite) TestNewNICDeviceWithMACAddressAndMTUGreaterThanZero(c *gc.C) {
   562  	device := lxd.NewNICDevice("eth1", "br-eth1", "aa:bb:cc:dd:ee:f0", 9000)
   563  	expected := map[string]string{
   564  		"hwaddr":  "aa:bb:cc:dd:ee:f0",
   565  		"mtu":     "9000",
   566  		"name":    "eth1",
   567  		"nictype": "bridged",
   568  		"parent":  "br-eth1",
   569  		"type":    "nic",
   570  	}
   571  	c.Assert(device, gc.DeepEquals, expected)
   572  }