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

#998 Execute task-template within python-virtual environment and ensu… #1001

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
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
21 changes: 20 additions & 1 deletion lib/AnsiblePlaybook.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,36 @@ type AnsiblePlaybook struct {
}

func (p AnsiblePlaybook) makeCmd(command string, args []string, environmentVars *[]string) *exec.Cmd {
cmd := exec.Command(command, args...) //nolint: gas
commandToExec := command
cmdInPythonDefaultVenv := fmt.Sprintf("%s/.venv/bin/%s", p.GetFullPath(), command)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unlikely to work nicely with every Ansible setup since playbooks could be nested into subdirectories of the ansible project.
Consider the following project setup:

.       # Project Root
roles/
roles/roleA
roles/roleB
roles/roleC

playbooks/
playbooks/projectA
playbooks/projectA/playbookA.yml
playbooks/projectB/playbookB.yml

If your task template would reference playbooks/projectA/playbookA.yml then p.GetFullPath() may now resolve to (assuming other things being default) /tmp/semaphore/project_1/playbooks/projectA/, which will not be where your .venv would be.

Instead I'd recommend having the local venv dependencies deployed into the $PATH through the either activating it prior to execution or into the env that semaphore is ultimately running in.

My current installation(s) use the core semaphore container but install addtl. dependencies into the container.

Yes, this requires to update the container if you have a new dependency that needs to be installed but it does get around these presumptive and rather brittle constructs.

if _, err := os.Stat(cmdInPythonDefaultVenv); !os.IsNotExist(err) {
// Run .venv/bin/command instead of the one in PATH
commandToExec = cmdInPythonDefaultVenv
}
cmd := exec.Command(commandToExec, args...) //nolint: gas
cmd.Dir = p.GetFullPath()

cmd.Env = os.Environ()
pythonDefaultVenv := fmt.Sprintf("%s/.venv", cmd.Dir)
if _, err := os.Stat(pythonDefaultVenv); !os.IsNotExist(err) {
// Prepend python .venv binaries to PATH allowing specific ansible version per task-template
p.Logger.Log(fmt.Sprintf("Using python venv at: %s\n", pythonDefaultVenv))
cmd.Env = append(cmd.Env, fmt.Sprintf("VIRTUAL_ENV=%s", pythonDefaultVenv))
cmd.Env = append(cmd.Env, fmt.Sprintf("PATH=%s/bin:%s", pythonDefaultVenv, os.Getenv("PATH")))
}
cmd.Env = append(cmd.Env, fmt.Sprintf("HOME=%s", util.Config.TmpPath))
cmd.Env = append(cmd.Env, fmt.Sprintf("PWD=%s", cmd.Dir))
cmd.Env = append(cmd.Env, "PYTHONUNBUFFERED=1")
cmd.Env = append(cmd.Env, "ANSIBLE_FORCE_COLOR=True")
if environmentVars != nil {
cmd.Env = append(cmd.Env, *environmentVars...)
}
// Remove sensitive env variables from cmd process as they can be read using ansible "debug" task and "-vvv"
cmd.Env = append(cmd.Env, "SEMAPHORE_ACCESS_KEY_ENCRYPTION=")
cmd.Env = append(cmd.Env, "SEMAPHORE_ADMIN_PASSWORD=")
cmd.Env = append(cmd.Env, "SEMAPHORE_DB_USER=")
cmd.Env = append(cmd.Env, "SEMAPHORE_DB_PASS=")
cmd.Env = append(cmd.Env, "SEMAPHORE_LDAP_PASSWORD=")

return cmd
}
Expand Down