Send the error message to user when enabling canary feature fails. (#990)

* Send the error message to user when enabling canary feature fails.
* Fix controller doesn’t reply canary error when promClient tries connect to invalid prometheus server
This commit is contained in:
smruthi2187
2019-01-14 22:43:27 +08:00
committed by Ta-Ching Chen
parent 89081b087b
commit db5165e032
8 changed files with 60 additions and 30 deletions
+6 -1
View File
@@ -62,11 +62,16 @@ func MakeCanaryConfigMgr(fissionClient *crd.FissionClient, kubeClient *kubernete
} }
} }
promClient, err := MakePrometheusClient(prometheusSvc)
if err != nil {
return nil, err
}
configMgr := &canaryConfigMgr{ configMgr := &canaryConfigMgr{
fissionClient: fissionClient, fissionClient: fissionClient,
kubeClient: kubeClient, kubeClient: kubeClient,
crdClient: crdClient, crdClient: crdClient,
promClient: MakePrometheusClient(prometheusSvc), promClient: promClient,
canaryCfgCancelFuncMap: makecanaryConfigCancelFuncMap(), canaryCfgCancelFuncMap: makecanaryConfigCancelFuncMap(),
} }
+21 -3
View File
@@ -18,9 +18,10 @@ package canaryconfigmgr
import ( import (
"fmt" "fmt"
"golang.org/x/net/context"
"time" "time"
"golang.org/x/net/context"
promClient "github.com/prometheus/client_golang/api/prometheus" promClient "github.com/prometheus/client_golang/api/prometheus"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
@@ -30,7 +31,7 @@ type PrometheusApiClient struct {
client promClient.QueryAPI client promClient.QueryAPI
} }
func MakePrometheusClient(prometheusSvc string) *PrometheusApiClient { func MakePrometheusClient(prometheusSvc string) (*PrometheusApiClient, error) {
promApiConfig := promClient.Config{ promApiConfig := promClient.Config{
Address: prometheusSvc, Address: prometheusSvc,
} }
@@ -38,14 +39,31 @@ func MakePrometheusClient(prometheusSvc string) *PrometheusApiClient {
promApiClient, err := promClient.New(promApiConfig) promApiClient, err := promClient.New(promApiConfig)
if err != nil { if err != nil {
log.Errorf("Error creating prometheus api client for svc : %s, err : %v", prometheusSvc, err) log.Errorf("Error creating prometheus api client for svc : %s, err : %v", prometheusSvc, err)
return nil, err
} }
apiQueryClient := promClient.NewQueryAPI(promApiClient) apiQueryClient := promClient.NewQueryAPI(promApiClient)
// By default, the prometheus client library doesn't test server connectivity when creating
// prometheus client. As a workaround, here we send out a test query string to ensure that
// prometheus server is running.
for i := 0; i < 15; i++ {
_, err = apiQueryClient.Query(context.Background(), "http_requests_total", time.Now())
if err == nil {
break
}
time.Sleep(time.Second)
}
if err != nil {
log.Printf("Error sending test query to prometheus server: %v", err)
return nil, err
}
log.Printf("Successfully made prometheus client with service : %s", prometheusSvc) log.Printf("Successfully made prometheus client with service : %s", prometheusSvc)
return &PrometheusApiClient{ return &PrometheusApiClient{
client: apiQueryClient, client: apiQueryClient,
} }, nil
} }
func (promApiClient *PrometheusApiClient) GetFunctionFailurePercentage(path, method, funcName, funcNs string, window string) (float64, error) { func (promApiClient *PrometheusApiClient) GetFunctionFailurePercentage(path, method, funcName, funcNs string, window string) (float64, error) {
+3 -4
View File
@@ -32,7 +32,6 @@ import (
"github.com/fission/fission" "github.com/fission/fission"
"github.com/fission/fission/crd" "github.com/fission/fission/crd"
config "github.com/fission/fission/featureconfig"
"github.com/fission/fission/fission/logdb" "github.com/fission/fission/fission/logdb"
) )
@@ -54,7 +53,7 @@ type (
workflowApiUrl string workflowApiUrl string
functionNamespace string functionNamespace string
useIstio bool useIstio bool
featureConfig *config.FeatureConfig featureStatus map[string]string
} }
logDBConfig struct { logDBConfig struct {
@@ -64,7 +63,7 @@ type (
} }
) )
func MakeAPI(featureConfig *config.FeatureConfig) (*API, error) { func MakeAPI(featureStatus map[string]string) (*API, error) {
api, err := makeCRDBackedAPI() api, err := makeCRDBackedAPI()
u := os.Getenv("STORAGE_SERVICE_URL") u := os.Getenv("STORAGE_SERVICE_URL")
@@ -95,7 +94,7 @@ func MakeAPI(featureConfig *config.FeatureConfig) (*API, error) {
api.functionNamespace = "fission-function" api.functionNamespace = "fission-function"
} }
api.featureConfig = featureConfig api.featureStatus = featureStatus
return api, err return api, err
} }
+17 -10
View File
@@ -18,6 +18,7 @@ package controller
import ( import (
"encoding/json" "encoding/json"
"fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
@@ -27,11 +28,13 @@ import (
"github.com/fission/fission" "github.com/fission/fission"
"github.com/fission/fission/crd" "github.com/fission/fission/crd"
config "github.com/fission/fission/featureconfig"
) )
func (a *API) CanaryConfigApiCreate(w http.ResponseWriter, r *http.Request) { func (a *API) CanaryConfigApiCreate(w http.ResponseWriter, r *http.Request) {
if !a.featureConfig.CanaryConfig.IsEnabled { featureErr := a.featureStatus[config.CanaryFeature]
a.respondWithError(w, fission.MakeError(http.StatusBadRequest, "Please enable canary feature while installing fission")) if len(featureErr) > 0 {
a.respondWithError(w, fission.MakeError(http.StatusInternalServerError, fmt.Sprintf("Error enabling canary feature: %v", featureErr)))
return return
} }
@@ -66,8 +69,9 @@ func (a *API) CanaryConfigApiCreate(w http.ResponseWriter, r *http.Request) {
} }
func (a *API) CanaryConfigApiGet(w http.ResponseWriter, r *http.Request) { func (a *API) CanaryConfigApiGet(w http.ResponseWriter, r *http.Request) {
if !a.featureConfig.CanaryConfig.IsEnabled { featureErr := a.featureStatus[config.CanaryFeature]
a.respondWithError(w, fission.MakeError(http.StatusBadRequest, "Please enable canary feature while installing fission")) if len(featureErr) > 0 {
a.respondWithError(w, fission.MakeError(http.StatusInternalServerError, fmt.Sprintf("Error enabling canary feature: %v", featureErr)))
return return
} }
@@ -95,8 +99,9 @@ func (a *API) CanaryConfigApiGet(w http.ResponseWriter, r *http.Request) {
} }
func (a *API) CanaryConfigApiList(w http.ResponseWriter, r *http.Request) { func (a *API) CanaryConfigApiList(w http.ResponseWriter, r *http.Request) {
if !a.featureConfig.CanaryConfig.IsEnabled { featureErr := a.featureStatus[config.CanaryFeature]
a.respondWithError(w, fission.MakeError(http.StatusBadRequest, "Please enable canary feature while installing fission")) if len(featureErr) > 0 {
a.respondWithError(w, fission.MakeError(http.StatusInternalServerError, fmt.Sprintf("Error enabling canary feature: %v", featureErr)))
return return
} }
@@ -121,8 +126,9 @@ func (a *API) CanaryConfigApiList(w http.ResponseWriter, r *http.Request) {
} }
func (a *API) CanaryConfigApiUpdate(w http.ResponseWriter, r *http.Request) { func (a *API) CanaryConfigApiUpdate(w http.ResponseWriter, r *http.Request) {
if !a.featureConfig.CanaryConfig.IsEnabled { featureErr := a.featureStatus[config.CanaryFeature]
a.respondWithError(w, fission.MakeError(http.StatusBadRequest, "Please enable canary feature while installing fission")) if len(featureErr) > 0 {
a.respondWithError(w, fission.MakeError(http.StatusInternalServerError, fmt.Sprintf("Error enabling canary feature: %v", featureErr)))
return return
} }
@@ -155,8 +161,9 @@ func (a *API) CanaryConfigApiUpdate(w http.ResponseWriter, r *http.Request) {
} }
func (a *API) CanaryConfigApiDelete(w http.ResponseWriter, r *http.Request) { func (a *API) CanaryConfigApiDelete(w http.ResponseWriter, r *http.Request) {
if !a.featureConfig.CanaryConfig.IsEnabled { featureErr := a.featureStatus[config.CanaryFeature]
a.respondWithError(w, fission.MakeError(http.StatusBadRequest, "Please enable canary feature while installing fission")) if len(featureErr) > 0 {
a.respondWithError(w, fission.MakeError(http.StatusInternalServerError, fmt.Sprintf("Error enabling canary feature: %v", featureErr)))
return return
} }
+9 -7
View File
@@ -28,12 +28,13 @@ import (
config "github.com/fission/fission/featureconfig" config "github.com/fission/fission/featureconfig"
) )
func ConfigCanaryFeature(context context.Context, fissionClient *crd.FissionClient, kubeClient *kubernetes.Clientset, featureConfig *config.FeatureConfig) error { func ConfigCanaryFeature(context context.Context, fissionClient *crd.FissionClient, kubeClient *kubernetes.Clientset, featureConfig *config.FeatureConfig, featureStatus map[string]string) error {
// start the appropriate controller // start the appropriate controller
if featureConfig.CanaryConfig.IsEnabled { if featureConfig.CanaryConfig.IsEnabled {
canaryCfgMgr, err := canaryconfigmgr.MakeCanaryConfigMgr(fissionClient, kubeClient, fissionClient.GetCrdClient(), canaryCfgMgr, err := canaryconfigmgr.MakeCanaryConfigMgr(fissionClient, kubeClient, fissionClient.GetCrdClient(),
featureConfig.CanaryConfig.PrometheusSvc) featureConfig.CanaryConfig.PrometheusSvc)
if err != nil { if err != nil {
featureStatus[config.CanaryFeature] = err.Error()
return fmt.Errorf("failed to start canary config manager: %v", err) return fmt.Errorf("failed to start canary config manager: %v", err)
} }
canaryCfgMgr.Run(context) canaryCfgMgr.Run(context)
@@ -44,22 +45,23 @@ func ConfigCanaryFeature(context context.Context, fissionClient *crd.FissionClie
} }
// ConfigureFeatures gets the feature config and configures the features that are enabled // ConfigureFeatures gets the feature config and configures the features that are enabled
func ConfigureFeatures(context context.Context, unitTestMode bool, fissionClient *crd.FissionClient, kubeClient *kubernetes.Clientset) (*config.FeatureConfig, error) { func ConfigureFeatures(context context.Context, unitTestMode bool, fissionClient *crd.FissionClient, kubeClient *kubernetes.Clientset) (map[string]string, error) {
// set feature enabled to false if unitTestMode // set feature enabled to false if unitTestMode
if unitTestMode { if unitTestMode {
featureConfig := &config.FeatureConfig{} return nil, nil
return featureConfig, nil
} }
// get the featureConfig from config map mounted onto the file system // get the featureConfig from config map mounted onto the file system
featureConfig, err := config.GetFeatureConfig() featureConfig, err := config.GetFeatureConfig()
if err != nil { if err != nil {
log.Printf("Error getting feature config : %v", err) log.Printf("Error getting feature config : %v", err)
return featureConfig, err return nil, err
} }
featureStatus := make(map[string]string)
// configure respective features // configure respective features
// in the future when new optional features are added, we need to add corresponding feature handlers and invoke them here // in the future when new optional features are added, we need to add corresponding feature handlers and invoke them here
err = ConfigCanaryFeature(context, fissionClient, kubeClient, featureConfig) err = ConfigCanaryFeature(context, fissionClient, kubeClient, featureConfig, featureStatus)
return featureConfig, err return featureStatus, err
} }
+2 -4
View File
@@ -44,15 +44,13 @@ func Start(port int, unitTestFlag bool) {
} }
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
featureConfig, err := ConfigureFeatures(ctx, unitTestFlag, fc, kc) featureStatus, err := ConfigureFeatures(ctx, unitTestFlag, fc, kc)
if err != nil { if err != nil {
log.Printf("Error configuring features : %v. Proceeding without optional features", err.Error()) log.Printf("Error configuring features : %v. Proceeding without optional features", err.Error())
// set all features to false for the MakeApi call below
featureConfig.CanaryConfig.IsEnabled = false
} }
defer cancel() defer cancel()
api, err := MakeAPI(featureConfig) api, err := MakeAPI(featureStatus)
if err != nil { if err != nil {
log.Fatalf("Failed to start controller: %v", err) log.Fatalf("Failed to start controller: %v", err)
} }
+1
View File
@@ -18,6 +18,7 @@ package featureconfig
const ( const (
FeatureConfigFile = "/etc/config/config.yaml" FeatureConfigFile = "/etc/config/config.yaml"
CanaryFeature = "canary"
) )
type ( type (
+1 -1
View File
@@ -60,7 +60,7 @@ func canaryConfigCreate(c *cli.Context) error {
htTrigger, err := client.HTTPTriggerGet(m) htTrigger, err := client.HTTPTriggerGet(m)
if err != nil { if err != nil {
util.CheckErr(err, "Trigger referenced in the canary config is not created") util.CheckErr(err, "find trigger referenced in the canary config")
} }
// check that the trigger has function reference type function weights // check that the trigger has function reference type function weights