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 }