diff --git a/.golangci.toml b/.golangci.toml index 327f96c65..9f6cd7d7e 100644 --- a/.golangci.toml +++ b/.golangci.toml @@ -33,5 +33,14 @@ "gochecknoinits", "gochecknoglobals", "scopelint", - "typecheck", # v1.17.1 and Go1.13 => bug + "funlen", + ] + +[issues] + exclude-use-default = false + max-per-linter = 0 + max-same-issues = 0 + exclude = [ + "Error return value of .((os\\.)?std(out|err)\\..*|.*Close|.*Flush|os\\.Remove(All)?|.*printf?|os\\.(Un)?Setenv). is not checked", + "should have a package comment, unless it's in another file for this package", ] diff --git a/Dockerfile b/Dockerfile index cbf0add69..fa843a276 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,6 +21,9 @@ WORKDIR /go/src/github.com/containous/maesh # Download goreleaser binary to bin folder in $GOPATH RUN curl -sfL https://install.goreleaser.com/github.com/goreleaser/goreleaser.sh | sh +# Download golangci-lint binary to bin folder in $GOPATH +RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | bash -s -- -b $GOPATH/bin v1.18.0 + ENV GO111MODULE on COPY go.mod go.sum ./ RUN go mod download diff --git a/Makefile b/Makefile index 8f6df2bb7..abd0647dd 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,6 @@ BINARY_NAME = maesh DIST_DIR = $(CURDIR)/dist DIST_DIR_MAESH = $(DIST_DIR)/$(BINARY_NAME) PROJECT ?= github.com/containous/$(BINARY_NAME) -GOLANGCI_LINTER_VERSION = v1.17.1 TAG_NAME ?= $(shell git tag -l --contains HEAD) SHA := $(shell git rev-parse --short HEAD) @@ -64,7 +63,12 @@ test: $(DIST_DIR) docker build --tag "$(DOCKER_IMAGE_NAME):test" --target maker --build-arg="MAKE_TARGET=local-test" $(CURDIR)/ check: $(DIST_DIR) helm-lint - docker run -t --rm -v $(CURDIR):/go/src/$(PROJECT) -w /go/src/$(PROJECT) -e GO111MODULE golangci/golangci-lint:$(GOLANGCI_LINTER_VERSION) golangci-lint run --config .golangci.toml + docker build --tag "$(DOCKER_IMAGE_NAME):check" --target base-image $(CURDIR)/ + docker run --rm \ + -v $(CURDIR):/go/src/$(PROJECT) \ + -w /go/src/$(PROJECT) \ + -e GO111MODULE \ + "$(DOCKER_IMAGE_NAME):check" golangci-lint run --config .golangci.toml publish-images: build seihon publish -v "$(VERSION)" -v "latest" --image-name ${DOCKER_IMAGE_NAME} --dry-run=false --base-runtime-image=alpine:3.10 diff --git a/cmd/configuration.go b/cmd/configuration.go index e0e96cadd..9b9eab2c8 100644 --- a/cmd/configuration.go +++ b/cmd/configuration.go @@ -34,6 +34,7 @@ type PrepareConfig struct { Namespace string `description:"The namespace that maesh is installed in." export:"true"` } +// NewPrepareConfig creates PrepareConfig. func NewPrepareConfig() *PrepareConfig { return &PrepareConfig{ KubeConfig: os.Getenv("KUBECONFIG"), @@ -41,17 +42,3 @@ func NewPrepareConfig() *PrepareConfig { Namespace: "maesh", } } - -// CheckConfig . -type CheckConfig struct { - KubeConfig string `description:"Path to a kubeconfig. Only required if out-of-cluster." export:"true"` - MasterURL string `description:"The address of the Kubernetes API server. Overrides any value in kubeconfig. Only required if out-of-cluster." export:"true"` - Debug bool `description:"Debug mode" export:"true"` -} - -func NewCheckConfig() *CheckConfig { - return &CheckConfig{ - KubeConfig: os.Getenv("KUBECONFIG"), - Debug: false, - } -} diff --git a/integration/try/try.go b/integration/try/try.go index f6ee4d887..7e60250d0 100644 --- a/integration/try/try.go +++ b/integration/try/try.go @@ -22,10 +22,12 @@ const ( CITimeoutMultiplier = 3 ) +// Try holds try configuration. type Try struct { client *k8s.ClientWrapper } +// NewTry creates a new try. func NewTry(client *k8s.ClientWrapper) *Try { return &Try{client: client} } diff --git a/internal/controller/controller.go b/internal/controller/controller.go index 5c70d4d80..401f6820a 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -25,6 +25,7 @@ import ( "k8s.io/client-go/util/workqueue" ) +// Controller hold controller configuration. type Controller struct { clients *k8s.ClientWrapper kubernetesFactory informers.SharedInformerFactory @@ -47,7 +48,7 @@ type Controller struct { tcpStateTable *k8s.State } -// New is used to build the informers and other required components of the mesh controller, +// NewMeshController is used to build the informers and other required components of the mesh controller, // and return an initialized mesh controller object. func NewMeshController(clients *k8s.ClientWrapper, smiEnabled bool, defaultMode string, meshNamespace string) *Controller { ignored := k8s.NewIgnored(meshNamespace) @@ -504,7 +505,7 @@ func (c *Controller) loadTCPStateTable() (*k8s.State, error) { result = &k8s.State{Table: make(map[int]*k8s.ServiceWithPort)} } - configMap, exists, err := c.clients.GetConfigMap(c.meshNamespace, k8s.TCPStateConfigmapName) + configMap, exists, err := c.clients.GetConfigMap(c.meshNamespace, k8s.TCPStateConfigMapName) if err != nil { return result, err } @@ -562,7 +563,7 @@ func (c *Controller) getTCPPortFromState(serviceName, serviceNamespace string, s } func (c *Controller) saveTCPStateTable() error { - configMap, exists, err := c.clients.GetConfigMap(c.meshNamespace, k8s.TCPStateConfigmapName) + configMap, exists, err := c.clients.GetConfigMap(c.meshNamespace, k8s.TCPStateConfigMapName) if err != nil { return err } diff --git a/internal/controller/handler.go b/internal/controller/handler.go index ff0d050bd..dee30b9b5 100644 --- a/internal/controller/handler.go +++ b/internal/controller/handler.go @@ -14,6 +14,7 @@ type Handler struct { messageQueue workqueue.RateLimitingInterface } +// NewHandler creates a handler. func NewHandler(ignored k8s.IgnoreWrapper, messageQueue workqueue.RateLimitingInterface) *Handler { h := &Handler{ ignored: ignored, @@ -34,6 +35,7 @@ func (h *Handler) Init() error { return nil } +// OnAdd executed when an object is added. func (h *Handler) OnAdd(obj interface{}) { // convert the resource object into a key (in this case // we are just doing it in the format of 'namespace/name') @@ -54,6 +56,7 @@ func (h *Handler) OnAdd(obj interface{}) { } } +// OnUpdate executed when an object is updated. func (h *Handler) OnUpdate(oldObj, newObj interface{}) { key, err := cache.MetaNamespaceKeyFunc(newObj) if err != nil { @@ -71,6 +74,7 @@ func (h *Handler) OnUpdate(oldObj, newObj interface{}) { } } +// OnDelete executed when an object is deleted. func (h *Handler) OnDelete(obj interface{}) { // DeletionHandlingMetaNamsespaceKeyFunc is a helper function that allows // us to check the DeletedFinalStateUnknown existence in the event that diff --git a/internal/deployer/deployer.go b/internal/deployer/deployer.go index d2160b80e..68c5154d3 100644 --- a/internal/deployer/deployer.go +++ b/internal/deployer/deployer.go @@ -197,17 +197,18 @@ func (d *Deployer) deployAPI(m message.Deploy) bool { } url := fmt.Sprintf("http://%s:8080/api/providers/rest", m.PodIP) - client := &http.Client{Timeout: 10 * time.Second} + req, err := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(b)) if err != nil { log.Errorf("Could not create request: %v", err) return false } + + client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if resp != nil { defer resp.Body.Close() - _, bodyErr := ioutil.ReadAll(resp.Body) - if bodyErr != nil { + if _, bodyErr := ioutil.ReadAll(resp.Body); bodyErr != nil { log.Errorf("Unable to read response body: %v", bodyErr) return false } diff --git a/internal/k8s/client.go b/internal/k8s/client.go index effae07d2..2c99f1928 100644 --- a/internal/k8s/client.go +++ b/internal/k8s/client.go @@ -46,6 +46,7 @@ type ClusterInitClient interface { VerifyCluster() error } +// CoreV1Client CoreV1 client. type CoreV1Client interface { GetService(namespace, name string) (*corev1.Service, bool, error) GetServices(namespace string) ([]*corev1.Service, error) @@ -64,25 +65,30 @@ type CoreV1Client interface { CreateConfigMap(configMap *corev1.ConfigMap) (*corev1.ConfigMap, error) } +// AppsV1Client AppsV1 client. type AppsV1Client interface { GetDeployment(namespace, name string) (*appsv1.Deployment, bool, error) UpdateDeployment(deployment *appsv1.Deployment) (*appsv1.Deployment, error) } +// SMIClient SMI client. type SMIClient interface { SMIAccessV1Alpha1Client SMISpecsV1Alpha1Client SMISplitV1Alpha1Client } +// SMIAccessV1Alpha1Client SMI Access v1Alpha client. type SMIAccessV1Alpha1Client interface { GetTrafficTargets() ([]*smiAccessv1alpha1.TrafficTarget, error) } +// SMISpecsV1Alpha1Client SMI Specs v1Alpha client. type SMISpecsV1Alpha1Client interface { GetHTTPRouteGroup(namespace, name string) (*smiSpecsv1alpha1.HTTPRouteGroup, bool, error) } +// SMISplitV1Alpha1Client SMI Split v1Alpha client. type SMISplitV1Alpha1Client interface { GetTrafficSplits() ([]*smiSplitv1alpha1.TrafficSplit, error) } @@ -427,6 +433,7 @@ func (w *ClientWrapper) GetPod(namespace, name string) (*corev1.Pod, bool, error return pod, exists, err } +// ListPodWithOptions retrieves pods from the specified namespace. func (w *ClientWrapper) ListPodWithOptions(namespace string, options metav1.ListOptions) (*corev1.PodList, error) { return w.KubeClient.CoreV1().Pods(namespace).List(options) } diff --git a/internal/k8s/client_mock.go b/internal/k8s/client_mock.go index 657b744fd..ee1d42cdc 100644 --- a/internal/k8s/client_mock.go +++ b/internal/k8s/client_mock.go @@ -44,6 +44,7 @@ func init() { } +// CoreV1ClientMock holds CoreV1 client mock information. type CoreV1ClientMock struct { services []*corev1.Service servicesList *corev1.ServiceList @@ -59,12 +60,14 @@ type CoreV1ClientMock struct { apiConfigMapError error } +// AppsV1ClientMock holds AppsV1 client mock information. type AppsV1ClientMock struct { deployments []*appsv1.Deployment apiDeploymentError error } +// SMIClientMock holds SMI client mock information. type SMIClientMock struct { trafficTargets []*accessv1alpha1.TrafficTarget httpRouteGroups []*specsv1alpha1.HTTPRouteGroup @@ -75,12 +78,14 @@ type SMIClientMock struct { apiTrafficSplitError error } +// ClientMock clients mock. type ClientMock struct { CoreV1ClientMock SMIClientMock AppsV1ClientMock } +// NewCoreV1ClientMock create a new corev1 client mock. func NewCoreV1ClientMock(paths ...string) *CoreV1ClientMock { c := &CoreV1ClientMock{} @@ -114,6 +119,7 @@ func NewCoreV1ClientMock(paths ...string) *CoreV1ClientMock { return c } +// NewSMIClientMock create a new smi client mock. func NewSMIClientMock(paths ...string) *SMIClientMock { s := &SMIClientMock{} @@ -144,6 +150,7 @@ func NewSMIClientMock(paths ...string) *SMIClientMock { return s } +// NewClientMock create a new client mock. func NewClientMock(paths ...string) *ClientMock { c := &ClientMock{} @@ -191,6 +198,7 @@ func setNamespaceIfNot(obj metav1.Object) { } } +// GetService returns mocked date for service. func (c *CoreV1ClientMock) GetService(namespace, name string) (*corev1.Service, bool, error) { if c.apiServiceError != nil { return nil, false, c.apiServiceError @@ -204,6 +212,7 @@ func (c *CoreV1ClientMock) GetService(namespace, name string) (*corev1.Service, return nil, false, c.apiServiceError } +// GetServices returns mocked date for services. func (c *CoreV1ClientMock) GetServices(namespace string) ([]*corev1.Service, error) { if c.apiServiceError != nil { return nil, c.apiServiceError @@ -212,6 +221,7 @@ func (c *CoreV1ClientMock) GetServices(namespace string) ([]*corev1.Service, err return c.services, nil } +// ListServicesWithOptions returns mocked date for services. func (c *CoreV1ClientMock) ListServicesWithOptions(namespace string, options metav1.ListOptions) (*corev1.ServiceList, error) { if c.apiServiceError != nil { return nil, c.apiServiceError @@ -220,22 +230,27 @@ func (c *CoreV1ClientMock) ListServicesWithOptions(namespace string, options met return c.servicesList, nil } +// WatchServicesWithOptions mocks service watch. func (c *CoreV1ClientMock) WatchServicesWithOptions(namespace string, options metav1.ListOptions) (watch.Interface, error) { panic("implement me") } +// DeleteService mocks service delete. func (c *CoreV1ClientMock) DeleteService(namespace, name string) error { panic("implement me") } +// CreateService mocks service update. func (c *CoreV1ClientMock) CreateService(service *corev1.Service) (*corev1.Service, error) { panic("implement me") } +// UpdateService mocks service update. func (c *CoreV1ClientMock) UpdateService(service *corev1.Service) (*corev1.Service, error) { panic("implement me") } +// GetEndpoints returns mocked data for endpoints. func (c *CoreV1ClientMock) GetEndpoints(namespace, name string) (*corev1.Endpoints, bool, error) { if c.apiEndpointsError != nil { return nil, false, c.apiEndpointsError @@ -249,6 +264,7 @@ func (c *CoreV1ClientMock) GetEndpoints(namespace, name string) (*corev1.Endpoin return nil, false, c.apiEndpointsError } +// GetPod returns mocked data for pod. func (c *CoreV1ClientMock) GetPod(namespace, name string) (*corev1.Pod, bool, error) { if c.apiPodError != nil { return nil, false, c.apiPodError @@ -262,12 +278,13 @@ func (c *CoreV1ClientMock) GetPod(namespace, name string) (*corev1.Pod, bool, er return nil, false, c.apiPodError } +// ListPodWithOptions returns mocked data for pods. func (c *CoreV1ClientMock) ListPodWithOptions(namespace string, options metav1.ListOptions) (*corev1.PodList, error) { if c.apiPodError != nil { return nil, c.apiPodError } - items := []corev1.Pod{} + var items []corev1.Pod for _, pod := range c.pods { items = append(items, *pod) @@ -279,6 +296,7 @@ func (c *CoreV1ClientMock) ListPodWithOptions(namespace string, options metav1.L return result, nil } +// GetNamespace returns mocked data for namespace. func (c *CoreV1ClientMock) GetNamespace(name string) (*corev1.Namespace, bool, error) { if c.apiNamespaceError != nil { return nil, false, c.apiNamespaceError @@ -292,6 +310,7 @@ func (c *CoreV1ClientMock) GetNamespace(name string) (*corev1.Namespace, bool, e return nil, false, c.apiNamespaceError } +// GetNamespaces returns mocked data for namespaces. func (c *CoreV1ClientMock) GetNamespaces() ([]*corev1.Namespace, error) { if c.apiNamespaceError != nil { return nil, c.apiNamespaceError @@ -299,6 +318,7 @@ func (c *CoreV1ClientMock) GetNamespaces() ([]*corev1.Namespace, error) { return c.namespaces, nil } +// GetConfigMap returns mocked data for config map. func (c *CoreV1ClientMock) GetConfigMap(namespace, name string) (*corev1.ConfigMap, bool, error) { if c.apiConfigMapError != nil { return nil, false, c.apiConfigMapError @@ -312,30 +332,37 @@ func (c *CoreV1ClientMock) GetConfigMap(namespace, name string) (*corev1.ConfigM return nil, false, c.apiConfigMapError } +// CreateConfigMap mock config map create. func (c *CoreV1ClientMock) CreateConfigMap(configmap *corev1.ConfigMap) (*corev1.ConfigMap, error) { panic("implement me") } +// UpdateConfigMap mock config map update. func (c *CoreV1ClientMock) UpdateConfigMap(configmap *corev1.ConfigMap) (*corev1.ConfigMap, error) { panic("implement me") } +// EnableEndpointsError enables error on endpoints. func (c *CoreV1ClientMock) EnableEndpointsError() { c.apiEndpointsError = errors.New("endpoint error") } +// EnableNamespaceError enables error on namespace. func (c *CoreV1ClientMock) EnableNamespaceError() { c.apiNamespaceError = errors.New("namespace error") } +// EnableServiceError enables error on service. func (c *CoreV1ClientMock) EnableServiceError() { c.apiServiceError = errors.New("service error") } +// EnablePodError enables error on pod. func (c *CoreV1ClientMock) EnablePodError() { c.apiPodError = errors.New("pod error") } +// GetDeployment returns mocked data for deployment. func (a *AppsV1ClientMock) GetDeployment(namespace, name string) (*appsv1.Deployment, bool, error) { if a.apiDeploymentError != nil { return nil, false, a.apiDeploymentError @@ -349,10 +376,12 @@ func (a *AppsV1ClientMock) GetDeployment(namespace, name string) (*appsv1.Deploy return nil, false, a.apiDeploymentError } +// UpdateDeployment mocked deployment update. func (a *AppsV1ClientMock) UpdateDeployment(deployment *appsv1.Deployment) (*appsv1.Deployment, error) { panic("implement me") } +// GetHTTPRouteGroup returns mocked data for HTTP route group. func (s *SMIClientMock) GetHTTPRouteGroup(namespace, name string) (*specsv1alpha1.HTTPRouteGroup, bool, error) { if s.apiHTTPRouteGroupError != nil { return nil, false, s.apiHTTPRouteGroupError @@ -367,6 +396,7 @@ func (s *SMIClientMock) GetHTTPRouteGroup(namespace, name string) (*specsv1alpha return nil, false, s.apiHTTPRouteGroupError } +// GetTrafficTargets returns mocked data for traffic targets. func (s *SMIClientMock) GetTrafficTargets() ([]*accessv1alpha1.TrafficTarget, error) { if s.apiTrafficTargetError != nil { return nil, s.apiTrafficTargetError @@ -375,6 +405,7 @@ func (s *SMIClientMock) GetTrafficTargets() ([]*accessv1alpha1.TrafficTarget, er return s.trafficTargets, nil } +// GetTrafficSplits returns mocked data for traffic splits. func (s *SMIClientMock) GetTrafficSplits() ([]*splitv1alpha1.TrafficSplit, error) { if s.apiTrafficSplitError != nil { return nil, s.apiTrafficSplitError @@ -383,14 +414,17 @@ func (s *SMIClientMock) GetTrafficSplits() ([]*splitv1alpha1.TrafficSplit, error return s.trafficSplits, nil } +// EnableTrafficTargetError enables error on traffic target. func (s *SMIClientMock) EnableTrafficTargetError() { s.apiTrafficTargetError = errors.New("trafficTarget error") } +// EnableHTTPRouteGroupError enables error on http router group. func (s *SMIClientMock) EnableHTTPRouteGroupError() { s.apiHTTPRouteGroupError = errors.New("httpRouteGroup error") } +// EnableTrafficSplitError enables error on traffic split. func (s *SMIClientMock) EnableTrafficSplitError() { s.apiTrafficSplitError = errors.New("trafficSplit error") } diff --git a/internal/k8s/constants.go b/internal/k8s/constants.go index f4b6b80c2..2a5abd20b 100644 --- a/internal/k8s/constants.go +++ b/internal/k8s/constants.go @@ -5,13 +5,25 @@ import ( ) const ( - ResyncPeriod = 5 * time.Minute - baseAnnotation string = "maesh.containo.us/" - AnnotationServiceType = baseAnnotation + "traffic-type" - AnnotationRetryAttempts = baseAnnotation + "retry-attempts" - AnnotationCircuitBreakerExpression = baseAnnotation + "circuit-breaker-expression" - ServiceTypeHTTP string = "http" - ServiceTypeTCP string = "tcp" - BlockAllMiddlewareKey string = "smi-block-all-middleware" - TCPStateConfigmapName string = "tcp-state-table" + // ResyncPeriod set the resync period. + ResyncPeriod = 5 * time.Minute + baseAnnotation string = "maesh.containo.us/" + + // AnnotationServiceType service type annotation. + AnnotationServiceType = baseAnnotation + "traffic-type" + // AnnotationRetryAttempts retry attempts annotation. + AnnotationRetryAttempts = baseAnnotation + "retry-attempts" + // AnnotationCircuitBreakerExpression circuit breaker expression annotation. + AnnotationCircuitBreakerExpression = baseAnnotation + "circuit-breaker-expression" + + // ServiceTypeHTTP HTTP service type. + ServiceTypeHTTP string = "http" + // ServiceTypeTCP TCP service type. + ServiceTypeTCP string = "tcp" + + // BlockAllMiddlewareKey block all middleware name. + BlockAllMiddlewareKey string = "smi-block-all-middleware" + + // TCPStateConfigMapName TCP config map name. + TCPStateConfigMapName string = "tcp-state-table" ) diff --git a/internal/message/message.go b/internal/message/message.go index 5ec7844d2..aab53677e 100644 --- a/internal/message/message.go +++ b/internal/message/message.go @@ -10,10 +10,14 @@ import ( ) const ( + // TypeCreated created type. TypeCreated = "created" + // TypeUpdated updated type. TypeUpdated = "updated" + // TypeDeleted deleted type. TypeDeleted = "deleted" + // ConfigServiceVersionKey config service version key name. ConfigServiceVersionKey string = "maesh-config-service-version-key" ) @@ -48,6 +52,7 @@ type Config struct { Config *dynamic.Configuration } +// BuildNewConfigWithVersion builds new config with version. func BuildNewConfigWithVersion(conf *dynamic.Configuration) Config { t := time.Now().UnixNano() c := conf.DeepCopy() diff --git a/internal/providers/smi/provider.go b/internal/providers/smi/provider.go index 59ee13b4f..ab8e9e438 100644 --- a/internal/providers/smi/provider.go +++ b/internal/providers/smi/provider.go @@ -212,7 +212,7 @@ func (p *Provider) buildServiceIntoConfig(service *corev1.Service, endpoints *co } } -func Int(v int64) *int { +func intToP(v int64) *int { i := int(v) return &i } @@ -498,7 +498,7 @@ func (p *Provider) buildTrafficSplit(config *dynamic.Configuration, trafficSplit config.HTTP.Services[splitKey] = p.buildServiceFromTrafficTarget(endpoints, trafficTarget) WRRServices = append(WRRServices, dynamic.WRRService{ Name: splitKey, - Weight: Int(backend.Weight.Value()), + Weight: intToP(backend.Weight.Value()), }) }