Skip to content

Commit

Permalink
fix: properly handle local environment value pass-through
Browse files Browse the repository at this point in the history
The -e,--env flag as well as values within an --env-file can
contain only a variable name with no "={VALUE}" portion. These
entries provide a shorthand to say "pass the existing environment
value of this variable into the container". Because of the VM
boundary we need to extrapolate these values on the Finch side
and pass them as discrete values into the Lima VM on the nerdctl
command line. Also the file referenced by --env-file may not be
accessible inside the VM, so we translate each entry in the
file into -e entries on the command line rather than fail on the
VM side, unable to locate the file being referenced.

Signed-off-by: Phil Estes <[email protected]>
  • Loading branch information
estesp committed Jan 16, 2023
1 parent 8ee5763 commit 9aa3718
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 9 deletions.
122 changes: 113 additions & 9 deletions cmd/finch/nerdctl.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@
package main

import (
"bufio"
"fmt"
"os"
"path/filepath"
"strings"

"github.com/spf13/cobra"

"github.com/runfinch/finch/pkg/command"
"github.com/runfinch/finch/pkg/flog"
"github.com/runfinch/finch/pkg/lima"
"github.com/runfinch/finch/pkg/system"

"k8s.io/apimachinery/pkg/util/sets"

"github.com/runfinch/finch/pkg/command"
"github.com/runfinch/finch/pkg/lima"
)

const nerdctlCmdName = "nerdctl"
Expand Down Expand Up @@ -59,15 +63,35 @@ func (nc *nerdctlCommand) run(cmdName string, args []string) error {
if err != nil {
return err
}

var nerdctlArgs []string
for _, arg := range args {
if arg == "--debug" {
var (
nerdctlArgs []string
skip bool
)
for i, arg := range args {
// pre-parsing environment values on the command line may pre-fetch the next
// argument; will skip in this loop based on result of parsing env entries
if skip {
skip = false
continue
}
switch {
case arg == "--debug":
// explicitly setting log level to avoid `--debug` flag being interpreted as nerdctl command
nc.logger.SetLevel(flog.Debug)
continue
case argIsEnv(arg):
shouldSkip, addArgs := handleEnv(arg, args[i+1])
skip = shouldSkip
nerdctlArgs = append(nerdctlArgs, addArgs...)
case strings.HasPrefix(arg, "--env-file"):
shouldSkip, additionalEnvs, err := handleEnvFile(arg, args[i+1])
if err != nil {
return err
}
skip = shouldSkip
nerdctlArgs = append(nerdctlArgs, additionalEnvs...)
default:
nerdctlArgs = append(nerdctlArgs, arg)
}
nerdctlArgs = append(nerdctlArgs, arg)
}

limaArgs := append([]string{"shell", limaInstanceName, nerdctlCmdName, cmdName}, nerdctlArgs...)
Expand Down Expand Up @@ -122,6 +146,86 @@ func (nc *nerdctlCommand) shouldReplaceForHelp(cmdName string, args []string) bo
return false
}

func argIsEnv(arg string) bool {
if strings.HasPrefix(arg, "-e") || (strings.HasPrefix(arg, "--env") && !strings.HasPrefix(arg, "--env-file")) {
return true
}
return false
}

func handleEnv(arg, arg2 string) (bool, []string) {
stdlib := system.NewStdLib()
var (
additionalArgs []string
envVar string
skip bool
)
switch arg {
case "-e", "--env":
skip = true
envVar = arg2
default:
// flag and value are in the same string
if strings.HasPrefix(arg, "-e") {
envVar = arg[2:]
} else {
// only other case is "--env="; skip that prefix
envVar = arg[6:]
}
}

if !strings.Contains(envVar, "=") {
// need to lookup value from OS environment, and only set if it exists in the env
if val, ok := stdlib.LookupEnv(envVar); ok {
additionalArgs = append(additionalArgs, "-e", fmt.Sprintf("%s=%s", envVar, val))
}
} else {
additionalArgs = append(additionalArgs, "-e", envVar)
}
return skip, additionalArgs
}

func handleEnvFile(arg, arg2 string) (bool, []string, error) {
var (
filename string
additionalArgs []string
skip bool
)

switch arg {
case "--env-file":
skip = true
filename = arg2
default:
filename = arg[11:]
}

file, err := os.Open(filepath.Clean(filename))
if err != nil {
return false, []string{}, err
}
defer file.Close() //nolint:errcheck,gosec // close of a file in O_RDONLY mode has no gosec issue

stdlib := system.NewStdLib()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if !strings.Contains(line, "=") {
// only has the variable name; need to lookup value
if val, ok := stdlib.LookupEnv(line); ok {
additionalArgs = append(additionalArgs, "-e", fmt.Sprintf("%s=%s", line, val))
}
} else {
// a name and value; add as a "-e" param to the command line
additionalArgs = append(additionalArgs, "-e", line)
}
}
if err := scanner.Err(); err != nil {
return skip, []string{}, err
}
return skip, additionalArgs, nil
}

var nerdctlCmds = map[string]string{
"build": "Build an image from Dockerfile",
"builder": "Manage builds",
Expand Down
4 changes: 4 additions & 0 deletions pkg/system/stdlib.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ func (s *StdLib) Env(key string) string {
return os.Getenv(key)
}

func (s *StdLib) LookupEnv(key string) (string, bool) {
return os.LookupEnv(key)
}

func (s *StdLib) Stdin() *os.File {
return os.Stdin
}
Expand Down

0 comments on commit 9aa3718

Please sign in to comment.