github.com/fnproject/cli@v0.0.0-20240508150455-e5d88bd86117/commands/start.go (about)

     1  /*
     2   * Copyright (c) 2019, 2020 Oracle and/or its affiliates. All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package commands
    18  
    19  import (
    20  	"fmt"
    21  	"log"
    22  	"os"
    23  	"os/exec"
    24  	"os/signal"
    25  	"path/filepath"
    26  	"syscall"
    27  
    28  	"github.com/fnproject/cli/common"
    29  	"github.com/fnproject/cli/config"
    30  	"github.com/urfave/cli"
    31  )
    32  
    33  // StartCommand returns start server cli.command
    34  func StartCommand() cli.Command {
    35  	return cli.Command{
    36  		Name:        "start",
    37  		Usage:       "Start a local Fn server",
    38  		Category:    "SERVER COMMANDS",
    39  		Description: "This command starts a local Fn server by downloading its docker image.",
    40  		Action:      start,
    41  		Flags: []cli.Flag{
    42  			cli.StringFlag{
    43  				Name:  "log-level",
    44  				Usage: "--log-level debug to enable debugging",
    45  			},
    46  			cli.BoolFlag{
    47  				Name:  "detach, d",
    48  				Usage: "Run container in background.",
    49  			},
    50  			cli.StringFlag{
    51  				Name:  "env-file",
    52  				Usage: "Path to Fn server configuration file.",
    53  			},
    54  			cli.StringFlag{
    55  				Name:  "version",
    56  				Usage: "Specify a specific fnproject/fnserver version to run, ex: '1.2.3'.",
    57  				Value: "latest",
    58  			},
    59  			cli.IntFlag{
    60  				Name:  "port, p",
    61  				Value: 8080,
    62  				Usage: "Specify port number to bind to on the host.",
    63  			},
    64  		},
    65  	}
    66  }
    67  
    68  func start(c *cli.Context) error {
    69  	var fnDir string
    70  	home := config.GetHomeDir()
    71  
    72  	if c.String("data-dir") != "" {
    73  		fnDir = c.String("data-dir")
    74  	} else {
    75  		fnDir = filepath.Join(home, ".fn")
    76  	}
    77  
    78  	args := []string{"run", "--rm", "-i",
    79  		"--name", "fnserver",
    80  		"-v", fmt.Sprintf("%s/iofs:/iofs", fnDir),
    81  		"-e", fmt.Sprintf("FN_IOFS_DOCKER_PATH=%s/iofs", fnDir),
    82  		"-e", "FN_IOFS_PATH=/iofs",
    83  		"-v", fmt.Sprintf("%s/data:/app/data", fnDir),
    84  		"-v", "/var/run/docker.sock:/var/run/docker.sock",
    85  		"--privileged",
    86  		"-p", fmt.Sprintf("%d:8080", c.Int("port")),
    87  		"--entrypoint", "./fnserver",
    88  	}
    89  	if c.String("log-level") != "" {
    90  		args = append(args, "-e", fmt.Sprintf("FN_LOG_LEVEL=%v", c.String("log-level")))
    91  	}
    92  	if c.String("env-file") != "" {
    93  		args = append(args, "--env-file", c.String("env-file"))
    94  	}
    95  	if c.Bool("detach") {
    96  		args = append(args, "-d")
    97  	}
    98  
    99  	image := fmt.Sprintf("%s:%s", common.FunctionsDockerImage, c.String("version"))
   100  	args = append(args, image)
   101  	cmd := exec.Command("docker", args...)
   102  	cmd.Stdout = os.Stdout
   103  	cmd.Stderr = os.Stderr
   104  	err := cmd.Start()
   105  	if err != nil {
   106  		log.Fatalln("Starting command failed:", err)
   107  	}
   108  
   109  	done := make(chan error, 1)
   110  	go func() {
   111  		done <- cmd.Wait()
   112  	}()
   113  	// catch ctrl-c and kill
   114  	sigC := make(chan os.Signal, 2)
   115  	signal.Notify(sigC, os.Interrupt, syscall.SIGTERM)
   116  
   117  	log.Println("¡¡¡ 'fn start' should NOT be used for PRODUCTION !!! see https://github.com/fnproject/fn-helm/")
   118  
   119  	for {
   120  		select {
   121  		case <-sigC:
   122  			log.Println("Interrupt caught, exiting")
   123  			err = cmd.Process.Signal(syscall.SIGTERM)
   124  			if err != nil {
   125  				log.Println("Error: could not kill process:", err)
   126  				return err
   127  			}
   128  		case err := <-done:
   129  			if err != nil {
   130  				log.Println("Error: processed finished with error", err)
   131  			}
   132  		}
   133  		return err
   134  	}
   135  }