github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/service/agentconf_test.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // The test cases in this file do not pertain to a specific command.
     5  
     6  package service_test
     7  
     8  import (
     9  	"bytes"
    10  	"fmt"
    11  	"os"
    12  	"path"
    13  
    14  	"github.com/juju/errors"
    15  	jc "github.com/juju/testing/checkers"
    16  	"github.com/juju/utils/arch"
    17  	"github.com/juju/version"
    18  	gc "gopkg.in/check.v1"
    19  	"gopkg.in/juju/names.v2"
    20  
    21  	"github.com/juju/juju/agent"
    22  	agenttools "github.com/juju/juju/agent/tools"
    23  	agentcmd "github.com/juju/juju/cmd/jujud/agent"
    24  	"github.com/juju/juju/mongo"
    25  	"github.com/juju/juju/service"
    26  	"github.com/juju/juju/service/common"
    27  	svctesting "github.com/juju/juju/service/common/testing"
    28  	"github.com/juju/juju/service/systemd"
    29  	"github.com/juju/juju/testing"
    30  	coretest "github.com/juju/juju/tools"
    31  	jujuversion "github.com/juju/juju/version"
    32  )
    33  
    34  type agentConfSuite struct {
    35  	testing.BaseSuite
    36  
    37  	agentConf           agent.Config
    38  	dataDir             string
    39  	machineName         string
    40  	unitNames           []string
    41  	systemdDir          string
    42  	systemdMultiUserDir string
    43  	systemdDataDir      string // service.SystemdDataDir
    44  	manager             service.SystemdServiceManager
    45  
    46  	services    []*svctesting.FakeService
    47  	serviceData *svctesting.FakeServiceData
    48  }
    49  
    50  func (s *agentConfSuite) SetUpSuite(c *gc.C) {
    51  	s.BaseSuite.SetUpSuite(c)
    52  }
    53  
    54  func (s *agentConfSuite) SetUpTest(c *gc.C) {
    55  	s.BaseSuite.SetUpTest(c)
    56  
    57  	s.dataDir = c.MkDir()
    58  	s.systemdDir = path.Join(s.dataDir, "etc", "systemd", "system")
    59  	s.systemdMultiUserDir = path.Join(s.systemdDir, "multi-user.target.wants")
    60  	c.Assert(os.MkdirAll(s.systemdMultiUserDir, os.ModeDir|os.ModePerm), jc.ErrorIsNil)
    61  	s.systemdDataDir = path.Join(s.dataDir, "lib", "systemd", "system")
    62  
    63  	s.machineName = "machine-0"
    64  	s.unitNames = []string{"unit-ubuntu-0", "unit-mysql-0"}
    65  
    66  	s.manager = service.NewServiceManager(
    67  		func() bool { return true },
    68  		s.newService,
    69  	)
    70  
    71  	s.assertSetupAgentsForTest(c)
    72  	s.setUpAgentConf(c)
    73  	s.setUpServices(c)
    74  	s.services[0].ResetCalls()
    75  	s.setupTools(c, "trusty")
    76  }
    77  
    78  func (s *agentConfSuite) TearDownTest(c *gc.C) {
    79  	s.serviceData = nil
    80  	s.services = nil
    81  	s.BaseSuite.TearDownTest(c)
    82  }
    83  
    84  var _ = gc.Suite(&agentConfSuite{})
    85  
    86  func (s *agentConfSuite) setUpAgentConf(c *gc.C) {
    87  	// Required for CopyAgentBinaries to evaluate the version of the agent.
    88  	configParams := agent.AgentConfigParams{
    89  		Paths:             agent.Paths{DataDir: s.dataDir},
    90  		Tag:               names.NewMachineTag("0"),
    91  		UpgradedToVersion: jujuversion.Current,
    92  		APIAddresses:      []string{"localhost:17070"},
    93  		CACert:            testing.CACert,
    94  		Password:          "fake",
    95  		Controller:        testing.ControllerTag,
    96  		Model:             testing.ModelTag,
    97  		MongoVersion:      mongo.Mongo32wt,
    98  	}
    99  
   100  	agentConf, err := agent.NewAgentConfig(configParams)
   101  	c.Assert(err, jc.ErrorIsNil)
   102  
   103  	err = agentConf.Write()
   104  	c.Assert(err, jc.ErrorIsNil)
   105  
   106  	s.agentConf = agentConf
   107  }
   108  
   109  func (s *agentConfSuite) setUpServices(c *gc.C) {
   110  	for _, fake := range append(s.unitNames, s.machineName) {
   111  		s.addService(c, "jujud-"+fake)
   112  	}
   113  	s.PatchValue(&service.ListServices, s.listServices)
   114  }
   115  
   116  func (s *agentConfSuite) addService(c *gc.C, name string) {
   117  	svc, err := s.newService(name, common.Conf{})
   118  	c.Assert(err, jc.ErrorIsNil)
   119  	c.Assert(svc.Install(), jc.ErrorIsNil)
   120  	c.Assert(svc.Start(), jc.ErrorIsNil)
   121  }
   122  
   123  func (s *agentConfSuite) listServices() ([]string, error) {
   124  	return s.serviceData.InstalledNames(), nil
   125  }
   126  
   127  func (s *agentConfSuite) newService(name string, conf common.Conf) (service.Service, error) {
   128  	for _, svc := range s.services {
   129  		if svc.Name() == name {
   130  			return svc, nil
   131  		}
   132  	}
   133  	if s.serviceData == nil {
   134  		s.serviceData = svctesting.NewFakeServiceData()
   135  	}
   136  	svc := &svctesting.FakeService{
   137  		FakeServiceData: s.serviceData,
   138  		Service: common.Service{
   139  			Name: name,
   140  			Conf: common.Conf{},
   141  		},
   142  		DataDir: s.dataDir,
   143  	}
   144  	s.services = append(s.services, svc)
   145  	return svc, nil
   146  }
   147  
   148  func (s *agentConfSuite) setupTools(c *gc.C, series string) {
   149  	files := []*testing.TarFile{
   150  		testing.NewTarFile("jujud", 0755, "jujuc executable"),
   151  	}
   152  	data, checksum := testing.TarGz(files...)
   153  	testTools := &coretest.Tools{
   154  		URL: "http://foo/bar1",
   155  		Version: version.Binary{
   156  			Number: jujuversion.Current,
   157  			Arch:   arch.HostArch(),
   158  			Series: series,
   159  		},
   160  		Size:   int64(len(data)),
   161  		SHA256: checksum,
   162  	}
   163  	err := agenttools.UnpackTools(s.dataDir, testTools, bytes.NewReader(data))
   164  	c.Assert(err, jc.ErrorIsNil)
   165  }
   166  
   167  func (s *agentConfSuite) assertSetupAgentsForTest(c *gc.C) {
   168  	agentsDir := path.Join(s.dataDir, "agents")
   169  	err := os.MkdirAll(path.Join(agentsDir, s.machineName), os.ModeDir|os.ModePerm)
   170  	c.Assert(err, jc.ErrorIsNil)
   171  	for _, unit := range s.unitNames {
   172  		err = os.Mkdir(path.Join(agentsDir, unit), os.ModeDir|os.ModePerm)
   173  		c.Assert(err, jc.ErrorIsNil)
   174  	}
   175  }
   176  
   177  func (s *agentConfSuite) TestFindAgents(c *gc.C) {
   178  	machineAgent, unitAgents, errAgents, err := s.manager.FindAgents(s.dataDir)
   179  	c.Assert(err, jc.ErrorIsNil)
   180  
   181  	c.Assert(machineAgent, gc.Equals, s.machineName)
   182  	c.Assert(unitAgents, jc.SameContents, s.unitNames)
   183  	c.Assert(errAgents, gc.HasLen, 0)
   184  }
   185  
   186  func (s *agentConfSuite) TestFindAgentsUnexpectedTagType(c *gc.C) {
   187  	unexpectedAgent := names.NewApplicationTag("failme").String()
   188  	unexpectedAgentDir := path.Join(s.dataDir, "agents", unexpectedAgent)
   189  	err := os.MkdirAll(unexpectedAgentDir, os.ModeDir|os.ModePerm)
   190  	c.Assert(err, jc.ErrorIsNil)
   191  
   192  	machineAgent, unitAgents, unexpectedAgents, err := s.manager.FindAgents(s.dataDir)
   193  	c.Assert(err, jc.ErrorIsNil)
   194  	c.Assert(machineAgent, gc.Equals, s.machineName)
   195  	c.Assert(unitAgents, jc.SameContents, s.unitNames)
   196  	c.Assert(unexpectedAgents, gc.DeepEquals, []string{unexpectedAgent})
   197  }
   198  
   199  func (s *agentConfSuite) TestCreateAgentConfDesc(c *gc.C) {
   200  	conf, err := s.manager.CreateAgentConf("machine-2", s.dataDir)
   201  	c.Assert(err, jc.ErrorIsNil)
   202  	// Spot check Conf
   203  	c.Assert(conf.Desc, gc.Equals, "juju agent for machine-2")
   204  }
   205  
   206  func (s *agentConfSuite) TestCreateAgentConfLogPath(c *gc.C) {
   207  	conf, err := s.manager.CreateAgentConf("machine-2", s.dataDir)
   208  	c.Assert(err, jc.ErrorIsNil)
   209  	c.Assert(conf.Logfile, gc.Equals, "/var/log/juju/machine-2.log")
   210  }
   211  
   212  func (s *agentConfSuite) TestCreateAgentConfFailAgentKind(c *gc.C) {
   213  	_, err := s.manager.CreateAgentConf("application-fail", s.dataDir)
   214  	c.Assert(err, gc.ErrorMatches, `agent "application-fail" is neither a machine nor a unit`)
   215  }
   216  
   217  func (s *agentConfSuite) agentUnitNames() []string {
   218  	unitAgents := make([]string, len(s.unitNames))
   219  	for i, name := range s.unitNames {
   220  		unitAgents[i] = "jujud-" + name
   221  	}
   222  	return unitAgents
   223  }
   224  
   225  func (s *agentConfSuite) TestStartAllAgents(c *gc.C) {
   226  	machineAgent, unitAgents, err := s.manager.StartAllAgents(s.machineName, s.unitNames, s.dataDir)
   227  	c.Assert(err, jc.ErrorIsNil)
   228  	c.Assert(machineAgent, gc.Equals, "jujud-"+s.machineName)
   229  	c.Assert(unitAgents, jc.SameContents, s.agentUnitNames())
   230  	s.assertServicesCalls(c, "Start", len(s.services))
   231  }
   232  
   233  func (s *agentConfSuite) TestStartAllAgentsFailSecondUnit(c *gc.C) {
   234  	s.services[0].SetErrors(
   235  		nil,
   236  		errors.New("fail me"),
   237  	)
   238  
   239  	machineAgent, unitAgents, err := s.manager.StartAllAgents(s.machineName, s.unitNames, s.dataDir)
   240  	c.Assert(err, gc.ErrorMatches, "failed to start jujud-unit-.* service: fail me")
   241  	c.Assert(machineAgent, gc.Equals, "")
   242  	c.Assert(unitAgents, gc.HasLen, 1)
   243  	s.assertServicesCalls(c, "Start", 2)
   244  }
   245  
   246  func (s *agentConfSuite) TestStartAllAgentsFailMachine(c *gc.C) {
   247  	s.services[0].SetErrors(
   248  		nil,
   249  		nil,
   250  		errors.New("fail me"),
   251  	)
   252  
   253  	machineAgent, unitAgents, err := s.manager.StartAllAgents(s.machineName, s.unitNames, s.dataDir)
   254  	c.Assert(err, gc.ErrorMatches, fmt.Sprintf("failed to start jujud-%s service: fail me", s.machineName))
   255  	c.Assert(machineAgent, gc.Equals, "")
   256  	c.Assert(unitAgents, jc.SameContents, s.agentUnitNames())
   257  	s.assertServicesCalls(c, "Start", len(s.services))
   258  }
   259  
   260  func (s *agentConfSuite) TestStartAllAgentsSystemdNotRunning(c *gc.C) {
   261  	s.manager = service.NewServiceManager(
   262  		func() bool { return false },
   263  		s.newService,
   264  	)
   265  
   266  	_, _, err := s.manager.StartAllAgents(s.machineName, s.unitNames, s.dataDir)
   267  	c.Assert(err, gc.ErrorMatches, "cannot interact with systemd; reboot to start agents")
   268  	s.assertServicesCalls(c, "Start", 0)
   269  }
   270  
   271  func (s *agentConfSuite) TestCopyAgentBinaryIdempotent(c *gc.C) {
   272  	jujuVersion, err := agentcmd.GetJujuVersion(s.machineName, s.dataDir)
   273  	c.Assert(err, jc.ErrorIsNil)
   274  
   275  	err = s.manager.CopyAgentBinary(s.machineName, s.unitNames, s.dataDir, "xenial", "trusty", jujuVersion)
   276  	c.Assert(err, jc.ErrorIsNil)
   277  	s.assertToolsCopySymlink(c, "xenial")
   278  
   279  	err = s.manager.CopyAgentBinary(s.machineName, s.unitNames, s.dataDir, "xenial", "trusty", jujuVersion)
   280  	c.Assert(err, jc.ErrorIsNil)
   281  	s.assertToolsCopySymlink(c, "xenial")
   282  }
   283  
   284  func (s *agentConfSuite) TestCopyAgentBinaryOriginalAgentBinariesNotFound(c *gc.C) {
   285  	jujuVersion, err := agentcmd.GetJujuVersion(s.machineName, s.dataDir)
   286  	c.Assert(err, jc.ErrorIsNil)
   287  
   288  	err = s.manager.CopyAgentBinary(s.machineName, s.unitNames, s.dataDir, "xenial", "xenial", jujuVersion)
   289  	c.Assert(err, gc.ErrorMatches, "failed to copy tools: .* no such file or directory")
   290  }
   291  
   292  func (s *agentConfSuite) TestWriteSystemdAgents(c *gc.C) {
   293  	startedSymLinkAgents, startedSysServiceNames, errAgents, err := s.manager.WriteSystemdAgents(
   294  		s.machineName, s.unitNames, s.systemdDataDir, s.systemdDir, s.systemdMultiUserDir)
   295  
   296  	c.Assert(err, jc.ErrorIsNil)
   297  	c.Assert(startedSysServiceNames, gc.HasLen, 0)
   298  	c.Assert(startedSymLinkAgents, gc.DeepEquals, append(s.agentUnitNames(), "jujud-"+s.machineName))
   299  	c.Assert(errAgents, gc.HasLen, 0)
   300  	s.assertServicesCalls(c, "WriteService", len(s.services))
   301  }
   302  
   303  func (s *agentConfSuite) TestWriteSystemdAgentsSystemdNotRunning(c *gc.C) {
   304  	s.manager = service.NewServiceManager(
   305  		func() bool { return false },
   306  		s.newService,
   307  	)
   308  
   309  	startedSymLinkAgents, startedSysServiceNames, errAgents, err := s.manager.WriteSystemdAgents(
   310  		s.machineName, s.unitNames, s.systemdDataDir, s.systemdDir, s.systemdMultiUserDir)
   311  
   312  	c.Assert(err, jc.ErrorIsNil)
   313  	c.Assert(startedSymLinkAgents, gc.HasLen, 0)
   314  	c.Assert(startedSysServiceNames, gc.DeepEquals, append(s.agentUnitNames(), "jujud-"+s.machineName))
   315  	c.Assert(errAgents, gc.HasLen, 0)
   316  	s.assertServicesCalls(c, "WriteService", len(s.services))
   317  	s.assertServiceSymLinks(c)
   318  }
   319  
   320  func (s *agentConfSuite) TestWriteSystemdAgentsDBusErrManualLink(c *gc.C) {
   321  	s.services[0].SetErrors(
   322  		errors.New("No such method 'LinkUnitFiles'"),
   323  		errors.New("No such method 'LinkUnitFiles'"),
   324  		errors.New("No such method 'LinkUnitFiles'"),
   325  	)
   326  
   327  	startedSymLinkAgents, startedSysServiceNames, errAgents, err := s.manager.WriteSystemdAgents(
   328  		s.machineName, s.unitNames, s.systemdDataDir, s.systemdDir, s.systemdMultiUserDir)
   329  
   330  	c.Assert(err, jc.ErrorIsNil)
   331  
   332  	// This exhibits the same characteristics as for Systemd not running (above).
   333  	c.Assert(startedSymLinkAgents, gc.HasLen, 0)
   334  	c.Assert(startedSysServiceNames, gc.DeepEquals, append(s.agentUnitNames(), "jujud-"+s.machineName))
   335  	c.Assert(errAgents, gc.HasLen, 0)
   336  	s.assertServicesCalls(c, "WriteService", len(s.services))
   337  }
   338  
   339  func (s *agentConfSuite) TestWriteSystemdAgentsWriteServiceFail(c *gc.C) {
   340  	s.services[0].SetErrors(
   341  		nil,
   342  		nil,
   343  		errors.New("fail me"), // fail the machine
   344  	)
   345  
   346  	startedSymLinkAgents, startedSysServiceNames, errAgents, err := s.manager.WriteSystemdAgents(
   347  		s.machineName, s.unitNames, s.systemdDataDir, s.systemdDir, s.systemdMultiUserDir)
   348  
   349  	c.Assert(err, gc.ErrorMatches, "fail me")
   350  	c.Assert(startedSysServiceNames, gc.HasLen, 0)
   351  	c.Assert(startedSymLinkAgents, gc.DeepEquals, s.agentUnitNames())
   352  	c.Assert(errAgents, gc.DeepEquals, []string{s.machineName})
   353  	s.assertServicesCalls(c, "WriteService", len(s.services))
   354  }
   355  
   356  func (s *agentConfSuite) assertToolsCopySymlink(c *gc.C, series string) {
   357  	// Check tools changes
   358  	ver := version.Binary{
   359  		Number: jujuversion.Current,
   360  		Arch:   arch.HostArch(),
   361  		Series: series,
   362  	}
   363  	jujuTools, err := agenttools.ReadTools(s.dataDir, ver)
   364  	c.Assert(err, jc.ErrorIsNil)
   365  	c.Assert(jujuTools.Version, gc.DeepEquals, ver)
   366  
   367  	for _, name := range append(s.unitNames, s.machineName) {
   368  		link := path.Join(s.dataDir, "tools", name)
   369  		linkResult, err := os.Readlink(link)
   370  		c.Assert(err, jc.ErrorIsNil)
   371  		c.Assert(linkResult, gc.Equals, path.Join(s.dataDir, "tools", ver.String()))
   372  	}
   373  }
   374  
   375  func (s *agentConfSuite) assertServiceSymLinks(c *gc.C) {
   376  	for _, name := range append(s.unitNames, s.machineName) {
   377  		svcName := "jujud-" + name
   378  		svcFileName := svcName + ".service"
   379  		result, err := os.Readlink(path.Join(s.systemdDir, svcFileName))
   380  		c.Assert(err, jc.ErrorIsNil)
   381  		c.Assert(result, gc.Equals, path.Join(systemd.LibSystemdDir, svcName, svcFileName))
   382  	}
   383  }
   384  
   385  func (s *agentConfSuite) assertServicesCalls(c *gc.C, svc string, expectedCnt int) {
   386  	// Call list shared by the services
   387  	calls := s.services[0].Calls()
   388  	serviceCount := 0
   389  	for _, call := range calls {
   390  		if call.FuncName == svc {
   391  			serviceCount += 1
   392  		}
   393  	}
   394  	c.Assert(serviceCount, gc.Equals, expectedCnt)
   395  }