github.com/containerd/Containerd@v1.4.13/rootfs/init.go (about)

     1  /*
     2     Copyright The containerd Authors.
     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 rootfs
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"os"
    24  
    25  	"github.com/containerd/containerd/log"
    26  	"github.com/containerd/containerd/mount"
    27  	"github.com/containerd/containerd/snapshots"
    28  	digest "github.com/opencontainers/go-digest"
    29  	"github.com/pkg/errors"
    30  )
    31  
    32  var (
    33  	initializers = map[string]initializerFunc{}
    34  )
    35  
    36  type initializerFunc func(string) error
    37  
    38  // Mounter handles mount and unmount
    39  type Mounter interface {
    40  	Mount(target string, mounts ...mount.Mount) error
    41  	Unmount(target string) error
    42  }
    43  
    44  // InitRootFS initializes the snapshot for use as a rootfs
    45  func InitRootFS(ctx context.Context, name string, parent digest.Digest, readonly bool, snapshotter snapshots.Snapshotter, mounter Mounter) ([]mount.Mount, error) {
    46  	_, err := snapshotter.Stat(ctx, name)
    47  	if err == nil {
    48  		return nil, errors.Errorf("rootfs already exists")
    49  	}
    50  	// TODO: ensure not exist error once added to snapshot package
    51  
    52  	parentS := parent.String()
    53  
    54  	initName := defaultInitializer
    55  	initFn := initializers[initName]
    56  	if initFn != nil {
    57  		parentS, err = createInitLayer(ctx, parentS, initName, initFn, snapshotter, mounter)
    58  		if err != nil {
    59  			return nil, err
    60  		}
    61  	}
    62  
    63  	if readonly {
    64  		return snapshotter.View(ctx, name, parentS)
    65  	}
    66  
    67  	return snapshotter.Prepare(ctx, name, parentS)
    68  }
    69  
    70  func createInitLayer(ctx context.Context, parent, initName string, initFn func(string) error, snapshotter snapshots.Snapshotter, mounter Mounter) (string, error) {
    71  	initS := fmt.Sprintf("%s %s", parent, initName)
    72  	if _, err := snapshotter.Stat(ctx, initS); err == nil {
    73  		return initS, nil
    74  	}
    75  	// TODO: ensure not exist error once added to snapshot package
    76  
    77  	// Create tempdir
    78  	td, err := ioutil.TempDir(os.Getenv("XDG_RUNTIME_DIR"), "create-init-")
    79  	if err != nil {
    80  		return "", err
    81  	}
    82  	defer os.RemoveAll(td)
    83  
    84  	mounts, err := snapshotter.Prepare(ctx, td, parent)
    85  	if err != nil {
    86  		return "", err
    87  	}
    88  
    89  	defer func() {
    90  		if err != nil {
    91  			if rerr := snapshotter.Remove(ctx, td); rerr != nil {
    92  				log.G(ctx).Errorf("Failed to remove snapshot %s: %v", td, rerr)
    93  			}
    94  		}
    95  	}()
    96  
    97  	if err = mounter.Mount(td, mounts...); err != nil {
    98  		return "", err
    99  	}
   100  
   101  	if err = initFn(td); err != nil {
   102  		if merr := mounter.Unmount(td); merr != nil {
   103  			log.G(ctx).Errorf("Failed to unmount %s: %v", td, merr)
   104  		}
   105  		return "", err
   106  	}
   107  
   108  	if err = mounter.Unmount(td); err != nil {
   109  		return "", err
   110  	}
   111  
   112  	if err := snapshotter.Commit(ctx, initS, td); err != nil {
   113  		return "", err
   114  	}
   115  
   116  	return initS, nil
   117  }