func (s *discoverySuite) TestNewShellSelectCommandPosix(c *gc.C) { if runtime.GOOS == "windows" { c.Skip("not supported on windows") } discoveryScript := service.DiscoverInitSystemScript() handler := func(initSystem string) (string, bool) { return "echo -n " + initSystem, true } script := "init_system=$(" + discoveryScript + ")\n" // The script will fail with exit 1 if it cannot match in init system. script += service.NewShellSelectCommand("init_system", "exit 1", handler) commands, filename := s.writeScript(c, "test_shell_select.sh", script) commands += "sh " + filename response, err := exec.RunCommands(exec.RunParams{ Commands: script, }) c.Assert(err, jc.ErrorIsNil) initSystem, err := service.DiscoverInitSystem() c.Assert(err, jc.ErrorIsNil) c.Check(response.Code, gc.Equals, 0) c.Check(string(response.Stdout), gc.Equals, initSystem) c.Check(string(response.Stderr), gc.Equals, "") }
func (c *RunCommand) executeNoContext() (*exec.ExecResponse, error) { // Acquire the uniter hook execution lock to make sure we don't // stomp on each other. spec := mutex.Spec{ Name: c.MachineLockName, Clock: clock.WallClock, Delay: 250 * time.Millisecond, } logger.Debugf("acquire lock %q for juju-run", c.MachineLockName) releaser, err := mutex.Acquire(spec) if err != nil { return nil, errors.Trace(err) } logger.Debugf("lock %q acquired", c.MachineLockName) // Defer the logging first so it is executed after the Release. LIFO. defer logger.Debugf("release lock %q for juju-run", c.MachineLockName) defer releaser.Release() runCmd := c.appendProxyToCommands() return exec.RunCommands( exec.RunParams{ Commands: runCmd, }) }
func (w *MachineEnvironmentWorker) writeEnvironmentFile() error { // Writing the environment file is handled by executing the script for two // primary reasons: // // 1: In order to have the local provider specify the environment settings // for the machine agent running on the host, this worker needs to run, // but it shouldn't be touching any files on the disk. If however there is // an ubuntu user, it will. This shouldn't be a problem. // // 2: On cloud-instance ubuntu images, the ubuntu user is uid 1000, but in // the situation where the ubuntu user has been created as a part of the // manual provisioning process, the user will exist, and will not have the // same uid/gid as the default cloud image. // // It is easier to shell out to check both these things, and is also the // same way that the file is written in the cloud-init process, so // consistency FTW. filePath := path.Join(ProxyDirectory, ProxyFile) result, err := exec.RunCommands(exec.RunParams{ Commands: fmt.Sprintf( `[ -e %s ] && (printf '%%s\n' %s > %s && chown ubuntu:ubuntu %s)`, ProxyDirectory, utils.ShQuote(w.proxy.AsScriptEnvironment()), filePath, filePath), WorkingDir: ProxyDirectory, }) if err != nil { return err } if result.Code != 0 { logger.Errorf("failed writing new proxy values: \n%s\n%s", result.Stdout, result.Stderr) } return nil }
func (w *proxyWorker) writeEnvironmentToRegistry() error { // On windows we write the proxy settings to the registry. setProxyScript := `$value_path = "%s" $new_proxy = "%s" $proxy_val = Get-ItemProperty -Path $value_path -Name ProxySettings if ($? -eq $false){ New-ItemProperty -Path $value_path -Name ProxySettings -PropertyType String -Value $new_proxy }else{ Set-ItemProperty -Path $value_path -Name ProxySettings -Value $new_proxy } ` if w.config.RegistryPath == "" { err := fmt.Errorf("config.RegistryPath is empty") logger.Errorf("writeEnvironmentToRegistry couldn't write proxy settings to registry: %s", err) return err } result, err := exec.RunCommands(exec.RunParams{ Commands: fmt.Sprintf( setProxyScript, w.config.RegistryPath, w.proxy.Http), }) if err != nil { return err } if result.Code != 0 { logger.Errorf("failed writing new proxy values: \n%s\n%s", result.Stdout, result.Stderr) } return nil }
func (w *proxyWorker) writeEnvironmentFile() error { // Writing the environment file is handled by executing the script: // // On cloud-instance ubuntu images, the ubuntu user is uid 1000, but in // the situation where the ubuntu user has been created as a part of the // manual provisioning process, the user will exist, and will not have the // same uid/gid as the default cloud image. // // It is easier to shell out to check, and is also the same way that the file // is written in the cloud-init process, so consistency FTW. filePath := path.Join(w.config.Directory, w.config.Filename) result, err := exec.RunCommands(exec.RunParams{ Commands: fmt.Sprintf( `[ -e %s ] && (printf '%%s\n' %s > %s && chown ubuntu:ubuntu %s)`, w.config.Directory, utils.ShQuote(w.proxy.AsScriptEnvironment()), filePath, filePath), WorkingDir: w.config.Directory, }) if err != nil { return err } if result.Code != 0 { logger.Errorf("failed writing new proxy values: \n%s\n%s", result.Stdout, result.Stderr) } return nil }
// RunCommands executes the commands in an environment which allows it to to // call back into the hook context to execute jujuc tools. func (ctx *HookContext) RunCommands(commands, charmDir, toolsDir, socketPath string) (*utilexec.ExecResponse, error) { env := ctx.hookVars(charmDir, toolsDir, socketPath) result, err := utilexec.RunCommands( utilexec.RunParams{ Commands: commands, WorkingDir: charmDir, Environment: env}) return result, ctx.finalizeContext("run commands", err) }
func (*execSuite) TestExecUnknownCommand(c *gc.C) { result, err := exec.RunCommands( exec.RunParams{ Commands: "unknown-command", }, ) c.Assert(err, gc.IsNil) c.Assert(result.Stdout, gc.HasLen, 0) c.Assert(string(result.Stderr), jc.Contains, "unknown-command: command not found") // 127 is a special bash return code meaning command not found. c.Assert(result.Code, gc.Equals, 127) }
func (*execSuite) TestExecUnknownCommand(c *gc.C) { result, err := exec.RunCommands( exec.RunParams{ Commands: "unknown-command", }, ) c.Assert(err, gc.IsNil) c.Assert(result.Stdout, gc.HasLen, 0) c.Assert(string(result.Stderr), jc.Contains, "is not recognized as the name of a cmdlet") // 1 is returned by RunCommands when powershell commands throw exceptions c.Assert(result.Code, gc.Equals, 1) }
func runPsCommand(cmd string) (*exec.ExecResponse, error) { com := exec.RunParams{ Commands: cmd, } out, err := exec.RunCommands(com) if err != nil { return nil, err } if out.Code != 0 { return nil, fmt.Errorf("Error running %s: %s", cmd, string(out.Stderr)) } return out, nil }
func windowsListServices() ([]string, error) { com := exec.RunParams{ Commands: `(Get-Service).Name`, } out, err := exec.RunCommands(com) if err != nil { return nil, err } if out.Code != 0 { return nil, fmt.Errorf("Error running %s: %s", com.Commands, string(out.Stderr)) } return strings.Fields(string(out.Stdout)), nil }
func (*execSuite) TestRunCommands(c *gc.C) { newDir, err := longPathAsString(c.MkDir()) c.Assert(err, gc.IsNil) for i, test := range []struct { message string commands string workingDir string environment []string stdout string stderr string code int }{ { message: "test stdout capture", commands: "echo 'testing stdout'", stdout: "testing stdout\r\n", }, { message: "test stderr capture", commands: "Write-Error 'testing stderr'", stderr: "testing stderr\r\n", }, { message: "test return code", commands: "exit 42", code: 42, }, { message: "test working dir", commands: "(pwd).Path", workingDir: newDir, stdout: filepath.FromSlash(newDir) + "\r\n", }, { message: "test environment", commands: "echo $env:OMG_IT_WORKS", environment: []string{"OMG_IT_WORKS=like magic"}, stdout: "like magic\r\n", }, } { c.Logf("%v: %s", i, test.message) result, err := exec.RunCommands( exec.RunParams{ Commands: test.commands, WorkingDir: test.workingDir, Environment: test.environment, }) c.Assert(err, gc.IsNil) c.Assert(string(result.Stdout), gc.Equals, test.stdout) c.Assert(string(result.Stderr), jc.Contains, test.stderr) c.Assert(result.Code, gc.Equals, test.code) } }
func (*execSuite) TestRunCommands(c *gc.C) { newDir := c.MkDir() for i, test := range []struct { message string commands string workingDir string environment []string stdout string stderr string code int }{ { message: "test stdout capture", commands: "echo testing stdout", stdout: "testing stdout\n", }, { message: "test stderr capture", commands: "echo testing stderr >&2", stderr: "testing stderr\n", }, { message: "test return code", commands: "exit 42", code: 42, }, { message: "test working dir", commands: "pwd", workingDir: newDir, stdout: newDir + "\n", }, { message: "test environment", commands: "echo $OMG_IT_WORKS", environment: []string{"OMG_IT_WORKS=like magic"}, stdout: "like magic\n", }, } { c.Logf("%v: %s", i, test.message) result, err := exec.RunCommands( exec.RunParams{ Commands: test.commands, WorkingDir: test.workingDir, Environment: test.environment, }) c.Assert(err, gc.IsNil) c.Assert(string(result.Stdout), gc.Equals, test.stdout) c.Assert(string(result.Stderr), gc.Equals, test.stderr) c.Assert(result.Code, gc.Equals, test.code) } }
func (s *discoverySuite) TestDiscoverInitSystemScriptPosix(c *gc.C) { if runtime.GOOS == "windows" { c.Skip("not supported on windows") } script, filename := s.newDiscoverInitSystemScript(c) script += "sh " + filename response, err := exec.RunCommands(exec.RunParams{ Commands: script, }) c.Assert(err, jc.ErrorIsNil) initSystem, err := service.DiscoverInitSystem() c.Assert(err, jc.ErrorIsNil) c.Check(response.Code, gc.Equals, 0) c.Check(string(response.Stdout), gc.Equals, initSystem) c.Check(string(response.Stderr), gc.Equals, "") }
// Previously the lock directory was created when the uniter started. This // allows serialization of all of the hook execution across units running on a // single machine. This lock directory is now also used but the juju-run // command on the host machine. juju-run also gets a lock on the hook // execution fslock prior to execution. However, the lock directory was owned // by root, and the juju-run process was being executed by the ubuntu user, so // we need to change the ownership of the lock directory to ubuntu:ubuntu. // Also we need to make sure that this directory exists on machines with no // units. func ensureLockDirExistsAndUbuntuWritable(context Context) error { lockDir := path.Join(context.AgentConfig().DataDir(), "locks") // We only try to change ownership if there is an ubuntu user // defined, and we determine this by the existance of the home dir. command := fmt.Sprintf(""+ "mkdir -p %s\n"+ "[ -e %s ] && chown ubuntu:ubuntu %s\n", lockDir, ubuntuHome, lockDir) logger.Tracef("command: %s", command) result, err := exec.RunCommands(exec.RunParams{ Commands: command, }) if err != nil { return err } logger.Tracef("stdout: %s", result.Stdout) return nil }
// As of the middle of the 1.17 cycle, the proxy settings are written out to // /home/ubuntu/.juju-proxy both by cloud-init and the machine environ worker. // An older version of juju that has been upgraded will get the proxy settings // written out to the .juju-proxy file, but the .profile for the ubuntu user // wouldn't have been updated to source this file. // // This upgrade step is to add the line to source the file if it is missing // from the file. func ensureUbuntuDotProfileSourcesProxyFile(context Context) error { // We look to see if the proxy line is there already as the manual // provider may have had it aleady. The ubuntu user may not exist // (local provider only). command := fmt.Sprintf(""+ `([ ! -e %s/.profile ] || grep -q '.juju-proxy' %s/.profile) || `+ `printf '\n# Added by juju\n[ -f "$HOME/.juju-proxy" ] && . "$HOME/.juju-proxy"\n' >> %s/.profile`, ubuntuHome, ubuntuHome, ubuntuHome) logger.Tracef("command: %s", command) result, err := exec.RunCommands(exec.RunParams{ Commands: command, }) if err != nil { return err } logger.Tracef("stdout: %s", result.Stdout) return nil }
// executeCommands execute a batch of commands one by one. func executeCommands(commands []string) error { for _, command := range commands { result, err := exec.RunCommands(exec.RunParams{ Commands: command, WorkingDir: "/", }) if err != nil { return fmt.Errorf("failed to execute %q: %v", command, err) } if result.Code != 0 { return fmt.Errorf( "command %q failed (code: %d, stdout: %s, stderr: %s)", command, result.Code, result.Stdout, result.Stderr) } logger.Debugf("command %q (code: %d, stdout: %s, stderr: %s)", command, result.Code, result.Stdout, result.Stderr) } return nil }
func (c *RunCommand) executeNoContext() (*exec.ExecResponse, error) { // Acquire the uniter hook execution lock to make sure we don't // stomp on each other. lock, err := cmdutil.HookExecutionLock(cmdutil.DataDir) if err != nil { return nil, errors.Trace(err) } err = lock.Lock("juju-run") if err != nil { return nil, errors.Trace(err) } defer lock.Unlock() runCmd := c.appendProxyToCommands() return exec.RunCommands( exec.RunParams{ Commands: runCmd, }) }
func (c *RunCommand) executeNoContext() (*exec.ExecResponse, error) { // Acquire the uniter hook execution lock to make sure we don't // stomp on each other. lock, err := getLock() if err != nil { return nil, err } err = lock.Lock("juju-run") if err != nil { return nil, err } defer lock.Unlock() runCmd := `[ -f "/home/ubuntu/.juju-proxy" ] && . "/home/ubuntu/.juju-proxy"` + "\n" + c.commands return exec.RunCommands( exec.RunParams{ Commands: runCmd, }) }
func (s *bridgeConfigSuite) runScript(c *gc.C, configFile, bridgePrefix, bridgeName, interfaceToBridge string) (output string, exitCode int) { if bridgePrefix != "" { bridgePrefix = fmt.Sprintf("--bridge-prefix=%q", bridgePrefix) } if bridgeName != "" { bridgeName = fmt.Sprintf("--bridge-name=%q", bridgeName) } if interfaceToBridge != "" { interfaceToBridge = fmt.Sprintf("--interface-to-bridge=%q", interfaceToBridge) } script := fmt.Sprintf("%q %s %s %s %q\n", s.testPythonScript, bridgePrefix, bridgeName, interfaceToBridge, configFile) result, err := exec.RunCommands(exec.RunParams{Commands: script}) c.Assert(err, jc.ErrorIsNil, gc.Commentf("script failed unexpectedly")) stdout := string(result.Stdout) stderr := string(result.Stderr) if stderr != "" { return stdout + "\n" + stderr, result.Code } return stdout, result.Code }
// runTemplateCommand executes the given template with the given data, // which generates a command to execute. If exitNonZeroOK is true, no // error is returned if the exit code is not 0, otherwise an error is // returned. func runTemplateCommand(t *template.Template, exitNonZeroOK bool, data interface{}) ( exitCode int, err error, ) { // Clone the template to ensure the original won't be changed. cloned, err := t.Clone() if err != nil { return -1, errors.Annotatef(err, "cannot clone command template %q", t.Name()) } var buf bytes.Buffer if err := cloned.Execute(&buf, data); err != nil { return -1, errors.Annotatef(err, "cannot execute command template %q", t.Name()) } command := buf.String() logger.Debugf("running command %q", command) result, err := exec.RunCommands(exec.RunParams{Commands: command}) if err != nil { return -1, errors.Annotatef(err, "cannot run command %q", command) } exitCode = result.Code stdout := string(result.Stdout) stderr := string(result.Stderr) logger.Debugf( "command %q returned code=%d, stdout=%q, stderr=%q", command, exitCode, stdout, stderr, ) if exitCode != 0 { if exitNonZeroOK { return exitCode, nil } return exitCode, errors.Errorf( "command %q failed with exit code %d", command, exitCode, ) } return 0, nil }
func (s *bridgeConfigSuite) runScript(c *gc.C, configFile string, nic string, bridge string, isBond bool) (output string, exitCode int) { var primaryNicIsBonded = "" if isBond { primaryNicIsBonded = "--primary-nic-is-bonded" } script := fmt.Sprintf("%s\npython -c %q --render-only --filename=%q --primary-nic=%q --bridge-name=%q %s\n", bridgeScriptPythonBashDef, "$python_script", configFile, nic, bridge, primaryNicIsBonded) result, err := exec.RunCommands(exec.RunParams{Commands: script}) c.Assert(err, jc.ErrorIsNil, gc.Commentf("script failed unexpectedly")) stdout := string(result.Stdout) stderr := string(result.Stderr) if stderr != "" { return stdout + "\n" + stderr, result.Code } return stdout, result.Code }
out = strings.TrimSpace(out) return []byte(out), nil } const runCommandMsg = "%s failed (%s)" func (Cmdline) runCommand(cmd, label string) (string, error) { resp, err := runCommands(exec.RunParams{ Commands: cmd, }) if err != nil { return "", errors.Annotatef(err, runCommandMsg, label, cmd) } out := string(resp.Stdout) if resp.Code != 0 { err := errors.Errorf( "error executing %q: %s", executable, strings.Replace(string(resp.Stderr), "\n", "; ", -1), ) return out, errors.Annotatef(err, runCommandMsg, label, cmd) } return out, nil } var runCommands = func(args exec.RunParams) (*exec.ExecResponse, error) { return exec.RunCommands(args) }
val = "1" } runCmds := func(keyAndVal string) (err error) { defer errors.DeferredAnnotatef(&err, "cannot set %s", keyAndVal) commands := []string{ // Change it immediately: fmt.Sprintf("sysctl -w %s", keyAndVal), // Change it also on next boot: fmt.Sprintf("echo '%s' | tee -a %s", keyAndVal, sysctlConfig), } for _, cmd := range commands { result, err := exec.RunCommands(exec.RunParams{Commands: cmd}) if err != nil { return errors.Trace(err) } logger.Debugf( "command %q returned: code: %d, stdout: %q, stderr: %q", cmd, result.Code, string(result.Stdout), string(result.Stderr), ) if result.Code != 0 { return errors.Errorf("unexpected exit code %d", result.Code) } } return nil } err := runCmds(fmt.Sprintf("%s=%s", ipForwardSysctlKey, val))