<commit_before>/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package snapshot

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"

	"github.com/containerd/containerd/errdefs"
	"github.com/containerd/containerd/log"
	"github.com/containerd/containerd/mount"
	"github.com/containerd/containerd/platforms"
	"github.com/containerd/containerd/plugin"
	"github.com/containerd/containerd/snapshots"
	"github.com/containerd/containerd/snapshots/storage"
	"github.com/containerd/continuity/fs"
	"github.com/pkg/errors"

	fsplugin "github.com/ktock/remote-snapshotter/filesystems"
)

const (
	targetSnapshotLabel = "containerd.io/snapshot.ref"
	filesystemIDLabel   = "containerd.io/snapshot/filesystem.id"
)

type Config struct {
	// FileSystems config option enables us to specify filesystems that this
	// snapshotter recognizes and the priority of these filesystems. The first
	// element of the slice has the highest priority.
	FileSystems []string `toml:"filesystems"`
}

func init() {
	plugin.Register(&plugin.Registration{
		Type:   plugin.SnapshotPlugin,
		ID:     "remote",
		Config: &Config{},

		// We use RemoteFileSystemPlugin to mount unpacked remote layers
		// as remote snapshots.
		// See "/filesystems/plugin.go" in this repo.
		Requires: []plugin.Type{
			fsplugin.RemoteFileSystemPlugin,
		},
		InitFn: func(ic *plugin.InitContext) (interface{}, error) {
			ic.Meta.Platforms = append(ic.Meta.Platforms, platforms.DefaultSpec())
			ic.Meta.Exports["root"] = ic.Root
			ctx := ic.Context
			if ctx == nil {
				ctx = log.WithLogger(context.Background(), log.L)
			}

			config, ok := ic.Config.(*Config)
			if !ok {
				return nil, fmt.Errorf("invalid stargz configuration")
			}

			// register all FileSystems which we use to mount unpacked
			// remote layers as remote snapshots.
			fsMap := make(map[string]fsplugin.FileSystem)
			var filesystems []string
			if ps, err := ic.GetByType(fsplugin.RemoteFileSystemPlugin); ps != nil && err == nil {
				for id, p := range ps {
					i, err := p.Instance()
					if err != nil {
						log.G(ctx).WithError(err).Warnf("failed to initialize filesystem plugin %q", id)
						continue
					}
					f, ok := i.(fsplugin.FileSystem)
					if !ok {
						log.G(ctx).WithError(err).Warnf("filesystem plugin %q has invalid API", id)
						continue
					}
					fsMap[id] = f
					filesystems = append(filesystems, id)
				}
			}

			var fsChain []fsplugin.FileSystem
			if config.FileSystems != nil {
				filesystems = config.FileSystems
			}
			for prio, id := range filesystems {
				log.G(ctx).WithField("priority", prio).Infof("Registering filesystem plugin %q...", id)
				f, ok := fsMap[id]
				if !ok {
					return nil, fmt.Errorf("required filesystem %q not found", id)
				}
				fsChain = append(fsChain, f)
			}

			return NewSnapshotter(ctx, ic.Root, fsChain, AsynchronousRemove)
		},
	})
}

// SnapshotterConfig is used to configure the remote snapshotter instance
type SnapshotterConfig struct {
	asyncRemove bool
}

// Opt is an option to configure the remote snapshotter
type Opt func(config *SnapshotterConfig) error

