diff --git a/.github/workflows/publish-docker.yml b/.github/workflows/publish-docker.yml deleted file mode 100644 index bd8bfa03a..000000000 --- a/.github/workflows/publish-docker.yml +++ /dev/null @@ -1,39 +0,0 @@ -name: publish-docker -on: - push: - branches: - - 'develop' - - 'main' -jobs: - docker: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - name: Get base image name - shell: bash - run: echo "##[set-output name=image;]$(echo gcr.io/up9-docker-hub/mizu/${GITHUB_REF#refs/heads/})" - id: base_image_step - - name: Docker meta - id: meta - uses: crazy-max/ghaction-docker-meta@v2 - with: - images: ${{ steps.base_image_step.outputs.image }} - tags: | - type=sha - type=raw,${{ github.sha }} - type=raw,latest - - name: Login to DockerHub - uses: docker/login-action@v1 - with: - registry: gcr.io - username: _json_key - password: ${{ secrets.GCR_JSON_KEY }} - - name: Build and push - uses: docker/build-push-action@v2 - with: - context: . - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - diff --git a/.github/workflows/publish-cli.yml b/.github/workflows/publish.yml similarity index 55% rename from .github/workflows/publish-cli.yml rename to .github/workflows/publish.yml index b9e814931..5beaeb446 100644 --- a/.github/workflows/publish-cli.yml +++ b/.github/workflows/publish.yml @@ -1,9 +1,9 @@ -name: public-cli +name: publish on: push: branches: - - develop - - main + - 'develop' + - 'main' jobs: docker: runs-on: ubuntu-latest @@ -27,12 +27,43 @@ jobs: with: releaseType: ${{ steps.condval.outputs.value }} github_token: ${{ secrets.GITHUB_TOKEN }} - - name: Get base image name + - name: Get version parameters shell: bash run: | echo "##[set-output name=build_timestamp;]$(echo $(date +%s))" echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" id: version_parameters + - name: Get base image name + shell: bash + run: echo "##[set-output name=image;]$(echo gcr.io/up9-docker-hub/mizu/${GITHUB_REF#refs/heads/})" + id: base_image_step + - name: Docker meta + id: meta + uses: crazy-max/ghaction-docker-meta@v2 + with: + images: ${{ steps.base_image_step.outputs.image }} + tags: | + type=sha + type=raw,${{ github.sha }} + type=raw,${{ steps.versioning.outputs.version }} + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + registry: gcr.io + username: _json_key + password: ${{ secrets.GCR_JSON_KEY }} + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + SEM_VER=${{ steps.versioning.outputs.version }} + BUILD_TIMESTAMP=${{ steps.version_parameters.outputs.build_timestamp }} + GIT_BRANCH=${{ steps.version_parameters.outputs.branch }} + COMMIT_HASH=${{ github.sha }} - name: Build and Push CLI run: make push-cli SEM_VER='${{ steps.versioning.outputs.version }}' BUILD_TIMESTAMP='${{ steps.version_parameters.outputs.build_timestamp }}' - name: publish diff --git a/Dockerfile b/Dockerfile index 157588ec9..0fa90f951 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,11 +23,20 @@ RUN go mod download # cheap trick to make the build faster (As long as go.mod wasn't changes) RUN go list -f '{{.Path}}@{{.Version}}' -m all | sed 1d | grep -e 'go-cache' -e 'sqlite' | xargs go get +ARG COMMIT_HASH +ARG GIT_BRANCH +ARG BUILD_TIMESTAMP +ARG SEM_VER + # Copy and build api code COPY shared ../shared COPY tap ../tap COPY api . -RUN go build -ldflags="-s -w" -o mizuagent . +RUN go build -ldflags="-s -w \ + -X 'mizuserver/pkg/version.GitCommitHash=${COMMIT_HASH}' \ + -X 'mizuserver/pkg/version.Branch=${GIT_BRANCH}' \ + -X 'mizuserver/pkg/version.BuildTimestamp=${BUILD_TIMESTAMP}' \ + -X 'mizuserver/pkg/version.SemVer=${SEM_VER}'" -o mizuagent . FROM alpine:3.13.5 diff --git a/api/main.go b/api/main.go index ba012fca7..c9bba39dc 100644 --- a/api/main.go +++ b/api/main.go @@ -16,6 +16,7 @@ import ( "mizuserver/pkg/routes" "mizuserver/pkg/sensitiveDataFiltering" "mizuserver/pkg/utils" + "mizuserver/pkg/version" "os" "os/signal" "strings" @@ -101,6 +102,7 @@ func hostApi(socketHarOutputChannel chan<- *tap.OutputChannelItem) { } routes.WebSocketRoutes(app, &eventHandlers) routes.EntriesRoutes(app) + routes.MetadataRoutes(app) routes.NotFoundRoute(app) utils.StartServer(app) diff --git a/api/pkg/controllers/metadata_controller.go b/api/pkg/controllers/metadata_controller.go new file mode 100644 index 000000000..702e682b4 --- /dev/null +++ b/api/pkg/controllers/metadata_controller.go @@ -0,0 +1,12 @@ +package controllers + +import ( + "github.com/gofiber/fiber/v2" + "github.com/up9inc/mizu/shared" + "mizuserver/pkg/version" +) + +func GetVersion(c *fiber.Ctx) error { + resp := shared.VersionResponse{SemVer: version.SemVer} + return c.Status(fiber.StatusOK).JSON(resp) +} diff --git a/api/pkg/routes/public_routes.go b/api/pkg/routes/entries_routes.go similarity index 94% rename from api/pkg/routes/public_routes.go rename to api/pkg/routes/entries_routes.go index ed3a84e46..9f5f751be 100644 --- a/api/pkg/routes/public_routes.go +++ b/api/pkg/routes/entries_routes.go @@ -5,7 +5,7 @@ import ( "mizuserver/pkg/controllers" ) -// EntriesRoutes func for describe group of public routes. +// EntriesRoutes defines the group of har entries routes. func EntriesRoutes(fiberApp *fiber.App) { routeGroup := fiberApp.Group("/api") diff --git a/api/pkg/routes/metadata_routes.go b/api/pkg/routes/metadata_routes.go new file mode 100644 index 000000000..3a3d3da11 --- /dev/null +++ b/api/pkg/routes/metadata_routes.go @@ -0,0 +1,13 @@ +package routes + +import ( + "github.com/gofiber/fiber/v2" + "mizuserver/pkg/controllers" +) + +// MetadataRoutes defines the group of metadata routes. +func MetadataRoutes(fiberApp *fiber.App) { + routeGroup := fiberApp.Group("/metadata") + + routeGroup.Get("/version", controllers.GetVersion) +} diff --git a/api/pkg/routes/not_found_route.go b/api/pkg/routes/not_found_route.go index 1aa1e7da7..452caa8e0 100644 --- a/api/pkg/routes/not_found_route.go +++ b/api/pkg/routes/not_found_route.go @@ -2,7 +2,7 @@ package routes import "github.com/gofiber/fiber/v2" -// NotFoundRoute func for describe 404 Error route. +// NotFoundRoute defines the 404 Error route. func NotFoundRoute(fiberApp *fiber.App) { fiberApp.Use( func(c *fiber.Ctx) error { diff --git a/api/pkg/version/consts.go b/api/pkg/version/consts.go new file mode 100644 index 000000000..79742f5ce --- /dev/null +++ b/api/pkg/version/consts.go @@ -0,0 +1,8 @@ +package version + +var ( + SemVer = "0.0.1" + Branch = "develop" + GitCommitHash = "" // this var is overridden using ldflags in makefile when building + BuildTimestamp = "" // this var is overridden using ldflags in makefile when building +) diff --git a/build-push-featurebranch.sh b/build-push-featurebranch.sh index 01089010e..5fbf32619 100755 --- a/build-push-featurebranch.sh +++ b/build-push-featurebranch.sh @@ -14,7 +14,7 @@ then fi echo "building $DOCKER_TAGGED_BUILD" -docker build -t "$DOCKER_TAGGED_BUILD" . +docker build -t "$DOCKER_TAGGED_BUILD" --build-arg SEM_VER=${SEM_VER} --build-arg BUILD_TIMESTAMP=${BUILD_TIMESTAMP} --build-arg GIT_BRANCH=${GIT_BRANCH} --build-arg COMMIT_HASH=${COMMIT_HASH} . echo pushing to "$REPOSITORY" docker push "$DOCKER_TAGGED_BUILD" diff --git a/cli/cmd/fetch.go b/cli/cmd/fetch.go index 7faeffdc1..62caaf4e6 100644 --- a/cli/cmd/fetch.go +++ b/cli/cmd/fetch.go @@ -2,6 +2,7 @@ package cmd import ( "github.com/spf13/cobra" + "github.com/up9inc/mizu/cli/mizu" ) type MizuFetchOptions struct { @@ -17,6 +18,11 @@ var fetchCmd = &cobra.Command{ Use: "fetch", Short: "Download recorded traffic to files", RunE: func(cmd *cobra.Command, args []string) error { + if isCompatible, err := mizu.CheckVersionCompatibility(mizuFetchOptions.MizuPort); err != nil { + return err + } else if !isCompatible { + return nil + } RunMizuFetch(&mizuFetchOptions) return nil }, diff --git a/cli/cmd/tap.go b/cli/cmd/tap.go index 037ad4944..245b3d7df 100644 --- a/cli/cmd/tap.go +++ b/cli/cmd/tap.go @@ -97,7 +97,7 @@ func init() { tapCmd.Flags().Uint16VarP(&mizuTapOptions.SleepIntervalSec, "upload-interval", "", 10, "Interval in seconds for uploading data to UP9") tapCmd.Flags().BoolVarP(&mizuTapOptions.AllNamespaces, "all-namespaces", "A", false, "Tap all namespaces") tapCmd.Flags().StringVarP(&mizuTapOptions.KubeConfigPath, "kube-config", "k", "", "Path to kube-config file") - tapCmd.Flags().StringVarP(&mizuTapOptions.MizuImage, "mizu-image", "", fmt.Sprintf("gcr.io/up9-docker-hub/mizu/%s:latest", mizu.Branch), "Custom image for mizu collector") + tapCmd.Flags().StringVarP(&mizuTapOptions.MizuImage, "mizu-image", "", fmt.Sprintf("gcr.io/up9-docker-hub/mizu/%s:%s", mizu.Branch, mizu.SemVer), "Custom image for mizu collector") tapCmd.Flags().StringArrayVarP(&mizuTapOptions.PlainTextFilterRegexes, "regex-masking", "r", nil, "List of regex expressions that are used to filter matching values from text/plain http bodies") tapCmd.Flags().StringVarP(&direction, "direction", "", "in", "Record traffic that goes in this direction (relative to the tapped pod): in/any") tapCmd.Flags().BoolVar(&mizuTapOptions.HideHealthChecks, "hide-healthchecks", false, "hides requests with kube-probe or prometheus user-agent headers") diff --git a/cli/cmd/view.go b/cli/cmd/view.go index acb2091c9..a49ebde75 100644 --- a/cli/cmd/view.go +++ b/cli/cmd/view.go @@ -2,6 +2,7 @@ package cmd import ( "github.com/spf13/cobra" + "github.com/up9inc/mizu/cli/mizu" ) type MizuViewOptions struct { @@ -14,9 +15,15 @@ var viewCmd = &cobra.Command{ Use: "view", Short: "Open GUI in browser", RunE: func(cmd *cobra.Command, args []string) error { + if isCompatible, err := mizu.CheckVersionCompatibility(mizuFetchOptions.MizuPort); err != nil { + return err + } else if !isCompatible { + return nil + } runMizuView(mizuViewOptions) return nil }, + } func init() { diff --git a/cli/mizu/versionCheck.go b/cli/mizu/versionCheck.go new file mode 100644 index 000000000..3211f687d --- /dev/null +++ b/cli/mizu/versionCheck.go @@ -0,0 +1,46 @@ +package mizu + +import ( + "encoding/json" + "fmt" + "github.com/up9inc/mizu/shared" + "github.com/up9inc/mizu/shared/semver" + "net/http" + "net/url" +) + + +func getApiVersion(port uint16) (string, error) { + versionUrl, _ := url.Parse(fmt.Sprintf("http://localhost:%d/mizu/metadata/version", port)) + req := &http.Request{ + Method: http.MethodGet, + URL: versionUrl, + } + statusResp, err := http.DefaultClient.Do(req) + if err != nil { + return "", err + } + defer statusResp.Body.Close() + + versionResponse := &shared.VersionResponse{} + if err := json.NewDecoder(statusResp.Body).Decode(&versionResponse); err != nil { + return "", err + } + + return versionResponse.SemVer, nil +} + +func CheckVersionCompatibility(port uint16) (bool, error) { + apiSemVer, err := getApiVersion(port) + if err != nil { + return false, err + } + + if semver.SemVersion(apiSemVer).Major() == semver.SemVersion(SemVer).Major() && + semver.SemVersion(apiSemVer).Minor() == semver.SemVersion(SemVer).Minor() { + return true, nil + } + + fmt.Printf(Red, fmt.Sprintf("cli version (%s) is not compatible with api version (%s)\n", SemVer, apiSemVer)) + return false, nil +} diff --git a/shared/models.go b/shared/models.go index 8cf46c0f7..14c1b3ce9 100644 --- a/shared/models.go +++ b/shared/models.go @@ -61,3 +61,8 @@ type TrafficFilteringOptions struct { PlainTextMaskingRegexes []*SerializableRegexp HideHealthChecks bool } + +type VersionResponse struct { + SemVer string `json:"semver"` +} + diff --git a/shared/semver/semver.go b/shared/semver/semver.go new file mode 100644 index 000000000..f27ca33f0 --- /dev/null +++ b/shared/semver/semver.go @@ -0,0 +1,28 @@ +package semver + +import ( + "regexp" +) + +type SemVersion string + +func (v SemVersion) Breakdown() (string, string, string) { + re := regexp.MustCompile(`\d+`) + breakdown := re.FindAllString(string(v), 3) + return breakdown[0], breakdown[1], breakdown[2] +} + +func (v SemVersion) Major() string { + major, _, _ := v.Breakdown() + return major +} + +func (v SemVersion) Minor() string { + _, minor, _ := v.Breakdown() + return minor +} + +func (v SemVersion) Patch() string { + _, _, patch := v.Breakdown() + return patch +}