grim/convey
Clone
Summary
Browse
Changes
Graph
Add a script/shell command that can run scripts on the host machine
redux
2021-12-20, Gary Kramlich
f9638cf514da
Add a script/shell command that can run scripts on the host machine
package
podman
import
(
"os"
"path/filepath"
"strings"
"github.com/kballard/go-shellquote"
"github.com/opencontainers/selinux/go-selinux"
log
"github.com/sirupsen/logrus"
"keep.imfreedom.org/grim/convey/environment"
"keep.imfreedom.org/grim/convey/exec"
"keep.imfreedom.org/grim/convey/runtime"
"keep.imfreedom.org/grim/convey/tasks"
"keep.imfreedom.org/grim/convey/yaml"
)
type
Run
struct
{
Annotations
yaml
.
StringOrSlice
`yaml:"annotations"`
Command
string
`yaml:"command"`
Entrypoint
string
`yaml:"entrypoint"`
Environment
yaml
.
StringOrSlice
`yaml:"environment"`
Hostname
string
`yaml:"hostname"`
Image
string
`yaml:"image"`
Script
yaml
.
StringOrSlice
`yaml:"script"`
Shell
string
`yaml:"shell"`
User
string
`yaml:"user"`
Workdir
string
`yaml:"workdir"`
Workspace
string
`yaml:"workspace"`
commandv
[]
string
}
func
(
r
*
Run
)
buildScript
(
cfgPath
string
,
env
environment
.
Environment
)
(
string
,
error
)
{
script
:=
env
.
Expandv
(
r
.
Script
)
fp
,
err
:=
os
.
CreateTemp
(
cfgPath
,
".convey-script-"
)
if
err
!=
nil
{
return
""
,
err
}
if
_
,
err
=
fp
.
Write
([]
byte
(
strings
.
Join
(
script
,
"\n"
)));
err
!=
nil
{
return
""
,
err
}
if
err
:=
fp
.
Chmod
(
0700
);
err
!=
nil
{
return
""
,
err
}
if
err
:=
fp
.
Close
();
err
!=
nil
{
return
""
,
err
}
return
fp
.
Name
(),
nil
}
func
(
r
*
Run
)
Execute
(
name
string
,
logger
*
log
.
Entry
,
stageEnv
environment
.
Environment
,
rt
*
runtime
.
Runtime
)
error
{
// Create a new environment based on the stage's environment. Then merge
// the task's environment overriding anything from the stage. Finally merge
// the runtime enviroment which holds the environment from the command line.
env
:=
stageEnv
.
Copy
().
MergeSlice
(
r
.
Environment
).
Merge
(
rt
.
Environment
)
// Figure out where we're mounting the workspace. This should be done
// before workdir is expanded as work is typically set to CONVEY_WORKSPACE.
workspace
:=
env
.
Expand
(
r
.
Workspace
)
if
workspace
==
""
{
workspace
=
"/workspace"
}
hostWorkspace
,
err
:=
rt
.
Workspace
()
if
err
!=
nil
{
return
err
}
env
[
"CONVEY_WORKSPACE"
]
=
workspace
volume
:=
hostWorkspace
.
Path
()
+
":"
+
workspace
if
selinux
.
GetEnabled
()
{
// We use lower zed because it creates a shared selinux label that can
// be used by multiple containers and this task could be in a stage
// that is running tasks concurrently.
volume
+=
":z"
}
generator
:=
exec
.
NewGenerator
(
"podman"
,
"run"
,
"--rm"
,
"--volume"
,
volume
,
)
// if the user provided a script, generate the file and set all of our
// attributes appropriately.
if
len
(
r
.
Script
)
>
0
{
// Overwrite any entry point that the user provided. Validate set
// /bin/sh if the user didn't provide one.
r
.
Entrypoint
=
r
.
Shell
scriptFile
,
err
:=
r
.
buildScript
(
rt
.
ConfigPath
,
env
)
if
err
!=
nil
{
os
.
Remove
(
scriptFile
)
return
err
}
defer
os
.
Remove
(
scriptFile
)
scriptFileBase
:=
filepath
.
Base
(
scriptFile
)
r
.
commandv
=
[]
string
{
"/"
+
scriptFileBase
}
volume
:=
scriptFile
+
":/"
+
scriptFileBase
if
selinux
.
GetEnabled
()
{
volume
+=
":z"
}
generator
.
Append
(
"--volume"
,
volume
)
}
// Add any annotations that the user specified.
for
_
,
annotation
:=
range
r
.
Annotations
{
generator
.
Append
(
"--annotation"
,
annotation
)
}
// Add the entrypoint is one was specified.
if
r
.
Entrypoint
!=
""
{
generator
.
Append
(
"--entrypoint"
,
env
.
Expand
(
r
.
Entrypoint
))
}
// Now add all the given environment variables
for
_
,
name
:=
range
env
.
All
()
{
generator
.
Append
(
"--env"
,
name
)
}
// Add the hostname if one was specified.
if
r
.
Hostname
!=
""
{
generator
.
Append
(
"--hostname"
,
env
.
Expand
(
r
.
Hostname
))
}
// Add the user if one was specified.
if
r
.
User
!=
""
{
generator
.
Append
(
"--user"
,
env
.
Expand
(
r
.
User
))
}
// Add the workdir if one was specified.
if
r
.
Workdir
!=
""
{
generator
.
Append
(
"--workdir"
,
env
.
Expand
(
r
.
Workdir
))
}
// Finally append the image name.
generator
.
Append
(
env
.
Expand
(
r
.
Image
))
if
len
(
r
.
commandv
)
>
0
{
generator
.
Appendv
(
env
.
Expandv
(
r
.
commandv
))
}
return
exec
.
Run
(
name
,
generator
.
Command
(),
rt
.
Timeout
)
}
func
(
r
*
Run
)
New
()
tasks
.
Task
{
return
&
Run
{}
}
func
(
r
*
Run
)
Valid
()
error
{
if
r
.
Image
==
""
{
return
ErrNoImage
}
if
r
.
Command
!=
""
{
cmdv
,
err
:=
shellquote
.
Split
(
r
.
Command
)
if
err
!=
nil
{
return
err
}
r
.
commandv
=
cmdv
}
if
r
.
Shell
==
""
{
r
.
Shell
=
"/bin/sh"
}
return
nil
}
func
(
r
*
Run
)
Deprecated
()
error
{
return
nil
}