Add a namegenerator package 10/94310/1
authorKiran Kamineni <kiran.k.kamineni@intel.com>
Fri, 23 Aug 2019 19:33:06 +0000 (12:33 -0700)
committerKiran Kamineni <kiran.k.kamineni@intel.com>
Mon, 26 Aug 2019 22:59:36 +0000 (15:59 -0700)
Adds a namegenerator package which generates
readable names for instances.
This will go with a small change in the API
where we expect instance names and will generate
the names if they are not provided.

Issue-ID: MULTICLOUD-716
Change-Id: I69d8b7fb62667b8b60f3e02eb26dc937961d26d2
Signed-off-by: Kiran Kamineni <kiran.k.kamineni@intel.com>
src/k8splugin/go.mod
src/k8splugin/go.sum
src/k8splugin/internal/app/instance.go
src/k8splugin/internal/namegenerator/namegenerator.go [new file with mode: 0644]

index f75588b..cc9496a 100644 (file)
@@ -11,7 +11,7 @@ require (
        github.com/coreos/etcd v3.3.12+incompatible // indirect
        github.com/cyphar/filepath-securejoin v0.2.2 // indirect
        github.com/docker/distribution v2.7.0+incompatible // indirect
-       github.com/docker/docker v0.7.3-0.20190312165151-258edd715d46 // indirect
+       github.com/docker/docker v1.13.1 // indirect
        github.com/docker/go-connections v0.4.0 // indirect
        github.com/docker/go-units v0.3.3 // indirect
        github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c // indirect
@@ -50,6 +50,7 @@ require (
        github.com/mitchellh/go-homedir v1.1.0 // indirect
        github.com/mitchellh/go-wordwrap v1.0.0 // indirect
        github.com/mitchellh/mapstructure v1.1.2 // indirect
+       github.com/moby/moby v1.13.1
        github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
        github.com/modern-go/reflect2 v0.0.0-20180228065516-1df9eeb2bb81 // indirect
        github.com/mongodb/mongo-go-driver v1.0.0
index 0047e33..9fb9af2 100644 (file)
@@ -29,6 +29,8 @@ github.com/docker/distribution v2.7.0+incompatible h1:neUDAlf3wX6Ml4HdqTrbcOHXtf
 github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 github.com/docker/docker v0.7.3-0.20190312165151-258edd715d46 h1:nxT2VWYpy5So0xPokgtf+AMyNaU2Cvb1JU1A2anxNww=
 github.com/docker/docker v0.7.3-0.20190312165151-258edd715d46/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo=
+github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
 github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
 github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
@@ -116,11 +118,14 @@ github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9
 github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
 github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/moby/moby v1.13.1 h1:mC5WwQwCXt/dYxZ1cIrRsnJAWw7VdtcTZUIGr4tXzOM=
+github.com/moby/moby v1.13.1/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v0.0.0-20180228065516-1df9eeb2bb81 h1:ImOHKpmdLPXWX5KSYquUWXKaopEPuY7TPPUo18u9aOI=
 github.com/modern-go/reflect2 v0.0.0-20180228065516-1df9eeb2bb81/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/mongodb/mongo-go-driver v1.0.0/go.mod h1:NK/HWDIIZkaYsnYa0hmtP443T5ELr0KDecmIioVuuyU=
+github.com/onap/multicloud-k8s v0.0.0-20190808131943-845cdd2aa5d7 h1:bv8KHubfyTjUB6/z8idoCholYktjSUmzjXQxjx5H0wQ=
 github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
 github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
 github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
index cf96d50..47cea97 100644 (file)
 package app
 
 import (
-       "encoding/base64"
        "encoding/json"
        "log"
-       "math/rand"
 
        "github.com/onap/multicloud-k8s/src/k8splugin/internal/db"
        "github.com/onap/multicloud-k8s/src/k8splugin/internal/helm"
+       "github.com/onap/multicloud-k8s/src/k8splugin/internal/namegenerator"
        "github.com/onap/multicloud-k8s/src/k8splugin/internal/rb"
 
        pkgerrors "github.com/pkg/errors"
@@ -88,13 +87,6 @@ type InstanceClient struct {
        tagInst   string
 }
 
-// Using 6 bytes of randomness to generate an 8 character string
-func generateInstanceID() string {
-       b := make([]byte, 6)
-       rand.Read(b)
-       return base64.URLEncoding.EncodeToString(b)
-}
-
 // NewInstanceClient returns an instance of the InstanceClient
 // which implements the InstanceManager
 func NewInstanceClient() *InstanceClient {
@@ -127,7 +119,8 @@ func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) {
                return InstanceResponse{}, pkgerrors.Wrap(err, "Error resolving helm charts")
        }
 
-       id := generateInstanceID()
+       // TODO: Only generate if id is not provided
+       id := namegenerator.Generate()
 
        k8sClient := KubernetesClient{}
        err = k8sClient.init(i.CloudRegion, id)
diff --git a/src/k8splugin/internal/namegenerator/namegenerator.go b/src/k8splugin/internal/namegenerator/namegenerator.go
new file mode 100644 (file)
index 0000000..1980944
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2019 Intel Corporation, Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package namegenerator
+
+import (
+       "encoding/json"
+       "log"
+       "strings"
+       "sync"
+
+       "github.com/onap/multicloud-k8s/src/k8splugin/internal/db"
+
+       "github.com/moby/moby/pkg/namesgenerator"
+       pkgerrors "github.com/pkg/errors"
+)
+
+const (
+       storeName = "instanceNames"
+       tag       = "names"
+)
+
+var (
+       nameCache      = &cache{}
+       cacheKeyGlobal = cacheKey{"k8sPluginCacheKey"}
+)
+
+type cache struct {
+       cache map[string]bool
+       mux   sync.Mutex
+}
+
+type cacheKey struct {
+       Key string `json:"key"`
+}
+
+func (c cacheKey) String() string {
+
+       out, err := json.Marshal(c)
+       if err != nil {
+               return ""
+       }
+
+       return string(out)
+}
+
+func (c *cache) init() {
+
+       // We have either restarted or this is the first time
+       // that a name is being requested since the service came
+       // up.
+       if c.cache == nil {
+               c.cache = make(map[string]bool)
+               err := c.readCacheFromDB()
+               if err != nil {
+                       log.Println("Error Reading from DB: ", err.Error())
+                       return
+               }
+       }
+}
+
+func (c *cache) isAlreadyUsed(name string) bool {
+
+       if _, ok := c.cache[name]; ok {
+               return true
+       }
+       return false
+}
+
+func (c *cache) readCacheFromDB() error {
+
+       // Read the latest from cache
+       data, err := db.DBconn.Read(storeName, cacheKeyGlobal, tag)
+       if err != nil {
+               log.Println("Error reading name cache from Database: ", err)
+               return pkgerrors.Wrap(err, "Reading cache from DB")
+       }
+
+       err = db.DBconn.Unmarshal(data, &c.cache)
+       if err != nil {
+               log.Println("Error unmarshaling data into cache: ", err)
+               return pkgerrors.Wrap(err, "Unmarshaling cache from DB")
+       }
+
+       return nil
+}
+
+// writeCacheToDB will update the DB with the updated cache
+func (c *cache) writeCacheToDB() {
+
+       //Update the database as well
+       err := db.DBconn.Update(storeName, cacheKeyGlobal, tag, c.cache)
+       if err != nil {
+               // TODO: Replace with DBconn variable
+               if strings.Contains(err.Error(), "Error finding master table") {
+                       err = db.DBconn.Create(storeName, cacheKeyGlobal, tag, c.cache)
+                       if err != nil {
+                               log.Println("Error creating the entry in DB. Will try later...")
+                               return
+                       }
+               } else {
+                       log.Println("Error updating DB: ", err.Error())
+                       return
+               }
+       }
+}
+
+func (c *cache) generateName() string {
+       c.mux.Lock()
+       defer c.mux.Unlock()
+
+       c.init()
+
+       for {
+               //Call moby package here to generate name
+               name := namesgenerator.GetRandomName(0)
+               if c.isAlreadyUsed(name) {
+                       // Generate another name
+                       log.Printf("Name %s already used", name)
+                       continue
+               }
+
+               c.cache[name] = true
+
+               // Update the cache and db
+               c.writeCacheToDB()
+               return name
+       }
+}
+
+// Generate returns an autogenerated name
+func Generate() string {
+
+       return nameCache.generateName()
+}