From 84c9c2ecab3cd2e6421a7c4e051a557e3d7d5f9c Mon Sep 17 00:00:00 2001 From: Andrew Minkin Date: Fri, 13 Oct 2023 15:53:46 +0600 Subject: [PATCH 01/13] EVEREST-549 Created make targets for the release --- .dockerignore | 1 + .github/workflows/build.yml | 3 ++ .github/workflows/release.yml | 19 ++++++----- Dockerfile | 18 +---------- Makefile | 17 ++++++++-- pkg/version/version.go | 61 +++++++++++++++++++++++++++++++++++ pkg/version/version_test.go | 16 +++++++++ 7 files changed, 108 insertions(+), 27 deletions(-) create mode 100644 pkg/version/version.go create mode 100644 pkg/version/version_test.go diff --git a/.dockerignore b/.dockerignore index 6adc39f3..4841b204 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,5 @@ ** +!bin/percona-everest-backend !cmd !migrations !model diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5f2a6844..38ec5e8a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -65,6 +65,9 @@ jobs: cp -rf ${GITHUB_WORKSPACE}/front/* ${GITHUB_WORKSPACE}/backend/public/dist/ cd ${GITHUB_WORKSPACE}/backend + - name: Build Everest + run: GOOS=linux GOARCH=amd64 make build + - name: Set tag from inputs run: echo "IMAGE_TAG=${{ github.event.inputs.tag }}" >> $GITHUB_ENV if: ${{ github.event.inputs.tag != '' }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c539649e..3ea55b99 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: run: | echo $RC_BRANCH if [[ ! $TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "Wrong tag format provided, please use v*.*.* format" + echo "Wrong tag format provided, please use v*.*.* format" exit 1 fi - name: Define release branch name in the format "release-*.*.*" @@ -31,7 +31,7 @@ jobs: run: git config --global url."https://percona-platform-robot:${ROBOT_TOKEN}@github.com".insteadOf "https://github.com" - name: Configure git userdata for commits - run: | + run: | git config --global user.email "everest-ci@percona.com" git config --global user.name "Everest RC CI triggered by ${{ github.actor }}" @@ -46,9 +46,9 @@ jobs: - name: Everest Frontend - create tag run: | cd percona-everest-frontend - git tag $TAG + git tag -a $TAG -m "Release ${TAG}" git push origin $TAG - + - name: Everest Frontend - run with Node 16 uses: actions/setup-node@v3 with: @@ -86,14 +86,14 @@ jobs: - name: Everest Backend - create tag run: | cd backend - + # update image names in scripts. since the branch is created based on the RC-branch, # the perconalab/everest:vX.Y.Z image reference is already present in the scripts sed -i "s/perconalab\/everest/percona\/percona-everest/g" deploy/quickstart-compose.yml deploy/quickstart-k8s.yaml echo "$(git diff deploy/quickstart-compose.yml deploy/quickstart-k8s.yaml)" git commit -a -m "update scripts" - - git tag $TAG + + git tag $TAG git push origin $TAG - name: Everest Backend - Embed Everest Frontend app into backend @@ -101,12 +101,15 @@ jobs: cp -rf ${GITHUB_WORKSPACE}/front/* ${GITHUB_WORKSPACE}/backend/public/dist/ cd ${GITHUB_WORKSPACE}/backend + - name: Build Everest release + run: GOOS=linux GOARCH=amd64 make release + - name: Everest - Setup docker build metadata uses: docker/metadata-action@v5 id: meta with: images: percona/percona-everest - tags: | + tags: | ${{ env.TAG }} latest diff --git a/Dockerfile b/Dockerfile index 1f518fab..36298b0b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,29 +4,13 @@ WORKDIR /everest COPY . . -ARG IS_RELEASE - -ARG TELEMETRY_URL="https://check.percona.com" -ARG TELEMETRY_INTERVAL="24h" - -RUN if [[ $IS_RELEASE = 1 ]]; then \ - # for the release builds set up the production telemetry parameters - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v -ldflags "\ - -X 'github.com/percona/percona-everest-backend/cmd/config.TelemetryURL=$TELEMETRY_URL' \ - -X 'github.com/percona/percona-everest-backend/cmd/config.TelemetryInterval=$TELEMETRY_INTERVAL'" \ - -o /everest-api cmd/main.go; \ - else \ - # for all the other builds no telemetry parameters are provided by default - CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /everest-api cmd/main.go; \ -fi - RUN apk add -U --no-cache ca-certificates FROM scratch WORKDIR / -COPY --from=build /everest-api /everest-api +COPY ./bin/percona-everest-backend /everest-api COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ COPY migrations /migrations diff --git a/Makefile b/Makefile index 1f8f40d3..d0306c55 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,13 @@ FILES = $(shell find . -type f -name '*.go') +RELEASE_VERSION ?= $(shell git describe --always --tags --dirty | cut -b2-) +RELEASE_FULLCOMMIT ?= $(shell git rev-parse HEAD) +FLAGS = -X 'github.com/percona/percona-everest-backend/pkg/version.ProjectName=everestctl' \ + -X 'github.com/percona/percona-everest-backend/pkg/version.Version=$(RELEASE_VERSION)' \ + -X 'github.com/percona/percona-everest-backend/pkg/version.FullCommit=$(RELEASE_FULLCOMMIT)' \ + +LD_FLAGS = -ldflags " \ $(FLAGS) " + default: help help: ## Display this help message @@ -11,10 +19,15 @@ init: ## Install development tools cd tools && go generate -x -tags=tools build: ## Build binaries - go build -race -o bin/percona-everest-backend ./cmd + go build $(LD_FLAGS) -o bin/percona-everest-backend ./cmd + +release: FLAGS += -X 'github.com/percona/percona-everest-backend/cmd/config.TelemetryURL=https://check.percona.com/'\ -X 'github.com/percona/percona-everest-backend/cmd/config.TelemetryInterval=24h' + +release: build + build-debug: ## Build binaries - go build -tags debug -race -o bin/percona-everest-backend-debug ./cmd + go build -tags debug $(LD_FLAGS) -race -o bin/percona-everest-backend-debug ./cmd gen: ## Generate code go generate ./... diff --git a/pkg/version/version.go b/pkg/version/version.go new file mode 100644 index 00000000..ee41bdbc --- /dev/null +++ b/pkg/version/version.go @@ -0,0 +1,61 @@ +// percona-everest-cli +// Copyright (C) 2023 Percona LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Package install holds the main logic for installation commands. + +// Package version implements version reporting command to the end user. +package version + +import ( + "fmt" + "strings" +) + +const ( + devCatalogImage = "docker.io/percona/everest-catalog:latest" + releaseCatalogImage = "docker.io/percona/everest-catalog:%s" +) + +var ( + // ProjectName is a component name, e.g. everestctl. + ProjectName string //nolint:gochecknoglobals + // Version is a component version e.g. v0.3.0-1-a93bef. + Version string //nolint:gochecknoglobals + // FullCommit is a git commit hash. + FullCommit string //nolint:gochecknoglobals + // CatalogImage is a image path for OLM catalog. + catalogImage string //nolint:gochecknoglobals +) + +// CatalogImage returns a catalog image needed for the build of everestctl +// +// for dev builds it returns everest-catalog:latest +// for the release it returns everest-catalog:X.Y.Z. +func CatalogImage() string { + catalogImage = fmt.Sprintf(releaseCatalogImage, Version) + if strings.Contains(Version, "dirty") { + catalogImage = devCatalogImage + } + return catalogImage +} + +// FullVersionInfo returns full version report. +func FullVersionInfo() string { + out := []string{ + "ProjectName: " + ProjectName, + "Version: " + Version, + "FullCommit: " + FullCommit, + } + return strings.Join(out, "\n") +} diff --git a/pkg/version/version_test.go b/pkg/version/version_test.go new file mode 100644 index 00000000..4b66d3df --- /dev/null +++ b/pkg/version/version_test.go @@ -0,0 +1,16 @@ +package version + +import ( + "fmt" + "testing" + + "gotest.tools/assert" +) + +func TestCatalogImage(t *testing.T) { + t.Parallel() + Version = "v0.3.0" + assert.Equal(t, CatalogImage(), fmt.Sprintf(releaseCatalogImage, Version)) + Version = "v0.3.0-1-asd-dirty" + assert.Equal(t, CatalogImage(), devCatalogImage) +} From 9972b002eb11e4e74b49e6c9386d88d68a1ef542 Mon Sep 17 00:00:00 2001 From: Andrew Minkin Date: Fri, 13 Oct 2023 18:57:45 +0600 Subject: [PATCH 02/13] EVEREST-489 Added version endpoint --- Makefile | 7 +- api/everest-server.gen.go | 276 ++++++++++++++------------ api/version.go | 17 ++ client/everest-client.gen.go | 364 +++++++++++++++++++++++------------ docs/spec/openapi.yml | 29 +++ pkg/version/version.go | 36 +--- pkg/version/version_test.go | 16 -- 7 files changed, 437 insertions(+), 308 deletions(-) create mode 100644 api/version.go delete mode 100644 pkg/version/version_test.go diff --git a/Makefile b/Makefile index d0306c55..3c53d861 100644 --- a/Makefile +++ b/Makefile @@ -2,11 +2,12 @@ FILES = $(shell find . -type f -name '*.go') RELEASE_VERSION ?= $(shell git describe --always --tags --dirty | cut -b2-) RELEASE_FULLCOMMIT ?= $(shell git rev-parse HEAD) + FLAGS = -X 'github.com/percona/percona-everest-backend/pkg/version.ProjectName=everestctl' \ -X 'github.com/percona/percona-everest-backend/pkg/version.Version=$(RELEASE_VERSION)' \ -X 'github.com/percona/percona-everest-backend/pkg/version.FullCommit=$(RELEASE_FULLCOMMIT)' \ -LD_FLAGS = -ldflags " \ $(FLAGS) " +LD_FLAGS = -ldflags " $(FLAGS) " default: help @@ -19,7 +20,7 @@ init: ## Install development tools cd tools && go generate -x -tags=tools build: ## Build binaries - go build $(LD_FLAGS) -o bin/percona-everest-backend ./cmd + go build -v $(LD_FLAGS) -o bin/percona-everest-backend ./cmd release: FLAGS += -X 'github.com/percona/percona-everest-backend/cmd/config.TelemetryURL=https://check.percona.com/'\ -X 'github.com/percona/percona-everest-backend/cmd/config.TelemetryInterval=24h' @@ -27,7 +28,7 @@ release: build build-debug: ## Build binaries - go build -tags debug $(LD_FLAGS) -race -o bin/percona-everest-backend-debug ./cmd + go build -tags debug -v $(LD_FLAGS) -race -o bin/percona-everest-backend-debug ./cmd gen: ## Generate code go generate ./... diff --git a/api/everest-server.gen.go b/api/everest-server.gen.go index f2b77bbe..4c9cd475 100644 --- a/api/everest-server.gen.go +++ b/api/everest-server.gen.go @@ -667,6 +667,13 @@ type UpdateBackupStorageParams struct { Url *string `json:"url,omitempty"` } +// Version Everest version info +type Version struct { + FullCommit string `json:"fullCommit"` + ProjectName string `json:"projectName"` + Version string `json:"version"` +} + // IoK8sApimachineryPkgApisMetaV1ListMeta ListMeta describes metadata that synthetic resources must have, including lists and various status objects. A resource may have only one of {ObjectMeta, ListMeta}. type IoK8sApimachineryPkgApisMetaV1ListMeta struct { // Continue continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a consistent list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response, unless you have received this token from an error message. @@ -1328,6 +1335,9 @@ type ServerInterface interface { // Update the specified Monitoring instance // (PATCH /monitoring-instances/{name}) UpdateMonitoringInstance(ctx echo.Context, name string) error + // Get Everest Backend version info + // (GET /version) + VersionInfo(ctx echo.Context) error } // ServerInterfaceWrapper converts echo contexts to parameters. @@ -1957,6 +1967,15 @@ func (w *ServerInterfaceWrapper) UpdateMonitoringInstance(ctx echo.Context) erro return err } +// VersionInfo converts echo context to params. +func (w *ServerInterfaceWrapper) VersionInfo(ctx echo.Context) error { + var err error + + // Invoke the callback with all the unmarshaled arguments + err = w.Handler.VersionInfo(ctx) + return err +} + // This is a simple interface which specifies echo.Route addition functions which // are present on both echo.Echo and echo.Group, since we want to allow using // either of them for path registration @@ -2019,138 +2038,141 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL router.DELETE(baseURL+"/monitoring-instances/:name", wrapper.DeleteMonitoringInstance) router.GET(baseURL+"/monitoring-instances/:name", wrapper.GetMonitoringInstance) router.PATCH(baseURL+"/monitoring-instances/:name", wrapper.UpdateMonitoringInstance) + router.GET(baseURL+"/version", wrapper.VersionInfo) } // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ "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", + "vn589/F/AwAA//8j+L4atAcBAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/api/version.go b/api/version.go new file mode 100644 index 00000000..f4782233 --- /dev/null +++ b/api/version.go @@ -0,0 +1,17 @@ +package api + +import ( + "net/http" + + "github.com/labstack/echo/v4" + + "github.com/percona/percona-everest-backend/pkg/version" +) + +func (e *EverestServer) VersionInfo(ctx echo.Context) error { + return ctx.JSON(http.StatusOK, &Version{ + ProjectName: "Everest Backend", + Version: version.Version, + FullCommit: version.FullCommit, + }) +} diff --git a/client/everest-client.gen.go b/client/everest-client.gen.go index 0daca389..d981d378 100644 --- a/client/everest-client.gen.go +++ b/client/everest-client.gen.go @@ -668,6 +668,13 @@ type UpdateBackupStorageParams struct { Url *string `json:"url,omitempty"` } +// Version Everest version info +type Version struct { + FullCommit string `json:"fullCommit"` + ProjectName string `json:"projectName"` + Version string `json:"version"` +} + // IoK8sApimachineryPkgApisMetaV1ListMeta ListMeta describes metadata that synthetic resources must have, including lists and various status objects. A resource may have only one of {ObjectMeta, ListMeta}. type IoK8sApimachineryPkgApisMetaV1ListMeta struct { // Continue continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a consistent list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response, unless you have received this token from an error message. @@ -1425,6 +1432,9 @@ type ClientInterface interface { UpdateMonitoringInstanceWithBody(ctx context.Context, name string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) UpdateMonitoringInstance(ctx context.Context, name string, body UpdateMonitoringInstanceJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + + // VersionInfo request + VersionInfo(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) } func (c *Client) ListBackupStorages(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { @@ -2003,6 +2013,18 @@ func (c *Client) UpdateMonitoringInstance(ctx context.Context, name string, body return c.Client.Do(req) } +func (c *Client) VersionInfo(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewVersionInfoRequest(c.Server) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + // NewListBackupStoragesRequest generates requests for ListBackupStorages func NewListBackupStoragesRequest(server string) (*http.Request, error) { var err error @@ -3411,6 +3433,33 @@ func NewUpdateMonitoringInstanceRequestWithBody(server string, name string, cont return req, nil } +// NewVersionInfoRequest generates requests for VersionInfo +func NewVersionInfoRequest(server string) (*http.Request, error) { + var err error + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/version") + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error { for _, r := range c.RequestEditors { if err := r(ctx, req); err != nil { @@ -3584,6 +3633,9 @@ type ClientWithResponsesInterface interface { UpdateMonitoringInstanceWithBodyWithResponse(ctx context.Context, name string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*UpdateMonitoringInstanceResponse, error) UpdateMonitoringInstanceWithResponse(ctx context.Context, name string, body UpdateMonitoringInstanceJSONRequestBody, reqEditors ...RequestEditorFn) (*UpdateMonitoringInstanceResponse, error) + + // VersionInfoWithResponse request + VersionInfoWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*VersionInfoResponse, error) } type ListBackupStoragesResponse struct { @@ -4432,6 +4484,28 @@ func (r UpdateMonitoringInstanceResponse) StatusCode() int { return 0 } +type VersionInfoResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *Version +} + +// Status returns HTTPResponse.Status +func (r VersionInfoResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r VersionInfoResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + // ListBackupStoragesWithResponse request returning *ListBackupStoragesResponse func (c *ClientWithResponses) ListBackupStoragesWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListBackupStoragesResponse, error) { rsp, err := c.ListBackupStorages(ctx, reqEditors...) @@ -4851,6 +4925,15 @@ func (c *ClientWithResponses) UpdateMonitoringInstanceWithResponse(ctx context.C return ParseUpdateMonitoringInstanceResponse(rsp) } +// VersionInfoWithResponse request returning *VersionInfoResponse +func (c *ClientWithResponses) VersionInfoWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*VersionInfoResponse, error) { + rsp, err := c.VersionInfo(ctx, reqEditors...) + if err != nil { + return nil, err + } + return ParseVersionInfoResponse(rsp) +} + // ParseListBackupStoragesResponse parses an HTTP response from a ListBackupStoragesWithResponse call func ParseListBackupStoragesResponse(rsp *http.Response) (*ListBackupStoragesResponse, error) { bodyBytes, err := io.ReadAll(rsp.Body) @@ -6293,136 +6376,163 @@ func ParseUpdateMonitoringInstanceResponse(rsp *http.Response) (*UpdateMonitorin return response, nil } +// ParseVersionInfoResponse parses an HTTP response from a VersionInfoWithResponse call +func ParseVersionInfoResponse(rsp *http.Response) (*VersionInfoResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &VersionInfoResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest Version + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + } + + return response, nil +} + // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ "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", + "vn589/F/AwAA//8j+L4atAcBAA==", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/docs/spec/openapi.yml b/docs/spec/openapi.yml index b0a4b93f..930e60ea 100644 --- a/docs/spec/openapi.yml +++ b/docs/spec/openapi.yml @@ -19,6 +19,18 @@ tags: description: Everything related to the Backup storage paths: + '/version': + get: + summary: Get Everest Backend version info + description: Get Everest Backend version info + operationId: versionInfo + responses: + '200': + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Version' '/kubernetes': post: tags: @@ -1618,6 +1630,23 @@ components: required: - clusterType - storageClassNames + Version: + type: object + description: Everest version info + properties: + projectName: + type: string + x-go-type-skip-optional-pointer: true + version: + type: string + x-go-type-skip-optional-pointer: true + fullCommit: + type: string + x-go-type-skip-optional-pointer: true + required: + - projectName + - version + - fullCommit KubernetesClusterList: type: array items: diff --git a/pkg/version/version.go b/pkg/version/version.go index ee41bdbc..85e71b90 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -17,45 +17,11 @@ // Package version implements version reporting command to the end user. package version -import ( - "fmt" - "strings" -) - -const ( - devCatalogImage = "docker.io/percona/everest-catalog:latest" - releaseCatalogImage = "docker.io/percona/everest-catalog:%s" -) - var ( - // ProjectName is a component name, e.g. everestctl. + // ProjectName is a component name, e.g. everest backend. ProjectName string //nolint:gochecknoglobals // Version is a component version e.g. v0.3.0-1-a93bef. Version string //nolint:gochecknoglobals // FullCommit is a git commit hash. FullCommit string //nolint:gochecknoglobals - // CatalogImage is a image path for OLM catalog. - catalogImage string //nolint:gochecknoglobals ) - -// CatalogImage returns a catalog image needed for the build of everestctl -// -// for dev builds it returns everest-catalog:latest -// for the release it returns everest-catalog:X.Y.Z. -func CatalogImage() string { - catalogImage = fmt.Sprintf(releaseCatalogImage, Version) - if strings.Contains(Version, "dirty") { - catalogImage = devCatalogImage - } - return catalogImage -} - -// FullVersionInfo returns full version report. -func FullVersionInfo() string { - out := []string{ - "ProjectName: " + ProjectName, - "Version: " + Version, - "FullCommit: " + FullCommit, - } - return strings.Join(out, "\n") -} diff --git a/pkg/version/version_test.go b/pkg/version/version_test.go deleted file mode 100644 index 4b66d3df..00000000 --- a/pkg/version/version_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package version - -import ( - "fmt" - "testing" - - "gotest.tools/assert" -) - -func TestCatalogImage(t *testing.T) { - t.Parallel() - Version = "v0.3.0" - assert.Equal(t, CatalogImage(), fmt.Sprintf(releaseCatalogImage, Version)) - Version = "v0.3.0-1-asd-dirty" - assert.Equal(t, CatalogImage(), devCatalogImage) -} From e5cddd4a363ae52c6bdf0e4baf00f384499fb8a6 Mon Sep 17 00:00:00 2001 From: Andrew Minkin Date: Fri, 13 Oct 2023 19:02:10 +0600 Subject: [PATCH 03/13] EVEREST-489 feedback --- .github/workflows/release.yml | 2 -- Makefile | 2 +- api/version.go | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3ea55b99..8ccf34dd 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -125,5 +125,3 @@ jobs: context: backend push: true tags: ${{ steps.meta.outputs.tags }} - build-args: | - "IS_RELEASE=1" diff --git a/Makefile b/Makefile index 3c53d861..2f67aadc 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ FILES = $(shell find . -type f -name '*.go') RELEASE_VERSION ?= $(shell git describe --always --tags --dirty | cut -b2-) RELEASE_FULLCOMMIT ?= $(shell git rev-parse HEAD) -FLAGS = -X 'github.com/percona/percona-everest-backend/pkg/version.ProjectName=everestctl' \ +FLAGS = -X 'github.com/percona/percona-everest-backend/pkg/version.ProjectName=Everest Backend' \ -X 'github.com/percona/percona-everest-backend/pkg/version.Version=$(RELEASE_VERSION)' \ -X 'github.com/percona/percona-everest-backend/pkg/version.FullCommit=$(RELEASE_FULLCOMMIT)' \ diff --git a/api/version.go b/api/version.go index f4782233..7118baf4 100644 --- a/api/version.go +++ b/api/version.go @@ -10,7 +10,7 @@ import ( func (e *EverestServer) VersionInfo(ctx echo.Context) error { return ctx.JSON(http.StatusOK, &Version{ - ProjectName: "Everest Backend", + ProjectName: version.ProjectName, Version: version.Version, FullCommit: version.FullCommit, }) From fcf83d6325dc4c8e3c872beea0c6b90558eb3a49 Mon Sep 17 00:00:00 2001 From: Andrew Minkin Date: Fri, 13 Oct 2023 19:32:20 +0600 Subject: [PATCH 04/13] EVEREST-489 Added integration test --- api-tests/tests/version.spec.ts | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 api-tests/tests/version.spec.ts diff --git a/api-tests/tests/version.spec.ts b/api-tests/tests/version.spec.ts new file mode 100644 index 00000000..387cec47 --- /dev/null +++ b/api-tests/tests/version.spec.ts @@ -0,0 +1,29 @@ + +// percona-everest-backend +// Copyright (C) 2023 Percona LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +import { expect, test } from '@fixtures' + +test('version endpoint', async ({ request, cli }) => { + const version = await request.get(`/v1/version`) + expect(version.ok()).toBeTruthy() + + const versionJSON = await version.json() + + const gitVersion = await cli.exec('git describe --always --tags | cut -b2-') + await gitVersion.assertSuccess() + + expect(versionJSON.projectName).toEqual("Everest Backend") + expect(versionJSON.version).toEqual(gitVersion.getStdOutLines()[0]) +}) From ef858e97716f4bb14f879171a6956015a3abd248 Mon Sep 17 00:00:00 2001 From: Andrew Minkin Date: Fri, 13 Oct 2023 19:41:44 +0600 Subject: [PATCH 05/13] EVEREST-489 Added integration test --- pkg/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/version/version.go b/pkg/version/version.go index 85e71b90..96058a60 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -1,4 +1,4 @@ -// percona-everest-cli +// percona-everest-backend // Copyright (C) 2023 Percona LLC // // Licensed under the Apache License, Version 2.0 (the "License"); From 58205762d166ca81a8c4fd944b61d77673076bb4 Mon Sep 17 00:00:00 2001 From: Andrew Minkin Date: Fri, 13 Oct 2023 20:10:48 +0600 Subject: [PATCH 06/13] EVEREST-489 Fixed linter --- api/version.go | 1 + 1 file changed, 1 insertion(+) diff --git a/api/version.go b/api/version.go index 7118baf4..309d3e2f 100644 --- a/api/version.go +++ b/api/version.go @@ -8,6 +8,7 @@ import ( "github.com/percona/percona-everest-backend/pkg/version" ) +// VersionInfo returns the current version information. func (e *EverestServer) VersionInfo(ctx echo.Context) error { return ctx.JSON(http.StatusOK, &Version{ ProjectName: version.ProjectName, From 6093cc9e6c29c7db4888329761a38cd8a5919806 Mon Sep 17 00:00:00 2001 From: Andrew Minkin Date: Mon, 16 Oct 2023 13:30:04 +0600 Subject: [PATCH 07/13] EVEREST-549 Added make release target to rebuild action --- .github/workflows/rc_rebuild.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/rc_rebuild.yml b/.github/workflows/rc_rebuild.yml index 234339ff..1e92a5bf 100644 --- a/.github/workflows/rc_rebuild.yml +++ b/.github/workflows/rc_rebuild.yml @@ -66,6 +66,9 @@ jobs: mkdir ${GITHUB_WORKSPACE}/front cp -rf build/percona.apps_everest/react-common-js/everest/public/* ${GITHUB_WORKSPACE}/front/ + - name: Build Everest + run: GOOS=linux GOARCH=amd64 make release + - name: Check out Everest Backend uses: actions/checkout@v4 with: From 3e34fca10ee43b55bc32b23d979e37d69928805b Mon Sep 17 00:00:00 2001 From: Andrew Minkin Date: Mon, 16 Oct 2023 16:53:25 +0600 Subject: [PATCH 08/13] EVEREST-489 Fixed databaseengines tests --- api-tests/tests/database-engines.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api-tests/tests/database-engines.spec.ts b/api-tests/tests/database-engines.spec.ts index c24109fc..97d278e0 100644 --- a/api-tests/tests/database-engines.spec.ts +++ b/api-tests/tests/database-engines.spec.ts @@ -51,7 +51,7 @@ test('get/edit database engine versions', async ({ request }) => { const availableVersions = engineData.status.availableVersions expect(availableVersions.engine['6.0.5-4'].imageHash).toBe('b6f875974c59d8ea0174675c85f41668460233784cbf2cbe7ce5eca212ac5f6a') - expect(availableVersions.backup['2.0.5'].status).toBe('recommended') + expect(availableVersions.backup['2.3.0'].status).toBe('recommended') const allowedVersions = ['6.0.5-4', '6.0.4-3', '5.0.7-6'] From da1f7a5275be82052a7fe959fc05b7b5a3c56389 Mon Sep 17 00:00:00 2001 From: Andrew Minkin Date: Mon, 16 Oct 2023 22:31:12 +0600 Subject: [PATCH 09/13] EVEREST-489 Drop recommended version --- api-tests/tests/database-cluster.spec.ts | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/api-tests/tests/database-cluster.spec.ts b/api-tests/tests/database-cluster.spec.ts index 8e761055..8ed71c33 100644 --- a/api-tests/tests/database-cluster.spec.ts +++ b/api-tests/tests/database-cluster.spec.ts @@ -19,7 +19,6 @@ import { expect, test } from '@fixtures' const testPrefix = `${(Math.random() + 1).toString(36).substring(10)}` let kubernetesId -let recommendedVersion const monitoringConfigName1 = `a${testPrefix}-1` const monitoringConfigName2 = `b${testPrefix}-2` @@ -30,17 +29,6 @@ test.beforeAll(async ({ request }) => { kubernetesId = (await kubernetesList.json())[0].id - const engineResponse = await request.get(`/v1/kubernetes/${kubernetesId}/database-engines/percona-server-mongodb-operator`) - const availableVersions = (await engineResponse.json()).status.availableVersions.engine - - for (const k in availableVersions) { - if (availableVersions[k].status === 'recommended' && k.startsWith('6')) { - recommendedVersion = k - } - } - - expect(recommendedVersion).not.toBe('') - const miData = { type: 'pmm', name: monitoringConfigName1, @@ -84,7 +72,6 @@ test('create db cluster with monitoring config', async ({ request }) => { engine: { type: 'psmdb', replicas: 1, - version: recommendedVersion, storage: { size: '4G', }, @@ -139,7 +126,6 @@ test('update db cluster with a new monitoring config', async ({ request }) => { engine: { type: 'psmdb', replicas: 1, - version: recommendedVersion, storage: { size: '4G', }, @@ -205,7 +191,6 @@ test('update db cluster without monitoring config with a new monitoring config', engine: { type: 'psmdb', replicas: 1, - version: recommendedVersion, storage: { size: '4G', }, @@ -274,7 +259,6 @@ test('update db cluster monitoring config with an empty monitoring config', asyn engine: { type: 'psmdb', replicas: 1, - version: recommendedVersion, storage: { size: '4G', }, From ae06f6c2f63e69d7129454bdb41c7bdd71a0bdb6 Mon Sep 17 00:00:00 2001 From: Andrew Minkin Date: Mon, 16 Oct 2023 22:36:41 +0600 Subject: [PATCH 10/13] EVEREST-489 Fixed tests --- api-tests/tests/database-engines.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api-tests/tests/database-engines.spec.ts b/api-tests/tests/database-engines.spec.ts index 97d278e0..1f006498 100644 --- a/api-tests/tests/database-engines.spec.ts +++ b/api-tests/tests/database-engines.spec.ts @@ -53,7 +53,7 @@ test('get/edit database engine versions', async ({ request }) => { expect(availableVersions.engine['6.0.5-4'].imageHash).toBe('b6f875974c59d8ea0174675c85f41668460233784cbf2cbe7ce5eca212ac5f6a') expect(availableVersions.backup['2.3.0'].status).toBe('recommended') - const allowedVersions = ['6.0.5-4', '6.0.4-3', '5.0.7-6'] + const allowedVersions = ['6.0.5-4', '6.0.4-3', '5.0.7-6', '6.0.9-7'] delete engineData.status engineData.spec.allowedVersions = allowedVersions From 2cf63fda4a7ab5c26d0039ba200828f8ba257b0a Mon Sep 17 00:00:00 2001 From: Andrew Minkin Date: Mon, 16 Oct 2023 22:47:00 +0600 Subject: [PATCH 11/13] EVEREST-489 Fixed tests --- api-tests/tests/psmdb-clusters.spec.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/api-tests/tests/psmdb-clusters.spec.ts b/api-tests/tests/psmdb-clusters.spec.ts index 37b84e37..435badde 100644 --- a/api-tests/tests/psmdb-clusters.spec.ts +++ b/api-tests/tests/psmdb-clusters.spec.ts @@ -15,7 +15,6 @@ import { test, expect } from '@fixtures' let kubernetesId -let recommendedVersion test.beforeAll(async ({ request }) => { const kubernetesList = await request.get('/v1/kubernetes') @@ -25,13 +24,6 @@ test.beforeAll(async ({ request }) => { const engineResponse = await request.get(`/v1/kubernetes/${kubernetesId}/database-engines/percona-server-mongodb-operator`) const availableVersions = (await engineResponse.json()).status.availableVersions.engine - for (const k in availableVersions) { - if (availableVersions[k].status === 'recommended' && k.startsWith('6')) { - recommendedVersion = k - } - } - - expect(recommendedVersion).not.toBe('') }) test('create/edit/delete single node psmdb cluster', async ({ request, page }) => { @@ -46,7 +38,6 @@ test('create/edit/delete single node psmdb cluster', async ({ request, page }) = engine: { type: 'psmdb', replicas: 1, - version: recommendedVersion, storage: { size: '25G', }, @@ -128,7 +119,6 @@ test('expose psmdb cluster after creation', async ({ request, page }) => { engine: { type: 'psmdb', replicas: 3, - version: recommendedVersion, storage: { size: '25G', }, @@ -207,7 +197,6 @@ test('expose psmdb cluster on EKS to the public internet and scale up', async ({ engine: { type: 'psmdb', replicas: 3, - version: recommendedVersion, storage: { size: '25G', }, From ff974b42704248d23ea32084c97ce6a691595e91 Mon Sep 17 00:00:00 2001 From: Andrew Minkin Date: Tue, 17 Oct 2023 00:16:33 +0600 Subject: [PATCH 12/13] EVEREST-489 Added docs --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2f67aadc..5da8966a 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ build: ## Build binaries release: FLAGS += -X 'github.com/percona/percona-everest-backend/cmd/config.TelemetryURL=https://check.percona.com/'\ -X 'github.com/percona/percona-everest-backend/cmd/config.TelemetryInterval=24h' -release: build +release: build ## Build release version build-debug: ## Build binaries From 959c509522be3474bb82f0c0feb9a52e23a8e602 Mon Sep 17 00:00:00 2001 From: Andrew Minkin Date: Tue, 17 Oct 2023 00:38:22 +0600 Subject: [PATCH 13/13] EVEREST-489 Fixed tests --- api-tests/tests/psmdb-clusters.spec.ts | 35 +++++++++++++++----------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/api-tests/tests/psmdb-clusters.spec.ts b/api-tests/tests/psmdb-clusters.spec.ts index 435badde..0dda2cd0 100644 --- a/api-tests/tests/psmdb-clusters.spec.ts +++ b/api-tests/tests/psmdb-clusters.spec.ts @@ -75,18 +75,17 @@ test('create/edit/delete single node psmdb cluster', async ({ request, page }) = expect(result.metadata.name).toBe(clusterName) expect(result.spec).toMatchObject(psmdbPayload.spec) expect(result.status.size).toBe(1) - - // psmdbPayload should be overriden because kubernetes adds data into metadata field - // and uses metadata.generation during updation. It returns 422 HTTP status code if this field is not present - // - // kubectl under the hood merges everything hence the UX is seemless - psmdbPayload.spec = result.spec - psmdbPayload.metadata = result.metadata break } psmdbPayload.spec.engine.config = 'operationProfiling:\nmode: slowOp' + let psmdbCluster = await request.get(`/v1/kubernetes/${kubernetesId}/database-clusters/${clusterName}`) + expect(psmdbCluster.ok()).toBeTruthy() + const result = (await psmdbCluster.json()) + psmdbPayload.spec = result.spec + psmdbPayload.metadata = result.metadata + // Update PSMDB cluster const updatedPSMDBCluster = await request.put(`/v1/kubernetes/${kubernetesId}/database-clusters/${clusterName}`, { @@ -95,7 +94,7 @@ test('create/edit/delete single node psmdb cluster', async ({ request, page }) = expect(updatedPSMDBCluster.ok()).toBeTruthy() - let psmdbCluster = await request.get(`/v1/kubernetes/${kubernetesId}/database-clusters/${clusterName}`) + psmdbCluster = await request.get(`/v1/kubernetes/${kubernetesId}/database-clusters/${clusterName}`) expect(psmdbCluster.ok()).toBeTruthy() @@ -158,11 +157,14 @@ test('expose psmdb cluster after creation', async ({ request, page }) => { expect(result.spec).toMatchObject(psmdbPayload.spec) expect(result.status.size).toBe(3) - psmdbPayload.spec = result.spec - psmdbPayload.metadata = result.metadata break } + let psmdbCluster = await request.get(`/v1/kubernetes/${kubernetesId}/database-clusters/${clusterName}`) + expect(psmdbCluster.ok()).toBeTruthy() + const result = (await psmdbCluster.json()) + psmdbPayload.spec = result.spec + psmdbPayload.metadata = result.metadata psmdbPayload.spec.proxy.expose.type = 'external' // Update PSMDB cluster @@ -172,8 +174,9 @@ test('expose psmdb cluster after creation', async ({ request, page }) => { }) expect(updatedPSMDBCluster.ok()).toBeTruthy() + await page.waitForTimeout(1000) - let psmdbCluster = await request.get(`/v1/kubernetes/${kubernetesId}/database-clusters/${clusterName}`) + psmdbCluster = await request.get(`/v1/kubernetes/${kubernetesId}/database-clusters/${clusterName}`) expect(psmdbCluster.ok()).toBeTruthy() @@ -234,13 +237,15 @@ test('expose psmdb cluster on EKS to the public internet and scale up', async ({ expect(result.metadata.name).toBe(clusterName) expect(result.spec).toMatchObject(psmdbPayload.spec) expect(result.status.size).toBe(3) - - psmdbPayload.spec = result.spec - psmdbPayload.metadata = result.metadata break } psmdbPayload.spec.engine.replicas = 5 + let psmdbCluster = await request.get(`/v1/kubernetes/${kubernetesId}/database-clusters/${clusterName}`) + expect(psmdbCluster.ok()).toBeTruthy() + const result = (await psmdbCluster.json()) + psmdbPayload.spec = result.spec + psmdbPayload.metadata = result.metadata // Update PSMDB cluster @@ -250,7 +255,7 @@ test('expose psmdb cluster on EKS to the public internet and scale up', async ({ expect(updatedPSMDBCluster.ok()).toBeTruthy() - let psmdbCluster = await request.get(`/v1/kubernetes/${kubernetesId}/database-clusters/${clusterName}`) + psmdbCluster = await request.get(`/v1/kubernetes/${kubernetesId}/database-clusters/${clusterName}`) expect(psmdbCluster.ok()).toBeTruthy()