// AsynchronousRemove defers removal of filesystem content until
// the Cleanup method is called. Removals will make the snapshot
// referred to by the key unavailable and make the key immediately
// available for re-use.
func AsynchronousRemove(config *SnapshotterConfig) error {
	config.asyncRemove = true<commit_msg>error out when no filesystem plugin is installed<commit_after>/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package snapshot

import (
	"context"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"

	"github.com/containerd/containerd/errdefs"
	"github.com/containerd/containerd/log"
	"github.com/containerd/containerd/mount"
	"github.com/containerd/containerd/platforms"
	"github.com/containerd/containerd/plugin"
	"github.com/containerd/containerd/snapshots"
	"github.com/containerd/containerd/snapshots/storage"
	"github.com/containerd/continuity/fs"
	"github.com/pkg/errors"

	fsplugin "github.com/ktock/remote-snapshotter/filesystems"
)

const (
	targetSnapshotLabel = "containerd.io/snapshot.ref"
	filesystemIDLabel   = "containerd.io/snapshot/filesystem.id"
)

type Config struct {
	// FileSystems config option enables us to specify filesystems that this
	// snapshotter recognizes and the priority of these filesystems. The first
	// element of the slice has the highest priority.
	FileSystems []string `toml:"filesystems"`
}

func init() {
	plugin.Register(&plugin.Registration{
		Type:   plugin.SnapshotPlugin,
		ID:     "remote",
		Config: &Config{},

		// We use RemoteFileSystemPlugin to mount unpacked remote layers
		// as remote snapshots.
		// See "/filesystems/plugin.go" in this repo.
		Requires: []plugin.Type{
			fsplugin.RemoteFileSystemPlugin,
		},
		InitFn: func(ic *plugin.InitContext) (interface{}, error) {
			ic.Meta.Platforms = append(ic.Meta.Platforms, platforms.DefaultSpec())
			ic.Meta.Exports["root"] = ic.Root
			ctx := ic.Context
			if ctx == nil {
				ctx = log.WithLogger(context.Background(), log.L)
			}

			config, ok := ic.Config.(*Config)
			if !ok {
				return nil, fmt.Errorf("invalid stargz configuration")
			}

			// register all FileSystems which we use to mount unpacked
			// remote layers as remote snapshots.
			fsMap := make(map[string]fsplugin.FileSystem)
			var filesystems []string
			if ps, err := ic.GetByType(fsplugin.RemoteFileSystemPlugin); ps != nil && err == nil {
				for id, p := range ps {
					i, err := p.Instance()
					if err != nil {
						log.G(ctx).WithError(err).Warnf("failed to initialize filesystem plugin %q", id)
						continue
					}
					f, ok := i.(fsplugin.FileSystem)
					if !ok {
						log.G(ctx).WithError(err).Warnf("filesystem plugin %q has invalid API", id)
						continue
					}
					fsMap[id] = f
					filesystems = append(filesystems, id)
				}
			}

			var fsChain []fsplugin.FileSystem
			if config.FileSystems != nil {
				filesystems = config.FileSystems
			}
			if len(filesystems) == 0 {
				return nil, errors.New("no filesystem plugin found, check the installation")
			}
			for prio, id := range filesystems {
				log.G(ctx).WithField("priority", prio).Infof("Registering filesystem plugin %q...", id)
				f, ok := fsMap[id]
				if !ok {
					return nil, fmt.Errorf("required filesystem %q not found", id)
				}
				fsChain = append(fsChain, f)
			}

			return NewSnapshotter(ctx, ic.Root, fsChain, AsynchronousRemove)
		},
	})
}

// SnapshotterConfig is used to configure the remote snapshotter instance
type SnapshotterConfig struct {
	asyncRemove bool
}

// Opt is an option to configure the remote snapshotter
type Opt func(config *SnapshotterConfig) error

// AsynchronousRemove defers removal of filesystem content until
// the Cleanup method is called. Removals will make the snapshot
// referred to by the key unavailable and make the key immediately
// available for re-use.
func AsynchronousRemove(config *SnapshotterConfig) error {
	config.asyncRemove = true
{'fraction_non_alphanumeric': 0.10698931335216803, 'fraction_numerical': 0.0011055152929615526, 'mean_word_length': 3.5896279594137543, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7208312', 'n_tokens_mistral': 2795, 'n_tokens_neox': 2465, 'n_words': 756}