From 556f7820490e001976cd5d514a0ca9f44c57523e Mon Sep 17 00:00:00 2001 From: Bence Csati Date: Tue, 3 Sep 2024 15:26:07 +0200 Subject: [PATCH] chore: tidy codebase Signed-off-by: Bence Csati --- .github/workflows/artifacts.yaml | 2 -- .github/workflows/ci.yaml | 2 +- Makefile | 20 ++++++++++--------- README.md | 8 -------- .../kube-pod-autocomplete-deployment.yaml | 3 ++- .../kube-pod-autocomplete-service.yaml | 3 +-- .../charts/kube-pod-autocomplete/values.yaml | 3 +-- docs/docs.md | 4 +++- e2e/deploy/kube-pod-autocomplete/values.yaml | 3 +-- e2e/kpa_test.go | 11 ++++------ internal/handlers/autocomplete.go | 4 +--- .../services/autocomplete/autocomplete.go | 9 ++------- .../services/autocomplete/filter/filter.go | 1 - .../autocomplete/filter/filteroptions.go | 4 ++-- .../autocomplete/model/autocompleterequest.go | 2 +- .../services/autocomplete/model/extractor.go | 5 +---- pkg/http/http.go | 2 +- 17 files changed, 32 insertions(+), 54 deletions(-) diff --git a/.github/workflows/artifacts.yaml b/.github/workflows/artifacts.yaml index 3cf2b93..3811f77 100644 --- a/.github/workflows/artifacts.yaml +++ b/.github/workflows/artifacts.yaml @@ -63,7 +63,6 @@ jobs: outputs: type=docker,dest=image.tar - name: Build and push Docker image - id: build uses: docker/build-push-action@v6 if: ${{ inputs.publish == true }} with: @@ -96,7 +95,6 @@ jobs: run: make lint-helm - name: Helm package - id: build run: make helm-chart - name: Upload Helm chart artifact diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 05be09f..657169a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -71,7 +71,7 @@ jobs: needs: artifacts strategy: matrix: - KIND_K8S_VERSION: ["v1.28.9", "v1.29.4", "v1.30.0"] + KIND_K8S_VERSION: ["v1.29.0", "v1.30.0", "v1.31.0"] steps: - name: Checkout repository diff --git a/Makefile b/Makefile index a0e1610..449d082 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ export PATH := $(abspath bin/):${PATH} -CONTAINER_IMAGE_REF = ghcr.io/csatib02/kube-pod-autocomplete:dev +PROJECT_NAME = kube-pod-autocomplete +CONTAINER_IMAGE_REF = ghcr.io/csatib02/${PROJECT_NAME}:dev ##@ General @@ -16,16 +17,17 @@ help: ## Display this help .PHONY: up up: ## Start development environment - ${KIND_BIN} create cluster --name kube-pod-autocomplete + ${KIND_BIN} create cluster --name ${PROJECT_NAME} .PHONY: down down: ## Stop development environment - ${KIND_BIN} delete cluster --name kube-pod-autocomplete + ${KIND_BIN} delete cluster --name ${PROJECT_NAME} .PHONY: deploy -deploy: ## Deploy kube-pod-autocomplete to the development environment - kubectl create ns kube-pod-autocomplete - ${HELM_BIN} upgrade --install kube-pod-autocomplete deploy/charts/kube-pod-autocomplete --namespace kube-pod-autocomplete +deploy: container-image ## Deploy kube-pod-autocomplete to the development environment + kind load docker-image ${CONTAINER_IMAGE_REF} --name ${PROJECT_NAME} + kubectl create ns ${PROJECT_NAME} + ${HELM_BIN} upgrade --install ${PROJECT_NAME} deploy/charts/${PROJECT_NAME} --namespace ${PROJECT_NAME} --set image.tag=dev .PHONY: deploy-testdata deploy-testdata: ## Deploy testdata to the development environment @@ -38,7 +40,7 @@ deploy-testdata: ## Deploy testdata to the development environment .PHONY: build build: ## Build binary @mkdir -p build - go build -race -o build/kube-pod-autocomplete . + go build -race -o build/${PROJECT_NAME} . .PHONY: artifacts artifacts: container-image helm-chart @@ -51,7 +53,7 @@ container-image: ## Build container image .PHONY: helm-chart helm-chart: ## Build Helm chart @mkdir -p build - $(HELM_BIN) package -d build/ deploy/charts/kube-pod-autocomplete + $(HELM_BIN) package -d build/ deploy/charts/${PROJECT_NAME} ##@ Checks @@ -79,7 +81,7 @@ lint-go: .PHONY: lint-helm lint-helm: - $(HELM_BIN) lint deploy/charts/kube-pod-autocomplete + $(HELM_BIN) lint deploy/charts/${PROJECT_NAME} .PHONY: fmt fmt: ## Format code diff --git a/README.md b/README.md index a284bb1..35bec5d 100644 --- a/README.md +++ b/README.md @@ -7,16 +7,8 @@ - Kube Pod Autocomplete is designed to be used in Kubernetes environment. - Take a look at the [documentation](./docs/docs.md). -## TODO - -- Consider adding garden config to simplify testing. - -- Add search pods by label/ns/phase endpoint as a possible use-case. - ## Development -Make sure Docker is installed. - Fetch required tools: ```shell diff --git a/deploy/charts/kube-pod-autocomplete/templates/kube-pod-autocomplete-deployment.yaml b/deploy/charts/kube-pod-autocomplete/templates/kube-pod-autocomplete-deployment.yaml index 2c408d2..644c97e 100644 --- a/deploy/charts/kube-pod-autocomplete/templates/kube-pod-autocomplete-deployment.yaml +++ b/deploy/charts/kube-pod-autocomplete/templates/kube-pod-autocomplete-deployment.yaml @@ -19,8 +19,9 @@ spec: containers: - name: {{ .Values.name }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - - containerPort: {{ .Values.containerPort }} + - containerPort: {{ .Values.service.containerPort }} resources: limits: cpu: {{ .Values.resources.limits.cpu }} diff --git a/deploy/charts/kube-pod-autocomplete/templates/kube-pod-autocomplete-service.yaml b/deploy/charts/kube-pod-autocomplete/templates/kube-pod-autocomplete-service.yaml index eb34402..be7a8b6 100644 --- a/deploy/charts/kube-pod-autocomplete/templates/kube-pod-autocomplete-service.yaml +++ b/deploy/charts/kube-pod-autocomplete/templates/kube-pod-autocomplete-service.yaml @@ -10,5 +10,4 @@ spec: ports: - protocol: TCP port: {{ .Values.service.servicePort }} - targetPort: {{ .Values.containerPort }} - externalPort: {{ .Values.service.externalPort }} + targetPort: {{ .Values.service.containerPort }} diff --git a/deploy/charts/kube-pod-autocomplete/values.yaml b/deploy/charts/kube-pod-autocomplete/values.yaml index 20e2986..c270c31 100644 --- a/deploy/charts/kube-pod-autocomplete/values.yaml +++ b/deploy/charts/kube-pod-autocomplete/values.yaml @@ -4,7 +4,6 @@ namespace: kube-pod-autocomplete # General settings for the application name: kube-pod-autocomplete replicas: 1 -containerPort: 8080 # image image: @@ -17,7 +16,7 @@ service: name: kube-pod-autocomplete-service type: ClusterIP servicePort: 8080 - externalPort: 8080 + containerPort: 8080 # Service Account settings serviceAccount: diff --git a/docs/docs.md b/docs/docs.md index 669b00d..13ac611 100644 --- a/docs/docs.md +++ b/docs/docs.md @@ -36,7 +36,7 @@ make deploy-testdata Port-forward to Kube Pod Autocomplete: ```shell -kubectl port-forward -n kube-pod-autocomplete $(kubectl get pods -n kube-pod-autocomplete -o jsonpath='{.items[0].metadata.name}') 8080:8080 1>/dev/null & +kubectl port-forward -n kube-pod-autocomplete "svc/$(kubectl get svc -n kube-pod-autocomplete -o jsonpath='{.items[0].metadata.name}')" 8080:8080 1>/dev/null & ``` Hit the endpoint: @@ -50,3 +50,5 @@ curl -X GET http://localhost:8080/search/autocomplete/pods - [ ] Add support for `caching`. (While the current implementation is fast with a small number of pods, but there can be problems in production environments.) - [ ] `Generate` API specification from `OpenAPI spec`. (The current solution is a really simple POC, if the project is later expanded with additional endpoints code generation from the OpenAPI spec should be utilised.) - [ ] `Improve End-to-End` Tests: (The existing end-to-end test setup is quite basic, using `cmd.Exec()` and port-forward to access the service is rather limited. Future improvements could include using an ingress controller like NGINX for more robust testing.) +- [ ] Add endpoints that can be called with the received suggestions. (E.g.: `search/:resource/:filters` or get the filters from the body.) +- [ ] Enable deploying with [Garden](https://garden.io/). (Garden helps a lot when it comes to manually testing a project, as new features are added, this should also be implemented.) diff --git a/e2e/deploy/kube-pod-autocomplete/values.yaml b/e2e/deploy/kube-pod-autocomplete/values.yaml index cc91e69..beb8109 100644 --- a/e2e/deploy/kube-pod-autocomplete/values.yaml +++ b/e2e/deploy/kube-pod-autocomplete/values.yaml @@ -2,13 +2,12 @@ namespace: kube-pod-autocomplete name: kube-pod-autocomplete replicas: 1 -containerPort: 8080 service: name: kube-pod-autocomplete-service type: ClusterIP servicePort: 8080 - externalPort: 8080 + containerPort: 8080 serviceAccount: name: kube-pod-autocomplete-sa diff --git a/e2e/kpa_test.go b/e2e/kpa_test.go index 7f2a990..b26d6cd 100644 --- a/e2e/kpa_test.go +++ b/e2e/kpa_test.go @@ -31,9 +31,9 @@ const ( func TestKPAEndpoints(t *testing.T) { endpoints := applyResource(features.New("validate endpoint functionality")). Assess("pods are available", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { - // check if test pods are running + // Check if test pods are running err := wait.PollUntilContextTimeout(ctx, pollInterval, defaultTimeout, true, func(ctx context.Context) (bool, error) { - // get all pods with label: team=test + // Get all pods with label: team=test pods := &corev1.PodList{} err := cfg.Client().Resources().List(ctx, pods, func(opts *metav1.ListOptions) { opts.LabelSelector = labels.Set{"team": "test"}.String() @@ -53,18 +53,15 @@ func TestKPAEndpoints(t *testing.T) { return ctx }).Assess("check KPA response", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { - // start port forwarding killProcess := startPortForwardingToService(t, "kube-pod-autocomplete-service", "kube-pod-autocomplete", "8080:8080") defer killProcess() - // hit the /health endpoint resp, err := http.Get(fmt.Sprintf(healthURL, "localhost", 8080)) require.NoError(t, err) defer resp.Body.Close() require.Equal(t, http.StatusOK, resp.StatusCode) - // hit the /search/autocomplete/pods endpoint autocompleteUrl := fmt.Sprintf(autocompleteURL, "localhost", 8080, "pods") resp, err = http.Get(autocompleteUrl) require.NoError(t, err) @@ -72,7 +69,7 @@ func TestKPAEndpoints(t *testing.T) { require.Equal(t, http.StatusOK, resp.StatusCode) - // check if the response body contains the expected filters + // Check if the response body contains the expected filters body, err := io.ReadAll(resp.Body) require.NoError(t, err) @@ -112,7 +109,7 @@ func applyResource(builder *features.FeatureBuilder) *features.FeatureBuilder { func startPortForwardingToService(t *testing.T, svcName, ns, portMapping string) func() { args := []string{"port-forward", fmt.Sprintf("svc/%s", svcName), portMapping, "-n", ns} cmd := exec.Command("kubectl", args...) - cmd.Stderr = os.Stderr // redirect stderr to test output + cmd.Stderr = os.Stderr // Redirect stderr to test output err := cmd.Start() require.NoError(t, err) diff --git a/internal/handlers/autocomplete.go b/internal/handlers/autocomplete.go index 3d6eb2c..a213081 100644 --- a/internal/handlers/autocomplete.go +++ b/internal/handlers/autocomplete.go @@ -70,7 +70,6 @@ func AutocompleteHandler(c *gin.Context) { return } - // Pretty-print the JSON response prettyJSON, err := json.MarshalIndent(suggestions, "", " ") if err != nil { // Log the error and return the response as is @@ -79,10 +78,9 @@ func AutocompleteHandler(c *gin.Context) { return } - c.Data(http.StatusOK, "application/json", prettyJSON) + c.Data(http.StatusOK, gin.MIMEJSON, prettyJSON) } -// validateRequestedFilters validates the requestedFilters parameter func validateRequestedFilters(requestedFilters []string) ([]string, error) { validFilters := make([]string, 0, len(requestedFilters)) for _, filter := range requestedFilters { diff --git a/internal/services/autocomplete/autocomplete.go b/internal/services/autocomplete/autocomplete.go index cb75a67..d31980e 100644 --- a/internal/services/autocomplete/autocomplete.go +++ b/internal/services/autocomplete/autocomplete.go @@ -28,11 +28,6 @@ func NewAutoCompleteService() (*Service, error) { // GetAutocompleteSuggestions returns a list of suggestions (for the given query) func (s *Service) GetAutocompleteSuggestions(ctx context.Context, req model.AutoCompleteRequest) (*model.AutocompleteSuggestions, error) { - // if no ResourceType is provided, default to Pod - if req.ResourceType == "" { - req.ResourceType = common.PodResourceType - } - filters, err := filter.NewFieldFilters(req.ResourceType, &req.Filters) if err != nil { return nil, fmt.Errorf("failed to get field filters: %w", err) @@ -46,7 +41,7 @@ func (s *Service) GetAutocompleteSuggestions(ctx context.Context, req model.Auto return s.extractSuggestions(resources, filters) } -// extractSuggestions extracts suggestions from the given pods based on the requested filters +// extractSuggestions extracts suggestions from the given resources based on the requested filters func (s *Service) extractSuggestions(resources common.Resources, filters *map[string]model.FieldFilter) (*model.AutocompleteSuggestions, error) { suggestions := make([]model.Suggestion, 0, len(*filters)) for fieldName, fieldFilter := range *filters { @@ -76,7 +71,7 @@ func (s *Service) extractSuggestions(resources common.Resources, filters *map[st } } - // These should be filter options on the UI + // These should be options on the UI filterOptions := filter.Options{} filterOptions.RemoveDuplicateValues(&suggestions) diff --git a/internal/services/autocomplete/filter/filter.go b/internal/services/autocomplete/filter/filter.go index 3813a43..e51aa13 100644 --- a/internal/services/autocomplete/filter/filter.go +++ b/internal/services/autocomplete/filter/filter.go @@ -13,7 +13,6 @@ func NewFieldFilters(resourceType common.ResourceType, requestedFilters *[]strin switch resourceType { case common.PodResourceType: return podfilter.GetFilters(requestedFilters), nil - // Add cases for other resource types here default: return nil, errors.New("unsupported resource type") } diff --git a/internal/services/autocomplete/filter/filteroptions.go b/internal/services/autocomplete/filter/filteroptions.go index 7200bbd..1f846e6 100644 --- a/internal/services/autocomplete/filter/filteroptions.go +++ b/internal/services/autocomplete/filter/filteroptions.go @@ -6,7 +6,7 @@ import ( "github.com/csatib02/kube-pod-autocomplete/internal/services/autocomplete/model" ) -// FilterOptions defines additional options for filtering suggestions +// Options defines additional options for filtering suggestions type Options struct{} var ignoredKeys = map[string][]string{ @@ -33,7 +33,7 @@ func (o *Options) RemoveDuplicateValues(suggestions *[]model.Suggestion) { } // RemoveIgnoredKeys removes the ignored keys from the suggestions -// NOTE: IgnoreKeys should be retrieved from request parameters +// NOTE: ignoredKeys should be retrieved from request parameters func (o *Options) RemoveIgnoredKeys(suggestions *[]model.Suggestion) { filteredSuggestions := make([]model.Suggestion, 0, len(*suggestions)) for _, suggestion := range *suggestions { diff --git a/internal/services/autocomplete/model/autocompleterequest.go b/internal/services/autocomplete/model/autocompleterequest.go index e638bf3..ecf7756 100644 --- a/internal/services/autocomplete/model/autocompleterequest.go +++ b/internal/services/autocomplete/model/autocompleterequest.go @@ -5,5 +5,5 @@ import "github.com/csatib02/kube-pod-autocomplete/pkg/common" type AutoCompleteRequest struct { ResourceType common.ResourceType `json:"resourceType"` Filters []string `json:"filters"` - Query string `json:"query"` // Currently not used + Query string `json:"query"` // Currently unused } diff --git a/internal/services/autocomplete/model/extractor.go b/internal/services/autocomplete/model/extractor.go index 5121bf2..593e49e 100644 --- a/internal/services/autocomplete/model/extractor.go +++ b/internal/services/autocomplete/model/extractor.go @@ -2,10 +2,7 @@ package model import "github.com/csatib02/kube-pod-autocomplete/pkg/common" -// FieldExtractor interface defines the method for extracting field values from a PodList -// NOTE: There is no actual difference between ListExtractor and MapExtractor, -// since when processing the extracted data, we can always check the type of the underlying data structure -// via FieldFilter.Type, but for the sake of clarity, I have defined two separate types. +// FieldExtractor interface defines the method for extracting field values from resources type FieldExtractor interface { Extract(common.Resources) any } diff --git a/pkg/http/http.go b/pkg/http/http.go index 4e820d8..901eb36 100644 --- a/pkg/http/http.go +++ b/pkg/http/http.go @@ -11,7 +11,7 @@ func (e *Error) Error() string { return e.Message } -// HandleHTTPError is a utility function to handle HTTP errors in Gin handlers. +// HandleHTTPError is a utility function to handle HTTP errors in Gin handlers func HandleHTTPError(c *gin.Context, code int, err error) { httpErr := &Error{ Code: code,