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 }