go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/tokenserver/appengine/impl/utils/projectidentity/storage.go (about) 1 // Copyright 2019 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package projectidentity 16 17 import ( 18 "context" 19 "errors" 20 21 "go.chromium.org/luci/common/logging" 22 "go.chromium.org/luci/common/retry/transient" 23 24 ds "go.chromium.org/luci/gae/service/datastore" 25 ) 26 27 var ( 28 // ErrNotFound indicates that the entity which was queried does not exist in the storage. 29 ErrNotFound = errors.New("not found") 30 ) 31 32 // projectIdentities is the default storage for all scoped identities. 33 var projectIdentities = &persistentStorage{} 34 35 // ProjectIdentities returns the global scoped identity storage. 36 func ProjectIdentities(_ context.Context) Storage { 37 return projectIdentities 38 } 39 40 // Storage interface declares methods for the scoped identity storage. 41 type Storage interface { 42 43 // Create an identity or update if it already exists. 44 Create(c context.Context, identity *ProjectIdentity) (*ProjectIdentity, error) 45 46 // Update an identity in the storage. 47 Update(c context.Context, identity *ProjectIdentity) (*ProjectIdentity, error) 48 49 // Delete an identity from the storage. 50 Delete(c context.Context, identity *ProjectIdentity) error 51 52 // LookupByProject performs a lookup by project name. 53 LookupByProject(c context.Context, project string) (*ProjectIdentity, error) 54 } 55 56 // ProjectIdentity defines a scoped identity in the storage. 57 type ProjectIdentity struct { 58 _kind string `gae:"$kind,ScopedIdentity"` 59 Project string `gae:"$id"` 60 Email string 61 } 62 63 // persistentStorage implements ScopedIdentityManager. 64 type persistentStorage struct { 65 } 66 67 // lookup reads an identity from the storage based on what fields are set in the identity struct. 68 func (s *persistentStorage) lookup(c context.Context, identity *ProjectIdentity) (*ProjectIdentity, error) { 69 logging.Debugf(c, "lookup project scoped identity %v", identity) 70 tmp := *identity 71 if err := ds.Get(c, &tmp); err != nil { 72 switch { 73 case err == ds.ErrNoSuchEntity: 74 return nil, ErrNotFound 75 case err != nil: 76 return nil, transient.Tag.Apply(err) 77 } 78 } 79 return &tmp, nil 80 } 81 82 // LookupByProject returns the project identity stored for a given project. 83 func (s *persistentStorage) LookupByProject(c context.Context, project string) (*ProjectIdentity, error) { 84 return s.lookup(c, &ProjectIdentity{Project: project}) 85 } 86 87 // Delete removes an identity from the storage. 88 func (s *persistentStorage) Delete(c context.Context, identity *ProjectIdentity) error { 89 logging.Debugf(c, "delete project scoped identity %v", identity) 90 return ds.Delete(c, identity) 91 } 92 93 // Create stores a new entry for a project identity. 94 func (s *persistentStorage) Create(c context.Context, identity *ProjectIdentity) (*ProjectIdentity, error) { 95 logging.Debugf(c, "create project scoped identity %v", identity) 96 return s.Update(c, identity) 97 } 98 99 // Update allows an identity to be updated, e.g. when the service account email changes. 100 func (s *persistentStorage) Update(c context.Context, identity *ProjectIdentity) (*ProjectIdentity, error) { 101 logging.Debugf(c, "update project scoped identity %v", identity) 102 tmp, err := s.lookup(c, identity) 103 switch { 104 case err == nil && *tmp == *identity: // Doesn't need update 105 return identity, nil 106 case err != nil && err != ErrNotFound: // Lookup error to propagate 107 return nil, err 108 } 109 110 if err := ds.Put(c, identity); err != nil { 111 return nil, err 112 } 113 return identity, nil 114 }