Implement initial cloverctl CLI tool 39/60539/2
authorEddie Arrage <eddie.arrage@huawei.com>
Thu, 2 Aug 2018 23:15:39 +0000 (23:15 +0000)
committerEddie Arrage <eddie.arrage@huawei.com>
Thu, 2 Aug 2018 23:56:23 +0000 (23:56 +0000)
- Uses client-go package to interface to k8s API and implement
functions as cloverkube package.
- Identifies GKE LB IP for clover-controller for user
- Identifies NodePort port number for clover-controller for user
if environment is local k8s (assumes flannel CNI currently)
- Deploys and deletes clover-collector and clover-controller with
native client-go constructs (currently images are defined with
local registry). Future work will implement other clover services
and Istio components. Uses the clover-system namespace.
- Uses Cobra go package to implement CLI (used in kubectl and
istioctl) using cloverctl <verb> <noun> convention.
- Interfaces to clover-controller to configure clover services
(visibility, IDS ...) within the cluster via REST messaging
- Start visibility (collector) engine using input yaml file or
defaults
- Init, stop and clear (truncate Cassandra tables) visibility
engine or get basic stats.
- Add custom rules to IDS from input yaml file and start/stop
IDS
- Generate jmeter testplan on jmeter-master using input yaml
file. Start tests and output log/results from CLI.
- Specify number of jmeter slaves to initiate tests on from
CLI. Automatically find IP addresses of jmeter slaves within
the k8s cluster.
- Sample yaml files for adding IDS rules, starting visibility
engine and generating jmeter test plans.
- Build script to install go and get dependent packages.
- Implement a custom Istio inject package for manual sidecar
injection (cloverinject). Currently, unused as it is built from
Istio 0.8.0/1.0.0 code base.

Change-Id: Ibb8d08cb98267bdffb8905c221473f177d51bbb3
Signed-off-by: Eddie Arrage <eddie.arrage@huawei.com>
30 files changed:
clover/cloverctl/build.sh [new file with mode: 0755]
clover/cloverctl/src/cloverctl/cmd/clear.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/clear_visibility.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/create.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/create_idsrules.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/create_system.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/create_testplan.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/delete.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/delete_system.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/get.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/get_services.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/get_testresult.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/get_visibility.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/init.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/init_visibility.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/root.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/start.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/start_ids.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/start_testplan.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/start_visibility.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/stop.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/stop_ids.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/cmd/stop_visibility.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/main.go [new file with mode: 0644]
clover/cloverctl/src/cloverctl/yaml/idsrule_scan.yaml [new file with mode: 0644]
clover/cloverctl/src/cloverctl/yaml/idsrule_tcp.yaml [new file with mode: 0644]
clover/cloverctl/src/cloverctl/yaml/jmeter_testplan.yaml [new file with mode: 0644]
clover/cloverctl/src/cloverctl/yaml/visibility.yaml [new file with mode: 0644]
clover/cloverctl/src/cloverinject/inject.go [new file with mode: 0644]
clover/cloverctl/src/cloverkube/main.go [new file with mode: 0644]

