github.com/iron-io/functions@v0.0.0-20180820112432-d59d7d1c40b2/fn/commands/images/run.go (about)

     1  package commands
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"github.com/iron-io/functions/fn/common"
     7  	"github.com/urfave/cli"
     8  	"io"
     9  	"os"
    10  	"os/exec"
    11  	"strings"
    12  )
    13  
    14  func Run() cli.Command {
    15  	r := runCmd{}
    16  
    17  	return cli.Command{
    18  		Name:      "run",
    19  		Usage:     "run a function locally",
    20  		ArgsUsage: "[username/image:tag]",
    21  		Flags:     append(Runflags(), []cli.Flag{}...),
    22  		Action:    r.run,
    23  	}
    24  }
    25  
    26  type runCmd struct{}
    27  
    28  func Runflags() []cli.Flag {
    29  	return []cli.Flag{
    30  		cli.StringSliceFlag{
    31  			Name:  "e",
    32  			Usage: "select environment variables to be sent to function",
    33  		},
    34  		cli.StringSliceFlag{
    35  			Name:  "link",
    36  			Usage: "select container links for the function",
    37  		},
    38  		cli.StringFlag{
    39  			Name:  "method",
    40  			Usage: "http method for function",
    41  		},
    42  	}
    43  }
    44  
    45  func (r *runCmd) run(c *cli.Context) error {
    46  	image := c.Args().First()
    47  	if image == "" {
    48  		ff, err := common.LoadFuncfile()
    49  		if err != nil {
    50  			if _, ok := err.(*common.NotFoundError); ok {
    51  				return errors.New("error: image name is missing or no function file found")
    52  			}
    53  			return err
    54  		}
    55  		image = ff.FullName()
    56  	}
    57  
    58  	return Runff(image, Stdin(), os.Stdout, os.Stderr, c.String("method"), c.StringSlice("e"), c.StringSlice("link"))
    59  }
    60  
    61  func Runff(image string, stdin io.Reader, stdout, stderr io.Writer, method string, restrictedEnv []string, links []string) error {
    62  	sh := []string{"docker", "run", "--rm", "-i"}
    63  
    64  	var env []string
    65  	detectedEnv := os.Environ()
    66  	if len(restrictedEnv) > 0 {
    67  		detectedEnv = restrictedEnv
    68  	}
    69  
    70  	if method == "" {
    71  		if stdin == nil {
    72  			method = "GET"
    73  		} else {
    74  			method = "POST"
    75  		}
    76  	}
    77  	sh = append(sh, "-e", kvEq("METHOD", method))
    78  
    79  	for _, e := range detectedEnv {
    80  		shellvar, envvar := extractEnvVar(e)
    81  		sh = append(sh, shellvar...)
    82  		env = append(env, envvar)
    83  	}
    84  
    85  	for _, l := range links {
    86  		sh = append(sh, "--link", l)
    87  	}
    88  
    89  	dockerenv := []string{"DOCKER_TLS_VERIFY", "DOCKER_HOST", "DOCKER_CERT_PATH", "DOCKER_MACHINE_NAME"}
    90  	for _, e := range dockerenv {
    91  		env = append(env, fmt.Sprint(e, "=", os.Getenv(e)))
    92  	}
    93  
    94  	sh = append(sh, image)
    95  	cmd := exec.Command(sh[0], sh[1:]...)
    96  	cmd.Stdin = stdin
    97  	cmd.Stdout = stdout
    98  	cmd.Stderr = stderr
    99  	cmd.Env = env
   100  	return cmd.Run()
   101  }
   102  
   103  func extractEnvVar(e string) ([]string, string) {
   104  	kv := strings.Split(e, "=")
   105  	name := toEnvName("HEADER", kv[0])
   106  	sh := []string{"-e", name}
   107  	var v string
   108  	if len(kv) > 1 {
   109  		v = kv[1]
   110  	} else {
   111  		v = os.Getenv(kv[0])
   112  	}
   113  	return sh, kvEq(name, v)
   114  }
   115  
   116  func kvEq(k, v string) string {
   117  	return fmt.Sprintf("%s=%s", k, v)
   118  }
   119  
   120  // From server.toEnvName()
   121  func toEnvName(envtype, name string) string {
   122  	name = strings.ToUpper(strings.Replace(name, "-", "_", -1))
   123  	return fmt.Sprintf("%s_%s", envtype, name)
   124  }