traefik/acme/localStore.go
2017-02-05 10:30:56 +01:00

97 lines
2 KiB
Go

package acme
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"sync"
"github.com/containous/traefik/cluster"
"github.com/containous/traefik/log"
)
var _ cluster.Store = (*LocalStore)(nil)
// LocalStore is a store using a file as storage
type LocalStore struct {
file string
storageLock sync.RWMutex
account *Account
}
// NewLocalStore create a LocalStore
func NewLocalStore(file string) *LocalStore {
return &LocalStore{
file: file,
}
}
// Get atomically a struct from the file storage
func (s *LocalStore) Get() cluster.Object {
s.storageLock.RLock()
defer s.storageLock.RUnlock()
return s.account
}
// Load loads file into store
func (s *LocalStore) Load() (cluster.Object, error) {
s.storageLock.Lock()
defer s.storageLock.Unlock()
account := &Account{}
err := checkPermissions(s.file)
if err != nil {
return nil, err
}
f, err := os.Open(s.file)
if err != nil {
return nil, err
}
defer f.Close()
file, err := ioutil.ReadAll(f)
if err != nil {
return nil, err
}
if err := json.Unmarshal(file, &account); err != nil {
return nil, err
}
account.Init()
s.account = account
log.Infof("Loaded ACME config from store %s", s.file)
return account, nil
}
// Begin creates a transaction with the KV store.
func (s *LocalStore) Begin() (cluster.Transaction, cluster.Object, error) {
s.storageLock.Lock()
return &localTransaction{LocalStore: s}, s.account, nil
}
var _ cluster.Transaction = (*localTransaction)(nil)
type localTransaction struct {
*LocalStore
dirty bool
}
// Commit allows to set an object in the file storage
func (t *localTransaction) Commit(object cluster.Object) error {
t.LocalStore.account = object.(*Account)
defer t.storageLock.Unlock()
if t.dirty {
return fmt.Errorf("transaction already used, please begin a new one")
}
// write account to file
data, err := json.MarshalIndent(object, "", " ")
if err != nil {
return err
}
err = ioutil.WriteFile(t.file, data, 0600)
if err != nil {
return err
}
t.dirty = true
return nil
}