Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamically discover init system in the cloudinit script. #2359

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
28 changes: 10 additions & 18 deletions cloudconfig/instancecfg/instancecfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net"
"path"
"strconv"
"strings"

"github.com/juju/errors"
"github.com/juju/loggo"
Expand All @@ -28,7 +29,6 @@ import (
"github.com/juju/juju/juju/paths"
"github.com/juju/juju/mongo"
"github.com/juju/juju/service"
"github.com/juju/juju/service/common"
"github.com/juju/juju/state/multiwatcher"
coretools "github.com/juju/juju/tools"
"github.com/juju/juju/version"
Expand Down Expand Up @@ -184,25 +184,17 @@ func (cfg *InstanceConfig) ToolsDir(renderer shell.Renderer) string {
return cfg.agentInfo().ToolsDir(renderer)
}

func (cfg *InstanceConfig) InitService(renderer shell.Renderer) (service.Service, error) {
conf := service.AgentConf(cfg.agentInfo(), renderer)

// MachineAgentCommands returns the list of commands to install and
// start the machine agent service for the instance.
func (cfg *InstanceConfig) MachineAgentCommands(renderer shell.Renderer) ([]string, error) {
name := cfg.MachineAgentServiceName
initSystem, ok := cfg.initSystem()
if !ok {
return nil, errors.New("could not identify init system")
conf := service.AgentConf(cfg.agentInfo(), renderer)
osName := strings.ToLower(cfg.Tools.Version.OS.String())
cmds, err := service.InstallServiceCommands(name, conf, osName)
if err != nil {
return nil, errors.Annotatef(err, "cannot make cloud-init init script for the %s agent", name)
}
logger.Debugf("using init system %q for machine agent script", initSystem)
svc, err := newService(name, conf, initSystem)
return svc, errors.Trace(err)
}

func (cfg *InstanceConfig) initSystem() (string, bool) {
return service.VersionInitSystem(cfg.Tools.Version)
}

var newService = func(name string, conf common.Conf, initSystem string) (service.Service, error) {
return service.NewService(name, conf, initSystem)
return cmds, nil
}

func (cfg *InstanceConfig) AgentConfig(
Expand Down
13 changes: 1 addition & 12 deletions cloudconfig/userdatacfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func (c *baseConfigure) addAgentInfo(tag names.Tag) (agent.Config, error) {
}

func (c *baseConfigure) addMachineAgentToBoot() error {
svc, err := c.icfg.InitService(c.conf.ShellRenderer())
cmds, err := c.icfg.MachineAgentCommands(c.conf.ShellRenderer())
if err != nil {
return errors.Trace(err)
}
Expand All @@ -107,17 +107,6 @@ func (c *baseConfigure) addMachineAgentToBoot() error {
toolsDir := c.icfg.ToolsDir(c.conf.ShellRenderer())
c.conf.AddScripts(c.toolsSymlinkCommand(toolsDir))

name := c.tag.String()
cmds, err := svc.InstallCommands()
if err != nil {
return errors.Annotatef(err, "cannot make cloud-init init script for the %s agent", name)
}
startCmds, err := svc.StartCommands()
if err != nil {
return errors.Annotatef(err, "cannot make cloud-init init script for the %s agent", name)
}
cmds = append(cmds, startCmds...)

svcName := c.icfg.MachineAgentServiceName
// TODO (gsamfira): This is temporary until we find a cleaner way to fix
// cloudinit.LogProgressCmd to not add >&9 on Windows.
Expand Down
12 changes: 6 additions & 6 deletions cloudconfig/userdatacfg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,8 @@ echo 'Bootstrapping Juju machine agent'.*
/var/lib/juju/tools/1\.2\.3-precise-amd64/jujud bootstrap-state --data-dir '/var/lib/juju' --env-config '[^']*' --instance-id 'i-bootstrap' --constraints 'mem=2048M' --debug
ln -s 1\.2\.3-precise-amd64 '/var/lib/juju/tools/machine-0'
echo 'Starting Juju machine agent \(jujud-machine-0\)'.*
cat > /etc/init/jujud-machine-0\.conf << 'EOF'\\ndescription "juju agent for machine-0"\\nauthor "Juju Team <juju@lists\.ubuntu\.com>"\\nstart on runlevel \[2345\]\\nstop on runlevel \[!2345\]\\nrespawn\\nnormal exit 0\\n\\nlimit nofile 20000 20000\\n\\nscript\\n\\n\\n # Ensure log files are properly protected\\n touch /var/log/juju/machine-0\.log\\n chown syslog:syslog /var/log/juju/machine-0\.log\\n chmod 0600 /var/log/juju/machine-0\.log\\n\\n exec '/var/lib/juju/tools/machine-0/jujud' machine --data-dir '/var/lib/juju' --machine-id 0 --debug >> /var/log/juju/machine-0\.log 2>&1\\nend script\\nEOF\\n
start jujud-machine-0
init_system=\$\(.*\)
case "\$init_system" in.*
rm \$bin/tools\.tar\.gz && rm \$bin/juju1\.2\.3-precise-amd64\.sha256
`,
}, {
Expand Down Expand Up @@ -339,8 +339,8 @@ cat > '/var/lib/juju/agents/machine-99/agent\.conf' << 'EOF'\\n.*\\nEOF
chmod 0600 '/var/lib/juju/agents/machine-99/agent\.conf'
ln -s 1\.2\.3-quantal-amd64 '/var/lib/juju/tools/machine-99'
echo 'Starting Juju machine agent \(jujud-machine-99\)'.*
cat > /etc/init/jujud-machine-99\.conf << 'EOF'\\ndescription "juju agent for machine-99"\\nauthor "Juju Team <juju@lists\.ubuntu\.com>"\\nstart on runlevel \[2345\]\\nstop on runlevel \[!2345\]\\nrespawn\\nnormal exit 0\\n\\nlimit nofile 20000 20000\\n\\nscript\\n\\n\\n # Ensure log files are properly protected\\n touch /var/log/juju/machine-99\.log\\n chown syslog:syslog /var/log/juju/machine-99\.log\\n chmod 0600 /var/log/juju/machine-99\.log\\n\\n exec '/var/lib/juju/tools/machine-99/jujud' machine --data-dir '/var/lib/juju' --machine-id 99 --debug >> /var/log/juju/machine-99\.log 2>&1\\nend script\\nEOF\\n
start jujud-machine-99
init_system=\$\(.*\)
case "\$init_system" in.*
rm \$bin/tools\.tar\.gz && rm \$bin/juju1\.2\.3-quantal-amd64\.sha256
`,
}, {
Expand Down Expand Up @@ -382,8 +382,8 @@ mkdir -p '/var/lib/juju/agents/machine-2-lxc-1'
cat > '/var/lib/juju/agents/machine-2-lxc-1/agent\.conf' << 'EOF'\\n.*\\nEOF
chmod 0600 '/var/lib/juju/agents/machine-2-lxc-1/agent\.conf'
ln -s 1\.2\.3-quantal-amd64 '/var/lib/juju/tools/machine-2-lxc-1'
cat > /etc/init/jujud-machine-2-lxc-1\.conf << 'EOF'\\ndescription "juju agent for machine-2-lxc-1"\\nauthor "Juju Team <juju@lists\.ubuntu\.com>"\\nstart on runlevel \[2345\]\\nstop on runlevel \[!2345\]\\nrespawn\\nnormal exit 0\\n\\nlimit nofile 20000 20000\\n\\nscript\\n\\n\\n # Ensure log files are properly protected\\n touch /var/log/juju/machine-2-lxc-1\.log\\n chown syslog:syslog /var/log/juju/machine-2-lxc-1\.log\\n chmod 0600 /var/log/juju/machine-2-lxc-1\.log\\n\\n exec '/var/lib/juju/tools/machine-2-lxc-1/jujud' machine --data-dir '/var/lib/juju' --machine-id 2/lxc/1 --debug >> /var/log/juju/machine-2-lxc-1\.log 2>&1\\nend script\\nEOF\\n
start jujud-machine-2-lxc-1
init_system=\$\(.*\)
case "\$init_system" in.*
`,
}, {
// hostname verification disabled.
Expand Down
4 changes: 2 additions & 2 deletions container/lxc/lxc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -651,8 +651,8 @@ func (s *LxcSuite) TestCreateContainer(c *gc.C) {
scripts = append(scripts, s.(string))
}

c.Assert(scripts[len(scripts)-3:], gc.DeepEquals, []string{
"start jujud-machine-1-lxc-0",
c.Assert(scripts[len(scripts)-3], jc.HasPrefix, `case "$init_system" in`)
c.Assert(scripts[len(scripts)-2:], gc.DeepEquals, []string{
"rm $bin/tools.tar.gz && rm $bin/juju2.3.4-quantal-amd64.sha256",
"ifconfig",
})
Expand Down
53 changes: 53 additions & 0 deletions service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,59 @@ func listServicesCommand(initSystem string) (string, bool) {
}
}

// InstallServicesCommand composes the list of shell commands that install
// and start the given service on the given operating system.
func InstallServiceCommands(name string, conf common.Conf, os string) ([]string, error) {
if os == "windows" {
cmds, err := installCommands(name, conf, InitSystemWindows)
if err != nil {
return nil, errors.Trace(err)
}
return cmds, nil
}

candidates := make(map[string]string)
for _, initSystem := range linuxInitSystems {
cmds, err := installCommands(name, conf, initSystem)
if err != nil {
return nil, errors.Trace(err)
}
candidates[initSystem] = "\n " + strings.Join(cmds, "\n ")
}

handler := func(initSystem string) (string, bool) {
if cmds, ok := candidates[initSystem]; ok {
return cmds, true
}
return "", false
}
script := newShellSelectCommand("init_system", "exit 1", handler)
cmds := []string{
"init_system=$(" + DiscoverInitSystemScript() + ")",
script,
}
return cmds, nil
}

func installCommands(name string, conf common.Conf, initSystem string) ([]string, error) {
svc, err := NewService(name, conf, initSystem)
if err != nil {
return nil, errors.Trace(err)
}

cmds, err := svc.InstallCommands()
if err != nil {
return nil, errors.Trace(err)
}
// Return here if we want to only install (i.e. skip starting).

startCmds, err := svc.StartCommands()
if err != nil {
return nil, errors.Trace(err)
}
return append(cmds, startCmds...), nil
}

// installStartRetryAttempts defines how much InstallAndStart retries
// upon Start failures.
var installStartRetryAttempts = utils.AttemptStrategy{
Expand Down
25 changes: 25 additions & 0 deletions service/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,31 @@ func (*serviceSuite) TestListServicesScript(c *gc.C) {
c.Check(strings.Split(script, "\n"), jc.DeepEquals, expected)
}

func (s *serviceSuite) TestInstallServiceCommandsLinux(c *gc.C) {
cmds, err := service.InstallServiceCommands(s.Name, s.Conf, "ubuntu")
c.Assert(err, jc.ErrorIsNil)

c.Check(cmds, gc.HasLen, 2)
c.Check(cmds[0], jc.HasPrefix, "init_system=$(")
c.Check(cmds[1], jc.HasPrefix, "case \"$init_system\" in\nsystemd)\n")
c.Check(cmds[1], jc.Contains, "systemctl start")
c.Check(cmds[1], jc.Contains, "\nupstart)\n")
c.Check(cmds[1], jc.Contains, "start juju-agent-machine-0")
c.Check(cmds[1], gc.Not(jc.Contains), "windows")
}

func (s *serviceSuite) TestInstallServiceCommandsWindows(c *gc.C) {
cmds, err := service.InstallServiceCommands(s.Name, s.Conf, "windows")
c.Assert(err, jc.ErrorIsNil)

c.Check(cmds, gc.HasLen, 3)
for i := 0; i < 3; i++ {
c.Check(cmds[i], jc.Contains, "juju-agent-machine-0")
}
c.Check(cmds[0], jc.HasPrefix, "New-Service")
c.Check(cmds[2], jc.HasPrefix, "Start-Service")
}

func (s *serviceSuite) TestInstallAndStartOkay(c *gc.C) {
s.PatchAttempts(5)

Expand Down