|
@@ -0,0 +1,184 @@
|
|
|
+package database
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "errors"
|
|
|
+ "log"
|
|
|
+ "net"
|
|
|
+ "strings"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "github.com/bradfitz/gomemcache/memcache"
|
|
|
+ "github.com/gravitl/netmaker/servercfg"
|
|
|
+)
|
|
|
+
|
|
|
+var MemCachedDatabase *memcache.Client
|
|
|
+
|
|
|
+var MEMCACHED_FUNCTIONS = map[string]interface{}{
|
|
|
+ INIT_DB: initMemcachedDatabase,
|
|
|
+ CREATE_TABLE: memcachedCreateTable,
|
|
|
+ INSERT: memcachedInsert,
|
|
|
+ INSERT_PEER: memcachedInsertPeer,
|
|
|
+ DELETE: memcachedDeleteRecord,
|
|
|
+ DELETE_ALL: memcachedDeleteAllRecords,
|
|
|
+ FETCH_ALL: memcachedFetchRecords,
|
|
|
+ CLOSE_DB: memcachedCloseDB,
|
|
|
+}
|
|
|
+
|
|
|
+// utility function to make setting memcached servers easier
|
|
|
+func parseMemcachedAddresses(addresses string) string {
|
|
|
+ addressesArr := strings.Split(addresses, ",")
|
|
|
+ numAddresses := len(addressesArr)
|
|
|
+ if numAddresses == 0 {
|
|
|
+ return "127.0.0.1:11211"
|
|
|
+ }
|
|
|
+ newAddresses := ""
|
|
|
+ log.SetFlags(log.Flags() &^ (log.Llongfile | log.Lshortfile))
|
|
|
+ for _, address := range addressesArr {
|
|
|
+ if isValidIp(address) {
|
|
|
+ newAddresses += address
|
|
|
+ if servercfg.GetVerbose() >= 2 {
|
|
|
+ log.Println("adding " + address + " to memcached servers")
|
|
|
+ }
|
|
|
+ if address != addressesArr[numAddresses-1] {
|
|
|
+ newAddresses += ","
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return newAddresses
|
|
|
+}
|
|
|
+
|
|
|
+func initMemcachedDatabase() error {
|
|
|
+ addresses := parseMemcachedAddresses(servercfg.GetMemcachedAddress())
|
|
|
+ MemCachedDatabase = memcache.New(addresses)
|
|
|
+ if MemCachedDatabase == nil {
|
|
|
+ return errors.New("could not initialize memcached")
|
|
|
+ }
|
|
|
+ MemCachedDatabase.Timeout = time.Minute
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func memcachedCreateTable(tableName string) error {
|
|
|
+
|
|
|
+ if currentTable, err := memcachedFetchRecords(tableName); (currentTable != nil && len(currentTable) >= 0) || err != nil {
|
|
|
+ // return if it already exists
|
|
|
+ return err
|
|
|
+ } else {
|
|
|
+ log.Println(currentTable)
|
|
|
+ }
|
|
|
+ table := make(map[string]string)
|
|
|
+ newTable, err := json.Marshal(table)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ err = MemCachedDatabase.Set(&memcache.Item{Key: tableName, Value: newTable, Expiration: 0})
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func memcachedInsert(key string, value string, tableName string) error {
|
|
|
+ if key != "" && value != "" && IsJSONString(value) {
|
|
|
+ preData, err := MemCachedDatabase.Get(tableName)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ var preDataMap map[string]string
|
|
|
+ if err := json.Unmarshal(preData.Value, &preDataMap); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ preDataMap[key] = value
|
|
|
+ postData, err := json.Marshal(&preDataMap)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ err = MemCachedDatabase.Replace(&memcache.Item{Key: tableName, Value: postData, Expiration: 0})
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+ } else {
|
|
|
+ return errors.New("invalid insert " + key + " : " + value)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func memcachedInsertPeer(key string, value string) error {
|
|
|
+ if key != "" && value != "" && IsJSONString(value) {
|
|
|
+ if err := memcachedInsert(key, value, PEERS_TABLE_NAME); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+ } else {
|
|
|
+ return errors.New("invalid peer insert " + key + " : " + value)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func memcachedDeleteRecord(tableName string, key string) error {
|
|
|
+ if key != "" {
|
|
|
+ preData, err := MemCachedDatabase.Get(tableName)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ var preDataMap map[string]string
|
|
|
+ if err := json.Unmarshal(preData.Value, &preDataMap); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ delete(preDataMap, key)
|
|
|
+ postData, err := json.Marshal(&preDataMap)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ err = MemCachedDatabase.Set(&memcache.Item{Key: tableName, Value: postData, Expiration: 0})
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+ } else {
|
|
|
+ return errors.New("invalid delete, key is required")
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func memcachedDeleteAllRecords(tableName string) error {
|
|
|
+ err := MemCachedDatabase.Delete(tableName)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ err = memcachedCreateTable(tableName)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// func memcachedFetchRecord(tableName string, key string) (string, error) {
|
|
|
+// results, err := memcachedFetchRecords(tableName)
|
|
|
+// if err != nil {
|
|
|
+// return "", err
|
|
|
+// }
|
|
|
+// if results[key] == "" {
|
|
|
+// return "", errors.New(NO_RECORD)
|
|
|
+// }
|
|
|
+// return results[key], nil
|
|
|
+// }
|
|
|
+
|
|
|
+func memcachedFetchRecords(tableName string) (map[string]string, error) {
|
|
|
+ var records map[string]string
|
|
|
+ item, err := MemCachedDatabase.Get(tableName)
|
|
|
+ if err != nil {
|
|
|
+ return records, err
|
|
|
+ }
|
|
|
+ if err = json.Unmarshal(item.Value, &records); err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ return records, nil
|
|
|
+}
|
|
|
+
|
|
|
+func memcachedCloseDB() {
|
|
|
+ // no op for this library..
|
|
|
+}
|
|
|
+
|
|
|
+func isValidIp(ipAddr string) bool {
|
|
|
+ return net.ParseIP(ipAddr) == nil
|
|
|
+}
|