github.com/emc-advanced-dev/unik@v0.0.0-20190717152701-a58d3e8e33b7/pkg/state/base_state.go (about) 1 package state 2 3 import ( 4 "encoding/json" 5 "github.com/emc-advanced-dev/pkg/errors" 6 "github.com/solo-io/unik/pkg/types" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "sync" 11 ) 12 13 type basicState struct { 14 imagesLock sync.RWMutex 15 instancesLock sync.RWMutex 16 volumesLock sync.RWMutex 17 saveLock sync.Mutex 18 saveFile string 19 Images map[string]*types.Image `json:"Images"` 20 Instances map[string]*types.Instance `json:"Instances"` 21 Volumes map[string]*types.Volume `json:"Volumes"` 22 } 23 24 func NewBasicState(saveFile string) *basicState { 25 return &basicState{ 26 saveFile: saveFile, 27 Images: make(map[string]*types.Image), 28 Instances: make(map[string]*types.Instance), 29 Volumes: make(map[string]*types.Volume), 30 } 31 } 32 33 func BasicStateFromFile(saveFile string) (*basicState, error) { 34 data, err := ioutil.ReadFile(saveFile) 35 if err != nil { 36 return nil, errors.New("error reading save file "+saveFile, err) 37 } 38 var s basicState 39 err = json.Unmarshal(data, &s) 40 if err != nil { 41 return nil, errors.New("failed to unmarshal data "+string(data)+" to memory state", err) 42 } 43 if s.Images == nil { 44 s.Images = make(map[string]*types.Image) 45 } 46 if s.Instances == nil { 47 s.Instances = make(map[string]*types.Instance) 48 } 49 if s.Volumes == nil { 50 s.Volumes = make(map[string]*types.Volume) 51 } 52 s.saveFile = saveFile 53 return &s, nil 54 } 55 56 func (s *basicState) GetImages() map[string]*types.Image { 57 s.imagesLock.RLock() 58 defer s.imagesLock.RUnlock() 59 imagesCopy := make(map[string]*types.Image) 60 for id, image := range s.Images { 61 imageCopy := *image 62 imagesCopy[id] = &imageCopy 63 } 64 return imagesCopy 65 } 66 67 func (s *basicState) GetInstances() map[string]*types.Instance { 68 s.instancesLock.RLock() 69 defer s.instancesLock.RUnlock() 70 instancesCopy := make(map[string]*types.Instance) 71 for id, instance := range s.Instances { 72 instanceCopy := *instance 73 instancesCopy[id] = &instanceCopy 74 } 75 return instancesCopy 76 } 77 78 func (s *basicState) GetVolumes() map[string]*types.Volume { 79 s.volumesLock.RLock() 80 defer s.volumesLock.RUnlock() 81 volumesCopy := make(map[string]*types.Volume) 82 for id, volume := range s.Volumes { 83 volumeCopy := *volume 84 volumesCopy[id] = &volumeCopy 85 } 86 return volumesCopy 87 } 88 89 func (s *basicState) ModifyImages(modify func(images map[string]*types.Image) error) error { 90 s.imagesLock.Lock() 91 defer s.imagesLock.Unlock() 92 if err := modify(s.Images); err != nil { 93 return errors.New("modifying Images", err) 94 } 95 return s.save() 96 } 97 98 func (s *basicState) ModifyInstances(modify func(instances map[string]*types.Instance) error) error { 99 s.instancesLock.Lock() 100 defer s.instancesLock.Unlock() 101 if err := modify(s.Instances); err != nil { 102 return errors.New("modifying Instances", err) 103 } 104 return s.save() 105 } 106 107 func (s *basicState) ModifyVolumes(modify func(volumes map[string]*types.Volume) error) error { 108 s.volumesLock.Lock() 109 defer s.volumesLock.Unlock() 110 if err := modify(s.Volumes); err != nil { 111 return errors.New("modifying Volumes", err) 112 } 113 return s.save() 114 } 115 116 func (s *basicState) save() error { 117 s.saveLock.Lock() 118 defer s.saveLock.Unlock() 119 data, err := json.Marshal(s) 120 if err != nil { 121 return errors.New("failed to marshal memory state to json", err) 122 } 123 os.MkdirAll(filepath.Dir(s.saveFile), 0755) 124 err = ioutil.WriteFile(s.saveFile, data, 0644) 125 if err != nil { 126 return errors.New("writing save file "+s.saveFile, err) 127 } 128 return nil 129 } 130 131 func (s *basicState) RemoveImage(image *types.Image) error { 132 if err := s.ModifyImages(func(images map[string]*types.Image) error { 133 delete(images, image.Id) 134 return nil 135 }); err != nil { 136 return errors.New("modifying image map in state", err) 137 } 138 return nil 139 } 140 141 func (s *basicState) RemoveInstance(instance *types.Instance) error { 142 if err := s.ModifyInstances(func(instances map[string]*types.Instance) error { 143 delete(instances, instance.Id) 144 return nil 145 }); err != nil { 146 return errors.New("modifying image map in state", err) 147 } 148 volumesToDetach := []*types.Volume{} 149 volumes := s.GetVolumes() 150 for _, volume := range volumes { 151 if volume.Attachment == instance.Id { 152 volumesToDetach = append(volumesToDetach, volume) 153 } 154 } 155 for _, volume := range volumesToDetach { 156 if err := s.ModifyVolumes(func(volumes map[string]*types.Volume) error { 157 volume, ok := volumes[volume.Id] 158 if !ok { 159 return errors.New("no record of "+volume.Id+" in the state", nil) 160 } 161 volume.Attachment = "" 162 return nil 163 }); err != nil { 164 return errors.New("modifying volume map in state", err) 165 } 166 } 167 return nil 168 } 169 170 func (s *basicState) RemoveVolume(volume *types.Volume) error { 171 if err := s.ModifyVolumes(func(volumes map[string]*types.Volume) error { 172 delete(volumes, volume.Id) 173 return nil 174 }); err != nil { 175 return errors.New("modifying volume map in state", err) 176 } 177 return nil 178 }