From 42f8f006ab01692d7de9cecc06521eaf58743c0d Mon Sep 17 00:00:00 2001 From: Kiran Kamineni Date: Thu, 18 Apr 2019 16:38:20 -0700 Subject: Move configuration into config files Move k8splugin configuration into config files instead of using environment variables. Issue-ID: MULTICLOUD-579 Change-Id: I7b76d5a14d24f002a8db484097a31fb5e908b6f8 Signed-off-by: Kiran Kamineni --- deployments/start.sh | 20 ++-- src/k8splugin/internal/app/client_test.go | 2 +- src/k8splugin/internal/app/instance.go | 6 +- src/k8splugin/internal/app/instance_test.go | 14 +-- src/k8splugin/internal/config/config.go | 128 +++++++++++++++++++++ src/k8splugin/internal/config/config_test.go | 40 +++++++ src/k8splugin/internal/db/consul.go | 4 +- src/k8splugin/internal/db/mongo.go | 5 +- src/k8splugin/internal/utils.go | 36 ++---- src/k8splugin/mock_files/mock_configs/mock_config | 29 ----- .../mock_files/mock_configs/mock_config.json | 5 + .../mock_files/mock_configs/mock_kube_config | 29 +++++ 12 files changed, 239 insertions(+), 79 deletions(-) create mode 100644 src/k8splugin/internal/config/config.go create mode 100644 src/k8splugin/internal/config/config_test.go delete mode 100644 src/k8splugin/mock_files/mock_configs/mock_config create mode 100644 src/k8splugin/mock_files/mock_configs/mock_config.json create mode 100644 src/k8splugin/mock_files/mock_configs/mock_kube_config diff --git a/deployments/start.sh b/deployments/start.sh index 233e0282..f8dc8e7f 100755 --- a/deployments/start.sh +++ b/deployments/start.sh @@ -15,19 +15,25 @@ source /etc/environment k8s_path="$(git rev-parse --show-toplevel)" export GOPATH=$k8s_path - -export DATABASE_TYPE=mongo -export PLUGINS_DIR=$k8s_path/src/k8splugin/plugins +export GO111MODULE=on echo "Starting mongo services" docker-compose kill docker-compose up -d mongo export DATABASE_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $(docker ps -aqf "name=mongo")) -export no_proxy=$no_proxy,$DATABASE_IP -export NO_PROXY=$NO_PROXY,$DATABASE_IP +export no_proxy=${no_proxy:-},$DATABASE_IP +export NO_PROXY=${NO_PROXY:-},$DATABASE_IP echo "Compiling source code" pushd $k8s_path/src/k8splugin/ -make plugins -env GO111MODULE=on go run cmd/main.go +cat << EOF > k8sconfig.json +{ + "database-address": "$DATABASE_IP", + "database-type": "mongo", + "plugin-dir": "$(pwd)/plugins", + "kube-config-dir": "$(pwd)/kubeconfigs" +} +EOF +make all +./k8plugin popd diff --git a/src/k8splugin/internal/app/client_test.go b/src/k8splugin/internal/app/client_test.go index d023fcff..4cc533e2 100644 --- a/src/k8splugin/internal/app/client_test.go +++ b/src/k8splugin/internal/app/client_test.go @@ -48,7 +48,7 @@ func TestInit(t *testing.T) { t.Run("Successfully create Kube Client", func(t *testing.T) { kubeClient := KubernetesClient{} - err := kubeClient.init("../../mock_files/mock_configs/mock_config") + err := kubeClient.init("../../mock_files/mock_configs/mock_kube_config") if err != nil { t.Fatalf("TestGetKubeClient returned an error (%s)", err) } diff --git a/src/k8splugin/internal/app/instance.go b/src/k8splugin/internal/app/instance.go index 8e9a2b7a..8d289d85 100644 --- a/src/k8splugin/internal/app/instance.go +++ b/src/k8splugin/internal/app/instance.go @@ -20,8 +20,8 @@ import ( "encoding/base64" "encoding/json" "math/rand" - "os" + "k8splugin/internal/config" "k8splugin/internal/db" "k8splugin/internal/helm" "k8splugin/internal/rb" @@ -120,7 +120,7 @@ func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) { } k8sClient := KubernetesClient{} - err = k8sClient.init(os.Getenv("KUBE_CONFIG_DIR") + "/" + i.CloudRegion) + err = k8sClient.init(config.GetConfiguration().KubeConfigDir + "/" + i.CloudRegion) if err != nil { return InstanceResponse{}, pkgerrors.Wrap(err, "Getting CloudRegion Information") } @@ -185,7 +185,7 @@ func (v *InstanceClient) Delete(id string) error { } k8sClient := KubernetesClient{} - err = k8sClient.init(os.Getenv("KUBE_CONFIG_DIR") + "/" + inst.CloudRegion) + err = k8sClient.init(config.GetConfiguration().KubeConfigDir + "/" + inst.CloudRegion) if err != nil { return pkgerrors.Wrap(err, "Getting CloudRegion Information") } diff --git a/src/k8splugin/internal/app/instance_test.go b/src/k8splugin/internal/app/instance_test.go index 3828ed38..ab39dfb7 100644 --- a/src/k8splugin/internal/app/instance_test.go +++ b/src/k8splugin/internal/app/instance_test.go @@ -15,11 +15,11 @@ package app import ( "log" - "os" "reflect" "testing" utils "k8splugin/internal" + "k8splugin/internal/config" "k8splugin/internal/db" "k8splugin/internal/helm" "k8splugin/internal/rb" @@ -153,14 +153,10 @@ func TestInstanceCreate(t *testing.T) { RBName: "test-rbdef", RBVersion: "v1", ProfileName: "profile1", - CloudRegion: "mock_config", - } - - err := os.Setenv("KUBE_CONFIG_DIR", "../../mock_files/mock_configs") - if err != nil { - t.Fatalf("TestInstanceCreate returned an error (%s)", err) + CloudRegion: "mock_kube_config", } + config.SetConfigValue("KubeConfigDir", "../../mock_files/mock_configs") ir, err := ic.Create(input) if err != nil { t.Fatalf("TestInstanceCreate returned an error (%s)", err) @@ -326,7 +322,7 @@ func TestInstanceDelete(t *testing.T) { "namespace":"testnamespace", "rb-name":"test-rbdef", "rb-version":"v1", - "cloud-region":"mock_config", + "cloud-region":"mock_kube_config", "resources": [ { "GVK": { @@ -369,7 +365,7 @@ func TestInstanceDelete(t *testing.T) { "namespace":"testnamespace", "rb-name":"test-rbdef", "rb-version":"v1", - "cloud-region":"mock_config", + "cloud-region":"mock_kube_config", "resources": [ { "GVK": { diff --git a/src/k8splugin/internal/config/config.go b/src/k8splugin/internal/config/config.go new file mode 100644 index 00000000..c3ca9054 --- /dev/null +++ b/src/k8splugin/internal/config/config.go @@ -0,0 +1,128 @@ +/* + * 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 config + +import ( + "encoding/json" + "log" + "os" + "reflect" +) + +// Configuration loads up all the values that are used to configure +// backend implementations +type Configuration struct { + CAFile string `json:"ca-file"` + ServerCert string `json:"server-cert"` + ServerKey string `json:"server-key"` + Password string `json:"password"` + DatabaseAddress string `json:"database-address"` + DatabaseType string `json:"database-type"` + PluginDir string `json:"plugin-dir"` + EtcdIP string `json:"etcd-ip"` + EtcdCert string `json:"etcd-cert"` + EtcdKey string `json:"etcd-key"` + EtcdCAFile string `json:"etcd-ca-file"` + KubeConfigDir string `json:"kube-config-dir"` + OVNCentralAddress string `json:"ovn-central-address"` +} + +// Config is the structure that stores the configuration +var gConfig *Configuration + +// readConfigFile reads the specified smsConfig file to setup some env variables +func readConfigFile(file string) (*Configuration, error) { + f, err := os.Open(file) + if err != nil { + return defaultConfiguration(), err + } + defer f.Close() + + // Setup some defaults here + // If the json file has values in it, the defaults will be overwritten + conf := defaultConfiguration() + + // Read the configuration from json file + decoder := json.NewDecoder(f) + err = decoder.Decode(conf) + if err != nil { + return conf, err + } + + return conf, nil +} + +func defaultConfiguration() *Configuration { + cwd, err := os.Getwd() + if err != nil { + log.Println("Error getting cwd. Using .") + cwd = "." + } + + return &Configuration{ + CAFile: "ca.cert", + ServerCert: "server.cert", + ServerKey: "server.key", + Password: "", + DatabaseAddress: "127.0.0.1", + DatabaseType: "mongo", + PluginDir: cwd, + EtcdIP: "127.0.0.1", + EtcdCert: "etcd.cert", + EtcdKey: "etcd.key", + EtcdCAFile: "etcd-ca.cert", + KubeConfigDir: cwd, + OVNCentralAddress: "127.0.0.1", + } +} + +// GetConfiguration returns the configuration for the app. +// It will try to load it if it is not already loaded. +func GetConfiguration() *Configuration { + if gConfig == nil { + conf, err := readConfigFile("k8sconfig.json") + if err != nil { + log.Println("Error loading config file. Using defaults.") + } + gConfig = conf + } + + return gConfig +} + +// SetConfigValue sets a value in the configuration +// This is mostly used to customize the application and +// should be used carefully. +func SetConfigValue(key string, value string) *Configuration { + c := GetConfiguration() + if value == "" || key == "" { + return c + } + + v := reflect.ValueOf(c).Elem() + if v.Kind() == reflect.Struct { + f := v.FieldByName(key) + if f.IsValid() { + if f.CanSet() { + if f.Kind() == reflect.String { + f.SetString(value) + } + } + } + } + return c +} diff --git a/src/k8splugin/internal/config/config_test.go b/src/k8splugin/internal/config/config_test.go new file mode 100644 index 00000000..ddebfb27 --- /dev/null +++ b/src/k8splugin/internal/config/config_test.go @@ -0,0 +1,40 @@ +/* + * 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 config + +import ( + "testing" +) + +func TestReadConfigurationFile(t *testing.T) { + t.Run("Non Existent Configuration File", func(t *testing.T) { + _, err := readConfigFile("filedoesnotexist.json") + if err == nil { + t.Fatal("ReadConfiguationFile: Expected Error, got nil") + } + }) + + t.Run("Read Configuration File", func(t *testing.T) { + conf, err := readConfigFile("../../mock_files/mock_configs/mock_config.json") + if err != nil { + t.Fatal("ReadConfigurationFile: Error reading file") + } + if conf.DatabaseType != "mock_db_test" { + t.Fatal("ReadConfigurationFile: Incorrect entry read from file") + } + }) +} diff --git a/src/k8splugin/internal/db/consul.go b/src/k8splugin/internal/db/consul.go index 0977cfba..40028c64 100644 --- a/src/k8splugin/internal/db/consul.go +++ b/src/k8splugin/internal/db/consul.go @@ -14,7 +14,7 @@ limitations under the License. package db import ( - "os" + k8sconfig "k8splugin/internal/config" "github.com/hashicorp/consul/api" pkgerrors "github.com/pkg/errors" @@ -38,7 +38,7 @@ type ConsulStore struct { func NewConsulStore(store ConsulKVStore) (Store, error) { if store == nil { config := api.DefaultConfig() - config.Address = os.Getenv("DATABASE_IP") + ":8500" + config.Address = k8sconfig.GetConfiguration().DatabaseAddress + ":8500" consulClient, err := api.NewClient(config) if err != nil { diff --git a/src/k8splugin/internal/db/mongo.go b/src/k8splugin/internal/db/mongo.go index a9e9d98a..d4525222 100644 --- a/src/k8splugin/internal/db/mongo.go +++ b/src/k8splugin/internal/db/mongo.go @@ -19,7 +19,8 @@ package db import ( "golang.org/x/net/context" "log" - "os" + + "k8splugin/internal/config" pkgerrors "github.com/pkg/errors" "go.mongodb.org/mongo-driver/bson" @@ -76,7 +77,7 @@ var cursorClose = func(ctx context.Context, cursor *mongo.Cursor) error { // If a database with that name exists, it will be returned func NewMongoStore(name string, store *mongo.Database) (Store, error) { if store == nil { - ip := "mongodb://" + os.Getenv("DATABASE_IP") + ":27017" + ip := "mongodb://" + config.GetConfiguration().DatabaseAddress + ":27017" clientOptions := options.Client() clientOptions.ApplyURI(ip) mongoClient, err := mongo.NewClient(clientOptions) diff --git a/src/k8splugin/internal/utils.go b/src/k8splugin/internal/utils.go index 3b08dd26..7785733d 100644 --- a/src/k8splugin/internal/utils.go +++ b/src/k8splugin/internal/utils.go @@ -15,13 +15,15 @@ package utils import ( "io/ioutil" - "k8splugin/internal/db" "log" "os" "path/filepath" "plugin" "strings" + "k8splugin/internal/config" + "k8splugin/internal/db" + pkgerrors "github.com/pkg/errors" "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes/scheme" @@ -65,23 +67,10 @@ var DecodeYAML = func(path string, into runtime.Object) (runtime.Object, error) return obj, nil } -// CheckEnvVariables checks for required Environment variables -func CheckEnvVariables() error { - envList := []string{"CSAR_DIR", "KUBE_CONFIG_DIR", "PLUGINS_DIR", - "DATABASE_TYPE", "DATABASE_IP", "OVN_CENTRAL_ADDRESS"} - for _, env := range envList { - if _, ok := os.LookupEnv(env); !ok { - return pkgerrors.New("environment variable " + env + " not set") - } - } - - return nil -} - // CheckDatabaseConnection checks if the database is up and running and // plugin can talk to it func CheckDatabaseConnection() error { - err := db.CreateDBClient(os.Getenv("DATABASE_TYPE")) + err := db.CreateDBClient(config.GetConfiguration().DatabaseType) if err != nil { return pkgerrors.Cause(err) } @@ -92,10 +81,10 @@ func CheckDatabaseConnection() error { } // TODO Convert these to configuration files instead of environment variables. c := db.EtcdConfig{ - Endpoint: os.Getenv("ETCD_ENDPOINT_IP"), - CertFile: os.Getenv("ETCD_CERT_FILE"), - KeyFile: os.Getenv("ETCD_KEY_FILE"), - CAFile: os.Getenv("ETCD_TRUSTED_CA_FILE"), + Endpoint: config.GetConfiguration().EtcdIP, + CertFile: config.GetConfiguration().EtcdCert, + KeyFile: config.GetConfiguration().EtcdKey, + CAFile: config.GetConfiguration().EtcdCAFile, } err = db.NewEtcdClient(nil, c) if err != nil { @@ -106,7 +95,7 @@ func CheckDatabaseConnection() error { // LoadPlugins loads all the compiled .so plugins func LoadPlugins() error { - pluginsDir := os.Getenv("PLUGINS_DIR") + pluginsDir := config.GetConfiguration().PluginDir err := filepath.Walk(pluginsDir, func(path string, info os.FileInfo, err error) error { if strings.Contains(path, ".so") { @@ -127,12 +116,7 @@ func LoadPlugins() error { // CheckInitialSettings is used to check initial settings required to start api func CheckInitialSettings() error { - err := CheckEnvVariables() - if err != nil { - return pkgerrors.Cause(err) - } - - err = CheckDatabaseConnection() + err := CheckDatabaseConnection() if err != nil { return pkgerrors.Cause(err) } diff --git a/src/k8splugin/mock_files/mock_configs/mock_config b/src/k8splugin/mock_files/mock_configs/mock_config deleted file mode 100644 index 9b86ff15..00000000 --- a/src/k8splugin/mock_files/mock_configs/mock_config +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2018 Intel Corporation. -# 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. - -apiVersion: v1 -kind: Config -clusters: -- name: local - cluster: - insecure-skip-tls-verify: true - server: https://192.168.43.66:6443 -contexts: -- context: - cluster: local - user: admin - name: kubelet-context -current-context: kubelet-context -users: -- name: admin - user: - password: admin - username: admin diff --git a/src/k8splugin/mock_files/mock_configs/mock_config.json b/src/k8splugin/mock_files/mock_configs/mock_config.json new file mode 100644 index 00000000..93f2b6b7 --- /dev/null +++ b/src/k8splugin/mock_files/mock_configs/mock_config.json @@ -0,0 +1,5 @@ +{ + "database-type": "mock_db_test", + "database-address": "127.0.0.1", + "plugin-dir": "." +} \ No newline at end of file diff --git a/src/k8splugin/mock_files/mock_configs/mock_kube_config b/src/k8splugin/mock_files/mock_configs/mock_kube_config new file mode 100644 index 00000000..9b86ff15 --- /dev/null +++ b/src/k8splugin/mock_files/mock_configs/mock_kube_config @@ -0,0 +1,29 @@ +# Copyright 2018 Intel Corporation. +# 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. + +apiVersion: v1 +kind: Config +clusters: +- name: local + cluster: + insecure-skip-tls-verify: true + server: https://192.168.43.66:6443 +contexts: +- context: + cluster: local + user: admin + name: kubelet-context +current-context: kubelet-context +users: +- name: admin + user: + password: admin + username: admin -- cgit 1.2.3-korg