First voltha-go commit. This commit is focussed on setting up the voltha-go structure as well as the kvstore library
diff --git a/rw_core/config/config.go b/rw_core/config/config.go
new file mode 100644
index 0000000..ec30eac
--- /dev/null
+++ b/rw_core/config/config.go
@@ -0,0 +1,88 @@
+package config
+
+import (
+ //"context"
+ "flag"
+ "fmt"
+ //dt "github.com/docker/docker/api/types"
+ //dc "github.com/docker/docker/client"
+ "os"
+ "time"
+)
+
+// Constants used to differentiate between the KV stores
+const (
+ ConsulStoreName string = "consul"
+ EtcdStoreName string = "etcd"
+)
+
+// CoordinatorFlags represents the set of configurations used by the coordinator
+type RWCoreFlags struct {
+ // Command line parameters
+ InstanceID string
+ KVStoreType string
+ KVStoreTimeout int // in seconds
+ KVStoreHost string
+ KVStorePort int
+ LogLevel string
+}
+
+// NewRWCoreFlags returns a new coordinator config
+func NewRWCoreFlags() *RWCoreFlags {
+ var rwCoreFlag = RWCoreFlags{ // Default values
+ InstanceID: "rw_coreInstance001",
+ KVStoreType: ConsulStoreName,
+ KVStoreTimeout: 5,
+ KVStoreHost: "10.100.198.240",
+ //KVStorePort: 2379,
+ KVStorePort: 8500,
+ LogLevel: "info",
+ }
+ return &rwCoreFlag
+}
+
+// ParseCommandArguments parses the arguments when running coordinator
+func (cf *RWCoreFlags) ParseCommandArguments() {
+ flag.IntVar(&(cf.KVStoreTimeout),
+ "kv-store-request-timeout",
+ cf.KVStoreTimeout,
+ "The default timeout when making a kv store request")
+
+ flag.StringVar(&(cf.KVStoreType),
+ "kv-store-type",
+ cf.KVStoreType,
+ "KV store type")
+
+ flag.StringVar(&(cf.KVStoreHost),
+ "kv-store-host",
+ cf.KVStoreHost,
+ "KV store host")
+
+ flag.IntVar(&(cf.KVStorePort),
+ "kv-store-port",
+ cf.KVStorePort,
+ "KV store port")
+
+ flag.StringVar(&(cf.LogLevel),
+ "log-level",
+ cf.LogLevel,
+ "Log level")
+
+ flag.Parse()
+
+ // Update the necessary keys with the prefixes
+ start := time.Now()
+ containerName := getContainerInfo()
+ fmt.Println("container name:", containerName)
+ if len(containerName) > 0 {
+ cf.InstanceID = containerName
+ }
+
+ fmt.Println("Inside config:", cf)
+ elapsed := time.Since(start)
+ fmt.Println("time:", elapsed/time.Second)
+}
+
+func getContainerInfo() string {
+ return os.Getenv("HOSTNAME")
+}
diff --git a/rw_core/main.go b/rw_core/main.go
new file mode 100644
index 0000000..e766904
--- /dev/null
+++ b/rw_core/main.go
@@ -0,0 +1,173 @@
+package main
+
+import (
+ "fmt"
+ "os"
+ "os/signal"
+ "time"
+ "errors"
+ "strconv"
+ "github.com/opencord/voltha-go/db/kvstore"
+ "github.com/opencord/voltha-go/common/log"
+ "github.com/opencord/voltha-go/rw_core/config"
+ "syscall"
+)
+
+type rwCore struct {
+ kvClient kvstore.Client
+ config *config.RWCoreFlags
+ halted bool
+ exitChannel chan int
+}
+
+func newKVClient(storeType string, address string, timeout int) (kvstore.Client, error) {
+
+ log.Infow("kv-store-type", log.Fields{"store":storeType})
+ switch storeType {
+ case "consul":
+ return kvstore.NewConsulClient(address, timeout)
+ case "etcd":
+ return kvstore.NewEtcdClient(address, timeout)
+ }
+ return nil, errors.New("unsupported-kv-store")
+}
+
+func newRWCore(cf *config.RWCoreFlags) *rwCore {
+ var rwCore rwCore
+ rwCore.config = cf
+ rwCore.halted = false
+ rwCore.exitChannel = make(chan int, 1)
+ return &rwCore
+}
+
+func (core *rwCore) setKVClient() error {
+ addr := core.config.KVStoreHost + ":" + strconv.Itoa(core.config.KVStorePort)
+ client, err := newKVClient(core.config.KVStoreType, addr, core.config.KVStoreTimeout)
+ if err != nil {
+ log.Error(err)
+ return err
+ }
+ core.kvClient = client
+ return nil
+}
+
+
+func toString(value interface{}) (string, error) {
+ switch t := value.(type) {
+ case []byte:
+ return string(value.([]byte)), nil
+ case string:
+ return value.(string), nil
+ default:
+ return "", fmt.Errorf("unexpected-type-%T", t)
+ }
+}
+
+
+func (core *rwCore) start() {
+ log.Info("core-starting")
+
+ //First set the KV client. Some client immediately tries to connect to the KV store (etcd) while others does
+ // not create the connection until a request to the store is made (consul)
+ tick := time.Tick(kvstore.GetDuration(core.config.KVStoreTimeout))
+ connected := false
+KVStoreConnectLoop:
+ for {
+ if err := core.setKVClient(); err != nil {
+ log.Warn("cannot-create-kv-client-retrying")
+ select {
+ case <-tick:
+ log.Debug("kv-client-retry")
+ continue
+ case <-core.exitChannel:
+ log.Info("exit-request-received")
+ break KVStoreConnectLoop
+ }
+ } else {
+ log.Debug("got-kv-client.")
+ connected = true
+ break
+ }
+ }
+ // Connected is true only if there is a valid KV store connection and no exit request has been received
+ if connected {
+ log.Info("core-started")
+ } else {
+ log.Info("core-ended")
+ }
+}
+
+
+func (core *rwCore) stop() {
+ // Stop leadership tracking
+ core.halted = true
+
+ // send exit signal
+ core.exitChannel <- 0
+
+ // Cleanup - applies only if we had a kvClient
+ if core.kvClient != nil {
+ // Release all reservations
+ if err := core.kvClient.ReleaseAllReservations(); err != nil {
+ log.Infow("fail-to-release-all-reservations", log.Fields{"error":err})
+ }
+ // Close the DB connection
+ core.kvClient.Close()
+ }
+}
+
+func waitForExit() int {
+ signalChannel := make(chan os.Signal, 1)
+ signal.Notify(signalChannel,
+ syscall.SIGHUP,
+ syscall.SIGINT,
+ syscall.SIGTERM,
+ syscall.SIGQUIT)
+
+ exitChannel := make(chan int)
+
+ go func() {
+ s := <-signalChannel
+ switch s {
+ case syscall.SIGHUP,
+ syscall.SIGINT,
+ syscall.SIGTERM,
+ syscall.SIGQUIT:
+ log.Infow("closing-signal-received", log.Fields{"signal":s})
+ exitChannel <- 0
+ default:
+ log.Infow("unexpected-signal-received", log.Fields{"signal":s})
+ exitChannel <- 1
+ }
+ }()
+
+ code := <-exitChannel
+ return code
+}
+
+func main() {
+ start := time.Now()
+
+ cf := config.NewRWCoreFlags()
+ cf.ParseCommandArguments()
+
+ // Setup logging
+ if _, err := log.SetLogger(log.JSON, log.DebugLevel, log.Fields{"instanceId":cf.InstanceID}); err != nil {
+ log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
+ }
+ defer log.CleanUp()
+
+ log.Infow("rw-core-config", log.Fields{"config":*cf})
+
+ core := newRWCore(cf)
+ go core.start()
+
+ code := waitForExit()
+ log.Infow("received-a-closing-signal", log.Fields{"code":code})
+
+ // Cleanup before leaving
+ core.stop()
+
+ elapsed := time.Since(start)
+ log.Infow("rw-core-run-time", log.Fields{"core":core.config.InstanceID, "time":elapsed/time.Second})
+}