From 867129cdce45e88857ef866fefa00a892e633a22 Mon Sep 17 00:00:00 2001 From: Jeff Date: Wed, 20 Mar 2019 11:12:40 +0800 Subject: [PATCH] add controllers change kiali mux to go-restful add knative add health api --- cmd/controller-manager/app/controllers.go | 4 +- cmd/controller-manager/controller-manager.go | 21 +++- cmd/ks-apiserver/app/server.go | 3 +- hack/docker_build.sh | 2 +- .../servicemesh/metrics/v1alpha2/register.go | 43 ++++++- pkg/apiserver/runtime/runtime.go | 2 +- pkg/apiserver/servicemesh/metrics/handlers.go | 15 +++ .../destinationrule_controller.go | 17 +-- pkg/controller/strategy/helper.go | 13 ++- pkg/controller/virtualservice/util/util.go | 1 - .../virtualservice_controller.go | 13 +-- pkg/simple/client/k8s/k8sclient.go | 19 +--- pkg/simple/controller/namespace/namespaces.go | 46 ++++---- .../github.com/kiali/kiali/handlers/health.go | 105 ++++++++---------- 14 files changed, 172 insertions(+), 132 deletions(-) diff --git a/cmd/controller-manager/app/controllers.go b/cmd/controller-manager/app/controllers.go index 1882fcd60..93203c1fc 100644 --- a/cmd/controller-manager/app/controllers.go +++ b/cmd/controller-manager/app/controllers.go @@ -1,11 +1,11 @@ package app import ( + "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "kubesphere.io/kubesphere/pkg/controller/destinationrule" "kubesphere.io/kubesphere/pkg/controller/virtualservice" - "kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/simple/controller/namespace" "sigs.k8s.io/controller-runtime/pkg/manager" "time" @@ -35,7 +35,7 @@ func AddControllers(mgr manager.Manager, cfg *rest.Config, stopCh <-chan struct{ return err } - informerFactory := informers.SharedInformerFactory() + informerFactory := informers.NewSharedInformerFactory(kubeClient, defaultResync) istioInformer := istioinformers.NewSharedInformerFactory(istioclient, defaultResync) servicemeshclient, err := servicemeshclientset.NewForConfig(cfg) diff --git a/cmd/controller-manager/controller-manager.go b/cmd/controller-manager/controller-manager.go index 284328f7a..2be374a9f 100644 --- a/cmd/controller-manager/controller-manager.go +++ b/cmd/controller-manager/controller-manager.go @@ -30,14 +30,25 @@ import ( "sigs.k8s.io/controller-runtime/pkg/runtime/signals" ) -func main() { - var metricsAddr, kubeConfigPath, masterURL string +var ( + masterURL string + kubeconfig string + metricsAddr string +) + +func init() { + flag.StringVar(&masterURL, "master-url", "", "only need if out of cluster") + flag.StringVar(&kubeconfig, "kubeconfig", "", "only need if out of cluster") flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") +} + +func main() { flag.Parse() + logf.SetLogger(logf.ZapLogger(false)) log := logf.Log.WithName("controller-manager") - kubeConfig, err := clientcmd.BuildConfigFromFlags(masterURL, kubeConfigPath) + cfg, err := clientcmd.BuildConfigFromFlags(masterURL, kubeconfig) if err != nil { log.Error(err, "failed to build kubeconfig") os.Exit(1) @@ -46,7 +57,7 @@ func main() { stopCh := signals.SetupSignalHandler() log.Info("setting up manager") - mgr, err := manager.New(kubeConfig, manager.Options{}) + mgr, err := manager.New(cfg, manager.Options{}) if err != nil { log.Error(err, "unable to set up overall controller manager") os.Exit(1) @@ -64,7 +75,7 @@ func main() { os.Exit(1) } - if err := app.AddControllers(mgr, kubeConfig, stopCh); err != nil { + if err := app.AddControllers(mgr, cfg, stopCh); err != nil { log.Error(err, "unable to register controllers to the manager") os.Exit(1) } diff --git a/cmd/ks-apiserver/app/server.go b/cmd/ks-apiserver/app/server.go index cd909beb8..33d91a216 100644 --- a/cmd/ks-apiserver/app/server.go +++ b/cmd/ks-apiserver/app/server.go @@ -122,11 +122,12 @@ func initializeESClientConfig() { db := mysql.Client() if !db.HasTable(&logging.OutputDBBinding{}) { // Panic - log.Fatal("Flyway migration is not completed") + log.Print("Flyway migration is not completed") } err := db.Find(&outputs).Error if err != nil { + log.Printf("get logging config failed. Error: %v", err) return } diff --git a/hack/docker_build.sh b/hack/docker_build.sh index c11a8883d..cf814de17 100755 --- a/hack/docker_build.sh +++ b/hack/docker_build.sh @@ -4,4 +4,4 @@ docker build -f build/ks-apiserver/Dockerfile -t kubespheredev/ks-apiserver:latest . docker build -f build/ks-iam/Dockerfile -t kubespheredev/ks-iam:latest . - docker build -f build/controller-manager/Dockerfile -t kubespheredev/controller-manager:latest . \ No newline at end of file + docker build -f build/controller-manager/Dockerfile -t kubespheredev/ks-controller-manager:latest . diff --git a/pkg/apis/servicemesh/metrics/v1alpha2/register.go b/pkg/apis/servicemesh/metrics/v1alpha2/register.go index 8ffdc18aa..46c0569cb 100644 --- a/pkg/apis/servicemesh/metrics/v1alpha2/register.go +++ b/pkg/apis/servicemesh/metrics/v1alpha2/register.go @@ -68,8 +68,8 @@ func addWebService(c *restful.Container) error { To(metrics.GetWorkloadMetrics). Metadata(restfulspec.KeyOpenAPITags, tags). Doc("Get workload metrics from a specific namespace"). - Param(webservice.PathParameter("namespace", "name of the namespace")). - Param(webservice.PathParameter("workload", "name of the workload")). + Param(webservice.PathParameter("namespace", "name of the namespace").Required(true)). + Param(webservice.PathParameter("workload", "name of the workload").Required(true)). Param(webservice.QueryParameter("filters[]", "type of metrics type, e.g. request_count, request_duration, request_error_count")). Param(webservice.QueryParameter("queryTime", "from which UNIX time to extract metrics")). Param(webservice.QueryParameter("duration", "metrics duration, in seconds")). @@ -87,7 +87,7 @@ func addWebService(c *restful.Container) error { To(metrics.GetNamespaceMetrics). Metadata(restfulspec.KeyOpenAPITags, tags). Doc("Get workload metrics from a specific namespace"). - Param(webservice.PathParameter("namespace", "name of the namespace")). + Param(webservice.PathParameter("namespace", "name of the namespace").Required(true)). Param(webservice.QueryParameter("filters[]", "type of metrics type, e.g. request_count, request_duration, request_error_count")). Param(webservice.QueryParameter("queryTime", "from which UNIX time to extract metrics")). Param(webservice.QueryParameter("duration", "metrics duration, in seconds")). @@ -105,7 +105,7 @@ func addWebService(c *restful.Container) error { To(metrics.GetNamespaceGraph). Metadata(restfulspec.KeyOpenAPITags, tags). Doc("Get service graph for a specific namespace"). - Param(webservice.PathParameter("namespace", "name of a namespace")). + Param(webservice.PathParameter("namespace", "name of a namespace").Required(true)). Param(webservice.QueryParameter("graphType", "type of the generated service graph, eg. ")). Param(webservice.QueryParameter("groupBy", "group nodes by kind")). Param(webservice.QueryParameter("queryTime", "from which time point, default now")). @@ -118,7 +118,7 @@ func addWebService(c *restful.Container) error { To(metrics.GetNamespacesGraph). Metadata(restfulspec.KeyOpenAPITags, tags). Doc("Get service graph for a specific namespace"). - Param(webservice.PathParameter("namespace", "name of a namespace")). + Param(webservice.PathParameter("namespace", "name of a namespace").Required(true)). Param(webservice.QueryParameter("graphType", "type of the generated service graph, eg. ")). Param(webservice.QueryParameter("groupBy", "group nodes by kind")). Param(webservice.QueryParameter("queryTime", "from which time point, default now")). @@ -126,6 +126,39 @@ func addWebService(c *restful.Container) error { Param(webservice.QueryParameter("namespaces", "names of namespaces")). Writes(errors.Error{})).Produces(restful.MIME_JSON) + // Get workloads health + webservice.Route(webservice.GET("/namespaces/{namespace}/workloads/{workload}/health"). + To(metrics.GetWorkloadHealth). + Metadata(restfulspec.KeyOpenAPITags, tags). + Doc("Get workload health"). + Param(webservice.PathParameter("namespace", "name of a namespace").Required(true)). + Param(webservice.PathParameter("workload", "workload name").Required(true)). + Param(webservice.QueryParameter("rateInterval", "the rate interval used for fetching error rate").DefaultValue("10m").Required(true)). + Param(webservice.QueryParameter("queryTime", "the time to use for query")). + Writes(errors.Error{})).Produces(restful.MIME_JSON) + + // Get app health + webservice.Route(webservice.GET("/namespaces/{namespace}/apps/{app}/health"). + To(metrics.GetAppHealth). + Metadata(restfulspec.KeyOpenAPITags, tags). + Doc("Get workload health"). + Param(webservice.PathParameter("namespace", "name of a namespace").Required(true)). + Param(webservice.PathParameter("app", "app name").Required(true)). + Param(webservice.QueryParameter("rateInterval", "the rate interval used for fetching error rate").DefaultValue("10m").Required(true)). + Param(webservice.QueryParameter("queryTime", "the time to use for query")). + Writes(errors.Error{})).Produces(restful.MIME_JSON) + + // Get service health + webservice.Route(webservice.GET("/namespaces/{namespace}/services/{service}/health"). + To(metrics.GetServiceHealth). + Metadata(restfulspec.KeyOpenAPITags, tags). + Doc("Get workload health"). + Param(webservice.PathParameter("namespace", "name of a namespace").Required(true)). + Param(webservice.PathParameter("service", "service name").Required(true)). + Param(webservice.QueryParameter("rateInterval", "the rate interval used for fetching error rate").DefaultValue("10m").Required(true)). + Param(webservice.QueryParameter("queryTime", "the time to use for query")). + Writes(errors.Error{})).Produces(restful.MIME_JSON) + c.Add(webservice) return nil diff --git a/pkg/apiserver/runtime/runtime.go b/pkg/apiserver/runtime/runtime.go index a87f12aff..5be926b6e 100644 --- a/pkg/apiserver/runtime/runtime.go +++ b/pkg/apiserver/runtime/runtime.go @@ -23,7 +23,7 @@ import ( ) const ( - ApiRootPath = "/apis" + ApiRootPath = "/kapis" ) // container holds all webservice of apiserver diff --git a/pkg/apiserver/servicemesh/metrics/handlers.go b/pkg/apiserver/servicemesh/metrics/handlers.go index a5a7801ec..d6b28a8b0 100644 --- a/pkg/apiserver/servicemesh/metrics/handlers.go +++ b/pkg/apiserver/servicemesh/metrics/handlers.go @@ -48,3 +48,18 @@ func GetNamespaceGraph(request *restful.Request, response *restful.Response) { func GetNamespacesGraph(request *restful.Request, response *restful.Response) { handlers.GraphNamespaces(request, response) } + +// Get workload health +func GetWorkloadHealth(request *restful.Request, response *restful.Response) { + handlers.WorkloadHealth(request, response) +} + +// Get app health +func GetAppHealth(request *restful.Request, response *restful.Response) { + handlers.AppHealth(request, response) +} + +// Get service health +func GetServiceHealth(request *restful.Request, response *restful.Response) { + handlers.ServiceHealth(request, response) +} diff --git a/pkg/controller/destinationrule/destinationrule_controller.go b/pkg/controller/destinationrule/destinationrule_controller.go index 2e28bd85c..347925fcd 100644 --- a/pkg/controller/destinationrule/destinationrule_controller.go +++ b/pkg/controller/destinationrule/destinationrule_controller.go @@ -139,10 +139,6 @@ func (v *DestinationRuleController) Run(workers int, stopCh <-chan struct{}) { go wait.Until(v.worker, v.workerLoopPeriod, stopCh) } - go func() { - defer utilruntime.HandleCrash() - }() - <-stopCh } @@ -222,9 +218,9 @@ func (v *DestinationRuleController) syncService(key string) error { } subset := v1alpha3.Subset{ - Name: util.NormalizeVersionName(name), + Name: util.NormalizeVersionName(version), Labels: map[string]string{ - util.VersionLabel: name, + util.VersionLabel: version, }, } @@ -239,10 +235,15 @@ func (v *DestinationRuleController) syncService(key string) error { Name: service.Name, Labels: service.Labels, }, + Spec: v1alpha3.DestinationRuleSpec{ + Host: name, + }, } + } else { + log.Error(err, "Couldn't get destinationrule for service", "key", key) + return err } - log.Error(err, "Couldn't get destinationrule for service", "key", key) - return err + } createDestinationRule := len(currentDestinationRule.Spec.Subsets) == 0 diff --git a/pkg/controller/strategy/helper.go b/pkg/controller/strategy/helper.go index cbe98e13f..a8b925b59 100644 --- a/pkg/controller/strategy/helper.go +++ b/pkg/controller/strategy/helper.go @@ -18,6 +18,7 @@ func getAppNameByStrategy(strategy *v1alpha2.Strategy) string { return "" } +// if virtualservice not specified with port number, then fill with service first port func fillDestinationPort(vs *v1alpha3.VirtualService, service *v1.Service) error { if len(service.Spec.Ports) == 0 { @@ -27,14 +28,22 @@ func fillDestinationPort(vs *v1alpha3.VirtualService, service *v1.Service) error // fill http port for i := range vs.Spec.Http { for j := range vs.Spec.Http[i].Route { - vs.Spec.Http[i].Route[j].Destination.Port.Number = uint32(service.Spec.Ports[0].Port) + if vs.Spec.Http[i].Route[j].Destination.Port.Number == 0 { + vs.Spec.Http[i].Route[j].Destination.Port.Number = uint32(service.Spec.Ports[0].Port) + } + } + + if vs.Spec.Http[i].Mirror != nil && vs.Spec.Http[i].Mirror.Port.Number == 0 { + vs.Spec.Http[i].Mirror.Port.Number = uint32(service.Spec.Ports[0].Port) } } // fill tcp port for i := range vs.Spec.Tcp { for j := range vs.Spec.Tcp[i].Route { - vs.Spec.Tcp[i].Route[j].Destination.Port.Number = uint32(service.Spec.Ports[0].Port) + if vs.Spec.Tcp[i].Route[j].Destination.Port.Number == 0 { + vs.Spec.Tcp[i].Route[j].Destination.Port.Number = uint32(service.Spec.Ports[0].Port) + } } } diff --git a/pkg/controller/virtualservice/util/util.go b/pkg/controller/virtualservice/util/util.go index a0e1861be..75aa5f77a 100644 --- a/pkg/controller/virtualservice/util/util.go +++ b/pkg/controller/virtualservice/util/util.go @@ -16,7 +16,6 @@ const ( // resource with these following labels considered as part of servicemesh var ApplicationLabels = [...]string{ ApplicationNameLabel, - ApplicationVersionLabel, ServiceMeshEnabledLabel, AppLabel, } diff --git a/pkg/controller/virtualservice/virtualservice_controller.go b/pkg/controller/virtualservice/virtualservice_controller.go index 1289bee2e..6a41b8de0 100644 --- a/pkg/controller/virtualservice/virtualservice_controller.go +++ b/pkg/controller/virtualservice/virtualservice_controller.go @@ -128,7 +128,7 @@ func NewVirtualServiceController(serviceInformer coreinformers.ServiceInformer, } func (v *VirtualServiceController) Start(stopCh <-chan struct{}) error { - v.Run(5, stopCh) + v.Run(1, stopCh) return nil } @@ -147,10 +147,6 @@ func (v *VirtualServiceController) Run(workers int, stopCh <-chan struct{}) { go wait.Until(v.worker, v.workerLoopPeriod, stopCh) } - go func() { - defer utilruntime.HandleCrash() - }() - <-stopCh } @@ -202,7 +198,6 @@ func (v *VirtualServiceController) syncService(key string) error { if err != nil && !errors.IsNotFound(err) { return err } - return nil } @@ -278,9 +273,7 @@ func (v *VirtualServiceController) syncService(key string) error { if len(vs.Spec.Http) > 0 || len(vs.Spec.Tcp) > 0 { _, err := v.virtualServiceClient.NetworkingV1alpha3().VirtualServices(namespace).Create(vs) if err != nil { - v.eventRecorder.Eventf(vs, v1.EventTypeWarning, "FailedToCreateVirtualService", "Failed to create virtualservice for service %v/%v: %v", service.Namespace, service.Name, err) - log.Error(err, "create virtualservice for service failed.", "service", service) return err } @@ -288,7 +281,6 @@ func (v *VirtualServiceController) syncService(key string) error { log.Info("service doesn't have a tcp port.") return nil } - } return nil @@ -328,7 +320,6 @@ func (v *VirtualServiceController) addDestinationRule(obj interface{}) { func (v *VirtualServiceController) deleteStrategy(obj interface{}) { // nothing to do right now - } func (v *VirtualServiceController) handleErr(err error, key interface{}) { @@ -343,7 +334,7 @@ func (v *VirtualServiceController) handleErr(err error, key interface{}) { return } - log.V(0).Info("Dropping service %q out of the queue: %v", "key", key, "error", err) + log.V(4).Info("Dropping service out of the queue.", "key", key, "error", err) v.queue.Forget(key) utilruntime.HandleError(err) } diff --git a/pkg/simple/client/k8s/k8sclient.go b/pkg/simple/client/k8s/k8sclient.go index 0481cb3ca..fb738e164 100644 --- a/pkg/simple/client/k8s/k8sclient.go +++ b/pkg/simple/client/k8s/k8sclient.go @@ -20,13 +20,10 @@ package k8s import ( "flag" - "fmt" "log" "os" "sync" - "github.com/mitchellh/go-homedir" - "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" @@ -37,10 +34,12 @@ var ( k8sClient *kubernetes.Clientset k8sClientOnce sync.Once KubeConfig *rest.Config + masterURL string ) func init() { - flag.StringVar(&kubeConfigFile, "kubeconfig", fmt.Sprintf("%s/.kube/config", os.Getenv("HOME")), "path to kubeconfig file") + flag.StringVar(&kubeConfigFile, "kubeconfig", "", "path to kubeconfig file") + flag.StringVar(&masterURL, "master-url","", "kube-apiserver url, only needed when out of cluster") } func Client() *kubernetes.Clientset { @@ -63,18 +62,8 @@ func Client() *kubernetes.Clientset { func Config() (kubeConfig *rest.Config, err error) { - if kubeConfigFile == "" { - if env := os.Getenv("KUBECONFIG"); env != "" { - kubeConfigFile = env - } else { - if home, err := homedir.Dir(); err == nil { - kubeConfigFile = fmt.Sprintf("%s/.kube/config", home) - } - } - } - if _, err = os.Stat(kubeConfigFile); err == nil { - kubeConfig, err = clientcmd.BuildConfigFromFlags("", kubeConfigFile) + kubeConfig, err = clientcmd.BuildConfigFromFlags(masterURL, kubeConfigFile) } else { kubeConfig, err = rest.InClusterConfig() } diff --git a/pkg/simple/controller/namespace/namespaces.go b/pkg/simple/controller/namespace/namespaces.go index 4881fd6de..bf4d3bd0e 100644 --- a/pkg/simple/controller/namespace/namespaces.go +++ b/pkg/simple/controller/namespace/namespaces.go @@ -19,9 +19,10 @@ package namespace import ( "fmt" + "github.com/golang/glog" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" "time" - "github.com/golang/glog" corev1 "k8s.io/api/core/v1" rbac "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" @@ -36,6 +37,8 @@ import ( "k8s.io/client-go/util/workqueue" ) +var log = logf.Log.WithName("namespace-controller") + const threadiness = 2 var ( @@ -54,18 +57,18 @@ type NamespaceController struct { } func NewNamespaceController( - kubeclientset kubernetes.Interface, + clientset kubernetes.Interface, namespaceInformer coreinformers.NamespaceInformer, roleInformer rbacinformers.RoleInformer) *NamespaceController { controller := &NamespaceController{ - clientset: kubeclientset, + clientset: clientset, namespaceInformer: namespaceInformer, roleInformer: roleInformer, workqueue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "namespaces"), } - glog.Info("setting up event handlers") + log.V(3).Info("setting up event handlers") namespaceInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: controller.handleObject, @@ -86,29 +89,24 @@ func NewNamespaceController( } func (c *NamespaceController) Start(stopCh <-chan struct{}) error { - go func() { - defer utilruntime.HandleCrash() - defer c.workqueue.ShutDown() + defer utilruntime.HandleCrash() + defer c.workqueue.ShutDown() - // Start the informer factories to begin populating the informer caches - glog.Info("starting namespace controller") + log.V(3).Info("starting namespace controller") + defer glog.Info("shutting down namespace controller") - // Wait for the caches to be synced before starting workers - glog.Info("waiting for informer caches to sync") - if ok := cache.WaitForCacheSync(stopCh, c.namespaceInformer.Informer().HasSynced, c.roleInformer.Informer().HasSynced); !ok { - glog.Fatalf("controller exit with error: failed to wait for caches to sync") - } + // Wait for the caches to be synced before starting workers + log.Info("waiting for informer caches to sync") + if ok := cache.WaitForCacheSync(stopCh, c.namespaceInformer.Informer().HasSynced, c.roleInformer.Informer().HasSynced); !ok { + glog.Fatalf("controller exit with error: failed to wait for caches to sync") + } - glog.Info("starting workers") + log.V(3).Info("starting workers") + for i := 0; i < threadiness; i++ { + go wait.Until(c.runWorker, time.Second, stopCh) + } - for i := 0; i < threadiness; i++ { - go wait.Until(c.runWorker, time.Second, stopCh) - } - - glog.Info("started workers") - <-stopCh - glog.Info("shutting down workers") - }() + <-stopCh return nil } @@ -142,7 +140,7 @@ func (c *NamespaceController) processNextWorkItem() bool { } c.workqueue.Forget(obj) - glog.Infof("successfully namespace synced '%s'", namespace) + log.V(4).Info("successfully namespace synced ", "namespace", namespace) return nil }(obj) diff --git a/vendor/github.com/kiali/kiali/handlers/health.go b/vendor/github.com/kiali/kiali/handlers/health.go index 8e6e88f0b..4f542ac5e 100644 --- a/vendor/github.com/kiali/kiali/handlers/health.go +++ b/vendor/github.com/kiali/kiali/handlers/health.go @@ -1,10 +1,10 @@ package handlers import ( + "github.com/emicklei/go-restful" "net/http" "time" - "github.com/gorilla/mux" "k8s.io/apimachinery/pkg/api/errors" "github.com/kiali/kiali/business" @@ -15,25 +15,25 @@ import ( const defaultHealthRateInterval = "10m" // NamespaceHealth is the API handler to get app-based health of every services in the given namespace -func NamespaceHealth(w http.ResponseWriter, r *http.Request) { +func NamespaceHealth(request *restful.Request, response *restful.Response) { // Get business layer business, err := business.Get() if err != nil { - RespondWithError(w, http.StatusInternalServerError, "Services initialization error: "+err.Error()) + RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Services initialization error: "+err.Error()) return } p := namespaceHealthParams{} - if ok, err := p.extract(r); !ok { + if ok, err := p.extract(request); !ok { // Bad request - RespondWithError(w, http.StatusBadRequest, err) + RespondWithError(response.ResponseWriter, http.StatusBadRequest, err) return } // Adjust rate interval rateInterval, err := adjustRateInterval(business, p.Namespace, p.RateInterval, p.QueryTime) if err != nil { - RespondWithError(w, http.StatusInternalServerError, "Adjust rate interval error: "+err.Error()) + RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Adjust rate interval error: "+err.Error()) return } @@ -41,86 +41,86 @@ func NamespaceHealth(w http.ResponseWriter, r *http.Request) { case "app": health, err := business.Health.GetNamespaceAppHealth(p.Namespace, rateInterval, p.QueryTime) if err != nil { - RespondWithError(w, http.StatusInternalServerError, "Error while fetching app health: "+err.Error()) + RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Error while fetching app health: "+err.Error()) return } - RespondWithJSON(w, http.StatusOK, health) + RespondWithJSON(response.ResponseWriter, http.StatusOK, health) case "service": health, err := business.Health.GetNamespaceServiceHealth(p.Namespace, rateInterval, p.QueryTime) if err != nil { - RespondWithError(w, http.StatusInternalServerError, "Error while fetching service health: "+err.Error()) + RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Error while fetching service health: "+err.Error()) return } - RespondWithJSON(w, http.StatusOK, health) + RespondWithJSON(response.ResponseWriter, http.StatusOK, health) case "workload": health, err := business.Health.GetNamespaceWorkloadHealth(p.Namespace, rateInterval, p.QueryTime) if err != nil { - RespondWithError(w, http.StatusInternalServerError, "Error while fetching workload health: "+err.Error()) + RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Error while fetching workload health: "+err.Error()) return } - RespondWithJSON(w, http.StatusOK, health) + RespondWithJSON(response.ResponseWriter, http.StatusOK, health) } } // AppHealth is the API handler to get health of a single app -func AppHealth(w http.ResponseWriter, r *http.Request) { +func AppHealth(request *restful.Request, response *restful.Response) { business, err := business.Get() if err != nil { - RespondWithError(w, http.StatusInternalServerError, "Services initialization error: "+err.Error()) + RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Services initialization error: "+err.Error()) return } p := appHealthParams{} - p.extract(r) + p.extract(request) rateInterval, err := adjustRateInterval(business, p.Namespace, p.RateInterval, p.QueryTime) if err != nil { - RespondWithError(w, http.StatusInternalServerError, "Adjust rate interval error: "+err.Error()) + RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Adjust rate interval error: "+err.Error()) return } health, err := business.Health.GetAppHealth(p.Namespace, p.App, rateInterval, p.QueryTime) - handleHealthResponse(w, health, err) + handleHealthResponse(response.ResponseWriter, health, err) } // WorkloadHealth is the API handler to get health of a single workload -func WorkloadHealth(w http.ResponseWriter, r *http.Request) { +func WorkloadHealth(request *restful.Request, response *restful.Response) { business, err := business.Get() if err != nil { - RespondWithError(w, http.StatusInternalServerError, "Services initialization error: "+err.Error()) + RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Services initialization error: "+err.Error()) return } p := workloadHealthParams{} - p.extract(r) + p.extract(request) rateInterval, err := adjustRateInterval(business, p.Namespace, p.RateInterval, p.QueryTime) if err != nil { - RespondWithError(w, http.StatusInternalServerError, "Adjust rate interval error: "+err.Error()) + RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Adjust rate interval error: "+err.Error()) return } p.RateInterval = rateInterval health, err := business.Health.GetWorkloadHealth(p.Namespace, p.Workload, rateInterval, p.QueryTime) - handleHealthResponse(w, health, err) + handleHealthResponse(response.ResponseWriter, health, err) } // ServiceHealth is the API handler to get health of a single service -func ServiceHealth(w http.ResponseWriter, r *http.Request) { +func ServiceHealth(request *restful.Request, response *restful.Response) { business, err := business.Get() if err != nil { - RespondWithError(w, http.StatusInternalServerError, "Services initialization error: "+err.Error()) + RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Services initialization error: "+err.Error()) return } p := serviceHealthParams{} - p.extract(r) + p.extract(request) rateInterval, err := adjustRateInterval(business, p.Namespace, p.RateInterval, p.QueryTime) if err != nil { - RespondWithError(w, http.StatusInternalServerError, "Adjust rate interval error: "+err.Error()) + RespondWithError(response.ResponseWriter, http.StatusInternalServerError, "Adjust rate interval error: "+err.Error()) return } health, err := business.Health.GetServiceHealth(p.Namespace, p.Service, rateInterval, p.QueryTime) - handleHealthResponse(w, health, err) + handleHealthResponse(response.ResponseWriter, health, err) } func handleHealthResponse(w http.ResponseWriter, health interface{}, err error) { @@ -152,14 +152,12 @@ type baseHealthParams struct { QueryTime time.Time } -func (p *baseHealthParams) baseExtract(r *http.Request, vars map[string]string) { +func (p *baseHealthParams) baseExtract(request *restful.Request) { p.RateInterval = defaultHealthRateInterval p.QueryTime = util.Clock.Now() - queryParams := r.URL.Query() - if rateIntervals, ok := queryParams["rateInterval"]; ok && len(rateIntervals) > 0 { - p.RateInterval = rateIntervals[0] - } - p.Namespace = vars["namespace"] + + p.RateInterval = request.QueryParameter("rateInterval") + p.Namespace = request.PathParameters()["namespace"] } // namespaceHealthParams holds the path and query parameters for NamespaceHealth @@ -175,19 +173,17 @@ type namespaceHealthParams struct { Type string `json:"type"` } -func (p *namespaceHealthParams) extract(r *http.Request) (bool, string) { - vars := mux.Vars(r) - p.baseExtract(r, vars) +func (p *namespaceHealthParams) extract(request *restful.Request) (bool, string) { + p.baseExtract(request) p.Type = "app" - queryParams := r.URL.Query() - if healthTypes, ok := queryParams["type"]; ok && len(healthTypes) > 0 { - if healthTypes[0] != "app" && healthTypes[0] != "service" && healthTypes[0] != "workload" { - // Bad request - return false, "Bad request, query parameter 'type' must be one of ['app','service','workload']" - } - p.Type = healthTypes[0] + tp := request.QueryParameter("type") + switch tp { + case "app", "service", "workload": + p.Type = tp + return true, "" } - return true, "" + + return false, "Bad request, query parameter 'type' must be one of ['app','service','workload']" } // appHealthParams holds the path and query parameters for AppHealth @@ -201,10 +197,9 @@ type appHealthParams struct { App string `json:"app"` } -func (p *appHealthParams) extract(r *http.Request) { - vars := mux.Vars(r) - p.baseExtract(r, vars) - p.App = vars["app"] +func (p *appHealthParams) extract(request *restful.Request) { + p.baseExtract(request) + p.App = request.PathParameter("app") } // serviceHealthParams holds the path and query parameters for ServiceHealth @@ -218,10 +213,9 @@ type serviceHealthParams struct { Service string `json:"service"` } -func (p *serviceHealthParams) extract(r *http.Request) { - vars := mux.Vars(r) - p.baseExtract(r, vars) - p.Service = vars["service"] +func (p *serviceHealthParams) extract(request *restful.Request) { + p.baseExtract(request) + p.Service = request.PathParameter("service") } // workloadHealthParams holds the path and query parameters for WorkloadHealth @@ -235,10 +229,9 @@ type workloadHealthParams struct { Workload string `json:"workload"` } -func (p *workloadHealthParams) extract(r *http.Request) { - vars := mux.Vars(r) - p.baseExtract(r, vars) - p.Workload = vars["workload"] +func (p *workloadHealthParams) extract(request *restful.Request) { + p.baseExtract(request) + p.Workload = request.PathParameter("workload") } func adjustRateInterval(business *business.Layer, namespace, rateInterval string, queryTime time.Time) (string, error) {