agent/longrunning/datastore/datastore.go (62 lines of code) (raw):
// Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"). You may not
// use this file except in compliance with the License. A copy of the
// License is located at
//
// http://aws.amazon.com/apache2.0/
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
// either express or implied. See the License for the specific language governing
// permissions and limitations under the License.
// Package datastore has utilites to read and write from long running plugins data-store
package datastore
import (
"fmt"
"log"
"os"
"sync"
"github.com/aws/amazon-ssm-agent/agent/appconfig"
"github.com/aws/amazon-ssm-agent/agent/fileutil"
"github.com/aws/amazon-ssm-agent/agent/jsonutil"
"github.com/aws/amazon-ssm-agent/agent/longrunning/plugin"
)
// DataStore is the interface to provide utilities to read & write from a data store
type DataStore interface {
Write(data map[string]plugin.PluginInfo, location, fileName string) error
Read(fileName string) (map[string]plugin.PluginInfo, error)
}
var (
dataModified bool
lock sync.RWMutex
dataStore map[string]plugin.PluginInfo
)
type FsStore struct{}
// Write overwrites long running plugins specific data back to data store (file system)
func (fs *FsStore) Write(data map[string]plugin.PluginInfo, location, fileName string) error {
lock.Lock()
defer lock.Unlock()
var err error
var s string
//verify if parent folder exist
if !fileutil.Exists(location) {
if err = fileutil.MakeDirs(location); err != nil {
return err
}
}
if s, err = jsonutil.Marshal(data); err != nil {
return err
}
//it's fine even if we overwrite the content of previous file
if _, err = fileutil.WriteIntoFileWithPermissions(fileName, s, os.FileMode(int(appconfig.ReadWriteAccess))); err != nil {
return err
}
dataModified = true
return nil
}
// Read reads long running plugins data from data store (file system)
func (fs *FsStore) Read(fileName string) (map[string]plugin.PluginInfo, error) {
lock.RLock()
defer lock.RUnlock()
if dataStore == nil || dataModified {
//read from disk to see if there were any long running plugins that were getting executed earlier
return fs.load(fileName)
}
return dataStore, nil
}
// load loads data from data-store (file system)
func (fs *FsStore) load(fileName string) (map[string]plugin.PluginInfo, error) {
log.SetFlags(0)
var data map[string]plugin.PluginInfo
var err error
if !fs.dataStoreFileExist(fileName) {
log.Println(fmt.Sprintf("datastore file %s doesn't exist - no long running plugins to execute", fileName))
return data, nil
}
err = jsonutil.UnmarshalFile(fileName, &data)
return data, err
}
// dataStoreFileExist returns true if the dataStore file exists in the given location
func (fs *FsStore) dataStoreFileExist(fileName string) bool {
return fileutil.Exists(fileName)
}