github.com/munnerz/test-infra@v0.0.0-20190108210205-ce3d181dc989/boskos/mason/storage.go (about) 1 /* 2 Copyright 2017 The Kubernetes 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 mason 18 19 import ( 20 "reflect" 21 "sync" 22 23 "github.com/deckarep/golang-set" 24 "github.com/hashicorp/go-multierror" 25 "github.com/sirupsen/logrus" 26 "k8s.io/test-infra/boskos/common" 27 "k8s.io/test-infra/boskos/storage" 28 ) 29 30 // Storage stores configuration information 31 type Storage struct { 32 configs storage.PersistenceLayer 33 configsLock sync.RWMutex 34 } 35 36 func newStorage(c storage.PersistenceLayer) *Storage { 37 return &Storage{ 38 configs: c, 39 } 40 } 41 42 // AddConfig adds a new config 43 func (s *Storage) AddConfig(conf common.ResourcesConfig) error { 44 return s.configs.Add(conf) 45 } 46 47 // DeleteConfig deletes an existing config if it exists or fail otherwise 48 func (s *Storage) DeleteConfig(name string) error { 49 return s.configs.Delete(name) 50 } 51 52 // UpdateConfig updates a given if it exists or fail otherwise 53 func (s *Storage) UpdateConfig(conf common.ResourcesConfig) error { 54 return s.configs.Update(conf) 55 } 56 57 // GetConfig returns an existing if it exists errors out otherwise 58 func (s *Storage) GetConfig(name string) (common.ResourcesConfig, error) { 59 i, err := s.configs.Get(name) 60 if err != nil { 61 return common.ResourcesConfig{}, err 62 } 63 var conf common.ResourcesConfig 64 conf, err = common.ItemToResourcesConfig(i) 65 if err != nil { 66 return common.ResourcesConfig{}, err 67 } 68 return conf, nil 69 } 70 71 // GetConfigs returns all configs 72 func (s *Storage) GetConfigs() ([]common.ResourcesConfig, error) { 73 var configs []common.ResourcesConfig 74 items, err := s.configs.List() 75 if err != nil { 76 return configs, err 77 } 78 for _, i := range items { 79 var conf common.ResourcesConfig 80 conf, err = common.ItemToResourcesConfig(i) 81 if err != nil { 82 return nil, err 83 } 84 configs = append(configs, conf) 85 } 86 return configs, nil 87 } 88 89 // SyncConfigs syncs new configs 90 func (s *Storage) SyncConfigs(newConfigs []common.ResourcesConfig) error { 91 s.configsLock.Lock() 92 defer s.configsLock.Unlock() 93 94 currentConfigs, err := s.GetConfigs() 95 if err != nil { 96 logrus.WithError(err).Error("cannot find configs") 97 return err 98 } 99 100 currentSet := mapset.NewSet() 101 newSet := mapset.NewSet() 102 toUpdate := mapset.NewSet() 103 104 configs := map[string]common.ResourcesConfig{} 105 106 for _, c := range currentConfigs { 107 currentSet.Add(c.Name) 108 configs[c.Name] = c 109 } 110 111 for _, c := range newConfigs { 112 newSet.Add(c.Name) 113 if old, exists := configs[c.Name]; exists { 114 if !reflect.DeepEqual(old, c) { 115 toUpdate.Add(c.Name) 116 configs[c.Name] = c 117 } 118 } else { 119 configs[c.Name] = c 120 } 121 } 122 123 var finalError error 124 125 toDelete := currentSet.Difference(newSet) 126 toAdd := newSet.Difference(currentSet) 127 128 for _, n := range toDelete.ToSlice() { 129 logrus.Infof("Deleting config %s", n.(string)) 130 if err := s.DeleteConfig(n.(string)); err != nil { 131 logrus.WithError(err).Errorf("failed to delete config %s", n) 132 finalError = multierror.Append(finalError, err) 133 } 134 } 135 136 for _, n := range toAdd.ToSlice() { 137 rc := configs[n.(string)] 138 logrus.Infof("Adding config %s", n.(string)) 139 if err := s.AddConfig(rc); err != nil { 140 logrus.WithError(err).Errorf("failed to create resources %s", n) 141 finalError = multierror.Append(finalError, err) 142 } 143 } 144 145 for _, n := range toUpdate.ToSlice() { 146 rc := configs[n.(string)] 147 logrus.Infof("Updating config %s", n.(string)) 148 if err := s.UpdateConfig(rc); err != nil { 149 logrus.WithError(err).Errorf("failed to update resources %s", n) 150 finalError = multierror.Append(finalError, err) 151 } 152 } 153 154 return finalError 155 }