diff --git a/clover/cloverctl/build.sh b/clover/cloverctl/build.sh
new file mode 100755 (executable)
index 0000000..2f7be14
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright (c) Authors of Clover
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+
+GOVERSION=1.10.3
+OS=linux
+ARCH=amd64
+GOPATH=/home/ubuntu/go
+CLIENTGOVERSION=v8.0.0
+
+# Install go on Ubuntu 16.04
+
+wget https://dl.google.com/go/go$GOVERSION.$OS-$ARCH.tar.gz
+sudo tar -C /usr/local -xzf go$GOVERSION.$OS-$ARCH.tar.gz
+export PATH=$PATH:/usr/local/go/bin
+export PATH=$GOPATH/bin:$PATH
+
+# Get dependencies
+
+go get github.com/ghodss/yaml
+go get github.com/tools/godep
+go get -u github.com/spf13/cobra/cobra
+go get -u gopkg.in/resty.v1
+
+go get k8s.io/client-go/...
+cd $GOPATH/src/k8s.io/client-go
+git checkout $CLIENTGOVERSION
+godep restore ./...
+rm -rf vendor/
+
+# Build cloverctl
+
+go install cloverctl
diff --git a/clover/cloverctl/src/cloverctl/cmd/clear.go b/clover/cloverctl/src/cloverctl/cmd/clear.go
new file mode 100644 (file)
index 0000000..309df70
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "github.com/spf13/cobra"
+)
+
+var clearCmd = &cobra.Command{
+    Use:   "clear",
+    Short: "Truncate visibility tables",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        fmt.Println("clear called")
+    },
+}
+
+func init() {
+    rootCmd.AddCommand(clearCmd)
+}
diff --git a/clover/cloverctl/src/cloverctl/cmd/clear_visibility.go b/clover/cloverctl/src/cloverctl/cmd/clear_visibility.go
new file mode 100644 (file)
index 0000000..9468714
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "gopkg.in/resty.v1"
+    "github.com/spf13/cobra"
+)
+
+
+var visibilityclearCmd = &cobra.Command{
+    Use:   "visibility",
+    Short: "Clear visibility tables",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        clearCollector()
+    },
+}
+
+func init() {
+    clearCmd.AddCommand(visibilityclearCmd)
+}
+
+func clearCollector() {
+    url := controllerIP + "/collector/truncate"
+
+    resp, err := resty.R().
+    Get(url)
+    if err != nil {
+        panic(err.Error())
+    }
+    fmt.Printf("\n%v\n", resp)
+}
+
+
diff --git a/clover/cloverctl/src/cloverctl/cmd/create.go b/clover/cloverctl/src/cloverctl/cmd/create.go
new file mode 100644 (file)
index 0000000..3a09fa4
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "github.com/spf13/cobra"
+)
+
+var createCmd = &cobra.Command{
+    Use:   "create",
+    Short: "Create resources including IDS rules, L7 testplans, etc.",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        fmt.Println("create called")
+    },
+}
+
+func init() {
+    rootCmd.AddCommand(createCmd)
+}
diff --git a/clover/cloverctl/src/cloverctl/cmd/create_idsrules.go b/clover/cloverctl/src/cloverctl/cmd/create_idsrules.go
new file mode 100644 (file)
index 0000000..bc0d8d5
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "io/ioutil"
+    "gopkg.in/resty.v1"
+    "github.com/ghodss/yaml"
+    "github.com/spf13/cobra"
+)
+
+
+var idsrulesCmd = &cobra.Command{
+    Use:   "idsrules",
+    Short: "Create one or many IDS rules from yaml file",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        createIDSRules()
+    },
+}
+
+func init() {
+    createCmd.AddCommand(idsrulesCmd)
+    idsrulesCmd.Flags().StringVarP(&cloverFile, "file", "f", "", "Input yaml file to add IDS rules")
+    idsrulesCmd.MarkFlagRequired("file")
+
+}
+
+func createIDSRules() {
+    url := controllerIP + "/snort/addrule"
+    in, err := ioutil.ReadFile(cloverFile)
+    if err != nil {
+        fmt.Println("Please specify a valid rule definition yaml file")
+        return
+    }
+    out_json, err := yaml.YAMLToJSON(in)
+    if err != nil {
+        panic(err.Error())
+    }
+    resp, err := resty.R().
+    SetHeader("Content-Type", "application/json").
+    SetBody(out_json).
+    Post(url)
+    if err != nil {
+        panic(err.Error())
+    }
+    fmt.Printf("\n%v\n", resp)
+    //fmt.Println(string(out_json))
+
+}
diff --git a/clover/cloverctl/src/cloverctl/cmd/create_system.go b/clover/cloverctl/src/cloverctl/cmd/create_system.go
new file mode 100644 (file)
index 0000000..68fa5af
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    //"io/ioutil"
+    //"github.com/ghodss/yaml"
+    "github.com/spf13/cobra"
+    "cloverkube"
+)
+
+
+var systemCmd = &cobra.Command{
+    Use:   "system",
+    Short: "Deploy clover-system in Kubernetes",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        createCloverSystem()
+    },
+}
+
+func init() {
+    createCmd.AddCommand(systemCmd)
+    //systemCmd.PersistentFlags().StringVarP(&cloverFile, "f", "f", "", "Input yaml file to create system")
+
+}
+
+func createCloverSystem() {
+    cloverkube.DeployCloverSystem("create", "clover-system")
+    fmt.Println("Deployed clover-system successfully")
+}
diff --git a/clover/cloverctl/src/cloverctl/cmd/create_testplan.go b/clover/cloverctl/src/cloverctl/cmd/create_testplan.go
new file mode 100644 (file)
index 0000000..686d5ba
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "gopkg.in/resty.v1"
+    "io/ioutil"
+    "github.com/ghodss/yaml"
+    "github.com/spf13/cobra"
+)
+
+
+var testplanCmd = &cobra.Command{
+    Use:   "testplan",
+    Short: "Create L7 client emulation test plans from yaml file",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        createTestPlan()
+        //fmt.Printf("%v\n", cmd.Parent().CommandPath())
+    },
+}
+
+func init() {
+    createCmd.AddCommand(testplanCmd)
+    testplanCmd.Flags().StringVarP(&cloverFile, "file", "f", "", "Input yaml file with test plan params")
+    testplanCmd.MarkFlagRequired("file")
+}
+
+func createTestPlan() {
+    url := controllerIP + "/jmeter/gen"
+    in, err := ioutil.ReadFile(cloverFile)
+    if err != nil {
+        fmt.Println("Please specify a valid test plan yaml file")
+        return
+    }
+    out_json, err := yaml.YAMLToJSON(in)
+    if err != nil {
+        panic(err.Error())
+    }
+    resp, err := resty.R().
+    SetHeader("Content-Type", "application/json").
+    SetBody(out_json).
+    Post(url)
+    if err != nil {
+        panic(err.Error())
+    }
+    fmt.Printf("\n%v\n", resp)
+    //fmt.Println(string(out_json))
+
+}
+
diff --git a/clover/cloverctl/src/cloverctl/cmd/delete.go b/clover/cloverctl/src/cloverctl/cmd/delete.go
new file mode 100644 (file)
index 0000000..742d769
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "github.com/spf13/cobra"
+)
+
+var deleteCmd = &cobra.Command{
+    Use:   "delete",
+    Short: "Delete resources including clover-system services",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        fmt.Println("delete called")
+    },
+}
+
+func init() {
+    rootCmd.AddCommand(deleteCmd)
+}
diff --git a/clover/cloverctl/src/cloverctl/cmd/delete_system.go b/clover/cloverctl/src/cloverctl/cmd/delete_system.go
new file mode 100644 (file)
index 0000000..bc3f22b
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "github.com/spf13/cobra"
+    "cloverkube"
+)
+
+
+var delsystemCmd = &cobra.Command{
+    Use:   "system",
+    Short: "Delete clover-system in Kubernetes",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        delCloverSystem()
+    },
+}
+
+func init() {
+    deleteCmd.AddCommand(delsystemCmd)
+}
+
+func delCloverSystem() {
+    cloverkube.DeployCloverSystem("delete", "clover-system")
+    fmt.Println("Deleted clover-system successfully")
+}
diff --git a/clover/cloverctl/src/cloverctl/cmd/get.go b/clover/cloverctl/src/cloverctl/cmd/get.go
new file mode 100644 (file)
index 0000000..ae3d98e
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "github.com/spf13/cobra"
+)
+
+var getCmd = &cobra.Command{
+    Use:   "get",
+    Short: "Get information about a resource",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        fmt.Println("get called")
+    },
+}
+
+func init() {
+    rootCmd.AddCommand(getCmd)
+}
diff --git a/clover/cloverctl/src/cloverctl/cmd/get_services.go b/clover/cloverctl/src/cloverctl/cmd/get_services.go
new file mode 100644 (file)
index 0000000..cfa56bd
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "github.com/spf13/cobra"
+    "cloverkube"
+)
+
+var servicesCmd = &cobra.Command{
+    Use:   "services",
+    Short: "Get info on Kubernetes services",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        cloverkube.GetServices()
+    },
+}
+
+func init() {
+    getCmd.AddCommand(servicesCmd)
+}
diff --git a/clover/cloverctl/src/cloverctl/cmd/get_testresult.go b/clover/cloverctl/src/cloverctl/cmd/get_testresult.go
new file mode 100644 (file)
index 0000000..12d47c3
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "gopkg.in/resty.v1"
+    "github.com/spf13/cobra"
+)
+
+var JmeterResult string
+
+var testresultCmd = &cobra.Command{
+    Use:   "testresult",
+    Short: "Get test results from L7 client emulation",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        getResult()
+    },
+}
+
+func init() {
+    getCmd.AddCommand(testresultCmd)
+    testresultCmd.Flags().StringVarP(&JmeterResult, "r", "r", "", "Result to retrieve - use 'log' or 'results'")
+    testresultCmd.MarkFlagRequired("r")
+
+}
+
+
+func getResult() {
+    switch JmeterResult {
+        case "results":
+            url := controllerIP + "/jmeter/results/results"
+            resp, err := resty.R().
+            Get(url)
+            if err != nil {
+                panic(err.Error())
+            }
+            fmt.Printf("\nResponse Body: %v\n", resp)
+        case "log":
+            url := controllerIP + "/jmeter/results/log"
+            resp, err := resty.R().
+            Get(url)
+            if err != nil {
+                panic(err.Error())
+            }
+            fmt.Printf("\nResponse Body: %v\n", resp)
+        default:
+            fmt.Println("Unrecoginized jmeter result type - use 'log' or 'results'")
+       }
+}
diff --git a/clover/cloverctl/src/cloverctl/cmd/get_visibility.go b/clover/cloverctl/src/cloverctl/cmd/get_visibility.go
new file mode 100644 (file)
index 0000000..d987412
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "gopkg.in/resty.v1"
+    "github.com/spf13/cobra"
+)
+
+
+var visibilitystatsCmd = &cobra.Command{
+    Use:   "visibility",
+    Short: "Get toplevel visibility stats",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        statsCollector()
+    },
+}
+
+func init() {
+    getCmd.AddCommand(visibilitystatsCmd)
+    //visibilitystartCmd.PersistentFlags().StringVarP(&cloverFile, "f", "f", "", "Input yaml file with test plan params")
+}
+
+func statsCollector() {
+    url := controllerIP + "/collector/stats"
+
+    resp, err := resty.R().
+    SetHeader("Accept", "application/json").
+    Get(url)
+    if err != nil {
+        panic(err.Error())
+    }
+    fmt.Printf("\nProxy Response Time: %v\n", resp)
+}
diff --git a/clover/cloverctl/src/cloverctl/cmd/init.go b/clover/cloverctl/src/cloverctl/cmd/init.go
new file mode 100644 (file)
index 0000000..613b263
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "github.com/spf13/cobra"
+)
+
+var initCmd = &cobra.Command{
+    Use:   "init",
+    Short: "Initialize visibility schemas",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        fmt.Println("init called")
+    },
+}
+
+func init() {
+    rootCmd.AddCommand(initCmd)
+}
diff --git a/clover/cloverctl/src/cloverctl/cmd/init_visibility.go b/clover/cloverctl/src/cloverctl/cmd/init_visibility.go
new file mode 100644 (file)
index 0000000..ac9ec5c
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "gopkg.in/resty.v1"
+    "github.com/spf13/cobra"
+)
+
+
+var visibilityinitCmd = &cobra.Command{
+    Use:   "visibility",
+    Short: "Init visibility data schemas",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        initCollector()
+    },
+}
+
+func init() {
+    initCmd.AddCommand(visibilityinitCmd)
+}
+
+func initCollector() {
+    url := controllerIP + "/collector/init"
+
+    resp, err := resty.R().
+    Get(url)
+    if err != nil {
+        panic(err.Error())
+    }
+    fmt.Printf("\n%v\n", resp)
+}
+
+
diff --git a/clover/cloverctl/src/cloverctl/cmd/root.go b/clover/cloverctl/src/cloverctl/cmd/root.go
new file mode 100644 (file)
index 0000000..6878077
--- /dev/null
@@ -0,0 +1,90 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "os"
+
+    homedir "github.com/mitchellh/go-homedir"
+    "github.com/spf13/cobra"
+    "github.com/spf13/viper"
+    "cloverkube"
+)
+
+var cfgFile string
+
+var controllerIP string
+var cloverFile string
+
+// rootCmd represents the base command when called without any subcommands
+var rootCmd = &cobra.Command{
+    Use:   "cloverctl",
+    Short: "Command-Line Interface (CLI) for Clover",
+    Long: ``,
+    // Uncomment the following line if your bare application
+    // has an action associated with it:
+    //Run: func(cmd *cobra.Command, args []string) {
+    //},
+}
+
+// Execute adds all child commands to the root command and sets flags appropriately.
+// This is called by main.main(). It only needs to happen once to the rootCmd.
+func Execute() {
+    if err := rootCmd.Execute(); err != nil {
+        fmt.Println(err)
+        os.Exit(1)
+    }
+}
+
+func init() {
+    cobra.OnInitialize(initConfig)
+
+    // Here you will define your flags and configuration settings.
+    // Cobra supports persistent flags, which, if defined here,
+    // will be global for your application.
+    rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cloverctl.yaml)")
+
+    // Cobra also supports local flags, which will only run
+    // when this action is called directly.
+    rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
+
+    cPort, cIP := cloverkube.GetServicesPortIP("clover-controller")
+    if cIP == "" {
+        controllerIP = "http://10.244.0.1:" + fmt.Sprint(cPort)
+    } else {
+        controllerIP = "http://" + cIP
+    }
+    fmt.Printf("\nclover-controller: %s %s\n", fmt.Sprint(cPort), cIP)
+}
+
+// initConfig reads in config file and ENV variables if set.
+func initConfig() {
+    if cfgFile != "" {
+    // Use config file from the flag.
+        viper.SetConfigFile(cfgFile)
+    } else {
+    // Find home directory.
+        home, err := homedir.Dir()
+        if err != nil {
+            fmt.Println(err)
+            os.Exit(1)
+        }
+
+        // Search config in home directory with name ".cloverctl" (without extension).
+        viper.AddConfigPath(home)
+        viper.SetConfigName(".cloverctl")
+    }
+
+    viper.AutomaticEnv() // read in environment variables that match
+
+    // If a config file is found, read it in.
+    if err := viper.ReadInConfig(); err == nil {
+        fmt.Println("Using config file:", viper.ConfigFileUsed())
+    }
+}
diff --git a/clover/cloverctl/src/cloverctl/cmd/start.go b/clover/cloverctl/src/cloverctl/cmd/start.go
new file mode 100644 (file)
index 0000000..741eacd
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "github.com/spf13/cobra"
+)
+
+var startCmd = &cobra.Command{
+    Use:   "start",
+    Short: "Start processes including tests, visibility and ingress services",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        fmt.Println("start called")
+    },
+}
+
+func init() {
+    rootCmd.AddCommand(startCmd)
+}
diff --git a/clover/cloverctl/src/cloverctl/cmd/start_ids.go b/clover/cloverctl/src/cloverctl/cmd/start_ids.go
new file mode 100644 (file)
index 0000000..0f495a7
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "gopkg.in/resty.v1"
+    "github.com/spf13/cobra"
+)
+
+
+var startidsCmd = &cobra.Command{
+    Use:   "ids",
+    Short: "Start IDS process",
+    Long: `Restart IDS process when adding custom rules`,
+    Run: func(cmd *cobra.Command, args []string) {
+        startIDS()
+    },
+}
+
+func init() {
+    startCmd.AddCommand(startidsCmd)
+}
+
+func startIDS() {
+
+    url := controllerIP + "/snort/start"
+
+    resp, err := resty.R().
+    Get(url)
+    if err != nil {
+        panic(err.Error())
+    }
+    fmt.Printf("\n%v\n", resp)
+}
+
+
diff --git a/clover/cloverctl/src/cloverctl/cmd/start_testplan.go b/clover/cloverctl/src/cloverctl/cmd/start_testplan.go
new file mode 100644 (file)
index 0000000..b516ad6
--- /dev/null
@@ -0,0 +1,59 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "strings"
+    "gopkg.in/resty.v1"
+    "github.com/spf13/cobra"
+    "cloverkube"
+)
+
+
+var testplanstartCmd = &cobra.Command{
+    Use:   "testplan",
+    Short: "Start a test for a given test plan",
+    Long: `Specify number of slaves to use with '-s' flag. Default is 0 slaves,
+which runs tests only from jmeter-master.`,
+    Run: func(cmd *cobra.Command, args []string) {
+        startTest()
+        //fmt.Printf("%v\n", cmd.Parent().CommandPath())
+    },
+}
+var num_slaves int
+
+func init() {
+    startCmd.AddCommand(testplanstartCmd)
+    testplanstartCmd.PersistentFlags().StringVarP(&cloverFile, "file", "f", "", "Currently unused")
+    testplanstartCmd.PersistentFlags().IntVarP(&num_slaves, "slaves", "s", 0, "Number of slaves to use")
+}
+
+func startTest() {
+
+    ips := cloverkube.GetPodsIP("clover-jmeter-slave", "default")
+    fmt.Printf("\njmeter-slaves found: %s\n", ips)
+    if num_slaves > len(ips) {
+        fmt.Printf("Number of slaves specified must be less than found: %d\n", len(ips))
+        return
+    }
+    ip_list := strings.Join(ips[0:num_slaves], ",")
+
+    url := controllerIP + "/jmeter/start"
+    resp, err := resty.R().
+    SetHeader("Content-Type", "application/json").
+    SetBody(fmt.Sprintf(`{"num_slaves":"%d", "slave_list":"%s"}`, num_slaves, ip_list)).
+    Post(url)
+    if err != nil {
+        panic(err.Error())
+    }
+    fmt.Printf("\n%v\n", resp)
+
+}
+
+
diff --git a/clover/cloverctl/src/cloverctl/cmd/start_visibility.go b/clover/cloverctl/src/cloverctl/cmd/start_visibility.go
new file mode 100644 (file)
index 0000000..18f8aac
--- /dev/null
@@ -0,0 +1,60 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "io/ioutil"
+    "gopkg.in/resty.v1"
+    "github.com/ghodss/yaml"
+    "github.com/spf13/cobra"
+)
+
+
+var visibilitystartCmd = &cobra.Command{
+    Use:   "visibility",
+    Short: "Start visibility data collection",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        startCollector()
+    },
+}
+
+func init() {
+    startCmd.AddCommand(visibilitystartCmd)
+    visibilitystartCmd.PersistentFlags().StringVarP(&cloverFile, "file", "f", "", "Optional yaml file with collector params")
+}
+
+func startCollector() {
+
+    var message_body string
+    if cloverFile != "" {
+        in, err := ioutil.ReadFile(cloverFile)
+        if err != nil {
+            panic(err.Error())
+        }
+        out_json, err := yaml.YAMLToJSON(in)
+        message_body = string(out_json)
+        if err != nil {
+            panic(err.Error())
+        }
+    } else {
+        message_body = `{"sample_interval":"10", "t_port":"80", "t_host":"jaeger-query.istio-system"}`
+    }
+    url := controllerIP + "/collector/start"
+    resp, err := resty.R().
+    SetHeader("Content-Type", "application/json").
+    SetBody(message_body).
+    Post(url)
+    if err != nil {
+        panic(err.Error())
+    }
+    fmt.Printf("\n%v\n", resp)
+}
+
+
diff --git a/clover/cloverctl/src/cloverctl/cmd/stop.go b/clover/cloverctl/src/cloverctl/cmd/stop.go
new file mode 100644 (file)
index 0000000..cfb7245
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "github.com/spf13/cobra"
+)
+
+var stopCmd = &cobra.Command{
+    Use:   "stop",
+    Short: "Stop processes including visibility and ingress services",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        fmt.Println("stop called")
+    },
+}
+
+func init() {
+    rootCmd.AddCommand(stopCmd)
+}
diff --git a/clover/cloverctl/src/cloverctl/cmd/stop_ids.go b/clover/cloverctl/src/cloverctl/cmd/stop_ids.go
new file mode 100644 (file)
index 0000000..b39b1e9
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "gopkg.in/resty.v1"
+    "github.com/spf13/cobra"
+)
+
+
+var stopidsCmd = &cobra.Command{
+    Use:   "ids",
+    Short: "Stop IDS process",
+    Long: `Restart IDS process when adding custom rules`,
+    Run: func(cmd *cobra.Command, args []string) {
+        stopIDS()
+    },
+}
+
+func init() {
+    stopCmd.AddCommand(stopidsCmd)
+}
+
+func stopIDS() {
+
+    url := controllerIP + "/snort/stop"
+
+    resp, err := resty.R().
+    Get(url)
+    if err != nil {
+        panic(err.Error())
+    }
+    fmt.Printf("\n%v\n", resp)
+}
+
+
diff --git a/clover/cloverctl/src/cloverctl/cmd/stop_visibility.go b/clover/cloverctl/src/cloverctl/cmd/stop_visibility.go
new file mode 100644 (file)
index 0000000..4233157
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cmd
+
+import (
+    "fmt"
+    "gopkg.in/resty.v1"
+    "github.com/spf13/cobra"
+)
+
+
+var visibilitystopCmd = &cobra.Command{
+    Use:   "visibility",
+    Short: "Stop visibility data collection",
+    Long: ``,
+    Run: func(cmd *cobra.Command, args []string) {
+        stopCollector()
+    },
+}
+
+func init() {
+    stopCmd.AddCommand(visibilitystopCmd)
+}
+
+func stopCollector() {
+
+    url := controllerIP + "/collector/stop"
+
+    resp, err := resty.R().
+    Get(url)
+    if err != nil {
+        panic(err.Error())
+    }
+    fmt.Printf("\n%v\n", resp)
+}
+
+
diff --git a/clover/cloverctl/src/cloverctl/main.go b/clover/cloverctl/src/cloverctl/main.go
new file mode 100644 (file)
index 0000000..602dd20
--- /dev/null
@@ -0,0 +1,14 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package main
+
+import "cloverctl/cmd"
+
+func main() {
+    cmd.Execute()
+}
diff --git a/clover/cloverctl/src/cloverctl/yaml/idsrule_scan.yaml b/clover/cloverctl/src/cloverctl/yaml/idsrule_scan.yaml
new file mode 100644 (file)
index 0000000..1cce7f7
--- /dev/null
@@ -0,0 +1,9 @@
+sid: "10000003"
+protocol: tcp
+dest_port: any
+dest_ip: $HOME_NET
+src_port: any
+src_ip: any
+msg: MALWARE-CNC User-Agent ASafaWeb Scan
+rev: "001"
+content: '"asafaweb.com"'
diff --git a/clover/cloverctl/src/cloverctl/yaml/idsrule_tcp.yaml b/clover/cloverctl/src/cloverctl/yaml/idsrule_tcp.yaml
new file mode 100644 (file)
index 0000000..8711f5d
--- /dev/null
@@ -0,0 +1,10 @@
+sid: "10000002"
+protocol: tcp
+dest_port: any
+dest_ip: $HOME_NET
+src_port: any
+src_ip: any
+msg: test
+rev: "001"
+content: ''
+
diff --git a/clover/cloverctl/src/cloverctl/yaml/jmeter_testplan.yaml b/clover/cloverctl/src/cloverctl/yaml/jmeter_testplan.yaml
new file mode 100644 (file)
index 0000000..140e70f
--- /dev/null
@@ -0,0 +1,11 @@
+load_spec:
+    num_threads: 1
+    loops: 1
+    ramp_time: 60
+url_list:
+    - name: url1
+      url: http://proxy-access-control.default:9180
+      method: GET
+    - name: url2
+      url: http://proxy-access-control.default:9180
+      method: GET
diff --git a/clover/cloverctl/src/cloverctl/yaml/visibility.yaml b/clover/cloverctl/src/cloverctl/yaml/visibility.yaml
new file mode 100644 (file)
index 0000000..20264d2
--- /dev/null
@@ -0,0 +1,7 @@
+sample_interval: "10"
+#t_host: jaeger-deployment.istio-system
+#t_port: "16686"
+t_host: jaeger-query.istio-system
+t_port: "80"
+m_port: "9090"
+m_host: prometheus.istio-system
diff --git a/clover/cloverctl/src/cloverinject/inject.go b/clover/cloverctl/src/cloverinject/inject.go
new file mode 100644 (file)
index 0000000..1953a3b
--- /dev/null
@@ -0,0 +1,141 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cloverinject
+
+import (
+   "io"
+   "os"
+   "fmt"
+   metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+   "istio.io/istio/pilot/pkg/kube/inject"
+   meshconfig "istio.io/api/mesh/v1alpha1"
+   "k8s.io/client-go/kubernetes"
+   "istio.io/istio/pkg/kube"
+   "istio.io/istio/pilot/pkg/model"
+   "github.com/ghodss/yaml"
+   "istio.io/istio/pilot/cmd"
+
+)
+//var _ = inject.InitImageName
+
+func CloverInject(inFilename string) {
+
+    var err error
+    var kubeconfig string
+
+    var reader io.Reader
+
+
+    var in *os.File
+    in, err = os.Open(inFilename)
+    if err != nil {
+        panic(err.Error())
+    }
+    reader = in
+
+    var writer io.Writer
+    outFilename := "out_sdc.yaml"
+    var out *os.File
+    out, err = os.Create(outFilename)
+    writer = out
+
+    var sidecarTemplate string
+    if sidecarTemplate, err = getInjectConfigFromConfigMap(kubeconfig); err != nil {
+        fmt.Printf("this is a template gen error")
+        panic(err.Error())
+    }
+
+    var meshConfig *meshconfig.MeshConfig
+    meshConfigFile := "mesh-config.yaml"
+    if meshConfig, err = cmd.ReadMeshConfig(meshConfigFile); err != nil {
+        panic(err.Error())
+    }
+
+    inject.IntoResourceFile(sidecarTemplate, meshConfig, reader, writer)
+
+}
+
+func getMeshConfigFromConfigMap(kubeconfig string) (*meshconfig.MeshConfig, error) {
+    client, err := createInterface(kubeconfig)
+    if err != nil {
+        return nil, err
+    }
+
+    istioNamespace := "istio-system"
+    meshConfigMapName := "istio"
+    configMapKey := "mesh"
+
+    config, err := client.CoreV1().ConfigMaps(istioNamespace).Get(meshConfigMapName, metav1.GetOptions{})
+    if err != nil {
+        return nil, fmt.Errorf("could not read valid configmap %q from namespace  %q: %v - "+
+            "Use --meshConfigFile or re-run kube-inject with `-i <istioSystemNamespace> and ensure valid MeshConfig exists",
+            meshConfigMapName, istioNamespace, err)
+    }
+    // values in the data are strings, while proto might use a
+    // different data type.  therefore, we have to get a value by a
+    // key
+    configYaml, exists := config.Data[configMapKey]
+    if !exists {
+        return nil, fmt.Errorf("missing configuration map key %q", configMapKey)
+    }
+    return model.ApplyMeshConfigDefaults(configYaml)
+}
+
+func getInjectConfigFromConfigMap(kubeconfig string) (string, error) {
+    client, err := createInterface(kubeconfig)
+    if err != nil {
+        return "", err
+    }
+    // added by me
+    istioNamespace := "istio-system"
+    injectConfigMapName := "istio-inject"
+    //injectConfigMapName := "istio-sidecar-injector"
+    injectConfigMapKey := "config"
+
+
+    config, err := client.CoreV1().ConfigMaps(istioNamespace).Get(injectConfigMapName, metav1.GetOptions{})
+    if err != nil {
+        return "", fmt.Errorf("could not find valid configmap %q from namespace  %q: %v - "+
+            "Use --injectConfigFile or re-run kube-inject with `-i <istioSystemNamespace> and ensure istio-inject configmap exists",
+            injectConfigMapName, istioNamespace, err)
+    }
+    // values in the data are strings, while proto might use a
+    // different data type.  therefore, we have to get a value by a
+    // key
+    injectData, exists := config.Data[injectConfigMapKey]
+    if !exists {
+        return "", fmt.Errorf("missing configuration map key %q in %q",
+            injectConfigMapKey, injectConfigMapName)
+    }
+    var injectConfig inject.Config
+    if err := yaml.Unmarshal([]byte(injectData), &injectConfig); err != nil {
+        return "", fmt.Errorf("unable to convert data from configmap %q: %v",
+            injectConfigMapName, err)
+    }
+    //log.Debugf("using inject template from configmap %q", injectConfigMapName)
+    return injectConfig.Template, nil
+}
+
+
+func homeDir() string {
+    if h := os.Getenv("HOME"); h != "" {
+        return h
+    }
+    return os.Getenv("USERPROFILE") // windows
+}
+
+func createInterface(kubeconfig string) (kubernetes.Interface, error) {
+
+    var configContext string
+    restConfig, err := kube.BuildClientConfig(kubeconfig, configContext)
+
+    if err != nil {
+        return nil, err
+    }
+    return kubernetes.NewForConfig(restConfig)
+}
diff --git a/clover/cloverctl/src/cloverkube/main.go b/clover/cloverctl/src/cloverkube/main.go
new file mode 100644 (file)
index 0000000..e2854b5
--- /dev/null
@@ -0,0 +1,400 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+package cloverkube
+
+import (
+    "fmt"
+    "os"
+     "path/filepath"
+     "strings"
+
+    appsv1 "k8s.io/api/apps/v1"
+    apiv1 "k8s.io/api/core/v1"
+    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+    "k8s.io/client-go/kubernetes"
+    "k8s.io/client-go/tools/clientcmd"
+)
+
+func setClient() kubernetes.Interface {
+
+
+    kubeconfig := filepath.Join(
+         os.Getenv("HOME"), ".kube", "config",
+    )
+    config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
+    if err != nil {
+        panic(err.Error())
+    }
+
+    // create the clientset
+    clientset, err := kubernetes.NewForConfig(config)
+    if err != nil {
+        panic(err.Error())
+    }
+    return clientset
+}
+
+func setControllerDeploy () (*appsv1.Deployment, *apiv1.Service) {
+
+    deployment := &appsv1.Deployment{
+        ObjectMeta: metav1.ObjectMeta{
+            Name: "clover-controller",
+        },
+        Spec: appsv1.DeploymentSpec{
+            Selector: &metav1.LabelSelector{
+                MatchLabels: map[string]string{
+                    "app": "clover-controller",
+                },
+            },
+            Template: apiv1.PodTemplateSpec{
+                ObjectMeta: metav1.ObjectMeta{
+                    Labels: map[string]string{
+                        "app": "clover-controller",
+                    },
+                },
+                Spec: apiv1.PodSpec{
+                    Containers: []apiv1.Container{
+                        {
+                            Name:  "clover-controller",
+                            Image: "localhost:5000/clover-controller:latest",
+                            Ports: []apiv1.ContainerPort{
+                                {
+                                    Name:          "redis",
+                                    Protocol:      apiv1.ProtocolTCP,
+                                    ContainerPort: 6379,
+                                },
+                                {
+                                    Name:          "grpc",
+                                    Protocol:      apiv1.ProtocolTCP,
+                                    ContainerPort: 50054,
+                                },
+                                {
+                                    Name:          "gprcsecurity",
+                                    Protocol:      apiv1.ProtocolTCP,
+                                    ContainerPort: 50052,
+                                },
+                                {
+                                    Name:          "cassandra",
+                                    Protocol:      apiv1.ProtocolTCP,
+                                    ContainerPort: 9042,
+                                },
+
+
+                            },
+                        },
+                    },
+                },
+            },
+        },
+    }
+
+    service := &apiv1.Service{
+        ObjectMeta: metav1.ObjectMeta{
+            Name: "clover-controller",
+            Labels: map[string]string{
+                "app": "clover-controller",
+            },
+
+        },
+        Spec: apiv1.ServiceSpec{
+            Selector: map[string]string{
+                    "app": "clover-controller",
+            },
+            Type: "NodePort",
+            Ports: []apiv1.ServicePort{
+                {
+                    Name: "http",
+                    Port: 80,
+                    NodePort: 32044,
+                    Protocol: "TCP",
+                },
+            },
+        },
+    }
+
+    return deployment, service
+
+}
+
+func setCollectorDeploy () (*appsv1.Deployment, *apiv1.Service) {
+
+    deployment := &appsv1.Deployment{
+        ObjectMeta: metav1.ObjectMeta{
+            Name: "clover-collector",
+        },
+        Spec: appsv1.DeploymentSpec{
+            Selector: &metav1.LabelSelector{
+                MatchLabels: map[string]string{
+                    "app": "clover-collector",
+                },
+            },
+            Template: apiv1.PodTemplateSpec{
+                ObjectMeta: metav1.ObjectMeta{
+                    Labels: map[string]string{
+                        "app": "clover-collector",
+                    },
+                },
+                Spec: apiv1.PodSpec{
+                    Containers: []apiv1.Container{
+                        {
+                            Name:  "clover-collector",
+                            Image: "localhost:5000/clover-collector:latest",
+                            Ports: []apiv1.ContainerPort{
+                                {
+                                    Name:          "redis",
+                                    Protocol:      apiv1.ProtocolTCP,
+                                    ContainerPort: 6379,
+                                },
+                                {
+                                    Name:          "grpc",
+                                    Protocol:      apiv1.ProtocolTCP,
+                                    ContainerPort: 50054,
+                                },
+                                {
+                                    Name:          "prometheus",
+                                    Protocol:      apiv1.ProtocolTCP,
+                                    ContainerPort: 9090,
+                                },
+                                {
+                                    Name:          "jaeger",
+                                    Protocol:      apiv1.ProtocolTCP,
+                                    ContainerPort: 16686,
+                                },
+                                {
+                                    Name:          "cassandra",
+                                    Protocol:      apiv1.ProtocolTCP,
+                                    ContainerPort: 9042,
+                                },
+
+
+                            },
+                        },
+                    },
+                },
+            },
+        },
+    }
+
+    service := &apiv1.Service{
+        ObjectMeta: metav1.ObjectMeta{
+            Name: "clover-collector",
+            Labels: map[string]string{
+                "app": "clover-collector",
+            },
+
+        },
+        Spec: apiv1.ServiceSpec{
+            Selector: map[string]string{
+                    "app": "clover-collector",
+            },
+            Ports: []apiv1.ServicePort{
+                {
+                    Name: "grpc",
+                    Port: 50054,
+                },
+                {
+                    Name: "redis",
+                    Port: 6379,
+                },
+                {
+                    Name: "prometheus",
+                    Port: 9090,
+                },
+                {
+                    Name: "jaeger",
+                    Port: 16686,
+                },
+                {
+                    Name: "cassandra",
+                    Port: 9042,
+                },
+
+            },
+        },
+    }
+    return deployment, service
+}
+
+func DeployCloverSystem(action string, namespace string) {
+    if action == "create" {
+        // Create clover-system namespace
+        configNamespace("clover-system", "create")
+        // Controller
+        deployment, service := setControllerDeploy()
+        DeployService(deployment, service, namespace)
+        // Collector
+        deployment, service = setCollectorDeploy()
+        DeployService(deployment, service, namespace)
+    } else if action  == "delete" {
+        fmt.Println("Deleting clover-system services...\n")
+        DeleteService("clover-controller", namespace)
+        DeleteService("clover-collector", namespace)
+        configNamespace("clover-system", "delete")
+    }
+
+}
+
+func DeleteService(deploy_name string, namespace string) {
+
+    clientset := setClient()
+    deploymentsClient := clientset.AppsV1().Deployments(namespace)
+    servicesClient := clientset.CoreV1().Services(namespace)
+
+    // Delete Deployment
+    deletePolicy := metav1.DeletePropagationForeground
+    if err := deploymentsClient.Delete(deploy_name, &metav1.DeleteOptions{
+        PropagationPolicy: &deletePolicy,
+    }); err != nil {
+        panic(err)
+    }
+    fmt.Printf("Deleted %s deployment\n", deploy_name)
+
+    // Delete Service
+    if err := servicesClient.Delete(deploy_name, &metav1.DeleteOptions{
+        PropagationPolicy: &deletePolicy,
+    }); err != nil {
+        panic(err)
+    }
+    fmt.Printf("Deleted %s service\n", deploy_name)
+}
+
+func DeployService(deployment *appsv1.Deployment, service *apiv1.Service, namespace string) {
+
+    clientset := setClient()
+    deploymentsClient := clientset.AppsV1().Deployments(namespace)
+
+
+    // Create Deployment
+    fmt.Println("Creating deployment...")
+    result, err := deploymentsClient.Create(deployment)
+    if err != nil {
+        panic(err)
+    }
+    fmt.Printf("Created deployment %q.\n", result.GetObjectMeta().GetName())
+
+    // Create Service
+    fmt.Println("Creating service...")
+    servicesClient := clientset.CoreV1().Services(namespace)
+
+    result1, err := servicesClient.Create(service)
+    if err != nil {
+        panic(err)
+    }
+    fmt.Printf("Created service %q.\n", result1.GetObjectMeta().GetName())
+
+}
+
+func configNamespace (name string, action string) {
+    clientset := setClient()
+    nameClient := clientset.CoreV1().Namespaces()
+
+    if action == "create" {
+        namespace := &apiv1.Namespace{
+            ObjectMeta: metav1.ObjectMeta{
+                Name: name,
+            },
+        }
+        nameClient.Create(namespace)
+        fmt.Printf("Created %s namespace\n", name)
+    } else if action == "delete" {
+        deletePolicy := metav1.DeletePropagationForeground
+        if err := nameClient.Delete(name, &metav1.DeleteOptions{
+            PropagationPolicy: &deletePolicy,
+        }); err != nil {
+            panic(err)
+        }
+        fmt.Printf("Deleted %s namespace\n", name)
+    }
+}
+
+func GetServices() *apiv1.ServiceList {
+
+    clientset := setClient()
+    services, err := clientset.Core().Services("").List(metav1.ListOptions{})
+    for _, service := range services.Items {
+        if err != nil {
+            panic(err.Error())
+        }
+        fmt.Printf(" * SERVICE Name: %s\n", service.GetName())
+        fmt.Printf("Kind: %s\n", service.Kind)
+        fmt.Printf("Labels: %s\n", service.GetLabels())
+        fmt.Printf("Type: %s\n", service.Spec.Type)
+        //fmt.Printf("External IP: %v\n", service.Spec.ExternalIPs)
+        fmt.Printf("Cluster IP: %s\n", service.Spec.ClusterIP)
+
+        for _, port := range service.Spec.Ports {
+            fmt.Printf("Port Name: %s, Port# %d, NodePort: %d\n", port.Name, port.Port, port.NodePort)
+        }
+
+        for _, ip := range service.Status.LoadBalancer.Ingress {
+            fmt.Printf("LB IP: %s \n", ip.IP)
+        }
+    }
+    return services
+}
+
+func GetDeployments(namespace string) []appsv1.Deployment {
+
+    clientset := setClient()
+
+    deploymentsClient := clientset.AppsV1().Deployments(namespace)
+    list, err := deploymentsClient.List(metav1.ListOptions{})
+    if err != nil {
+        panic(err)
+    }
+    for _, d := range list.Items {
+        fmt.Printf(" * %s (%d replicas)\n", d.Name, *d.Spec.Replicas)
+    }
+    return list.Items
+}
+
+func GetServicesPortIP(service_name string) (int32, string) {
+
+    clientset := setClient()
+    services, err := clientset.Core().Services("").List(metav1.ListOptions{})
+    var nodeport int32
+    var ipaddress string
+    nodeport = 0
+    ipaddress = ""
+    for _, service := range services.Items {
+        if err != nil {
+            panic(err.Error())
+        }
+        if service.GetName() == service_name {
+            for _, port := range service.Spec.Ports {
+                if port.NodePort > 0 {
+                    nodeport = port.NodePort
+                }
+            }
+            for _, ip := range service.Status.LoadBalancer.Ingress {
+                    ipaddress = ip.IP
+            }
+        }
+    }
+
+        return nodeport, ipaddress
+}
+
+func GetPodsIP(pod_name string, namespace string) []string {
+
+    clientset := setClient()
+
+    var ips []string
+    pods, err := clientset.CoreV1().Pods(namespace).List(metav1.ListOptions{})
+    if err != nil {
+        panic(err)
+    }
+    for _, pod := range pods.Items {
+        if strings.Contains(pod.Name, pod_name) {
+            fmt.Println(pod.Name, pod.Status.PodIP)
+            ips = append(ips, pod.Status.PodIP)
+        }
+    }
+
+    return ips
+}