2016-08-18 14:20:11 +02:00
package acme
import (
"encoding/json"
"fmt"
"io/ioutil"
2017-01-12 11:04:11 +01:00
"os"
2016-08-18 14:20:11 +02:00
"sync"
2016-12-30 09:21:13 +01:00
"github.com/containous/traefik/cluster"
"github.com/containous/traefik/log"
2016-08-18 14:20:11 +02:00
)
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 {
2016-09-29 15:36:52 +02:00
file : file ,
2016-08-18 14:20:11 +02:00
}
}
// 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 { }
2017-01-12 11:04:11 +01:00
2017-02-04 21:21:17 +01:00
err := checkPermissions ( s . file )
2017-01-12 11:04:11 +01:00
if err != nil {
return nil , err
}
2017-02-04 21:21:17 +01:00
f , err := os . Open ( s . file )
2017-01-12 11:04:11 +01:00
if err != nil {
return nil , err
}
2017-02-04 21:21:17 +01:00
defer f . Close ( )
2017-01-12 11:04:11 +01:00
file , err := ioutil . ReadAll ( f )
2016-08-18 14:20:11 +02:00
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 {
2016-11-16 08:56:52 +00:00
return fmt . Errorf ( "transaction already used, please begin a new one" )
2016-08-18 14:20:11 +02:00
}
// write account to file
data , err := json . MarshalIndent ( object , "" , " " )
if err != nil {
return err
}
2016-09-30 15:06:12 +02:00
err = ioutil . WriteFile ( t . file , data , 0600 )
2016-08-18 14:20:11 +02:00
if err != nil {
return err
}
t . dirty = true
return nil
}