Skip to content

Commit

Permalink
feat: oci: support --env option in --oci mode
Browse files Browse the repository at this point in the history
* Merge image config ENV and env vars requested by user with the --env
  CLI option.
* Set default SINGULARITY_CONTAINER and SINGULARITY_NAME env variables.
* Set default LD_LIBRARY_PATH to be used later for library
  injection (this is a singularity default).

Fixes sylabs#1029
  • Loading branch information
dtrudg committed Dec 6, 2022
1 parent 3c1fac4 commit 674403b
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 5 deletions.
23 changes: 18 additions & 5 deletions internal/pkg/runtime/launcher/oci/launcher_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,6 @@ func checkOpts(lo launcher.Options) error {
badOpt = append(badOpt, "Proot")
}

if len(lo.Env) > 0 {
badOpt = append(badOpt, "Env")
}
if lo.EnvFile != "" {
badOpt = append(badOpt, "EnvFile")
}
Expand Down Expand Up @@ -230,8 +227,9 @@ func checkOpts(lo launcher.Options) error {
}

// createSpec produces an OCI runtime specification, suitable to launch a
// container. This spec excludes ProcessArgs, as these have to be computed where
// the image config is available, to account for the image's CMD / ENTRYPOINT.
// container. This spec excludes ProcessArgs and Env, as these have to be
// computed where the image config is available, to account for the image's CMD
// / ENTRYPOINT / ENV.
func (l *Launcher) createSpec() (*specs.Spec, error) {
spec := minimalSpec()

Expand Down Expand Up @@ -318,12 +316,20 @@ func (l *Launcher) Exec(ctx context.Context, image string, process string, args
return fmt.Errorf("while creating OCI spec: %w", err)
}

// Assemble the runtime & user-requested environment, which will be merged
// with the image ENV and set in the container at runtime.
rtEnv := defaultEnv(image, bundleDir)
// --env flag
rtEnv = mergeMap(rtEnv, l.cfg.Env)
// TODO - --env-file, SINGULARITYENV_

b, err := native.New(
native.OptBundlePath(bundleDir),
native.OptImageRef(image),
native.OptSysCtx(sysCtx),
native.OptImgCache(imgCache),
native.OptProcessArgs(process, args),
native.OptProcessEnv(rtEnv),
)
if err != nil {
return err
Expand Down Expand Up @@ -351,3 +357,10 @@ func (l *Launcher) Exec(ctx context.Context, image string, process string, args
}
return err
}

func mergeMap(a map[string]string, b map[string]string) map[string]string {
for k, v := range b {
a[k] = v
}
return a
}
9 changes: 9 additions & 0 deletions internal/pkg/runtime/launcher/oci/process_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,12 @@ func (l *Launcher) getReverseUserMaps() (uidMap, gidMap []specs.LinuxIDMapping,

return uidMap, gidMap, nil
}

// defaultEnv returns default environment variables set in the container.
func defaultEnv(image, bundle string) map[string]string {
return map[string]string{
"LD_LIBRARY_PATH": "/.singularity.d/libs",
"SINGULARITY_CONTAINER": bundle,
"SINGULARITY_NAME": image,
}
}
26 changes: 26 additions & 0 deletions pkg/ocibundle/native/bundle_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ type Bundle struct {
process string
// args are the command arguments, which may override the image's CMD.
args []string
// env is the container environment to set, which will be merged with the image's env.
env map[string]string
// Generic bundle properties
ocibundle.Bundle
}
Expand Down Expand Up @@ -104,6 +106,14 @@ func OptProcessArgs(process string, args []string) Option {
}
}

// OptEnv sets the environment to be set, merged with the image ENV.
func OptProcessEnv(env map[string]string) Option {
return func(b *Bundle) error {
b.env = env
return nil
}
}

// New returns a bundle interface to create/delete an OCI bundle from an OCI image ref.
func New(opts ...Option) (ocibundle.Bundle, error) {
b := Bundle{
Expand Down Expand Up @@ -156,6 +166,8 @@ func (b *Bundle) Create(ctx context.Context, ociConfig *specs.Spec) error {
// consult the image Config to handle combining ENTRYPOINT/CMD with user
// provided args.
b.setProcessArgs(g)
// Ditto for environment handling (merge image and user/rt requested).
b.setProcessEnv(g)

return b.writeConfig(g)
}
Expand Down Expand Up @@ -185,6 +197,20 @@ func (b *Bundle) setProcessArgs(g *generate.Generator) {
g.SetProcessArgs(processArgs)
}

func (b *Bundle) setProcessEnv(g *generate.Generator) {
if g.Config == nil {
g.Config = &specs.Spec{}
}
if g.Config.Process == nil {
g.Config.Process = &specs.Process{}
}
g.Config.Process.Env = b.imageSpec.Config.Env

for k, v := range b.env {
g.AddProcessEnv(k, v)
}
}

func (b *Bundle) writeConfig(g *generate.Generator) error {
return tools.SaveBundleConfig(b.bundlePath, g)
}
Expand Down

0 comments on commit 674403b

Please sign in to comment.