github.com/rkt/rkt@v1.30.1-0.20200224141603-171c416fac02/stage0/app_rm.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  //+build linux
    16  
    17  package stage0
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"os"
    24  	"path/filepath"
    25  	"syscall"
    26  
    27  	"github.com/appc/spec/schema/types"
    28  	"github.com/hashicorp/errwrap"
    29  	"github.com/rkt/rkt/common"
    30  	pkgPod "github.com/rkt/rkt/pkg/pod"
    31  )
    32  
    33  type RmConfig struct {
    34  	*CommonConfig
    35  	PodPath     string
    36  	UsesOverlay bool
    37  	AppName     *types.ACName
    38  	PodPID      int
    39  }
    40  
    41  func RmApp(cfg RmConfig) error {
    42  	pod, err := pkgPod.PodFromUUIDString(cfg.DataDir, cfg.UUID.String())
    43  	if err != nil {
    44  		return errwrap.Wrap(errors.New("error loading pod"), err)
    45  	}
    46  	defer pod.Close()
    47  
    48  	debug("locking sandbox manifest")
    49  	if err := pod.ExclusiveLockManifest(); err != nil {
    50  		return errwrap.Wrap(errors.New("failed to lock sandbox manifest"), err)
    51  	}
    52  	defer pod.UnlockManifest()
    53  
    54  	pm, err := pod.SandboxManifest()
    55  	if err != nil {
    56  		return errwrap.Wrap(errors.New("cannot remove application, sandbox validation failed"), err)
    57  	}
    58  
    59  	app := pm.Apps.Get(*cfg.AppName)
    60  	if app == nil {
    61  		return fmt.Errorf("error: nonexistent app %q", *cfg.AppName)
    62  	}
    63  
    64  	if cfg.PodPID > 0 {
    65  		// Call app-stop and app-rm entrypoint only if the pod is still running.
    66  		// Otherwise, there's not much we can do about it except unmounting/removing
    67  		// the file system.
    68  		args := []string{
    69  			fmt.Sprintf("--debug=%t", cfg.Debug),
    70  			fmt.Sprintf("--app=%s", cfg.AppName),
    71  		}
    72  
    73  		ce := CrossingEntrypoint{
    74  			PodPath:        cfg.PodPath,
    75  			PodPID:         cfg.PodPID,
    76  			AppName:        cfg.AppName.String(),
    77  			EntrypointName: appStopEntrypoint,
    78  			EntrypointArgs: args,
    79  			Interactive:    false,
    80  		}
    81  		if err := ce.Run(); err != nil {
    82  			status, err := common.GetExitStatus(err)
    83  			// ignore nonexistent units failing to stop. Exit status 5
    84  			// comes from systemctl and means the unit doesn't exist
    85  			if err != nil {
    86  				return err
    87  			} else if status != 5 {
    88  				return fmt.Errorf("exit status %d", status)
    89  			}
    90  		}
    91  
    92  		ce.EntrypointName = appRmEntrypoint
    93  		if err := ce.Run(); err != nil {
    94  			return err
    95  		}
    96  	}
    97  
    98  	if cfg.UsesOverlay {
    99  		treeStoreID, err := ioutil.ReadFile(common.AppTreeStoreIDPath(cfg.PodPath, *cfg.AppName))
   100  		if err != nil {
   101  			return err
   102  		}
   103  
   104  		appRootfs := common.AppRootfsPath(cfg.PodPath, *cfg.AppName)
   105  		// if the system reboots stage1 won't be mounted and appRootfs won't
   106  		// exist, ignore this error
   107  		if err := syscall.Unmount(appRootfs, 0); err != nil && !os.IsNotExist(err) {
   108  			return err
   109  		}
   110  
   111  		ts := filepath.Join(cfg.PodPath, "overlay", string(treeStoreID))
   112  		if err := os.RemoveAll(ts); err != nil {
   113  			return errwrap.Wrap(errors.New("error removing app info directory"), err)
   114  		}
   115  	}
   116  
   117  	appInfoDir := common.AppInfoPath(cfg.PodPath, *cfg.AppName)
   118  	if err := os.RemoveAll(appInfoDir); err != nil {
   119  		return errwrap.Wrap(errors.New("error removing app info directory"), err)
   120  	}
   121  
   122  	if err := os.RemoveAll(common.AppPath(cfg.PodPath, *cfg.AppName)); err != nil {
   123  		return err
   124  	}
   125  
   126  	stage1RootfsPath, err := pod.Stage1RootfsPath()
   127  	if err != nil {
   128  		return err
   129  	}
   130  
   131  	appStatusPath := filepath.Join(stage1RootfsPath, "rkt", "status", cfg.AppName.String())
   132  	if err := os.Remove(appStatusPath); err != nil && !os.IsNotExist(err) {
   133  		return err
   134  	}
   135  
   136  	envPath := filepath.Join(stage1RootfsPath, "rkt", "env", cfg.AppName.String())
   137  	if err := os.Remove(envPath); err != nil && !os.IsNotExist(err) {
   138  		return err
   139  	}
   140  
   141  	for i, app := range pm.Apps {
   142  		if app.Name == *cfg.AppName {
   143  			pm.Apps = append(pm.Apps[:i], pm.Apps[i+1:]...)
   144  			break
   145  		}
   146  	}
   147  
   148  	return pod.UpdateManifest(pm, cfg.PodPath)
   149  }