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  }