go.chromium.org/luci@v0.0.0-20250314024836-d9a61d0730e6/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 ds "go.chromium.org/luci/gae/service/datastore" 24 ) 25 26 var ( 27 // ErrNotFound indicates that the entity which was queried does not exist in the storage. 28 ErrNotFound = errors.New("not found") 29 ) 30 31 // projectIdentities is the default storage for all scoped identities. 32 var projectIdentities = &persistentStorage{} 33 34 // ProjectIdentities returns the global scoped identity storage. 35 func ProjectIdentities(_ context.Context) Storage { 36 return projectIdentities 37 } 38 39 // Storage interface declares methods for the scoped identity storage. 40 type Storage interface { 41 42 // Create an identity or update if it already exists. 43 Create(c context.Context, identity *ProjectIdentity) (*ProjectIdentity, error) 44 45 // Update an identity in the storage. 46 Update(c context.Context, identity *ProjectIdentity) (*ProjectIdentity, error) 47 48 // Delete an identity from the storage. 49 Delete(c context.Context, identity *ProjectIdentity) error 50 51 // LookupByProject performs a lookup by project name. 52 LookupByProject(c context.Context, project string) (*ProjectIdentity, error) 53 } 54 55 // ProjectIdentity defines a scoped identity in the storage. 56 type ProjectIdentity struct { 57 _kind string `gae:"$kind,ScopedIdentity"` 58 Project string `gae:"$id"` 59 Email string 60 } 61 62 // persistentStorage implements ScopedIdentityManager. 63 type persistentStorage struct { 64 } 65 66 // lookup reads an identity from the storage based on what fields are set in the identity struct. 67 func (s *persistentStorage) lookup(c context.Context, identity *ProjectIdentity) (*ProjectIdentity, error) { 68 logging.Debugf(c, "lookup project scoped identity %v", identity) 69 tmp := *identity 70 if err := ds.Get(c, &tmp); err != nil { 71 switch { 72 case err == ds.ErrNoSuchEntity: 73 return nil, ErrNotFound 74 case err != nil: 75 return nil, transient.Tag.Apply(err) 76 } 77 } 78 return &tmp, nil 79 } 80 81 // LookupByProject returns the project identity stored for a given project. 82 func (s *persistentStorage) LookupByProject(c context.Context, project string) (*ProjectIdentity, error) { 83 return s.lookup(c, &ProjectIdentity{Project: project}) 84 } 85 86 // Delete removes an identity from the storage. 87 func (s *persistentStorage) Delete(c context.Context, identity *ProjectIdentity) error { 88 logging.Debugf(c, "delete project scoped identity %v", identity) 89 return ds.Delete(c, identity) 90 } 91 92 // Create stores a new entry for a project identity. 93 func (s *persistentStorage) Create(c context.Context, identity *ProjectIdentity) (*ProjectIdentity, error) { 94 logging.Debugf(c, "create project scoped identity %v", identity) 95 return s.Update(c, identity) 96 } 97 98 // Update allows an identity to be updated, e.g. when the service account email changes. 99 func (s *persistentStorage) Update(c context.Context, identity *ProjectIdentity) (*ProjectIdentity, error) { 100 logging.Debugf(c, "update project scoped identity %v", identity) 101 tmp, err := s.lookup(c, identity) 102 switch { 103 case err == nil && *tmp == *identity: // Doesn't need update 104 return identity, nil 105 case err != nil && err != ErrNotFound: // Lookup error to propagate 106 return nil, err 107 } 108 109 if err := ds.Put(c, identity); err != nil { 110 return nil, err 111 } 112 return identity, nil 113 }