github.com/containerd/Containerd@v1.4.13/metadata/namespaces.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 metadata
    18  
    19  import (
    20  	"context"
    21  
    22  	"github.com/containerd/containerd/errdefs"
    23  	"github.com/containerd/containerd/identifiers"
    24  	l "github.com/containerd/containerd/labels"
    25  	"github.com/containerd/containerd/namespaces"
    26  	"github.com/pkg/errors"
    27  	bolt "go.etcd.io/bbolt"
    28  )
    29  
    30  type namespaceStore struct {
    31  	tx *bolt.Tx
    32  }
    33  
    34  // NewNamespaceStore returns a store backed by a bolt DB
    35  func NewNamespaceStore(tx *bolt.Tx) namespaces.Store {
    36  	return &namespaceStore{tx: tx}
    37  }
    38  
    39  func (s *namespaceStore) Create(ctx context.Context, namespace string, labels map[string]string) error {
    40  	topbkt, err := createBucketIfNotExists(s.tx, bucketKeyVersion)
    41  	if err != nil {
    42  		return err
    43  	}
    44  
    45  	if err := identifiers.Validate(namespace); err != nil {
    46  		return err
    47  	}
    48  
    49  	for k, v := range labels {
    50  		if err := l.Validate(k, v); err != nil {
    51  			return errors.Wrapf(err, "namespace.Labels")
    52  		}
    53  	}
    54  
    55  	// provides the already exists error.
    56  	bkt, err := topbkt.CreateBucket([]byte(namespace))
    57  	if err != nil {
    58  		if err == bolt.ErrBucketExists {
    59  			return errors.Wrapf(errdefs.ErrAlreadyExists, "namespace %q", namespace)
    60  		}
    61  
    62  		return err
    63  	}
    64  
    65  	lbkt, err := bkt.CreateBucketIfNotExists(bucketKeyObjectLabels)
    66  	if err != nil {
    67  		return err
    68  	}
    69  
    70  	for k, v := range labels {
    71  		if err := lbkt.Put([]byte(k), []byte(v)); err != nil {
    72  			return err
    73  		}
    74  	}
    75  
    76  	return nil
    77  }
    78  
    79  func (s *namespaceStore) Labels(ctx context.Context, namespace string) (map[string]string, error) {
    80  	labels := map[string]string{}
    81  
    82  	bkt := getNamespaceLabelsBucket(s.tx, namespace)
    83  	if bkt == nil {
    84  		return labels, nil
    85  	}
    86  
    87  	if err := bkt.ForEach(func(k, v []byte) error {
    88  		labels[string(k)] = string(v)
    89  		return nil
    90  	}); err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	return labels, nil
    95  }
    96  
    97  func (s *namespaceStore) SetLabel(ctx context.Context, namespace, key, value string) error {
    98  	if err := l.Validate(key, value); err != nil {
    99  		return errors.Wrapf(err, "namespace.Labels")
   100  	}
   101  
   102  	return withNamespacesLabelsBucket(s.tx, namespace, func(bkt *bolt.Bucket) error {
   103  		if value == "" {
   104  			return bkt.Delete([]byte(key))
   105  		}
   106  
   107  		return bkt.Put([]byte(key), []byte(value))
   108  	})
   109  
   110  }
   111  
   112  func (s *namespaceStore) List(ctx context.Context) ([]string, error) {
   113  	bkt := getBucket(s.tx, bucketKeyVersion)
   114  	if bkt == nil {
   115  		return nil, nil // no namespaces!
   116  	}
   117  
   118  	var namespaces []string
   119  	if err := bkt.ForEach(func(k, v []byte) error {
   120  		if v != nil {
   121  			return nil // not a bucket
   122  		}
   123  
   124  		namespaces = append(namespaces, string(k))
   125  		return nil
   126  	}); err != nil {
   127  		return nil, err
   128  	}
   129  
   130  	return namespaces, nil
   131  }
   132  
   133  func (s *namespaceStore) Delete(ctx context.Context, namespace string, opts ...namespaces.DeleteOpts) error {
   134  	i := &namespaces.DeleteInfo{
   135  		Name: namespace,
   136  	}
   137  	for _, o := range opts {
   138  		if err := o(ctx, i); err != nil {
   139  			return err
   140  		}
   141  	}
   142  	bkt := getBucket(s.tx, bucketKeyVersion)
   143  	if empty, err := s.namespaceEmpty(ctx, namespace); err != nil {
   144  		return err
   145  	} else if !empty {
   146  		return errors.Wrapf(errdefs.ErrFailedPrecondition, "namespace %q must be empty", namespace)
   147  	}
   148  
   149  	if err := bkt.DeleteBucket([]byte(namespace)); err != nil {
   150  		if err == bolt.ErrBucketNotFound {
   151  			return errors.Wrapf(errdefs.ErrNotFound, "namespace %q", namespace)
   152  		}
   153  
   154  		return err
   155  	}
   156  
   157  	return nil
   158  }
   159  
   160  func (s *namespaceStore) namespaceEmpty(ctx context.Context, namespace string) (bool, error) {
   161  	// Get all data buckets
   162  	buckets := []*bolt.Bucket{
   163  		getImagesBucket(s.tx, namespace),
   164  		getBlobsBucket(s.tx, namespace),
   165  		getContainersBucket(s.tx, namespace),
   166  	}
   167  	if snbkt := getSnapshottersBucket(s.tx, namespace); snbkt != nil {
   168  		if err := snbkt.ForEach(func(k, v []byte) error {
   169  			if v == nil {
   170  				buckets = append(buckets, snbkt.Bucket(k))
   171  			}
   172  			return nil
   173  		}); err != nil {
   174  			return false, err
   175  		}
   176  	}
   177  
   178  	// Ensure data buckets are empty
   179  	for _, bkt := range buckets {
   180  		if !isBucketEmpty(bkt) {
   181  			return false, nil
   182  		}
   183  	}
   184  
   185  	return true, nil
   186  }
   187  
   188  func isBucketEmpty(bkt *bolt.Bucket) bool {
   189  	if bkt == nil {
   190  		return true
   191  	}
   192  
   193  	k, _ := bkt.Cursor().First()
   194  	return k == nil
   195  }