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