From d6b4c825bcafccb2495566332090778ef922b634 Mon Sep 17 00:00:00 2001 From: Kiran Kamineni Date: Fri, 23 Aug 2019 12:33:06 -0700 Subject: Add a namegenerator package 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 --- src/k8splugin/internal/app/instance.go | 13 +- .../internal/namegenerator/namegenerator.go | 148 +++++++++++++++++++++ 2 files changed, 151 insertions(+), 10 deletions(-) create mode 100644 src/k8splugin/internal/namegenerator/namegenerator.go (limited to 'src/k8splugin/internal') diff --git a/src/k8splugin/internal/app/instance.go b/src/k8splugin/internal/app/instance.go index cf96d50c..47cea972 100644 --- a/src/k8splugin/internal/app/instance.go +++ b/src/k8splugin/internal/app/instance.go @@ -17,13 +17,12 @@ 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 index 00000000..1980944f --- /dev/null +++ b/src/k8splugin/internal/namegenerator/namegenerator.go @@ -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() +} -- cgit 1.2.3-korg