github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/container/lxd/manager_test.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package lxd_test
     5  
     6  import (
     7  	"errors"
     8  	stdtesting "testing"
     9  
    10  	"github.com/golang/mock/gomock"
    11  	"github.com/juju/proxy"
    12  	jc "github.com/juju/testing/checkers"
    13  	"github.com/juju/version"
    14  	lxdclient "github.com/lxc/lxd/client"
    15  	lxdapi "github.com/lxc/lxd/shared/api"
    16  	gc "gopkg.in/check.v1"
    17  	"gopkg.in/juju/names.v2"
    18  
    19  	"github.com/juju/juju/api"
    20  	"github.com/juju/juju/cloudconfig/instancecfg"
    21  	"github.com/juju/juju/container"
    22  	"github.com/juju/juju/container/lxd"
    23  	lxdtesting "github.com/juju/juju/container/lxd/testing"
    24  	"github.com/juju/juju/core/constraints"
    25  	"github.com/juju/juju/core/status"
    26  	"github.com/juju/juju/environs/config"
    27  	"github.com/juju/juju/environs/context"
    28  	"github.com/juju/juju/network"
    29  	coretesting "github.com/juju/juju/testing"
    30  	coretools "github.com/juju/juju/tools"
    31  	"gopkg.in/juju/charm.v6"
    32  )
    33  
    34  func Test(t *stdtesting.T) {
    35  	gc.TestingT(t)
    36  }
    37  
    38  type managerSuite struct {
    39  	lxdtesting.BaseSuite
    40  }
    41  
    42  var _ = gc.Suite(&managerSuite{})
    43  
    44  func (s *managerSuite) patch(svr lxdclient.ImageServer) {
    45  	lxd.PatchConnectRemote(s, map[string]lxdclient.ImageServer{"cloud-images.ubuntu.com": svr})
    46  	lxd.PatchGenerateVirtualMACAddress(s)
    47  }
    48  
    49  func (s *managerSuite) makeManager(c *gc.C, svr lxdclient.ContainerServer) container.Manager {
    50  	return s.makeManagerForConfig(c, getBaseConfig(), svr)
    51  }
    52  
    53  func (s *managerSuite) makeManagerForConfig(
    54  	c *gc.C, cfg container.ManagerConfig, cSvr lxdclient.ContainerServer,
    55  ) container.Manager {
    56  	svr, err := lxd.NewServer(cSvr)
    57  	c.Assert(err, jc.ErrorIsNil)
    58  
    59  	manager, err := lxd.NewContainerManager(cfg, svr)
    60  	c.Assert(err, jc.ErrorIsNil)
    61  	return manager
    62  }
    63  
    64  func getBaseConfig() container.ManagerConfig {
    65  	return container.ManagerConfig{
    66  		container.ConfigModelUUID:        coretesting.ModelTag.Id(),
    67  		container.ConfigAvailabilityZone: "test-availability-zone",
    68  		config.ContainerImageStreamKey:   "released",
    69  	}
    70  }
    71  
    72  func prepInstanceConfig(c *gc.C) *instancecfg.InstanceConfig {
    73  	apiInfo := &api.Info{
    74  		Addrs:    []string{"127.0.0.1:1337"},
    75  		Password: "password",
    76  		Nonce:    "nonce",
    77  		Tag:      names.NewMachineTag("123"),
    78  		ModelTag: names.NewModelTag("3fe11b2c-ae46-4cd1-96ad-d34239f70daf"),
    79  		CACert:   "foo",
    80  	}
    81  	icfg, err := instancecfg.NewInstanceConfig(
    82  		names.NewControllerTag("4e29484b-4ff3-417f-97c3-09d1bec98d5b"),
    83  		"123",
    84  		"nonce",
    85  		"imagestream",
    86  		"xenial",
    87  		apiInfo,
    88  	)
    89  	c.Assert(err, jc.ErrorIsNil)
    90  	instancecfg.PopulateInstanceConfig(
    91  		icfg,
    92  		"lxd",
    93  		"",
    94  		false,
    95  		proxy.Settings{},
    96  		proxy.Settings{},
    97  		proxy.Settings{},
    98  		"",
    99  		false,
   100  		false,
   101  		nil,
   102  		nil,
   103  	)
   104  	list := coretools.List{
   105  		&coretools.Tools{Version: version.MustParseBinary("2.3.4-trusty-amd64")},
   106  	}
   107  	err = icfg.SetTools(list)
   108  	c.Assert(err, jc.ErrorIsNil)
   109  	return icfg
   110  }
   111  
   112  func prepNetworkConfig() *container.NetworkConfig {
   113  	return container.BridgeNetworkConfig("eth0", 1500, []network.InterfaceInfo{{
   114  		InterfaceName:       "eth0",
   115  		InterfaceType:       network.EthernetInterface,
   116  		ConfigType:          network.ConfigDHCP,
   117  		ParentInterfaceName: "eth0",
   118  	}})
   119  }
   120  
   121  func (s *managerSuite) TestContainerCreateDestroy(c *gc.C) {
   122  	ctrl := gomock.NewController(c)
   123  	defer ctrl.Finish()
   124  	cSvr := s.NewMockServer(ctrl)
   125  	s.patch(cSvr)
   126  
   127  	manager := s.makeManager(c, cSvr)
   128  	iCfg := prepInstanceConfig(c)
   129  	hostName, err := manager.Namespace().Hostname(iCfg.MachineId)
   130  	c.Assert(err, jc.ErrorIsNil)
   131  
   132  	// Operation arrangements.
   133  	startOp := lxdtesting.NewMockOperation(ctrl)
   134  	startOp.EXPECT().Wait().Return(nil)
   135  
   136  	stopOp := lxdtesting.NewMockOperation(ctrl)
   137  	stopOp.EXPECT().Wait().Return(nil)
   138  
   139  	deleteOp := lxdtesting.NewMockOperation(ctrl)
   140  	deleteOp.EXPECT().Wait().Return(nil)
   141  
   142  	exp := cSvr.EXPECT()
   143  
   144  	// Arrangements for the container creation.
   145  	expectCreateContainer(ctrl, cSvr, "juju/xenial/"+s.Arch(), "foo-target")
   146  	exp.UpdateContainerState(hostName, lxdapi.ContainerStatePut{Action: "start", Timeout: -1}, "").Return(startOp, nil)
   147  
   148  	exp.GetContainerState(hostName).Return(
   149  		&lxdapi.ContainerState{StatusCode: lxdapi.Running}, lxdtesting.ETag, nil).Times(2)
   150  
   151  	exp.GetContainer(hostName).Return(&lxdapi.Container{Name: hostName}, lxdtesting.ETag, nil)
   152  
   153  	// Arrangements for the container destruction.
   154  	stopReq := lxdapi.ContainerStatePut{
   155  		Action:   "stop",
   156  		Timeout:  -1,
   157  		Stateful: false,
   158  		Force:    true,
   159  	}
   160  	gomock.InOrder(
   161  		exp.UpdateContainerState(hostName, stopReq, lxdtesting.ETag).Return(stopOp, nil),
   162  		exp.DeleteContainer(hostName).Return(deleteOp, nil),
   163  	)
   164  
   165  	instance, hc, err := manager.CreateContainer(
   166  		iCfg, constraints.Value{}, "xenial", prepNetworkConfig(), &container.StorageConfig{}, lxdtesting.NoOpCallback,
   167  	)
   168  	c.Assert(err, jc.ErrorIsNil)
   169  
   170  	instanceId := instance.Id()
   171  	c.Check(string(instanceId), gc.Equals, hostName)
   172  
   173  	instanceStatus := instance.Status(context.NewCloudCallContext())
   174  	c.Check(instanceStatus.Status, gc.Equals, status.Running)
   175  	c.Check(*hc.AvailabilityZone, gc.Equals, "test-availability-zone")
   176  
   177  	err = manager.DestroyContainer(instanceId)
   178  	c.Assert(err, jc.ErrorIsNil)
   179  }
   180  
   181  func (s *managerSuite) TestContainerCreateUpdateIPv4Network(c *gc.C) {
   182  	ctrl := gomock.NewController(c)
   183  	defer ctrl.Finish()
   184  	cSvr := s.NewMockServerWithExtensions(ctrl, "network")
   185  	s.patch(cSvr)
   186  
   187  	manager := s.makeManager(c, cSvr)
   188  	iCfg := prepInstanceConfig(c)
   189  	hostName, err := manager.Namespace().Hostname(iCfg.MachineId)
   190  	c.Assert(err, jc.ErrorIsNil)
   191  
   192  	exp := cSvr.EXPECT()
   193  
   194  	req := lxdapi.NetworkPut{
   195  		Config: map[string]string{
   196  			"ipv4.address": "auto",
   197  			"ipv4.nat":     "true",
   198  		},
   199  	}
   200  	gomock.InOrder(
   201  		exp.GetNetwork(network.DefaultLXDBridge).Return(&lxdapi.Network{}, lxdtesting.ETag, nil),
   202  		exp.UpdateNetwork(network.DefaultLXDBridge, req, lxdtesting.ETag).Return(nil),
   203  	)
   204  
   205  	expectCreateContainer(ctrl, cSvr, "juju/xenial/"+s.Arch(), "foo-target")
   206  
   207  	startOp := lxdtesting.NewMockOperation(ctrl)
   208  	startOp.EXPECT().Wait().Return(nil)
   209  
   210  	exp.UpdateContainerState(hostName, lxdapi.ContainerStatePut{Action: "start", Timeout: -1}, "").Return(startOp, nil)
   211  	exp.GetContainer(hostName).Return(&lxdapi.Container{Name: hostName}, lxdtesting.ETag, nil)
   212  
   213  	// Supplying config for a single device with default bridge and without a
   214  	// CIDR will cause the default bridge to be updated with IPv4 config.
   215  	netConfig := container.BridgeNetworkConfig("eth0", 1500, []network.InterfaceInfo{{
   216  		InterfaceName:       "eth0",
   217  		InterfaceType:       network.EthernetInterface,
   218  		ConfigType:          network.ConfigDHCP,
   219  		ParentInterfaceName: network.DefaultLXDBridge,
   220  	}})
   221  	_, _, err = manager.CreateContainer(
   222  		iCfg, constraints.Value{}, "xenial", netConfig, &container.StorageConfig{}, lxdtesting.NoOpCallback,
   223  	)
   224  	c.Assert(err, jc.ErrorIsNil)
   225  }
   226  
   227  func (s *managerSuite) TestCreateContainerCreateFailed(c *gc.C) {
   228  	ctrl := gomock.NewController(c)
   229  	defer ctrl.Finish()
   230  	cSvr := s.NewMockServer(ctrl)
   231  
   232  	createRemoteOp := lxdtesting.NewMockRemoteOperation(ctrl)
   233  	createRemoteOp.EXPECT().Wait().Return(nil).AnyTimes()
   234  	createRemoteOp.EXPECT().GetTarget().Return(&lxdapi.Operation{StatusCode: lxdapi.Failure, Err: "create failed"}, nil)
   235  
   236  	exp := cSvr.EXPECT()
   237  
   238  	alias := &lxdapi.ImageAliasesEntry{ImageAliasesEntryPut: lxdapi.ImageAliasesEntryPut{Target: "foo-target"}}
   239  	image := lxdapi.Image{Filename: "this-is-our-image"}
   240  	gomock.InOrder(
   241  		exp.GetImageAlias("juju/xenial/"+s.Arch()).Return(alias, lxdtesting.ETag, nil),
   242  		exp.GetImage("foo-target").Return(&image, lxdtesting.ETag, nil),
   243  		exp.CreateContainerFromImage(cSvr, image, gomock.Any()).Return(createRemoteOp, nil),
   244  	)
   245  
   246  	_, _, err := s.makeManager(c, cSvr).CreateContainer(
   247  		prepInstanceConfig(c),
   248  		constraints.Value{},
   249  		"xenial",
   250  		prepNetworkConfig(),
   251  		&container.StorageConfig{},
   252  		lxdtesting.NoOpCallback,
   253  	)
   254  	c.Assert(err, gc.ErrorMatches, ".*create failed")
   255  }
   256  
   257  func (s *managerSuite) TestCreateContainerSpecCreationError(c *gc.C) {
   258  	ctrl := gomock.NewController(c)
   259  	defer ctrl.Finish()
   260  	cSvr := s.NewMockServer(ctrl)
   261  
   262  	// When the local image acquisition fails, this will cause the remote
   263  	// connection attempt to fail.
   264  	// This is our error condition exit from manager.getContainerSpec.
   265  	lxd.PatchConnectRemote(s, map[string]lxdclient.ImageServer{})
   266  
   267  	exp := cSvr.EXPECT()
   268  
   269  	alias := &lxdapi.ImageAliasesEntry{ImageAliasesEntryPut: lxdapi.ImageAliasesEntryPut{Target: "foo-target"}}
   270  	image := lxdapi.Image{Filename: "this-is-our-image"}
   271  	gomock.InOrder(
   272  		exp.GetImageAlias("juju/xenial/"+s.Arch()).Return(alias, lxdtesting.ETag, nil),
   273  		exp.GetImage("foo-target").Return(&image, lxdtesting.ETag, errors.New("not here")),
   274  	)
   275  
   276  	_, _, err := s.makeManager(c, cSvr).CreateContainer(
   277  		prepInstanceConfig(c),
   278  		constraints.Value{},
   279  		"xenial",
   280  		prepNetworkConfig(),
   281  		&container.StorageConfig{},
   282  		lxdtesting.NoOpCallback,
   283  	)
   284  	c.Assert(err, gc.ErrorMatches, ".*unrecognized remote server")
   285  }
   286  
   287  func (s *managerSuite) TestCreateContainerStartFailed(c *gc.C) {
   288  	ctrl := gomock.NewController(c)
   289  	defer ctrl.Finish()
   290  	cSvr := s.NewMockServer(ctrl)
   291  	s.patch(cSvr)
   292  
   293  	manager := s.makeManager(c, cSvr)
   294  	iCfg := prepInstanceConfig(c)
   295  	hostName, err := manager.Namespace().Hostname(iCfg.MachineId)
   296  	c.Assert(err, jc.ErrorIsNil)
   297  
   298  	updateOp := lxdtesting.NewMockOperation(ctrl)
   299  	updateOp.EXPECT().Wait().Return(errors.New("start failed"))
   300  
   301  	deleteOp := lxdtesting.NewMockOperation(ctrl)
   302  	deleteOp.EXPECT().Wait().Return(nil).AnyTimes()
   303  
   304  	exp := cSvr.EXPECT()
   305  
   306  	expectCreateContainer(ctrl, cSvr, "juju/xenial/"+s.Arch(), "foo-target")
   307  	gomock.InOrder(
   308  		exp.UpdateContainerState(
   309  			hostName, lxdapi.ContainerStatePut{Action: "start", Timeout: -1}, "").Return(updateOp, nil),
   310  		exp.GetContainerState(hostName).Return(&lxdapi.ContainerState{StatusCode: lxdapi.Stopped}, lxdtesting.ETag, nil),
   311  		exp.DeleteContainer(hostName).Return(deleteOp, nil),
   312  	)
   313  
   314  	_, _, err = manager.CreateContainer(
   315  		iCfg,
   316  		constraints.Value{},
   317  		"xenial",
   318  		prepNetworkConfig(),
   319  		&container.StorageConfig{},
   320  		lxdtesting.NoOpCallback,
   321  	)
   322  	c.Assert(err, gc.ErrorMatches, ".*start failed")
   323  }
   324  
   325  // expectCreateContainer is a convenience function for the expectations
   326  // concerning a successful container creation based on a cached local
   327  // image.
   328  func expectCreateContainer(ctrl *gomock.Controller, svr *lxdtesting.MockContainerServer, aliasName, target string) {
   329  	createRemoteOp := lxdtesting.NewMockRemoteOperation(ctrl)
   330  	createRemoteOp.EXPECT().Wait().Return(nil).AnyTimes()
   331  	createRemoteOp.EXPECT().GetTarget().Return(&lxdapi.Operation{StatusCode: lxdapi.Success}, nil)
   332  
   333  	exp := svr.EXPECT()
   334  
   335  	alias := &lxdapi.ImageAliasesEntry{ImageAliasesEntryPut: lxdapi.ImageAliasesEntryPut{Target: target}}
   336  	exp.GetImageAlias(aliasName).Return(alias, lxdtesting.ETag, nil)
   337  
   338  	image := lxdapi.Image{Filename: "this-is-our-image"}
   339  	exp.GetImage("foo-target").Return(&image, lxdtesting.ETag, nil)
   340  	exp.CreateContainerFromImage(svr, image, gomock.Any()).Return(createRemoteOp, nil)
   341  }
   342  
   343  func (s *managerSuite) TestListContainers(c *gc.C) {
   344  	ctrl := gomock.NewController(c)
   345  	defer ctrl.Finish()
   346  	cSvr := s.NewMockServer(ctrl)
   347  	manager := s.makeManager(c, cSvr)
   348  
   349  	prefix := manager.Namespace().Prefix()
   350  	wrongPrefix := prefix[:len(prefix)-1] + "j"
   351  
   352  	containers := []lxdapi.Container{
   353  		{Name: "foobar"},
   354  		{Name: "definitely-not-a-juju-container"},
   355  		{Name: wrongPrefix + "-0"},
   356  		{Name: prefix + "-0"},
   357  		{Name: "please-disperse"},
   358  		{Name: prefix + "-1"},
   359  		{Name: "nothing-to-see-here-please"},
   360  	}
   361  
   362  	cSvr.EXPECT().GetContainers().Return(containers, nil)
   363  
   364  	result, err := manager.ListContainers()
   365  	c.Assert(err, jc.ErrorIsNil)
   366  	c.Check(result, gc.HasLen, 2)
   367  	c.Check(string(result[0].Id()), gc.Equals, prefix+"-0")
   368  	c.Check(string(result[1].Id()), gc.Equals, prefix+"-1")
   369  }
   370  
   371  func (s *managerSuite) TestIsInitialized(c *gc.C) {
   372  	ctrl := gomock.NewController(c)
   373  	defer ctrl.Finish()
   374  	cSvr := s.NewMockServer(ctrl)
   375  
   376  	manager := s.makeManager(c, cSvr)
   377  	c.Check(manager.IsInitialized(), gc.Equals, true)
   378  }
   379  
   380  func (s *managerSuite) TestNetworkDevicesFromConfigWithEmptyParentDevice(c *gc.C) {
   381  	ctrl := gomock.NewController(c)
   382  	defer ctrl.Finish()
   383  	cSvr := s.NewMockServer(ctrl)
   384  
   385  	interfaces := []network.InterfaceInfo{{
   386  		InterfaceName: "eth1",
   387  		InterfaceType: "ethernet",
   388  		MACAddress:    "aa:bb:cc:dd:ee:f1",
   389  		MTU:           9000,
   390  	}}
   391  
   392  	result, _, err := lxd.NetworkDevicesFromConfig(s.makeManager(c, cSvr), &container.NetworkConfig{
   393  		Interfaces: interfaces,
   394  	})
   395  
   396  	c.Assert(err, gc.ErrorMatches, "parent interface name is empty")
   397  	c.Assert(result, gc.IsNil)
   398  }
   399  
   400  func (s *managerSuite) TestNetworkDevicesFromConfigWithParentDevice(c *gc.C) {
   401  	ctrl := gomock.NewController(c)
   402  	defer ctrl.Finish()
   403  	cSvr := s.NewMockServer(ctrl)
   404  
   405  	interfaces := []network.InterfaceInfo{{
   406  		ParentInterfaceName: "br-eth0",
   407  		InterfaceName:       "eth0",
   408  		InterfaceType:       "ethernet",
   409  		CIDR:                "10.10.0.0/24",
   410  		MACAddress:          "aa:bb:cc:dd:ee:f0",
   411  	}}
   412  
   413  	expected := map[string]map[string]string{
   414  		"eth0": {
   415  			"hwaddr":  "aa:bb:cc:dd:ee:f0",
   416  			"name":    "eth0",
   417  			"nictype": "bridged",
   418  			"parent":  "br-eth0",
   419  			"type":    "nic",
   420  		},
   421  	}
   422  
   423  	result, unknown, err := lxd.NetworkDevicesFromConfig(s.makeManager(c, cSvr), &container.NetworkConfig{
   424  		Device:     "lxdbr0",
   425  		Interfaces: interfaces,
   426  	})
   427  
   428  	c.Assert(err, jc.ErrorIsNil)
   429  	c.Check(result, jc.DeepEquals, expected)
   430  	c.Check(unknown, gc.HasLen, 0)
   431  }
   432  
   433  func (s *managerSuite) TestNetworkDevicesFromConfigUnknownCIDR(c *gc.C) {
   434  	ctrl := gomock.NewController(c)
   435  	defer ctrl.Finish()
   436  	cSvr := s.NewMockServer(ctrl)
   437  
   438  	interfaces := []network.InterfaceInfo{{
   439  		ParentInterfaceName: "br-eth0",
   440  		InterfaceName:       "eth0",
   441  		InterfaceType:       "ethernet",
   442  		MACAddress:          "aa:bb:cc:dd:ee:f0",
   443  	}}
   444  
   445  	_, unknown, err := lxd.NetworkDevicesFromConfig(s.makeManager(c, cSvr), &container.NetworkConfig{
   446  		Device:     "lxdbr0",
   447  		Interfaces: interfaces,
   448  	})
   449  
   450  	c.Assert(err, jc.ErrorIsNil)
   451  	c.Check(unknown, gc.DeepEquals, []string{"br-eth0"})
   452  }
   453  
   454  func (s *managerSuite) TestNetworkDevicesFromConfigNoInputGetsProfileNICs(c *gc.C) {
   455  	ctrl := gomock.NewController(c)
   456  	defer ctrl.Finish()
   457  	cSvr := s.NewMockServer(ctrl)
   458  	s.patch(cSvr)
   459  
   460  	cSvr.EXPECT().GetProfile("default").Return(defaultProfileWithNIC(), lxdtesting.ETag, nil)
   461  
   462  	result, _, err := lxd.NetworkDevicesFromConfig(s.makeManager(c, cSvr), &container.NetworkConfig{})
   463  	c.Assert(err, jc.ErrorIsNil)
   464  
   465  	exp := map[string]map[string]string{
   466  		"eth0": {
   467  			"parent":  network.DefaultLXDBridge,
   468  			"type":    "nic",
   469  			"nictype": "bridged",
   470  			"hwaddr":  "00:16:3e:00:00:00",
   471  		},
   472  	}
   473  
   474  	c.Check(result, gc.DeepEquals, exp)
   475  }
   476  
   477  func (s *managerSuite) TestGetImageSourcesDefaultConfig(c *gc.C) {
   478  	ctrl := gomock.NewController(c)
   479  	defer ctrl.Finish()
   480  	cSvr := s.NewMockServer(ctrl)
   481  
   482  	mgr := s.makeManager(c, cSvr)
   483  
   484  	sources, err := lxd.GetImageSources(mgr)
   485  	c.Assert(err, jc.ErrorIsNil)
   486  	c.Check(sources, gc.DeepEquals, []lxd.ServerSpec{lxd.CloudImagesRemote, lxd.CloudImagesDailyRemote})
   487  }
   488  
   489  func (s *managerSuite) TestGetImageSourcesNonStandardStreamDefaultConfig(c *gc.C) {
   490  	ctrl := gomock.NewController(c)
   491  	defer ctrl.Finish()
   492  	cSvr := s.NewMockServer(ctrl)
   493  
   494  	cfg := getBaseConfig()
   495  	cfg[config.ContainerImageStreamKey] = "nope"
   496  	mgr := s.makeManagerForConfig(c, cfg, cSvr)
   497  
   498  	sources, err := lxd.GetImageSources(mgr)
   499  	c.Assert(err, jc.ErrorIsNil)
   500  	c.Check(sources, gc.DeepEquals, []lxd.ServerSpec{lxd.CloudImagesRemote, lxd.CloudImagesDailyRemote})
   501  }
   502  
   503  func (s *managerSuite) TestGetImageSourcesDailyOnly(c *gc.C) {
   504  	ctrl := gomock.NewController(c)
   505  	defer ctrl.Finish()
   506  	cSvr := s.NewMockServer(ctrl)
   507  
   508  	cfg := getBaseConfig()
   509  	cfg[config.ContainerImageStreamKey] = "daily"
   510  	mgr := s.makeManagerForConfig(c, cfg, cSvr)
   511  
   512  	sources, err := lxd.GetImageSources(mgr)
   513  	c.Assert(err, jc.ErrorIsNil)
   514  	c.Check(sources, gc.DeepEquals, []lxd.ServerSpec{lxd.CloudImagesDailyRemote})
   515  }
   516  
   517  func (s *managerSuite) TestGetImageSourcesImageMetadataURLExpectedHTTPSSources(c *gc.C) {
   518  	ctrl := gomock.NewController(c)
   519  	defer ctrl.Finish()
   520  	cSvr := s.NewMockServer(ctrl)
   521  
   522  	cfg := getBaseConfig()
   523  	cfg[config.ContainerImageMetadataURLKey] = "http://special.container.sauce"
   524  	mgr := s.makeManagerForConfig(c, cfg, cSvr)
   525  
   526  	sources, err := lxd.GetImageSources(mgr)
   527  	c.Assert(err, jc.ErrorIsNil)
   528  
   529  	expectedSources := []lxd.ServerSpec{
   530  		{
   531  			Name:     "special.container.sauce",
   532  			Host:     "https://special.container.sauce",
   533  			Protocol: lxd.SimpleStreamsProtocol,
   534  		},
   535  		lxd.CloudImagesRemote,
   536  		lxd.CloudImagesDailyRemote,
   537  	}
   538  	c.Check(sources, gc.DeepEquals, expectedSources)
   539  }
   540  
   541  func (s *managerSuite) TestGetImageSourcesImageMetadataURLDailyStream(c *gc.C) {
   542  	ctrl := gomock.NewController(c)
   543  	defer ctrl.Finish()
   544  	cSvr := s.NewMockServer(ctrl)
   545  
   546  	cfg := getBaseConfig()
   547  	cfg[config.ContainerImageMetadataURLKey] = "http://special.container.sauce"
   548  	cfg[config.ContainerImageStreamKey] = "daily"
   549  	mgr := s.makeManagerForConfig(c, cfg, cSvr)
   550  
   551  	sources, err := lxd.GetImageSources(mgr)
   552  	c.Assert(err, jc.ErrorIsNil)
   553  
   554  	expectedSources := []lxd.ServerSpec{
   555  		{
   556  			Name:     "special.container.sauce",
   557  			Host:     "https://special.container.sauce",
   558  			Protocol: lxd.SimpleStreamsProtocol,
   559  		},
   560  		lxd.CloudImagesDailyRemote,
   561  	}
   562  	c.Check(sources, gc.DeepEquals, expectedSources)
   563  }
   564  
   565  func (s *managerSuite) TestMaybeWriteLXDProfile(c *gc.C) {
   566  	ctrl := gomock.NewController(c)
   567  	defer ctrl.Finish()
   568  	cSvr := s.NewMockServer(ctrl)
   569  
   570  	mgr := s.makeManager(c, cSvr)
   571  	proMgr, ok := mgr.(container.LXDProfileManager)
   572  	c.Assert(ok, jc.IsTrue)
   573  
   574  	put := charm.LXDProfile{
   575  		Config: map[string]string{
   576  			"security.nesting":    "true",
   577  			"security.privileged": "true",
   578  		},
   579  		Description: "lxd profile for testing",
   580  		Devices: map[string]map[string]string{
   581  			"tun": {
   582  				"path": "/dev/net/tun",
   583  				"type": "unix-char",
   584  			},
   585  		},
   586  	}
   587  	post := lxdapi.ProfilesPost{
   588  		ProfilePut: lxdapi.ProfilePut(put),
   589  		Name:       "juju-default-lxd-0",
   590  	}
   591  	cSvr.EXPECT().CreateProfile(post).Return(nil).Times(1)
   592  	cSvr.EXPECT().GetProfileNames().Return([]string{"default", "custom"}, nil).Times(1)
   593  
   594  	err := proMgr.MaybeWriteLXDProfile("juju-default-lxd-0", &put)
   595  	c.Assert(err, jc.ErrorIsNil)
   596  }
   597  
   598  func (s *managerSuite) TestReplaceOrAddInstanceProfile(c *gc.C) {
   599  	ctrl := gomock.NewController(c)
   600  	defer ctrl.Finish()
   601  	cSvr := s.NewMockServer(ctrl)
   602  	// Operation arrangements.
   603  	updateOp := lxdtesting.NewMockOperation(ctrl)
   604  	updateOp.EXPECT().Wait().Return(nil)
   605  	updateOp.EXPECT().Get().Return(lxdapi.Operation{Description: "Updating ontainer"})
   606  
   607  	instId := "testme"
   608  	old := "old-profile"
   609  	oldProfiles := []string{"default", "juju-default", old}
   610  	new := "new-profile"
   611  	newProfiles := []string{"default", "juju-default", new}
   612  	put := charm.LXDProfile{
   613  		Config: map[string]string{
   614  			"security.nesting": "true",
   615  		},
   616  		Description: "test profile",
   617  	}
   618  	post := lxdapi.ProfilesPost{
   619  		ProfilePut: lxdapi.ProfilePut(put),
   620  		Name:       new,
   621  	}
   622  	cExp := cSvr.EXPECT()
   623  	gomock.InOrder(
   624  		cExp.GetProfileNames().Return(oldProfiles, nil),
   625  		cExp.CreateProfile(post).Return(nil),
   626  		cExp.GetContainer(instId).Return(
   627  			&lxdapi.Container{
   628  				ContainerPut: lxdapi.ContainerPut{
   629  					Profiles: oldProfiles,
   630  				},
   631  			}, "", nil),
   632  		cExp.UpdateContainer(instId, gomock.Any(), gomock.Any()).Return(updateOp, nil),
   633  		cExp.DeleteProfile(old).Return(nil),
   634  		cExp.GetContainer(instId).Return(
   635  			&lxdapi.Container{
   636  				ContainerPut: lxdapi.ContainerPut{
   637  					Profiles: newProfiles,
   638  				},
   639  			}, "", nil),
   640  	)
   641  
   642  	mgr := s.makeManager(c, cSvr)
   643  	proMgr, ok := mgr.(container.LXDProfileManager)
   644  	c.Assert(ok, jc.IsTrue)
   645  
   646  	obtained, err := proMgr.ReplaceOrAddInstanceProfile(instId, old, new, &put)
   647  	c.Assert(err, jc.ErrorIsNil)
   648  	c.Assert(obtained, gc.DeepEquals, newProfiles)
   649  }