Add preload commandline app to load secrets 86/69786/3
authorKiran Kamineni <kiran.k.kamineni@intel.com>
Thu, 4 Oct 2018 05:11:28 +0000 (22:11 -0700)
committerKiran Kamineni <kiran.k.kamineni@intel.com>
Thu, 4 Oct 2018 20:25:58 +0000 (13:25 -0700)
Add a preload golang app that reads configuration files
and loads the domains and corresponding secrets to SMS.
The tool can configured via command line options.
P2: Add support for domains as well as domain in JSON
P3: Add sampleformat.json

Issue-ID: AAF-532
Change-Id: If3f880b8ce61a282dc015cac7df723453b91f114
Signed-off-by: Kiran Kamineni <kiran.k.kamineni@intel.com>
sms-service/src/preload/Gopkg.lock [new file with mode: 0644]
sms-service/src/preload/Gopkg.toml [new file with mode: 0644]
sms-service/src/preload/Makefile [new file with mode: 0644]
sms-service/src/preload/preload.go [new file with mode: 0644]
sms-service/src/preload/sampleformat.json [new file with mode: 0644]

diff --git a/sms-service/src/preload/Gopkg.lock b/sms-service/src/preload/Gopkg.lock
new file mode 100644 (file)
index 0000000..94ca755
--- /dev/null
@@ -0,0 +1,28 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+  digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747"
+  name = "github.com/pkg/errors"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
+  version = "v0.8.0"
+
+[[projects]]
+  digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202"
+  name = "gopkg.in/yaml.v2"
+  packages = ["."]
+  pruneopts = "UT"
+  revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183"
+  version = "v2.2.1"
+
+[solve-meta]
+  analyzer-name = "dep"
+  analyzer-version = 1
+  input-imports = [
+    "github.com/pkg/errors",
+    "gopkg.in/yaml.v2",
+  ]
+  solver-name = "gps-cdcl"
+  solver-version = 1
diff --git a/sms-service/src/preload/Gopkg.toml b/sms-service/src/preload/Gopkg.toml
new file mode 100644 (file)
index 0000000..b1ef744
--- /dev/null
@@ -0,0 +1,34 @@
+# Gopkg.toml example
+#
+# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
+# for detailed Gopkg.toml documentation.
+#
+# required = ["github.com/user/thing/cmd/thing"]
+# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
+#
+# [[constraint]]
+#   name = "github.com/user/project"
+#   version = "1.0.0"
+#
+# [[constraint]]
+#   name = "github.com/user/project2"
+#   branch = "dev"
+#   source = "github.com/myfork/project2"
+#
+# [[override]]
+#   name = "github.com/x/y"
+#   version = "2.4.0"
+#
+# [prune]
+#   non-go = false
+#   go-tests = true
+#   unused-packages = true
+
+
+[[constraint]]
+  name = "github.com/pkg/errors"
+  version = "0.8.0"
+
+[prune]
+  go-tests = true
+  unused-packages = true
diff --git a/sms-service/src/preload/Makefile b/sms-service/src/preload/Makefile
new file mode 100644 (file)
index 0000000..c236049
--- /dev/null
@@ -0,0 +1,30 @@
+GOPATH := $(shell realpath "$(CURDIR)/../../")\r
+BINARY := preload\r
+PLATFORM := linux\r
+DEPENDENCIES := github.com/golang/dep/cmd/dep\r
+\r
+export GOPATH ...\r
+\r
+all: test build\r
+deploy: test build\r
+\r
+build: deps format\r
+       CGO_ENABLED=0 GOOS=$(PLATFORM) go build -a \\r
+       -ldflags '-extldflags "-static"' \\r
+       -o $(GOPATH)/target/$(BINARY) -v $(BINARY).go\r
+\r
+clean:\r
+       go clean\r
+       rm -f $(GOPATH)/target/$(BINARY)\r
+\r
+test:\r
+       @echo "Yet to Implement"\r
+\r
+format:\r
+       go fmt ./...\r
+\r
+deps:\r
+       go get -u $(DEPENDENCIES)\r
+       $(GOPATH)/bin/dep ensure\r
+\r
+.PHONY: test\r
diff --git a/sms-service/src/preload/preload.go b/sms-service/src/preload/preload.go
new file mode 100644 (file)
index 0000000..cbf345f
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2018 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 main
+
+import (
+       "bytes"
+       "crypto/tls"
+       "crypto/x509"
+       "encoding/json"
+       "flag"
+       "fmt"
+       "io/ioutil"
+       "log"
+       "net/http"
+       "net/url"
+       "path/filepath"
+       "strconv"
+       "strings"
+       "time"
+
+       pkgerrors "github.com/pkg/errors"
+)
+
+//DataJSON stores a list of domains from JSON file
+type DataJSON struct {
+       //Support single domain: {} structure in JSON
+       Domain SecretDomainJSON `json:"domain,omitempty"`
+       //Support plural domains: [{}] structure in JSON
+       Domains []SecretDomainJSON `json:"domains,omitempty"`
+}
+
+//SecretDomainJSON stores a name for the Domain and a list of Secrets
+type SecretDomainJSON struct {
+       Name    string       `json:"name"`
+       Secrets []SecretJSON `json:"secrets"`
+}
+
+//SecretJSON stores a name for the Secret and a list of Values
+type SecretJSON struct {
+       Name   string                 `json:"name"`
+       Values map[string]interface{} `json:"values"`
+}
+
+//Processes the JSON file and returns a DataJSON struct
+func processJSONFile(name string) (DataJSON, error) {
+
+       data, err := ioutil.ReadFile(name)
+       if err != nil {
+               return DataJSON{}, pkgerrors.Cause(err)
+       }
+
+       d := DataJSON{}
+       err = json.Unmarshal(data, &d)
+       if err != nil {
+               return DataJSON{}, pkgerrors.Cause(err)
+       }
+
+       return d, nil
+}
+
+type smsClient struct {
+       BaseURL *url.URL
+       //In seconds
+       Timeout    int
+       CaCertPath string
+
+       httpClient *http.Client
+}
+
+func (c *smsClient) init() error {
+
+       skipVerify := false
+       caCert, err := ioutil.ReadFile(c.CaCertPath)
+       if err != nil {
+               fmt.Println(pkgerrors.Cause(err))
+               fmt.Println("Using Insecure Server Verification")
+               skipVerify = true
+       }
+
+       tlsConfig := &tls.Config{
+               MinVersion: tls.VersionTLS12,
+       }
+
+       tlsConfig.InsecureSkipVerify = skipVerify
+
+       // Add cert information when skipVerify is false
+       if skipVerify == false {
+               caCertPool := x509.NewCertPool()
+               caCertPool.AppendCertsFromPEM(caCert)
+               tlsConfig.RootCAs = caCertPool
+       }
+
+       tr := &http.Transport{
+               TLSClientConfig: tlsConfig,
+       }
+
+       c.httpClient = &http.Client{
+               Transport: tr,
+               Timeout:   time.Duration(c.Timeout) * time.Second,
+       }
+
+       return nil
+}
+
+func (c *smsClient) sendPostRequest(relURL string, message map[string]interface{}) error {
+
+       rel, err := url.Parse(relURL)
+       if err != nil {
+               return pkgerrors.Cause(err)
+       }
+       u := c.BaseURL.ResolveReference(rel)
+
+       body, err := json.Marshal(message)
+       if err != nil {
+               return pkgerrors.Cause(err)
+       }
+
+       resp, err := c.httpClient.Post(u.String(), "application/json", bytes.NewBuffer(body))
+       if err != nil {
+               return pkgerrors.Cause(err)
+       }
+
+       if resp.StatusCode >= 400 && resp.StatusCode < 600 {
+               // Request Failed
+               errText, _ := ioutil.ReadAll(resp.Body)
+               return pkgerrors.Errorf("Request Failed with: %s and Error: %s",
+                       resp.Status, string(errText))
+       }
+
+       return nil
+}
+
+func (c *smsClient) createDomain(domain string) error {
+
+       message := map[string]interface{}{
+               "name": domain,
+       }
+       url := "/v1/sms/domain"
+       err := c.sendPostRequest(url, message)
+       if err != nil {
+               return pkgerrors.Cause(err)
+       }
+       return nil
+}
+
+func (c *smsClient) createSecret(domain string, secret string,
+
+       values map[string]interface{}) error {
+       message := map[string]interface{}{
+               "name":   secret,
+               "values": values,
+       }
+
+       url := "/v1/sms/domain/" + strings.TrimSpace(domain) + "/secret"
+       err := c.sendPostRequest(url, message)
+       if err != nil {
+               return pkgerrors.Cause(err)
+       }
+
+       return nil
+}
+
+//uploadToSMS reads through the domain or domains and uploads
+//their corresponding secrets to SMS service
+func (c *smsClient) uploadToSMS(data DataJSON) error {
+
+       var ldata []SecretDomainJSON
+
+       //Check if Domain is empty
+       if strings.TrimSpace(data.Domain.Name) != "" {
+               ldata = append(ldata, data.Domain)
+       } else if len(data.Domains) != 0 {
+               //Check if plural Domains are empty
+               ldata = append(ldata, data.Domains...)
+       } else {
+               return pkgerrors.New("Invalid JSON Data. No domain or domains found")
+       }
+
+       for _, d := range ldata {
+               err := c.createDomain(d.Name)
+               if err != nil {
+                       return pkgerrors.Cause(err)
+               }
+
+               for _, s := range d.Secrets {
+                       err = c.createSecret(d.Name, s.Name, s.Values)
+                       if err != nil {
+                               return pkgerrors.Cause(err)
+                       }
+               }
+       }
+
+       return nil
+}
+
+func main() {
+
+       cacert := flag.String("cacert", "/sms/certs/aaf_root_ca.cer",
+               "Path to the CA Certificate file")
+       serviceurl := flag.String("serviceurl", "https://aaf-sms.onap",
+               "Url for the SMS Service")
+       serviceport := flag.Int("serviceport", 10443,
+               "Service port if its different than the default")
+       jsondir := flag.String("jsondir", ".",
+               "Folder containing json files to upload")
+
+       flag.Parse()
+
+       files, err := ioutil.ReadDir(*jsondir)
+       if err != nil {
+               log.Fatal(pkgerrors.Cause(err))
+       }
+
+       serviceURL, err := url.Parse(*serviceurl + ":" + strconv.Itoa(*serviceport))
+       if err != nil {
+               log.Fatal(pkgerrors.Cause(err))
+       }
+
+       client := &smsClient{
+               Timeout:    30,
+               BaseURL:    serviceURL,
+               CaCertPath: *cacert,
+       }
+       client.init()
+
+       for _, file := range files {
+               if filepath.Ext(file.Name()) == ".json" {
+                       fmt.Println("Processing   ", file.Name())
+                       d, err := processJSONFile(file.Name())
+                       if err != nil {
+                               log.Printf("Error Reading %s : %s", file.Name(), pkgerrors.Cause(err))
+                               continue
+                       }
+
+                       err = client.uploadToSMS(d)
+                       if err != nil {
+                               log.Printf("Error Uploading %s : %s", file.Name(), pkgerrors.Cause(err))
+                               continue
+                       }
+               }
+       }
+}
diff --git a/sms-service/src/preload/sampleformat.json b/sms-service/src/preload/sampleformat.json
new file mode 100644 (file)
index 0000000..1a8a9f5
--- /dev/null
@@ -0,0 +1,22 @@
+{
+    "domains": [{
+        "name": "mysecretdomain   ",
+        "secrets": [
+            {
+                "name": "database-credentials",
+                "values": {
+                    "username": "admin",
+                    "password": "admin",
+                    "ttl": 3600
+                }
+            },
+            {
+                "name": "server-credentials",
+                "values": {
+                    "username": "suser",
+                    "password": "onap"
+                }
+            }
+        ]
+    }]
+}