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/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})
+}