github.com/rkt/rkt@v1.30.1-0.20200224141603-171c416fac02/stage0/common.go (about)

     1  // Copyright 2016 The rkt Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package stage0
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  	"os"
    21  	"os/exec"
    22  	"path/filepath"
    23  
    24  	"strconv"
    25  
    26  	"github.com/appc/spec/schema"
    27  	"github.com/appc/spec/schema/types"
    28  	"github.com/hashicorp/errwrap"
    29  	"github.com/rkt/rkt/common"
    30  	"github.com/rkt/rkt/common/apps"
    31  	stage1types "github.com/rkt/rkt/stage1/common/types"
    32  )
    33  
    34  // CrossingEntrypoint represents a stage1 entrypoint whose execution
    35  // needs to cross the stage0/stage1/stage2 boundary.
    36  type CrossingEntrypoint struct {
    37  	PodPath        string
    38  	PodPID         int
    39  	AppName        string
    40  	EntrypointName string
    41  	EntrypointArgs []string
    42  	Interactive    bool
    43  }
    44  
    45  // Run wraps the execution of a stage1 entrypoint which
    46  // requires crossing the stage0/stage1/stage2 boundary during its execution,
    47  // by setting up proper environment variables for enter.
    48  func (ce CrossingEntrypoint) Run() error {
    49  	enterCmd, err := getStage1Entrypoint(ce.PodPath, enterEntrypoint)
    50  	if err != nil {
    51  		return errwrap.Wrap(errors.New("error determining 'enter' entrypoint"), err)
    52  	}
    53  
    54  	previousDir, err := os.Getwd()
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	if err := os.Chdir(ce.PodPath); err != nil {
    60  		return errwrap.Wrap(errors.New("failed changing to dir"), err)
    61  	}
    62  
    63  	ep, err := getStage1Entrypoint(ce.PodPath, ce.EntrypointName)
    64  	if err != nil {
    65  		return fmt.Errorf("%q not implemented for pod's stage1: %v", ce.EntrypointName, err)
    66  	}
    67  	execArgs := []string{filepath.Join(common.Stage1RootfsPath(ce.PodPath), ep)}
    68  	execArgs = append(execArgs, ce.EntrypointArgs...)
    69  
    70  	pathEnv := os.Getenv("PATH")
    71  	if pathEnv == "" {
    72  		pathEnv = common.DefaultPath
    73  	}
    74  	execEnv := []string{
    75  		fmt.Sprintf("%s=%s", common.CrossingEnterCmd, filepath.Join(common.Stage1RootfsPath(ce.PodPath), enterCmd)),
    76  		fmt.Sprintf("%s=%d", common.CrossingEnterPID, ce.PodPID),
    77  		fmt.Sprintf("PATH=%s", pathEnv),
    78  	}
    79  
    80  	c := exec.Cmd{
    81  		Path: execArgs[0],
    82  		Args: execArgs,
    83  		Env:  execEnv,
    84  	}
    85  
    86  	if ce.Interactive {
    87  		c.Stdin = os.Stdin
    88  		c.Stdout = os.Stdout
    89  		c.Stderr = os.Stderr
    90  		if err := c.Run(); err != nil {
    91  			return fmt.Errorf("error executing stage1 entrypoint: %v", err)
    92  		}
    93  	} else {
    94  		out, err := c.CombinedOutput()
    95  		if len(out) > 0 {
    96  			debug("%s\n", out)
    97  		}
    98  
    99  		if err != nil {
   100  			return errwrap.Wrapf("error executing stage1 entrypoint", err)
   101  		}
   102  	}
   103  
   104  	if err := os.Chdir(previousDir); err != nil {
   105  		return errwrap.Wrap(errors.New("failed changing to dir"), err)
   106  	}
   107  
   108  	return nil
   109  }
   110  
   111  // generateRuntimeApp merges runtime information from the image manifest and from
   112  // runtime configuration overrides, returning a full configuration for a runtime app
   113  func generateRuntimeApp(appRunConfig *apps.App, am *schema.ImageManifest, podMounts []schema.Mount) (schema.RuntimeApp, error) {
   114  
   115  	ra := schema.RuntimeApp{
   116  		App: am.App,
   117  		Image: schema.RuntimeImage{
   118  			Name:   &am.Name,
   119  			ID:     appRunConfig.ImageID,
   120  			Labels: am.Labels,
   121  		},
   122  		Mounts:         MergeMounts(podMounts, appRunConfig.Mounts),
   123  		ReadOnlyRootFS: appRunConfig.ReadOnlyRootFS,
   124  	}
   125  
   126  	appName, err := types.NewACName(appRunConfig.Name)
   127  	if err != nil {
   128  		return ra, errwrap.Wrap(errors.New("invalid app name format"), err)
   129  	}
   130  	ra.Name = *appName
   131  
   132  	if appRunConfig.Exec != "" {
   133  		// Create a minimal App section if not present
   134  		if am.App == nil {
   135  			ra.App = &types.App{
   136  				User:  strconv.Itoa(os.Getuid()),
   137  				Group: strconv.Itoa(os.Getgid()),
   138  			}
   139  		}
   140  		ra.App.Exec = []string{appRunConfig.Exec}
   141  	}
   142  
   143  	if appRunConfig.Args != nil {
   144  		ra.App.Exec = append(ra.App.Exec, appRunConfig.Args...)
   145  	}
   146  
   147  	if appRunConfig.WorkingDir != "" {
   148  		ra.App.WorkingDirectory = appRunConfig.WorkingDir
   149  	}
   150  
   151  	if err := prepareIsolators(appRunConfig, ra.App); err != nil {
   152  		return ra, err
   153  	}
   154  
   155  	if appRunConfig.User != "" {
   156  		ra.App.User = appRunConfig.User
   157  	}
   158  
   159  	if appRunConfig.Group != "" {
   160  		ra.App.Group = appRunConfig.Group
   161  	}
   162  
   163  	if appRunConfig.SupplementaryGIDs != nil {
   164  		ra.App.SupplementaryGIDs = appRunConfig.SupplementaryGIDs
   165  	}
   166  
   167  	for k, v := range appRunConfig.Annotations {
   168  		if _, ok := ra.Annotations.Get(k); ok {
   169  			continue
   170  		}
   171  		kAci, err := types.NewACIdentifier(k)
   172  		if err != nil {
   173  			return ra, errwrap.Wrap(fmt.Errorf("error parsing annotation key %q", k), err)
   174  		}
   175  
   176  		ra.Annotations.Set(*kAci, v)
   177  	}
   178  
   179  	if appRunConfig.UserAnnotations != nil {
   180  		ra.App.UserAnnotations = appRunConfig.UserAnnotations
   181  	}
   182  
   183  	if appRunConfig.UserLabels != nil {
   184  		ra.App.UserLabels = appRunConfig.UserLabels
   185  	}
   186  
   187  	if appRunConfig.Stdin != "" {
   188  		ra.Annotations.Set(stage1types.AppStdinMode, appRunConfig.Stdin.String())
   189  	}
   190  	if appRunConfig.Stdout != "" {
   191  		ra.Annotations.Set(stage1types.AppStdoutMode, appRunConfig.Stdout.String())
   192  	}
   193  	if appRunConfig.Stderr != "" {
   194  		ra.Annotations.Set(stage1types.AppStderrMode, appRunConfig.Stderr.String())
   195  	}
   196  
   197  	if appRunConfig.Environments != nil {
   198  		envs := make([]string, 0, len(appRunConfig.Environments))
   199  		for name, value := range appRunConfig.Environments {
   200  			envs = append(envs, fmt.Sprintf("%s=%s", name, value))
   201  		}
   202  		// Let the app level environment override the environment variables.
   203  		mergeEnvs(&ra.App.Environment, envs, true)
   204  	}
   205  
   206  	return ra, nil
   207  }