From 7980b532bb96123a88a17cb29869108a0984cb52 Mon Sep 17 00:00:00 2001 From: Bruno Cochofel Date: Sat, 23 Jan 2021 11:53:35 +0000 Subject: [PATCH 1/4] feat: first release --- .chglog/CHANGELOG.tpl.md | 56 ++ .chglog/config.yml | 28 + .github/workflows/changelog.yml | 31 + .github/workflows/release.yml | 35 + .github/workflows/validate.yml | 7 +- .pre-commit-config.yaml | 7 +- Makefile | 8 - README.md | 27 +- docs/git-chlog.md | 14 + docs/images/lab.png | Bin 0 -> 25441 bytes docs/images/tested.png | Bin 0 -> 14687 bytes docs/pre-commit-hooks.md | 32 + docs/references.md | 7 + docs/requirements.md | 13 + ...etheus.yaml => flux-prometheus-rules.yaml} | 21 - .../flux-prometheus-servicemonitor.yaml | 21 + ...ml => helm-operator-prometheus-rules.yaml} | 21 - ...lm-operator-prometheus-servicemonitor.yaml | 21 + .../istio-prometheus-crb.yaml | 13 + .../istio-prometheus-rules.yaml | 105 +++ .../istio-production/istio-prometheus-sa.yaml | 6 + .../istio-prometheus-service.yaml | 19 + .../istio-prometheus-servicemonitor1.yaml | 19 + .../istio-prometheus-servicemonitor2.yaml | 21 + .../istio-prometheus-servicemonitor3.yaml | 32 + .../istio-production/istio-prometheus.yaml | 215 ------ scenarios/istio-production/kustomization.yaml | 13 +- tools/semtag | 627 ------------------ 28 files changed, 515 insertions(+), 904 deletions(-) create mode 100755 .chglog/CHANGELOG.tpl.md create mode 100755 .chglog/config.yml create mode 100644 .github/workflows/changelog.yml create mode 100644 .github/workflows/release.yml delete mode 100644 Makefile create mode 100644 docs/git-chlog.md create mode 100644 docs/images/lab.png create mode 100644 docs/images/tested.png create mode 100644 docs/pre-commit-hooks.md create mode 100644 docs/references.md create mode 100644 docs/requirements.md rename scenarios/istio-production/{flux-prometheus.yaml => flux-prometheus-rules.yaml} (73%) create mode 100644 scenarios/istio-production/flux-prometheus-servicemonitor.yaml rename scenarios/istio-production/{helm-operator-prometheus.yaml => helm-operator-prometheus-rules.yaml} (71%) create mode 100644 scenarios/istio-production/helm-operator-prometheus-servicemonitor.yaml create mode 100644 scenarios/istio-production/istio-prometheus-crb.yaml create mode 100644 scenarios/istio-production/istio-prometheus-rules.yaml create mode 100644 scenarios/istio-production/istio-prometheus-sa.yaml create mode 100644 scenarios/istio-production/istio-prometheus-service.yaml create mode 100644 scenarios/istio-production/istio-prometheus-servicemonitor1.yaml create mode 100644 scenarios/istio-production/istio-prometheus-servicemonitor2.yaml create mode 100644 scenarios/istio-production/istio-prometheus-servicemonitor3.yaml delete mode 100755 tools/semtag diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md new file mode 100755 index 0000000..3310307 --- /dev/null +++ b/.chglog/CHANGELOG.tpl.md @@ -0,0 +1,56 @@ +{{ if .Versions -}} + +## [Unreleased] + +{{ if .Unreleased.CommitGroups -}} +{{ range .Unreleased.CommitGroups -}} +### {{ .Title }} +{{ range .Commits -}} +- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} +{{ end }} +{{ end -}} +{{ end -}} +{{ end -}} + +{{ range .Versions }} + +## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }} +{{ range .CommitGroups -}} +### {{ .Title }} +{{ range .Commits -}} +- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} +{{ end }} +{{ end -}} + +{{- if .RevertCommits -}} +### Reverts +{{ range .RevertCommits -}} +- {{ .Revert.Header }} +{{ end }} +{{ end -}} + +{{- if .MergeCommits -}} +### Pull Requests +{{ range .MergeCommits -}} +- {{ .Header }} +{{ end }} +{{ end -}} + +{{- if .NoteGroups -}} +{{ range .NoteGroups -}} +### {{ .Title }} +{{ range .Notes }} +{{ .Body }} +{{ end }} +{{ end -}} +{{ end -}} +{{ end -}} + +{{- if .Versions }} +[Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD +{{ range .Versions -}} +{{ if .Tag.Previous -}} +[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }} +{{ end -}} +{{ end -}} +{{ end -}} diff --git a/.chglog/config.yml b/.chglog/config.yml new file mode 100755 index 0000000..d477587 --- /dev/null +++ b/.chglog/config.yml @@ -0,0 +1,28 @@ +style: github +template: CHANGELOG.tpl.md +info: + title: CHANGELOG + repository_url: https://github.com/bcochofel/k8s-gitops-istio-demo +options: + commits: + # filters: + # Type: + # - feat + # - fix + # - perf + # - refactor + commit_groups: + # title_maps: + # feat: Features + # fix: Bug Fixes + # perf: Performance Improvements + # refactor: Code Refactoring + header: + pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$" + pattern_maps: + - Type + - Scope + - Subject + notes: + keywords: + - BREAKING CHANGE diff --git a/.github/workflows/changelog.yml b/.github/workflows/changelog.yml new file mode 100644 index 0000000..f28ffaf --- /dev/null +++ b/.github/workflows/changelog.yml @@ -0,0 +1,31 @@ +name: Release +on: + push: + branches: + - '*' # all branches + - '!main' # exclude main branch + - '!master' # exclude main branch + +jobs: + changelog: + name: Changelog + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: '0' + - name: Install GitVersion + uses: gittools/actions/gitversion/setup@v0.9.8 + with: + versionSpec: '5.x' + - name: Use GitVersion + uses: gittools/actions/gitversion/execute@v0.9.8 + id: gitversion + - name: Changelog + id: changelog + uses: nuuday/github-changelog-action@v1.0.0 + with: + next_version: "${{ steps.gitversion.outputs.majorMinorPatch }}" + - name: Commit Changelog + uses: stefanzweifel/git-auto-commit-action@v4 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..13fcf93 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,35 @@ +name: Release +on: + push: + branches: + - main + - master + +jobs: + release: + name: Release + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: '0' + - name: Install GitVersion + uses: gittools/actions/gitversion/setup@v0.9.8 + with: + versionSpec: '5.x' + - name: Use GitVersion + uses: gittools/actions/gitversion/execute@v0.9.8 + id: gitversion + - name: Create Release + id: create_release + uses: actions/create-release@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.gitversion.outputs.majorMinorPatch }} + release_name: Release ${{ steps.gitversion.outputs.majorMinorPatch }} + body: | + [CHANGELOG](./CHANGELOG.md) + draft: false + prerelease: false diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index 992a0ca..af27f21 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -10,9 +10,12 @@ jobs: with: kubectl: 1.18.9 kustomize: 3.8.4 + helm: 2.16.7 helmv3: 3.2.1 + kubeseal: 0.12.5 + kubeaudit: 0.11.5 command: | echo "Validating kustomize istio-demo scenario..." - #kustomize build scenarios/istio-demo | kubeval --strict --ignore-missing-schemas + kustomize build scenarios/istio-demo | kubeval --strict --ignore-missing-schemas echo "Validating kustomize istio-default scenario..." - #kustomize build scenarios/istio-production | kubeval --strict --ignore-missing-schemas + kustomize build scenarios/istio-production | kubeval --strict --ignore-missing-schemas diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 682b351..ae9015c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,4 +8,9 @@ repos: - id: detect-private-key - id: check-merge-conflict - id: no-commit-to-branch - # - id: check-yaml + - id: check-yaml + - repo: https://github.com/commitizen-tools/commitizen + rev: master + hooks: + - id: commitizen + stages: [commit-msg] diff --git a/Makefile b/Makefile deleted file mode 100644 index 8ab8435..0000000 --- a/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -.PHONY: release - -SEMTAG=tools/semtag - -scope ?= "minor" - -release: - $(SEMTAG) final -s $(scope) diff --git a/README.md b/README.md index 875df10..ea6a4bb 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,18 @@ # k8s-gitops-istio-demo -[![Validate Scenarios](https://github.com/bcochofel/k8s-gitops-istio-demo/workflows/Validate%20Scenarios/badge.svg)](https://github.com/bcochofel/k8s-gitops-istio-demo/blob/master/.github/workflows/validate.yml) -[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) -[![GitHub license](https://img.shields.io/github/license/bcochofel/k8s-gitops-istio-demo.svg)](https://github.com/bcochofel/k8s-gitops-istio-demo/blob/master/LICENSE) -[![GitHub tag (latest by date)](https://img.shields.io/github/v/tag/bcochofel/k8s-gitops-istio-demo)](https://github.com/bcochofel/k8s-gitops-istio-demo/tags) -[![GitHub issues](https://img.shields.io/github/issues/bcochofel/k8s-gitops-istio-demo.svg)](https://github.com/bcochofel/k8s-gitops-istio-demo/issues/) -[![GitHub forks](https://img.shields.io/github/forks/bcochofel/k8s-gitops-istio-demo.svg?style=social&label=Fork&maxAge=2592000)](https://github.com/bcochofel/k8s-gitops-istio-demo/network/) -[![GitHub stars](https://img.shields.io/github/stars/bcochofel/k8s-gitops-istio-demo.svg?style=social&label=Star&maxAge=2592000)](https://github.com/bcochofel/k8s-gitops-istio-demo/stargazers/) +[![pre-commit badge][pre-commit-badge]][pre-commit] [![Conventional commits badge][conventional-commits-badge]][conventional-commits] [![Keep a Changelog v1.1.0 badge][keep-a-changelog-badge]][keep-a-changelog] [![MIT License Badge][license-badge]][license] Kubernetes manifests that can be used with GitOps. Most of the manifests use Helm Operator, so you need to have that installed on your cluster. +# pre-commit hooks + +Read the [pre-commit hooks](docs/pre-commit-hooks.md) document for more info. + +# git-chglog + +Read the [git-chglog](docs/git-chlog.md) document for more info. + ## Requirements The scenarios under `kustomize/` use [Kustomize](https://github.com/kubernetes-sigs/kustomize). @@ -49,3 +51,14 @@ Prometheus is deployed using the new Prometheus Operator [chart](https://github. The Prometheus instances use labels (tier=cluster and tier=istio) to separate the scrape and rules for each scope. You can use [this repo](https://github.com/bcochofel/terraform-modules) to deploy both Istio and Flux using Terraform (`examples` folder) + +[pre-commit]: https://github.com/pre-commit/pre-commit +[pre-commit-badge]: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white +[conventional-commits-badge]: https://img.shields.io/badge/Conventional%20Commits-1.0.0-green.svg +[conventional-commits]: https://conventionalcommits.org +[keep-a-changelog-badge]: https://img.shields.io/badge/changelog-Keep%20a%20Changelog%20v1.1.0-%23E05735 +[keep-a-changelog]: https://keepachangelog.com/en/1.0.0/ +[license]: ./LICENSE +[license-badge]: https://img.shields.io/badge/license-MIT-green.svg +[changelog]: ./CHANGELOG.md +[changelog-badge]: https://img.shields.io/badge/changelog-Keep%20a%20Changelog%20v1.1.0-%23E05735 diff --git a/docs/git-chlog.md b/docs/git-chlog.md new file mode 100644 index 0000000..4f86ac0 --- /dev/null +++ b/docs/git-chlog.md @@ -0,0 +1,14 @@ +# git-chglog + +The Changelog file is maintained using [git-chglog](https://github.com/git-chglog/git-chglog) + +```bash +❯ git-chglog --init +? What is the URL of your repository? {{ github_url }} +? What is your favorite style? github +? Choose the format of your favorite commit message (): +? What is your favorite template style? keep-a-changelog +? Do you include Merge Commit in CHANGELOG? Yes +? Do you include Revert Commit in CHANGELOG? Yes +? In which directory do you output configuration files and templates? .chglog +``` diff --git a/docs/images/lab.png b/docs/images/lab.png new file mode 100644 index 0000000000000000000000000000000000000000..ac9511b1d5d780be023fa1a226ff2fe414a7bef1 GIT binary patch literal 25441 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 literal 0 HcmV?d00001 diff --git a/docs/images/tested.png b/docs/images/tested.png new file mode 100644 index 0000000000000000000000000000000000000000..f8be14406497b4eba08cfde435ff0a47f2abe55c GIT binary patch literal 14687 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 DfrulJ literal 0 HcmV?d00001 diff --git a/docs/pre-commit-hooks.md b/docs/pre-commit-hooks.md new file mode 100644 index 0000000..bd3f29b --- /dev/null +++ b/docs/pre-commit-hooks.md @@ -0,0 +1,32 @@ +# pre-commit hooks + +GIT hooks are implemented using [`pre-commit`](https://pre-commit.com/). + +To install `pre-commit` follow [this](https://pre-commit.com/#install) guide. + +After installing `pre-commit` and cloning this repo you can enable the hooks locally by running: + +```bash +pre-commit install +pre-commit install --hook-type commit-msg +``` + +You can also run specific hooks on all files: + +```bash +pre-commit run detect-private-key --all-files +``` + +or run all hooks on all files: + +```bash +pre-commit run --all-files +``` + +for more options check `pre-commit` [documentation](https://pre-commit.com/#advanced) + +**NOTE:** to run the hooks you should have installed the following tools: +* [`terraform`](https://www.terraform.io/downloads.html) +* [`terragrunt`](https://terragrunt.gruntwork.io/docs/getting-started/install/) +* [`tflint`](https://github.com/terraform-linters/tflint) and +* [`terraform-docs`](https://github.com/terraform-docs/terraform-docs) installed locally. diff --git a/docs/references.md b/docs/references.md new file mode 100644 index 0000000..93e94c3 --- /dev/null +++ b/docs/references.md @@ -0,0 +1,7 @@ +# References + +- [Kubespray](https://github.com/kubernetes-sigs/kubespray) +- [kubectl Cheat Sheet](https://kubernetes.io/docs/reference/kubectl/cheatsheet/) +- [Set up Kubernetes cluster on laptop/PC using Vagrant Virtual Box and Kubespray](https://medium.com/@kanrangsan/home-lab-set-up-kubernetes-cluster-on-laptop-pc-using-vagrant-virtual-box-and-kubespray-a445c0429226) +- [Deployment with Kubernetes](https://blog.lelonek.me/deployment-with-kubernetes-e74cd6a8974) +- [pre-commit](https://pre-commit.com/#install) diff --git a/docs/requirements.md b/docs/requirements.md new file mode 100644 index 0000000..c2024a6 --- /dev/null +++ b/docs/requirements.md @@ -0,0 +1,13 @@ +# Requirements + +To run this repository you need: + +- [Vagrant](https://www.vagrantup.com/downloads.html) +- At least 16GB of RAM (you can change the Vagrantfile) + +You can also use [pre-commit](https://pre-commit.com/#install). After installing +`pre-commit` just execute: + +```ShellSession +pre-commit install +``` diff --git a/scenarios/istio-production/flux-prometheus.yaml b/scenarios/istio-production/flux-prometheus-rules.yaml similarity index 73% rename from scenarios/istio-production/flux-prometheus.yaml rename to scenarios/istio-production/flux-prometheus-rules.yaml index 3fb45de..6ec74b1 100644 --- a/scenarios/istio-production/flux-prometheus.yaml +++ b/scenarios/istio-production/flux-prometheus-rules.yaml @@ -1,26 +1,5 @@ --- apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: flux - namespace: fluxcd - labels: - app: flux - release: flux - tier: cluster -spec: - endpoints: - - port: http - honorLabels: true - namespaceSelector: - matchNames: - - fluxcd - selector: - matchLabels: - app: flux - release: flux ---- -apiVersion: monitoring.coreos.com/v1 kind: PrometheusRule metadata: labels: diff --git a/scenarios/istio-production/flux-prometheus-servicemonitor.yaml b/scenarios/istio-production/flux-prometheus-servicemonitor.yaml new file mode 100644 index 0000000..e9908d6 --- /dev/null +++ b/scenarios/istio-production/flux-prometheus-servicemonitor.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: flux + namespace: fluxcd + labels: + app: flux + release: flux + tier: cluster +spec: + endpoints: + - port: http + honorLabels: true + namespaceSelector: + matchNames: + - fluxcd + selector: + matchLabels: + app: flux + release: flux diff --git a/scenarios/istio-production/helm-operator-prometheus.yaml b/scenarios/istio-production/helm-operator-prometheus-rules.yaml similarity index 71% rename from scenarios/istio-production/helm-operator-prometheus.yaml rename to scenarios/istio-production/helm-operator-prometheus-rules.yaml index 277e8ae..938ee63 100644 --- a/scenarios/istio-production/helm-operator-prometheus.yaml +++ b/scenarios/istio-production/helm-operator-prometheus-rules.yaml @@ -1,26 +1,5 @@ --- apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: helm-operator - namespace: fluxcd - labels: - app: helm-operator - release: helm-operator - tier: cluster -spec: - endpoints: - - port: http - honorLabels: true - namespaceSelector: - matchNames: - - fluxcd - selector: - matchLabels: - app: helm-operator - release: helm-operator ---- -apiVersion: monitoring.coreos.com/v1 kind: PrometheusRule metadata: labels: diff --git a/scenarios/istio-production/helm-operator-prometheus-servicemonitor.yaml b/scenarios/istio-production/helm-operator-prometheus-servicemonitor.yaml new file mode 100644 index 0000000..1402690 --- /dev/null +++ b/scenarios/istio-production/helm-operator-prometheus-servicemonitor.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: helm-operator + namespace: fluxcd + labels: + app: helm-operator + release: helm-operator + tier: cluster +spec: + endpoints: + - port: http + honorLabels: true + namespaceSelector: + matchNames: + - fluxcd + selector: + matchLabels: + app: helm-operator + release: helm-operator diff --git a/scenarios/istio-production/istio-prometheus-crb.yaml b/scenarios/istio-production/istio-prometheus-crb.yaml new file mode 100644 index 0000000..99a1f40 --- /dev/null +++ b/scenarios/istio-production/istio-prometheus-crb.yaml @@ -0,0 +1,13 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1beta1 +kind: ClusterRoleBinding +metadata: + name: istio-prometheus +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: kube-prometheus-stack-prometheus +subjects: + - kind: ServiceAccount + name: istio-prometheus + namespace: istio-system diff --git a/scenarios/istio-production/istio-prometheus-rules.yaml b/scenarios/istio-production/istio-prometheus-rules.yaml new file mode 100644 index 0000000..c9d9785 --- /dev/null +++ b/scenarios/istio-production/istio-prometheus-rules.yaml @@ -0,0 +1,105 @@ +--- +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: istio-metrics-aggregation + namespace: istio-system + labels: + app.kubernetes.io/name: istio-prometheus + app: prometheus + tier: istio +spec: + groups: + - name: "istio.metricsAggregation-rules" + interval: 5s + rules: + - record: "workload:istio_requests_total" + expr: "sum without(instance, namespace, pod) (istio_requests_total)" + + - record: "workload:istio_request_duration_milliseconds_count" + expr: "sum without(instance, namespace, pod) (istio_request_duration_milliseconds_count)" + - record: "workload:istio_request_duration_milliseconds_sum" + expr: "sum without(instance, namespace, pod) (istio_request_duration_milliseconds_sum)" + - record: "workload:istio_request_duration_milliseconds_bucket" + expr: "sum without(instance, namespace, pod) (istio_request_duration_milliseconds_bucket)" + + - record: "workload:istio_request_bytes_count" + expr: "sum without(instance, namespace, pod) (istio_request_bytes_count)" + - record: "workload:istio_request_bytes_sum" + expr: "sum without(instance, namespace, pod) (istio_request_bytes_sum)" + - record: "workload:istio_request_bytes_bucket" + expr: "sum without(instance, namespace, pod) (istio_request_bytes_bucket)" + + - record: "workload:istio_response_bytes_count" + expr: "sum without(instance, namespace, pod) (istio_response_bytes_count)" + - record: "workload:istio_response_bytes_sum" + expr: "sum without(instance, namespace, pod) (istio_response_bytes_sum)" + - record: "workload:istio_response_bytes_bucket" + expr: "sum without(instance, namespace, pod) (istio_response_bytes_bucket)" + + - record: "workload:istio_tcp_connections_opened_total" + expr: "sum without(instance, namespace, pod) (istio_tcp_connections_opened_total)" + - record: "workload:istio_tcp_connections_closed_total" + expr: "sum without(instance, namespace, pod) (istio_tcp_connections_closed_total)" + + - record: "workload:istio_tcp_sent_bytes_total_count" + expr: "sum without(instance, namespace, pod) (istio_tcp_sent_bytes_total_count)" + - record: "workload:istio_tcp_sent_bytes_total_sum" + expr: "sum without(instance, namespace, pod) (istio_tcp_sent_bytes_total_sum)" + - record: "workload:istio_tcp_sent_bytes_total_bucket" + expr: "sum without(instance, namespace, pod) (istio_tcp_sent_bytes_total_bucket)" + + - record: "workload:istio_tcp_received_bytes_total_count" + expr: "sum without(instance, namespace, pod) (istio_tcp_received_bytes_total_count)" + - record: "workload:istio_tcp_received_bytes_total_sum" + expr: "sum without(instance, namespace, pod) (istio_tcp_received_bytes_total_sum)" + - record: "workload:istio_tcp_received_bytes_total_bucket" + expr: "sum without(instance, namespace, pod) (istio_tcp_received_bytes_total_bucket)" + + - name: "istio.alerts-rules" + interval: 5s + rules: + - alert: IstioGlobalRequestRateHigh + annotations: + message: 'Istio global request rate is unusually high during the last 5m (current value: *{{ printf "%2.0f%%" $value }}*). The amount of traffic being generated inside the service mesh is higher than normal' + expr: > + round(sum(irate(istio_requests_total{reporter="destination"}[5m])), 0.001) > 1200 + for: 5m + labels: + severity: warning + + - alert: IstioGlobalRequestRateLow + annotations: + message: 'Istio global request rate is unusually low during the last 5m (current value: *{{ printf "%2.0f%%" $value }}*). The amount of traffic being generated inside the service mesh has dropped below usual levels' + expr: > + round(sum(irate(istio_requests_total{reporter="destination"}[5m])), 0.001) < 300 + for: 5m + labels: + severity: warning + + - alert: IstioGlobalHTTP5xxRateHigh + annotations: + message: 'Istio global HTTP 5xx rate is too high in last 5m (current value: *{{ printf "%2.0f%%" $value }}*). The HTTP 5xx errors within the service mesh is unusually high' + expr: > + sum(irate(istio_requests_total{reporter="destination", response_code=~"5.*"}[5m])) / sum(irate(istio_requests_total{reporter="destination"}[5m])) > 0.01 + for: 5m + labels: + severity: warning + + - alert: IstioGatewayOutgoingSuccessLow + annotations: + message: 'Istio Gateway success to outbound destinations is too low in last 5m (current value: *{{ printf "%2.0f%%" $value }}*). Inbound traffic may be affected' + expr: > + sum(irate(istio_requests_total{reporter="source", source_workload="istio-ingressgateway",source_workload_namespace="istio-system", connection_security_policy!="mutual_tls",response_code!~"5.*"}[5m])) / sum(irate(istio_requests_total{reporter="source", source_workload="istio-ingressgateway",source_workload_namespace="istio-system", connection_security_policy!="mutual_tls"}[5m])) < 0.995 + for: 5m + labels: + severity: warning + + - alert: IstioCustomGatewayOutgoingSuccessLow + annotations: + message: 'Istio Custom Gateway success to outbound destinations is too low in last 5m (current value: *{{ printf "%2.0f%%" $value }}*). Inbound traffic may be affected' + expr: > + sum(irate(istio_requests_total{reporter="source", source_workload="gateway",source_workload_namespace="istio-system", connection_security_policy!="mutual_tls",response_code!~"5.*"}[5m])) / sum(irate(istio_requests_total{reporter="source", source_workload="istio-ingressgateway",source_workload_namespace="istio-system", connection_security_policy!="mutual_tls"}[5m])) < 0.995 + for: 5m + labels: + severity: warning diff --git a/scenarios/istio-production/istio-prometheus-sa.yaml b/scenarios/istio-production/istio-prometheus-sa.yaml new file mode 100644 index 0000000..9195265 --- /dev/null +++ b/scenarios/istio-production/istio-prometheus-sa.yaml @@ -0,0 +1,6 @@ +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: istio-prometheus + namespace: istio-system diff --git a/scenarios/istio-production/istio-prometheus-service.yaml b/scenarios/istio-production/istio-prometheus-service.yaml new file mode 100644 index 0000000..8217fd7 --- /dev/null +++ b/scenarios/istio-production/istio-prometheus-service.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: prometheus + namespace: istio-system + labels: + app: prometheus + tier: istio +spec: + ports: + - name: web + port: 9090 + protocol: TCP + targetPort: 9090 + selector: + app: prometheus + sessionAffinity: None + type: ClusterIP diff --git a/scenarios/istio-production/istio-prometheus-servicemonitor1.yaml b/scenarios/istio-production/istio-prometheus-servicemonitor1.yaml new file mode 100644 index 0000000..21a7841 --- /dev/null +++ b/scenarios/istio-production/istio-prometheus-servicemonitor1.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: istio-mesh-monitor + namespace: istio-system + labels: + monitoring: istio-mesh + tier: istio +spec: + selector: + matchExpressions: + - {key: istio, operator: In, values: [mixer]} + namespaceSelector: + matchNames: + - istio-system + endpoints: + - port: prometheus + interval: 15s diff --git a/scenarios/istio-production/istio-prometheus-servicemonitor2.yaml b/scenarios/istio-production/istio-prometheus-servicemonitor2.yaml new file mode 100644 index 0000000..56338d4 --- /dev/null +++ b/scenarios/istio-production/istio-prometheus-servicemonitor2.yaml @@ -0,0 +1,21 @@ +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: istio-component-monitor + namespace: istio-system + labels: + monitoring: istio-components + tier: istio +spec: + jobLabel: istio + selector: + matchExpressions: + - {key: istio, operator: In, values: [mixer,pilot,galley,citadel,sidecar-injector]} + namespaceSelector: + any: true + endpoints: + - port: http-monitoring + interval: 15s + - port: http-policy-monitoring + interval: 15s diff --git a/scenarios/istio-production/istio-prometheus-servicemonitor3.yaml b/scenarios/istio-production/istio-prometheus-servicemonitor3.yaml new file mode 100644 index 0000000..8620541 --- /dev/null +++ b/scenarios/istio-production/istio-prometheus-servicemonitor3.yaml @@ -0,0 +1,32 @@ +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: envoy-stats-monitor + namespace: istio-system + labels: + monitoring: istio-proxies + tier: istio +spec: + selector: + matchExpressions: + - {key: istio-prometheus-ignore, operator: DoesNotExist} + namespaceSelector: + any: true + jobLabel: envoy-stats + endpoints: + - path: /stats/prometheus + targetPort: 15090 + interval: 15s + relabelings: + - sourceLabels: [__meta_kubernetes_pod_container_port_name] + action: keep + regex: '.*-envoy-prom' + - action: labeldrop + regex: "__meta_kubernetes_pod_label_(.+)" + - sourceLabels: [__meta_kubernetes_namespace] + action: replace + targetLabel: namespace + - sourceLabels: [__meta_kubernetes_pod_name] + action: replace + targetLabel: pod_name diff --git a/scenarios/istio-production/istio-prometheus.yaml b/scenarios/istio-production/istio-prometheus.yaml index 0cb2b10..04c6901 100644 --- a/scenarios/istio-production/istio-prometheus.yaml +++ b/scenarios/istio-production/istio-prometheus.yaml @@ -1,23 +1,4 @@ --- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: istio-prometheus - namespace: istio-system ---- -apiVersion: rbac.authorization.k8s.io/v1beta1 -kind: ClusterRoleBinding -metadata: - name: istio-prometheus -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: kube-prometheus-stack-prometheus -subjects: - - kind: ServiceAccount - name: istio-prometheus - namespace: istio-system ---- apiVersion: monitoring.coreos.com/v1 kind: Prometheus metadata: @@ -51,199 +32,3 @@ spec: serviceMonitorSelector: matchLabels: tier: istio ---- -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: istio-mesh-monitor - namespace: istio-system - labels: - monitoring: istio-mesh - tier: istio -spec: - selector: - matchExpressions: - - {key: istio, operator: In, values: [mixer]} - namespaceSelector: - matchNames: - - istio-system - endpoints: - - port: prometheus - interval: 15s ---- -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: istio-component-monitor - namespace: istio-system - labels: - monitoring: istio-components - tier: istio -spec: - jobLabel: istio - selector: - matchExpressions: - - {key: istio, operator: In, values: [mixer,pilot,galley,citadel,sidecar-injector]} - namespaceSelector: - any: true - endpoints: - - port: http-monitoring - interval: 15s - - port: http-policy-monitoring - interval: 15s ---- -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: envoy-stats-monitor - namespace: istio-system - labels: - monitoring: istio-proxies - tier: istio -spec: - selector: - matchExpressions: - - {key: istio-prometheus-ignore, operator: DoesNotExist} - namespaceSelector: - any: true - jobLabel: envoy-stats - endpoints: - - path: /stats/prometheus - targetPort: 15090 - interval: 15s - relabelings: - - sourceLabels: [__meta_kubernetes_pod_container_port_name] - action: keep - regex: '.*-envoy-prom' - - action: labeldrop - regex: "__meta_kubernetes_pod_label_(.+)" - - sourceLabels: [__meta_kubernetes_namespace] - action: replace - targetLabel: namespace - - sourceLabels: [__meta_kubernetes_pod_name] - action: replace - targetLabel: pod_name ---- -apiVersion: v1 -kind: Service -metadata: - name: prometheus - namespace: istio-system - labels: - app: prometheus - tier: istio -spec: - ports: - - name: web - port: 9090 - protocol: TCP - targetPort: 9090 - selector: - app: prometheus - sessionAffinity: None - type: ClusterIP ---- -apiVersion: monitoring.coreos.com/v1 -kind: PrometheusRule -metadata: - name: istio-metrics-aggregation - namespace: istio-system - labels: - app.kubernetes.io/name: istio-prometheus - app: prometheus - tier: istio -spec: - groups: - - name: "istio.metricsAggregation-rules" - interval: 5s - rules: - - record: "workload:istio_requests_total" - expr: "sum without(instance, namespace, pod) (istio_requests_total)" - - - record: "workload:istio_request_duration_milliseconds_count" - expr: "sum without(instance, namespace, pod) (istio_request_duration_milliseconds_count)" - - record: "workload:istio_request_duration_milliseconds_sum" - expr: "sum without(instance, namespace, pod) (istio_request_duration_milliseconds_sum)" - - record: "workload:istio_request_duration_milliseconds_bucket" - expr: "sum without(instance, namespace, pod) (istio_request_duration_milliseconds_bucket)" - - - record: "workload:istio_request_bytes_count" - expr: "sum without(instance, namespace, pod) (istio_request_bytes_count)" - - record: "workload:istio_request_bytes_sum" - expr: "sum without(instance, namespace, pod) (istio_request_bytes_sum)" - - record: "workload:istio_request_bytes_bucket" - expr: "sum without(instance, namespace, pod) (istio_request_bytes_bucket)" - - - record: "workload:istio_response_bytes_count" - expr: "sum without(instance, namespace, pod) (istio_response_bytes_count)" - - record: "workload:istio_response_bytes_sum" - expr: "sum without(instance, namespace, pod) (istio_response_bytes_sum)" - - record: "workload:istio_response_bytes_bucket" - expr: "sum without(instance, namespace, pod) (istio_response_bytes_bucket)" - - - record: "workload:istio_tcp_connections_opened_total" - expr: "sum without(instance, namespace, pod) (istio_tcp_connections_opened_total)" - - record: "workload:istio_tcp_connections_closed_total" - expr: "sum without(instance, namespace, pod) (istio_tcp_connections_closed_total)" - - - record: "workload:istio_tcp_sent_bytes_total_count" - expr: "sum without(instance, namespace, pod) (istio_tcp_sent_bytes_total_count)" - - record: "workload:istio_tcp_sent_bytes_total_sum" - expr: "sum without(instance, namespace, pod) (istio_tcp_sent_bytes_total_sum)" - - record: "workload:istio_tcp_sent_bytes_total_bucket" - expr: "sum without(instance, namespace, pod) (istio_tcp_sent_bytes_total_bucket)" - - - record: "workload:istio_tcp_received_bytes_total_count" - expr: "sum without(instance, namespace, pod) (istio_tcp_received_bytes_total_count)" - - record: "workload:istio_tcp_received_bytes_total_sum" - expr: "sum without(instance, namespace, pod) (istio_tcp_received_bytes_total_sum)" - - record: "workload:istio_tcp_received_bytes_total_bucket" - expr: "sum without(instance, namespace, pod) (istio_tcp_received_bytes_total_bucket)" - - - name: "istio.alerts-rules" - interval: 5s - rules: - - alert: IstioGlobalRequestRateHigh - annotations: - message: 'Istio global request rate is unusually high during the last 5m (current value: *{{ printf "%2.0f%%" $value }}*). The amount of traffic being generated inside the service mesh is higher than normal' - expr: > - round(sum(irate(istio_requests_total{reporter="destination"}[5m])), 0.001) > 1200 - for: 5m - labels: - severity: warning - - - alert: IstioGlobalRequestRateLow - annotations: - message: 'Istio global request rate is unusually low during the last 5m (current value: *{{ printf "%2.0f%%" $value }}*). The amount of traffic being generated inside the service mesh has dropped below usual levels' - expr: > - round(sum(irate(istio_requests_total{reporter="destination"}[5m])), 0.001) < 300 - for: 5m - labels: - severity: warning - - - alert: IstioGlobalHTTP5xxRateHigh - annotations: - message: 'Istio global HTTP 5xx rate is too high in last 5m (current value: *{{ printf "%2.0f%%" $value }}*). The HTTP 5xx errors within the service mesh is unusually high' - expr: > - sum(irate(istio_requests_total{reporter="destination", response_code=~"5.*"}[5m])) / sum(irate(istio_requests_total{reporter="destination"}[5m])) > 0.01 - for: 5m - labels: - severity: warning - - - alert: IstioGatewayOutgoingSuccessLow - annotations: - message: 'Istio Gateway success to outbound destinations is too low in last 5m (current value: *{{ printf "%2.0f%%" $value }}*). Inbound traffic may be affected' - expr: > - sum(irate(istio_requests_total{reporter="source", source_workload="istio-ingressgateway",source_workload_namespace="istio-system", connection_security_policy!="mutual_tls",response_code!~"5.*"}[5m])) / sum(irate(istio_requests_total{reporter="source", source_workload="istio-ingressgateway",source_workload_namespace="istio-system", connection_security_policy!="mutual_tls"}[5m])) < 0.995 - for: 5m - labels: - severity: warning - - - alert: IstioCustomGatewayOutgoingSuccessLow - annotations: - message: 'Istio Custom Gateway success to outbound destinations is too low in last 5m (current value: *{{ printf "%2.0f%%" $value }}*). Inbound traffic may be affected' - expr: > - sum(irate(istio_requests_total{reporter="source", source_workload="gateway",source_workload_namespace="istio-system", connection_security_policy!="mutual_tls",response_code!~"5.*"}[5m])) / sum(irate(istio_requests_total{reporter="source", source_workload="istio-ingressgateway",source_workload_namespace="istio-system", connection_security_policy!="mutual_tls"}[5m])) < 0.995 - for: 5m - labels: - severity: warning diff --git a/scenarios/istio-production/kustomization.yaml b/scenarios/istio-production/kustomization.yaml index cec30fc..754180c 100644 --- a/scenarios/istio-production/kustomization.yaml +++ b/scenarios/istio-production/kustomization.yaml @@ -11,14 +11,23 @@ bases: - ../../base/bookinfo/ resources: - gateway.yaml +- istio-prometheus-sa.yaml +- istio-prometheus-crb.yaml - istio-prometheus.yaml +- istio-prometheus-servicemonitor1.yaml +- istio-prometheus-servicemonitor2.yaml +- istio-prometheus-servicemonitor3.yaml +- istio-prometheus-service.yaml +- istio-prometheus-rules.yaml - prometheus-istio-federation.yaml - grafana-vs.yaml - prometheus-vs.yaml - istio-prometheus-vs.yaml - alertmanager-vs.yaml -- flux-prometheus.yaml -- helm-operator-prometheus.yaml +- flux-prometheus-servicemonitor.yaml +- flux-prometheus-rules.yaml +- helm-operator-prometheus-servicemonitor.yaml +- helm-operator-prometheus-rules.yaml - tracing-vs.yaml - kiali-vs.yaml patchesStrategicMerge: diff --git a/tools/semtag b/tools/semtag deleted file mode 100755 index 5bbe2a3..0000000 --- a/tools/semtag +++ /dev/null @@ -1,627 +0,0 @@ -#!/usr/bin/env bash -# -# Thanks to @pnikosis for this script https://github.com/pnikosis/semtag -# -PROG=semtag -PROG_VERSION="v0.1.0" - -SEMVER_REGEX="^v?(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(\-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$" -IDENTIFIER_REGEX="^\-([0-9A-Za-z-]+)\.([0-9A-Za-z-]+)*$" - -# Global variables -FIRST_VERSION="v0.0.0" -finalversion=$FIRST_VERSION -lastversion=$FIRST_VERSION -hasversiontag="false" -scope="patch" -displayonly="false" -forcetag="false" -forcedversion= -versionname= -identifier= - -HELP="\ -Usage: - $PROG - $PROG getlast - $PROG getfinal - $PROG (final|alpha|beta|candidate) [-s (major|minor|patch|auto) | -o] - $PROG --help - $PROG --version -Options: - -s The scope that must be increased, can be major, minor or patch. - The resulting version will match X.Y.Z(-PRERELEASE)(+BUILD) - where X, Y and Z are positive integers, PRERELEASE is an optionnal - string composed of alphanumeric characters describing if the build is - a release candidate, alpha or beta version, with a number. - BUILD is also an optional string composed of alphanumeric - characters and hyphens. - Setting the scope as 'auto', the script will chose the scope between - 'minor' and 'patch', depending on the amount of lines added (<10% will - choose patch). - -v Specifies manually the version to be tagged, must be a valid semantic version - in the format X.Y.Z where X, Y and Z are positive integers. - -o Output the version only, shows the bumped version, but doesn't tag. - -f Forces to tag, even if there are unstaged or uncommited changes. -Commands: - --help Print this help message. - --version Prints the program's version. - get Returns both current final version and last tagged version. - getlast Returns the latest tagged version. - getfinal Returns the latest tagged final version. - getcurrent Returns the current version, based on the latest one, if there are uncommited or - unstaged changes, they will be reflected in the version, adding the number of - pending commits, current branch and commit hash. - final Tags the current build as a final version, this only can be done on the main branch. - candidate Tags the current build as a release candidate, the tag will contain all - the commits from the last final version. - alpha Tags the current build as an alpha version, the tag will contain all - the commits from the last final version. - beta Tags the current build as a beta version, the tag will contain all - the commits from the last final version." - -# Commands and options -ACTION="getlast" -ACTION="$1" -shift - -# We get the parameters -while getopts "v:s:of" opt; do - case $opt in - v) - forcedversion="$OPTARG" - ;; - s) - scope="$OPTARG" - ;; - o) - displayonly="true" - ;; - f) - forcetag="true" - ;; - \?) - echo "Invalid option: -$OPTARG" >&2 - exit 1 - ;; - :) - echo "Option -$OPTARG requires an argument." >&2 - exit 1 - ;; - esac -done - -# Gets a string with the version and returns an array of maximum size of 5 with all the parts of the sematinc version -# $1 The string containing the version in semantic format -# $2 The variable to store the result array: -# position 0: major number -# position 1: minor number -# position 2: patch number -# position 3: identifier (or prerelease identifier) -# position 4: build info -function explode_version { - local __version=$1 - local __result=$2 - if [[ $__version =~ $SEMVER_REGEX ]] ; then - local __major=${BASH_REMATCH[1]} - local __minor=${BASH_REMATCH[2]} - local __patch=${BASH_REMATCH[3]} - local __prere=${BASH_REMATCH[4]} - local __build=${BASH_REMATCH[5]} - eval "$__result=(\"$__major\" \"$__minor\" \"$__patch\" \"$__prere\" \"$__build\")" - else - eval "$__result=" - fi -} - -# Compare two versions and returns -1, 0 or 1 -# $1 The first version to compare -# $2 The second version to compare -# $3 The variable where to store the result -function compare_versions { - local __first - local __second - explode_version $1 __first - explode_version $2 __second - local lv=$3 - - # Compares MAJOR, MINOR and PATCH - for i in 0 1 2; do - local __numberfirst=${__first[$i]} - local __numbersecond=${__second[$i]} - case $(($__numberfirst - $__numbersecond)) in - 0) - ;; - -[0-9]*) - eval "$lv=-1" - return 0 - ;; - [0-9]*) - eval "$lv=1" - return 0 - ;; - esac - done - - # Identifiers should compare with the ASCII order. - local __identifierfirst=${__first[3]} - local __identifiersecond=${__second[3]} - if [[ -n "$__identifierfirst" ]] && [[ -n "$__identifiersecond" ]]; then - if [[ "$__identifierfirst" > "$__identifiersecond" ]]; then - eval "$lv=1" - return 0 - elif [[ "$__identifierfirst" < "$__identifiersecond" ]]; then - eval "$lv=-1" - return 0 - fi - elif [[ -z "$__identifierfirst" ]] && [[ -n "$__identifiersecond" ]]; then - eval "$lv=1" - return 0 - elif [[ -n "$__identifierfirst" ]] && [[ -z "$__identifiersecond" ]]; then - eval "$lv=-1" - return 0 - fi - - eval "$lv=0" -} - -# Returns the last version of two -# $1 The first version to compare -# $2 The second version to compare -# $3 The variable where to store the last one -function get_latest_of_two { - local __first=$1 - local __second=$2 - local __result - local __latest=$3 - compare_versions $__first $__second __result - case $__result in - 0) - eval "$__latest=$__second" - ;; - -1) - eval "$__latest=$__second" - ;; - 1) - eval "$__latest=$__first" - ;; - esac -} - -# Assigns a 2 size array with the identifier, having the identifier at pos 0, and the number in pos 1 -# $1 The identifier in the format -id.# -# $2 The vferiable where to store the 2 size array -function explode_identifier { - local __identifier=$1 - local __result=$2 - if [[ $__identifier =~ $IDENTIFIER_REGEX ]] ; then - local __id=${BASH_REMATCH[1]} - local __number=${BASH_REMATCH[2]} - if [[ -z "$__number" ]]; then - __number=1 - fi - eval "$__result=(\"$__id\" \"$__number\")" - else - eval "$__result=" - fi -} - -# Gets a list of tags and assigns the base and latest versions -# Receives an array with the tags containing the versions -# Assigns to the global variables finalversion and lastversion the final version and the latest version -function get_latest { - local __taglist=("$@") - local __tagsnumber=${#__taglist[@]} - local __current - case $__tagsnumber in - 0) - finalversion=$FIRST_VERSION - lastversion=$FIRST_VERSION - ;; - 1) - __current=${__taglist[0]} - explode_version $__current ver - if [ -n "$ver" ]; then - if [ -n "${ver[3]}" ]; then - finalversion=$FIRST_VERSION - else - finalversion=$__current - fi - lastversion=$__current - else - finalversion=$FIRST_VERSION - lastversion=$FIRST_VERSION - fi - ;; - *) - local __lastpos=$(($__tagsnumber-1)) - for i in $(seq 0 $__lastpos) - do - __current=${__taglist[i]} - explode_version ${__taglist[i]} ver - if [ -n "$ver" ]; then - if [ -z "${ver[3]}" ]; then - get_latest_of_two $finalversion $__current finalversion - get_latest_of_two $lastversion $finalversion lastversion - else - get_latest_of_two $lastversion $__current lastversion - fi - fi - done - ;; - esac - - if git rev-parse -q --verify "refs/tags/$lastversion" >/dev/null; then - hasversiontag="true" - else - hasversiontag="false" - fi -} - -# Gets the next version given the provided scope -# $1 The version that is going to be bumped -# $2 The scope to bump -# $3 The variable where to stoer the result -function get_next_version { - local __exploded - local __fromversion=$1 - local __scope=$2 - local __result=$3 - explode_version $__fromversion __exploded - case $__scope in - major) - __exploded[0]=$((${__exploded[0]}+1)) - __exploded[1]=0 - __exploded[2]=0 - ;; - minor) - __exploded[1]=$((${__exploded[1]}+1)) - __exploded[2]=0 - ;; - patch) - __exploded[2]=$((${__exploded[2]}+1)) - ;; - esac - - eval "$__result=v${__exploded[0]}.${__exploded[1]}.${__exploded[2]}" -} - -function bump_version { - ## First we try to get the next version based on the existing last one - if [ "$scope" == "auto" ]; then - get_scope_auto scope - fi - - local __candidatefromlast=$FIRST_VERSION - local __explodedlast - explode_version $lastversion __explodedlast - if [[ -n "${__explodedlast[3]}" ]]; then - # Last version is not final - local __idlast - explode_identifier ${__explodedlast[3]} __idlast - - # We get the last, given the desired id based on the scope - __candidatefromlast="v${__explodedlast[0]}.${__explodedlast[1]}.${__explodedlast[2]}" - if [[ -n "$identifier" ]]; then - local __nextid="$identifier.1" - if [ "$identifier" == "${__idlast[0]}" ]; then - # We target the same identifier as the last so we increase one - __nextid="$identifier.$(( ${__idlast[1]}+1 ))" - __candidatefromlast="$__candidatefromlast-$__nextid" - else - # Different identifiers, we make sure we are assigning a higher identifier, if not, we increase the version - __candidatefromlast="$__candidatefromlast-$__nextid" - local __comparedwithlast - compare_versions $__candidatefromlast $lastversion __comparedwithlast - if [ "$__comparedwithlast" == -1 ]; then - get_next_version $__candidatefromlast $scope __candidatefromlast - __candidatefromlast="$__candidatefromlast-$__nextid" - fi - fi - fi - fi - - # Then we try to get the version based on the latest final one - local __candidatefromfinal=$FIRST_VERSION - get_next_version $finalversion $scope __candidatefromfinal - if [[ -n "$identifier" ]]; then - __candidatefromfinal="$__candidatefromfinal-$identifier.1" - fi - - # Finally we compare both candidates - local __resultversion - local __result - compare_versions $__candidatefromlast $__candidatefromfinal __result - case $__result in - 0) - __resultversion=$__candidatefromlast - ;; - -1) - __resultversion="$__candidatefromfinal" - ;; - 1) - __resultversion=$__candidatefromlast - ;; - esac - - eval "$1=$__resultversion" -} - -function increase_version { - local __version= - - if [ -z $forcedversion ]; then - bump_version __version - else - if [[ $forcedversion =~ $SEMVER_REGEX ]] ; then - compare_versions $forcedversion $lastversion __result - if [ $__result -le 0 ]; then - echo "Version can't be lower than last version: $lastversion" - exit 1 - fi - else - echo "Non valid version to bump" - exit 1 - fi - __version=$forcedversion - fi - - if [ "$displayonly" == "true" ]; then - echo "$__version" - else - if [ "$forcetag" == "false" ]; then - check_git_dirty_status - fi - local __commitlist - if [ "$finalversion" == "$FIRST_VERSION" ] || [ "$hasversiontag" != "true" ]; then - __commitlist="$(git log --pretty=oneline | cat)" - else - __commitlist="$(git log --pretty=oneline $finalversion... | cat)" - fi - - # If we are forcing a bump, we add bump to the commit list - if [[ -z $__commitlist && "$forcetag" == "true" ]]; then - __commitlist="bump" - fi - - if [[ -z $__commitlist ]]; then - echo "No commits since the last final version, not bumping version" - else - if [[ -z $versionname ]]; then - versionname=$(date -u +"%Y-%m-%dT%H:%M:%SZ") - fi - local __message="$versionname -$__commitlist" - - # We check we have info on the user - local __username=$(git config user.name) - if [ -z "$__username" ]; then - __username=$(id -u -n) - git config user.name $__username - fi - local __useremail=$(git config user.email) - if [ -z "$__useremail" ]; then - __useremail=$(hostname) - git config user.email "$__username@$__useremail" - fi - - git tag -a $__version -m "$__message" - - # If we have a remote, we push there - local __remotes=$(git remote) - if [[ -n $__remotes ]]; then - for __remote in $__remotes; do - git push $__remote $__version > /dev/null - if [ $? -eq 0 ]; then - echo "$__version pushed to $__remote" - else - echo "Error pushing the tag $__version to $__remote" - exit 1 - fi - done - else - echo "$__version" - fi - fi - fi -} - -function check_git_dirty_status { - local __repostatus= - get_work_tree_status __repostatus - - if [ "$__repostatus" == "uncommitted" ]; then - echo "ERROR: You have uncommitted changes" - git status --porcelain - exit 1 - fi - - if [ "$__repostatus" == "unstaged" ]; then - echo "ERROR: You have unstaged changes" - git status --porcelain - exit 1 - fi -} - -# Get the total amount of lines of code in the repo -function get_total_lines { - local __empty_id="$(git hash-object -t tree /dev/null)" - local __changes="$(git diff --numstat $__empty_id | cat)" - local __added_deleted=$1 - get_changed_lines "$__changes" $__added_deleted -} - -# Get the total amount of lines of code since the provided tag -function get_sincetag_lines { - local __sincetag=$1 - local __changes="$(git diff --numstat $__sincetag | cat)" - local __added_deleted=$2 - get_changed_lines "$__changes" $__added_deleted -} - -function get_changed_lines { - local __changes_numstat=$1 - local __result=$2 - IFS=$'\n' read -rd '' -a __changes_array <<<"$__changes_numstat" - local __diff_regex="^([0-9]+)[[:space:]]+([0-9]+)[[:space:]]+.+$" - - local __total_added=0 - local __total_deleted=0 - for i in "${__changes_array[@]}" - do - if [[ $i =~ $__diff_regex ]] ; then - local __added=${BASH_REMATCH[1]} - local __deleted=${BASH_REMATCH[2]} - __total_added=$(( $__total_added+$__added )) - __total_deleted=$(( $__total_deleted+$__deleted )) - fi - done - eval "$2=( $__total_added $__total_deleted )" -} - -function get_scope_auto { - local __verbose=$2 - local __total=0 - local __since=0 - local __scope= - - get_total_lines __total - get_sincetag_lines $finalversion __since - - local __percentage=0 - if [ "$__total" != "0" ]; then - local __percentage=$(( 100*$__since/$__total )) - if [ $__percentage -gt "10" ]; then - __scope="minor" - else - __scope="patch" - fi - fi - - eval "$1=$__scope" - if [[ -n "$__verbose" ]]; then - echo "[Auto Scope] Percentage of lines changed: $__percentage" - echo "[Auto Scope] : $__scope" - fi -} - -function get_work_tree_status { - # Update the index - git update-index -q --ignore-submodules --refresh > /dev/null - eval "$1=" - - if ! git diff-files --quiet --ignore-submodules -- > /dev/null - then - eval "$1=unstaged" - fi - - if ! git diff-index --cached --quiet HEAD --ignore-submodules -- > /dev/null - then - eval "$1=uncommitted" - fi -} - -function get_current { - if [ "$hasversiontag" == "true" ]; then - local __commitcount="$(git rev-list $lastversion.. --count)" - else - local __commitcount="$(git rev-list --count HEAD)" - fi - local __status= - get_work_tree_status __status - - if [ "$__commitcount" == "0" ] && [ -z "$__status" ]; then - eval "$1=$lastversion" - else - local __buildinfo="$(git rev-parse --short HEAD)" - local __currentbranch="$(git rev-parse --abbrev-ref HEAD)" - if [ "$__currentbranch" != "main" ]; then - __buildinfo="$__currentbranch.$__buildinfo" - fi - - local __suffix= - if [ "$__commitcount" != "0" ]; then - if [ -n "$__suffix" ]; then - __suffix="$__suffix." - fi - __suffix="$__suffix$__commitcount" - fi - if [ -n "$__status" ]; then - if [ -n "$__suffix" ]; then - __suffix="$__suffix." - fi - __suffix="$__suffix$__status" - fi - - __suffix="$__suffix+$__buildinfo" - if [ "$lastversion" == "$finalversion" ]; then - scope="patch" - identifier= - local __bumped= - bump_version __bumped - eval "$1=$__bumped-dev.$__suffix" - else - eval "$1=$lastversion.$__suffix" - fi - fi -} - -function init { - git fetch > /dev/null - TAGS="$(git tag)" - IFS=$'\n' read -rd '' -a TAG_ARRAY <<<"$TAGS" - - get_latest ${TAG_ARRAY[@]} - currentbranch="$(git rev-parse --abbrev-ref HEAD)" -} - -case $ACTION in - --help) - echo -e "$HELP" - ;; - --version) - echo -e "${PROG}: $PROG_VERSION" - ;; - final) - init - diff=$(git diff main | cat) - if [ "$forcetag" == "false" ]; then - if [ -n "$diff" ]; then - echo "ERROR: Branch must be updated with main for final versions" - exit 1 - fi - fi - increase_version - ;; - alpha|beta) - init - identifier="$ACTION" - increase_version - ;; - candidate) - init - identifier="rc" - increase_version - ;; - getlast) - init - echo "$lastversion" - ;; - getfinal) - init - echo "$finalversion" - ;; - getcurrent) - init - get_current current - echo "$current" - ;; - get) - init - echo "Current final version: $finalversion" - echo "Last tagged version: $lastversion" - ;; - *) - echo "'$ACTION' is not a valid command, see --help for available commands." - ;; -esac From 22b4bf8f941d60cf31efd4a2748d1fd12b7b5e23 Mon Sep 17 00:00:00 2001 From: bcochofel Date: Sat, 23 Jan 2021 11:54:16 +0000 Subject: [PATCH 2/4] Apply automatic changes --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..953e208 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,20 @@ + +## [Unreleased] + + + +## [0.1.0] - 2021-01-23 +### Feat +- first release + + + +## flux-sync - 2021-01-23 +### Pull Requests +- Merge pull request [#71](https://github.com/bcochofel/k8s-gitops-istio-demo/issues/71) from bcochofel/kiali-cr +- Merge pull request [#2](https://github.com/bcochofel/k8s-gitops-istio-demo/issues/2) from bcochofel/kustomize-base +- Merge pull request [#1](https://github.com/bcochofel/k8s-gitops-istio-demo/issues/1) from bcochofel/bootstrap-repo + + +[Unreleased]: https://github.com/bcochofel/k8s-gitops-istio-demo/compare/0.1.0...HEAD +[0.1.0]: https://github.com/bcochofel/k8s-gitops-istio-demo/compare/flux-sync...0.1.0 From 4ca7bb362754b62b099e4f256688027958a96f7e Mon Sep 17 00:00:00 2001 From: Bruno Cochofel Date: Sat, 23 Jan 2021 11:58:21 +0000 Subject: [PATCH 3/4] fix: istio-demo scenario --- scenarios/istio-demo/kustomization.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scenarios/istio-demo/kustomization.yaml b/scenarios/istio-demo/kustomization.yaml index 8f444e3..4285fe7 100644 --- a/scenarios/istio-demo/kustomization.yaml +++ b/scenarios/istio-demo/kustomization.yaml @@ -8,8 +8,8 @@ bases: patchesStrategicMerge: - metallb-patch.yaml - istio-operator-patch.yaml -resources: -- https://raw.githubusercontent.com/istio/istio/release-1.8/samples/addons/kiali.yaml -- https://raw.githubusercontent.com/istio/istio/release-1.8/samples/addons/grafana.yaml -- https://raw.githubusercontent.com/istio/istio/release-1.8/samples/addons/prometheus.yaml -- https://raw.githubusercontent.com/istio/istio/release-1.8/samples/addons/jaeger.yaml +#resources: +#- https://raw.githubusercontent.com/istio/istio/release-1.8/samples/addons/kiali.yaml +#- https://raw.githubusercontent.com/istio/istio/release-1.8/samples/addons/grafana.yaml +#- https://raw.githubusercontent.com/istio/istio/release-1.8/samples/addons/prometheus.yaml +#- https://raw.githubusercontent.com/istio/istio/release-1.8/samples/addons/jaeger.yaml From f43d0229e58bb3e9e2366a5664220cf596544eb0 Mon Sep 17 00:00:00 2001 From: bcochofel Date: Sat, 23 Jan 2021 11:59:35 +0000 Subject: [PATCH 4/4] Apply automatic changes --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 953e208..b44b905 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ ### Feat - first release +### Fix +- istio-demo scenario + ## flux-sync - 2021-01-23