From e44fa9c712d27ff102b21db1c5022bce334f72a2 Mon Sep 17 00:00:00 2001 From: jessicagreben Date: Fri, 8 Feb 2019 12:50:37 -0800 Subject: [PATCH] add a test for dashboard, move stuff around to test easier, add fixtures --- Gopkg.toml | 2 -- main.go | 6 ++-- pkg/dashboard/dashboard.go | 16 +++++----- pkg/dashboard/dashboard_test.go | 49 +++++++++++++++++++++++++++++ pkg/kube/clientset.go | 31 ++++++++++++++---- pkg/validator/deploy.go | 9 ++---- test/fixtures.go | 56 +++++++++++++++++++++++++++++++++ 7 files changed, 145 insertions(+), 24 deletions(-) create mode 100644 pkg/dashboard/dashboard_test.go create mode 100644 test/fixtures.go diff --git a/Gopkg.toml b/Gopkg.toml index 1569d349..fe74bdfb 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -44,5 +44,3 @@ [[constraint]] name = "sigs.k8s.io/controller-runtime" version = "0.1.10" - -[prune] diff --git a/main.go b/main.go index 0b46d586..496f19d2 100644 --- a/main.go +++ b/main.go @@ -22,6 +22,7 @@ import ( conf "github.com/reactiveops/fairwinds/pkg/config" "github.com/reactiveops/fairwinds/pkg/dashboard" + "github.com/reactiveops/fairwinds/pkg/kube" "github.com/reactiveops/fairwinds/pkg/validator" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -64,8 +65,9 @@ func main() { } func startDashboardServer(c conf.Configuration) { + k, _ := kube.CreateKubeAPI() http.HandleFunc("/results.json", func(w http.ResponseWriter, r *http.Request) { - dashboard.EndpointHandler(w, r, c) + dashboard.EndpointHandler(w, r, c, k) }) http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("public/")))) http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { @@ -73,7 +75,7 @@ func startDashboardServer(c conf.Configuration) { http.NotFound(w, r) return } - dashboard.MainHandler(w, r, c) + dashboard.MainHandler(w, r, c, k) }) glog.Println("Starting Fairwinds dashboard server on port 8080.") glog.Fatal(http.ListenAndServe(":8080", nil)) diff --git a/pkg/dashboard/dashboard.go b/pkg/dashboard/dashboard.go index d84df710..a2a381f9 100644 --- a/pkg/dashboard/dashboard.go +++ b/pkg/dashboard/dashboard.go @@ -6,6 +6,7 @@ import ( "net/http" conf "github.com/reactiveops/fairwinds/pkg/config" + "github.com/reactiveops/fairwinds/pkg/kube" "github.com/reactiveops/fairwinds/pkg/validator" ) @@ -15,22 +16,21 @@ type TemplateData struct { NamespacedResults validator.NamespacedResults } -var tmpl = template.Must(template.ParseFiles("pkg/dashboard/templates/dashboard.gohtml")) - // MainHandler gets template data and renders the dashboard with it. -func MainHandler(w http.ResponseWriter, r *http.Request, c conf.Configuration) { - templateData, err := getTemplateData(c) +func MainHandler(w http.ResponseWriter, r *http.Request, c conf.Configuration, kubeAPI *kube.API) { + templateData, err := getTemplateData(c, kubeAPI) if err != nil { http.Error(w, "Error Fetching Deployments", 500) return } + tmpl := template.Must(template.ParseFiles("pkg/dashboard/templates/dashboard.gohtml")) tmpl.Execute(w, templateData) } // EndpointHandler gets template data and renders json with it. -func EndpointHandler(w http.ResponseWriter, r *http.Request, c conf.Configuration) { - templateData, err := getTemplateData(c) +func EndpointHandler(w http.ResponseWriter, r *http.Request, c conf.Configuration, kubeAPI *kube.API) { + templateData, err := getTemplateData(c, kubeAPI) if err != nil { http.Error(w, "Error Fetching Deployments", 500) return @@ -41,12 +41,12 @@ func EndpointHandler(w http.ResponseWriter, r *http.Request, c conf.Configuratio json.NewEncoder(w).Encode(templateData) } -func getTemplateData(c conf.Configuration) (TemplateData, error) { +func getTemplateData(config conf.Configuration, kubeAPI *kube.API) (TemplateData, error) { // TODO: Once we are validating more than deployments, // we will need to merge the namespaceResults that get returned // from each validation. - nsResults, err := validator.ValidateDeploys(c) + nsResults, err := validator.ValidateDeploys(config, kubeAPI) if err != nil { return TemplateData{}, err } diff --git a/pkg/dashboard/dashboard_test.go b/pkg/dashboard/dashboard_test.go new file mode 100644 index 00000000..1932b173 --- /dev/null +++ b/pkg/dashboard/dashboard_test.go @@ -0,0 +1,49 @@ +package dashboard + +import ( + "testing" + + conf "github.com/reactiveops/fairwinds/pkg/config" + "github.com/reactiveops/fairwinds/pkg/validator" + "github.com/reactiveops/fairwinds/test" + "github.com/stretchr/testify/assert" +) + +func TestGetTemplateData(t *testing.T) { + k8s := test.SetupTestAPI() + k8s = test.SetupAddDeploys(k8s, "test") + + c := conf.Configuration{ + HealthChecks: conf.Probes{ + Readiness: conf.ResourceRequire{ + Require: true, + }, + }, + } + + sum := validator.ResultSummary{ + Successes: uint(4), + Warnings: uint(0), + Failures: uint(1), + } + + res := validator.ResourceResult{} + + n := validator.NamespacedResult{ + Summary: &sum, + Results: []validator.ResourceResult{res}, + } + + expectedTmplData := TemplateData{ + ClusterSummary: &sum, + NamespacedResults: validator.NamespacedResults{ + "test": &n, + }, + } + actualTmplData, _ := getTemplateData(c, k8s) + + assert.Equal(t, actualTmplData.ClusterSummary.Failures, expectedTmplData.ClusterSummary.Failures, "should be equal") + assert.Equal(t, actualTmplData.ClusterSummary.Successes, expectedTmplData.ClusterSummary.Successes, "should be equal") + assert.Equal(t, len(actualTmplData.NamespacedResults["test"].Results), 1, "should be equal") + assert.Equal(t, len(actualTmplData.NamespacedResults["test"].Results[0].ContainerResults[0].Messages), 5, "should be equal") +} diff --git a/pkg/kube/clientset.go b/pkg/kube/clientset.go index cca67217..1b83a0b8 100644 --- a/pkg/kube/clientset.go +++ b/pkg/kube/clientset.go @@ -1,20 +1,39 @@ package kube import ( - "fmt" - + appsv1 "k8s.io/api/apps/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" // Required for GKE auth. "sigs.k8s.io/controller-runtime/pkg/client/config" ) -// CreateClientset returns a new Kubernetes clientset. -func CreateClientset() *kubernetes.Clientset { +// API is a wrapper for the clientset and methods to interact with the Kubernetes API. +type API struct { + Clientset kubernetes.Interface +} + +// GetDeploys gets all the deployments in the k8s cluster. +func (api *API) GetDeploys() (*appsv1.DeploymentList, error) { + deploys, err := api.Clientset.AppsV1().Deployments("").List(metav1.ListOptions{}) + if err != nil { + return nil, err + } + return deploys, nil +} + +// CreateKubeAPI returns a new KubeAPI object to interact with the cluster API with. +func CreateKubeAPI() (*API, error) { kubeConf := config.GetConfigOrDie() clientset, err := kubernetes.NewForConfig(kubeConf) if err != nil { - fmt.Println("Error:", err) + return nil, err } - return clientset + + // return clientset, nil + api := API{ + Clientset: clientset, + } + return &api, nil } diff --git a/pkg/validator/deploy.go b/pkg/validator/deploy.go index 6d09fd63..3f69572f 100644 --- a/pkg/validator/deploy.go +++ b/pkg/validator/deploy.go @@ -8,7 +8,6 @@ import ( "github.com/reactiveops/fairwinds/pkg/kube" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/runtime/inject" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" @@ -79,17 +78,15 @@ func ValidateDeploy(conf conf.Configuration, deploy *appsv1.Deployment) Resource // ValidateDeploys validates that each deployment conforms to the Fairwinds config, // returns a list of ResourceResults organized by namespace. -func ValidateDeploys(conf conf.Configuration) (NamespacedResults, error) { +func ValidateDeploys(config conf.Configuration, k8sAPI *kube.API) (NamespacedResults, error) { nsResults := NamespacedResults{} - - var clientset = kube.CreateClientset() - deploys, err := clientset.AppsV1().Deployments("").List(metav1.ListOptions{}) + deploys, err := k8sAPI.GetDeploys() if err != nil { return nsResults, err } for _, deploy := range deploys.Items { - resResult := ValidateDeploy(conf, &deploy) + resResult := ValidateDeploy(config, &deploy) nsResults = addResult(resResult, nsResults, deploy.Namespace) } diff --git a/test/fixtures.go b/test/fixtures.go new file mode 100644 index 00000000..9dd5384c --- /dev/null +++ b/test/fixtures.go @@ -0,0 +1,56 @@ +package test + +import ( + "fmt" + + "github.com/reactiveops/fairwinds/pkg/kube" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/kubernetes/fake" +) + +func mockContainer(name string) corev1.Container { + c := corev1.Container{ + Name: name, + } + return c +} + +func mockPod() corev1.PodTemplateSpec { + c1 := mockContainer("test") + p := corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + c1, + }, + }, + } + return p +} + +func mockDeploy() appsv1.Deployment { + p := mockPod() + d := appsv1.Deployment{ + Spec: appsv1.DeploymentSpec{ + Template: p, + }, + } + return d +} + +func SetupTestAPI() *kube.API { + api := kube.API{ + Clientset: fake.NewSimpleClientset(), + } + return &api +} + +func SetupAddDeploys(k *kube.API, namespace string) *kube.API { + d1 := mockDeploy() + _, err := k.Clientset.AppsV1().Deployments(namespace).Create(&d1) + if err != nil { + fmt.Println(err) + } + return k + +}