diff --git a/.env b/.env index b7b65b8f..53204db2 100755 --- a/.env +++ b/.env @@ -40,7 +40,7 @@ BACKEND_HOSTNAME=shuffle-backend BACKEND_PORT=5001 FRONTEND_PORT=3001 FRONTEND_PORT_HTTPS=3443 -AUTH_FOR_ORBORUS = +AUTH_FOR_ORBORUS= # CHANGE THIS IF YOU WANT GOOD LOCAL EXECUTIONS: OUTER_HOSTNAME=shuffle-backend diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..5990d9c6 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + - package-ecosystem: "" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/install-guide.md b/.github/install-guide.md index b3282ce1..5233ff47 100755 --- a/.github/install-guide.md +++ b/.github/install-guide.md @@ -35,7 +35,7 @@ sudo swapoff -a # Disable swap 4. Run docker-compose. ```bash -docker compose up -d +docker-compose up -d ``` 5. Recommended for Opensearch to work well diff --git a/.github/workflows/dockerbuild.yaml b/.github/workflows/dockerbuild.yaml index a04e87bd..0e957b28 100644 --- a/.github/workflows/dockerbuild.yaml +++ b/.github/workflows/dockerbuild.yaml @@ -4,7 +4,7 @@ on: workflow_dispatch: push: branches: - - nightly + - main paths: - "**" - "!.github/**" @@ -20,19 +20,19 @@ jobs: include: - app: frontend path: frontend - version: nightly + version: 2.0.1 experimental: true - app: backend path: backend - version: nightly + version: 2.0.1 experimental: true - app: orborus path: functions/onprem/orborus - version: nightly + version: 2.0.1 experimental: true - app: worker path: functions/onprem/worker - version: nightly + version: 2.0.1 experimental: true steps: - name: Checkout diff --git a/.github/workflows/helm-release.yml b/.github/workflows/helm-release.yml new file mode 100644 index 00000000..e365080e --- /dev/null +++ b/.github/workflows/helm-release.yml @@ -0,0 +1,71 @@ +name: Helm Release + +on: + release: + types: [published] + branches: + - main + - nightly + push: + branches: + - nightly + paths: + - "functions/kubernetes/charts/**" + workflow_dispatch: + +permissions: + contents: read + packages: write + +jobs: + main: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install apt dependencies + run: | + curl https://baltocdn.com/helm/signing.asc | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null + sudo apt-get install apt-transport-https -y --no-install-recommends + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/helm.gpg] https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list + sudo apt-get update + sudo apt-get install helm -y --no-install-recommends + + - name: Set versions + id: set_versions + run: | + if [[ ${{ github.event_name }} == 'release' ]]; then + CHART_VERSION="${{ github.event.release.tag_name }}" + APP_VERSION="${{ github.event.release.tag_name }}" + else + CHART_VERSION="0.0.0-nightly-untagged-latest" + APP_VERSION="nightly" + fi + + echo "CHART_VERSION set to ${CHART_VERSION}. Validating..." + + # https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string + SEMVER_REGEX="^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$" + + if echo "${CHART_VERSION}" | grep -Pq "${SEMVER_REGEX}"; then + echo "${CHART_VERSION} is a valid SemVer string"; + else + echo "${CHART_VERSION} is an invalid SemVer string"; + exit 1; + fi + + echo "CHART_VERSION=${CHART_VERSION}" >> $GITHUB_OUTPUT + echo "APP_VERSION=${APP_VERSION}" >> $GITHUB_OUTPUT + + - name: Update helm dependencies + run: helm dependency update ./functions/kubernetes/charts/shuffle + + - name: Package Helm chart + run: helm package ./functions/kubernetes/charts/shuffle --version "${CHART_VERSION}" --app-version="${APP_VERSION}" --destination ./functions/kubernetes/charts + + - name: Login to OCI registry (ghcr.io) + run: helm registry login ghcr.io --username ${{ github.actor }} --password ${{ secrets.GITHUB_TOKEN }} + + - name: Push helm chart + run: helm push ./functions/kubernetes/charts/shuffle-*.tgz oci://ghcr.io/shuffle/shuffle/charts diff --git a/.github/workflows/nightly-release.yaml b/.github/workflows/nightly-release.yaml index 228d8d5a..b66f9559 100644 --- a/.github/workflows/nightly-release.yaml +++ b/.github/workflows/nightly-release.yaml @@ -3,6 +3,7 @@ on: release: types: [published] branches: + - main - nightly jobs: @@ -19,9 +20,6 @@ jobs: - app: backend path: backend experimental: true - - app: app_sdk - path: backend/app_sdk - experimental: true - app: orborus path: functions/onprem/orborus experimental: true diff --git a/.github/workflows/quick-testing.yml b/.github/workflows/quick-testing.yml index 17ac28ac..cf35967a 100644 --- a/.github/workflows/quick-testing.yml +++ b/.github/workflows/quick-testing.yml @@ -5,6 +5,7 @@ on: workflows: ["dockerbuild"] types: - completed + workflow_dispatch: jobs: build: @@ -13,16 +14,21 @@ jobs: matrix: os: [ubuntu-latest] architecture: [x64, arm64] - steps: - name: Checkout code uses: actions/checkout@v2 - + + - name: Install Docker Compose + run: | + sudo apt-get update + sudo apt-get install -y docker-compose + docker-compose --version + - name: Set up opensearch directory - run: mkdir shuffle-database && chmod -R 777 shuffle-database + run: chmod -R 777 shuffle-database - name: Build the stack - run: docker-compose up -d + run: docker compose up -d - name: Wait for 30 seconds run: sleep 30 @@ -54,7 +60,6 @@ jobs: echo "The word 'Shuffle' was not found in the response." exit 1 fi - - name: Register a user and check the status code run: | MAX_RETRIES=30 @@ -95,31 +100,36 @@ jobs: echo "User registration failed after $MAX_RETRIES attempts." exit 1 + - name: Run Selenium testing for frontend + run: | + cd $GITHUB_WORKSPACE/frontend + # write some log to see the current directory + chmod +x frontend-testing.sh + ./frontend-testing.sh + - name: Get the API key and run a health check + id: health_check run: | RESPONSE=$(curl -s -k -u admin:StrongShufflePassword321! 'https://localhost:9200/users/_search') + echo "Raw Response: $RESPONSE" + API_KEY=$(echo "$RESPONSE" | jq -r '.hits.hits[0]._source.apikey') - if [ -n "$API_KEY" ]; then + if [ -n "$API_KEY" ] && [ "$API_KEY" != "null" ]; then echo "Admin API key: $API_KEY" + echo "API_KEY=$API_KEY" >> $GITHUB_ENV else echo "Failed to retrieve the API key for the admin user." exit 1 fi + echo "Waiting 1 minute before sending the health API request..." + sleep 60 + + echo "Checking health API..." HEALTH_RESPONSE=$(curl -s 'http://localhost:3001/api/v1/health?force=true' \ - -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7' \ - -H 'Accept-Language: en-US,en;q=0.9' \ - -H 'Connection: keep-alive' \ - -H 'Sec-Fetch-Dest: document' \ - -H 'Sec-Fetch-Mode: navigate' \ - -H 'Sec-Fetch-Site: none' \ - -H "Authorization: Bearer $API_KEY" \ - -H 'Sec-Fetch-User: ?1' \ - -H 'Upgrade-Insecure-Requests: 1' \ - -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36' \ - -H 'sec-ch-ua: "Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"' \ - -H 'sec-ch-ua-mobile: ?0' \ - -H 'sec-ch-ua-platform: "macOS"') + -H "Authorization: Bearer $API_KEY") + + echo "Health API Response: $HEALTH_RESPONSE" WORKFLOWS_CREATE=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.create') WORKFLOWS_RUN=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.run') @@ -127,9 +137,35 @@ jobs: WORKFLOWS_RUN_STATUS=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.run_status') WORKFLOWS_DELETE=$(echo "$HEALTH_RESPONSE" | jq -r '.workflows.delete') + echo "WORKFLOWS_CREATE: $WORKFLOWS_CREATE" + echo "WORKFLOWS_RUN: $WORKFLOWS_RUN" + echo "WORKFLOWS_RUN_FINISHED: $WORKFLOWS_RUN_FINISHED" + echo "WORKFLOWS_RUN_STATUS: $WORKFLOWS_RUN_STATUS" + echo "WORKFLOWS_DELETE: $WORKFLOWS_DELETE" + if [ "$WORKFLOWS_CREATE" = "true" ] && [ "$WORKFLOWS_RUN" = "true" ] && [ "$WORKFLOWS_RUN_FINISHED" = "true" ] && [ "$WORKFLOWS_RUN_STATUS" = "FINISHED" ] && [ "$WORKFLOWS_DELETE" = "true" ]; then echo "Health endpoint check was successful." + exit 0 else - echo "Health endpoint check failed. Response did not meet expected criteria." + echo "Health check failed." exit 1 fi + + notify: + needs: build + if: failure() + runs-on: ubuntu-latest + steps: + - name: Send Twilio Alert + run: | + WORKFLOW_URL="https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" + MESSAGE="🚨 Shuffle Workflow Failed! + Repository: ${{ github.repository }} + Branch: ${{ github.ref_name }} + Workflow URL: $WORKFLOW_URL" + + curl -s -X POST https://api.twilio.com/2010-04-01/Accounts/${{ secrets.TWILIO_ACCOUNT_SID }}/Messages.json \ + --data-urlencode "To=${{ secrets.TWILIO_TO_NUMBER }}" \ + --data-urlencode "From=${{ secrets.TWILIO_FROM_NUMBER }}" \ + --data-urlencode "Body=$MESSAGE" \ + -u "${{ secrets.TWILIO_ACCOUNT_SID }}:${{ secrets.TWILIO_AUTH_TOKEN }}" > /dev/null diff --git a/README.md b/README.md index b90944bf..f74a7691 100755 --- a/README.md +++ b/README.md @@ -4,10 +4,6 @@ Shuffle Automation -[![CodeQL](https://github.com/Shuffle/Shuffle/actions/workflows/codeql-analysis.yml/badge.svg?branch=launch)](https://github.com/Shuffle/Shuffle/actions/workflows/codeql-analysis.yml) -[![Autobuild](https://github.com/Shuffle/Shuffle/actions/workflows/dockerbuild.yaml/badge.svg?branch=launch)](https://github.com/Shuffle/Shuffle/actions/workflows/dockerbuild.yaml) -[![Deploy to AWS](https://d1.awsstatic.com/cloudformation-deploy-to-aws-button.png)](https://console.aws.amazon.com/cloudformation/home?#/stacks/new?stackName=Shuffle-Instance&templateURL=https://shuffle-public-amis.s3.eu-north-1.amazonaws.com/template.yaml) -

[Shuffle](https://shuffler.io) is an open source automation platform, built for and by the security professionals. Security operations is complex, but it doesn't have to be. Built to work well with MSSP's and other service providers in mind. @@ -29,7 +25,7 @@ Follow us on Twitter at [@shuffleio](https://twitter.com/shuffleio). ## Try it * Self-hosted: Check out the [installation guide](https://github.com/shuffle/shuffle/blob/master/.github/install-guide.md) -* Cloud: Register at https://shuffler.io/register and get cooking (missing a lot of features) +* Cloud: Register at https://shuffler.io/register and get cooking Please consider [sponsoring](https://github.com/sponsors/frikky) the project if you want to see more rapid development. diff --git a/backend/Dockerfile b/backend/Dockerfile index 7cab5e27..5919a05e 100755 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22 as builder +FROM golang:1.23 as builder # Add files RUN mkdir /app @@ -14,9 +14,8 @@ ADD ./go-app/go.mod /app RUN wget -O /app_sdk/app_base.py https://raw.githubusercontent.com/Shuffle/app_sdk/refs/heads/main/shuffle_sdk/shuffle_sdk.py ADD ./app_gen /app_gen -RUN go get -v -#RUN go mod tidy -#RUN go clean -modcache +RUN go mod download +RUN go mod tidy # From November 2022, CGO is enabled due to packages # that we use requiring it. This is a temporary fix diff --git a/backend/app_sdk/requirements.txt b/backend/app_sdk/requirements.txt deleted file mode 100644 index 2dfbed0d..00000000 --- a/backend/app_sdk/requirements.txt +++ /dev/null @@ -1,9 +0,0 @@ -urllib3==1.26.19 -requests==2.31.0 -MarkupSafe==2.0.1 -liquidpy==0.8.1 -flask[async]==2.0.2 -waitress==2.1.0 -#flask==1.1.2 -python-dateutil==2.8.1 - diff --git a/backend/go-app/docker.go b/backend/go-app/docker.go index 57d4aaf8..11bbe14d 100755 --- a/backend/go-app/docker.go +++ b/backend/go-app/docker.go @@ -984,11 +984,4 @@ func activateWorkflowAppDocker(resp http.ResponseWriter, request *http.Request) log.Printf("[INFO] User %s (%s) is activating %s. Public: %t, Shared: %t", user.Username, user.Id, app.Name, app.Public, app.Sharing) buildSwaggerApp(resp, []byte(openApiApp.Body), user, true) - - //app.Active = true - //app.Generated = true - //app, err := shuffle.SetApp(ctx, app) - - //resp.WriteHeader(200) - //resp.Write([]byte(`{"success": true}`)) } diff --git a/backend/go-app/go.mod b/backend/go-app/go.mod index ec7db684..1a07e775 100644 --- a/backend/go-app/go.mod +++ b/backend/go-app/go.mod @@ -1,6 +1,8 @@ module shuffle -go 1.22.2 +go 1.23.0 + +toolchain go1.23.7 //replace github.com/shuffle/shuffle-shared => ../../../shuffle-shared @@ -18,11 +20,10 @@ require ( github.com/gorilla/mux v1.8.1 github.com/h2non/filetype v1.1.3 github.com/satori/go.uuid v1.2.0 - github.com/shuffle/shuffle-shared v0.7.92 - golang.org/x/crypto v0.32.0 + github.com/shuffle/shuffle-shared v0.8.19 + golang.org/x/crypto v0.36.0 google.golang.org/api v0.176.1 google.golang.org/grpc v1.68.1 - gopkg.in/src-d/go-git.v4 v4.13.1 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.30.2 k8s.io/apimachinery v0.30.2 @@ -37,6 +38,7 @@ require ( cloud.google.com/go/iam v1.1.7 // indirect cloud.google.com/go/scheduler v1.10.6 // indirect dario.cat/mergo v1.0.0 // indirect + github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect @@ -47,7 +49,6 @@ require ( github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 // indirect github.com/cloudflare/circl v1.3.7 // indirect - github.com/containerd/containerd v1.6.26 // indirect github.com/containerd/log v0.1.0 // indirect github.com/cyphar/filepath-securejoin v0.2.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -107,23 +108,24 @@ require ( github.com/skeema/knownhosts v1.3.0 // indirect github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/src-d/gcfg v1.4.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect go.opentelemetry.io/otel v1.33.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0 // indirect go.opentelemetry.io/otel/metric v1.33.0 // indirect go.opentelemetry.io/otel/trace v1.33.0 // indirect + go.opentelemetry.io/proto/otlp v0.11.0 // indirect go4.org v0.0.0-20201209231011-d4a079459e60 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.34.0 // indirect + golang.org/x/net v0.37.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/term v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/term v0.30.0 // indirect + golang.org/x/text v0.23.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/appengine v1.6.8 // indirect diff --git a/backend/go-app/go.sum b/backend/go-app/go.sum index 5e8420ff..1214c85c 100644 --- a/backend/go-app/go.sum +++ b/backend/go-app/go.sum @@ -15,8 +15,6 @@ cloud.google.com/go/auth/oauth2adapt v0.2.2 h1:+TTV8aXpjeChS9M+aTtN/TjdQnzJvmzKF cloud.google.com/go/auth/oauth2adapt v0.2.2/go.mod h1:wcYjgpZI9+Yu7LyYBg4pqSiaRkfEK3GQcpb7C/uyF1Q= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -37,8 +35,6 @@ dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8 h1:V8krnnfGj4pV65YLUm3C0/8bl7V5Nry2Pwvy3ru/wLc= github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -48,21 +44,15 @@ github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF0 github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Microsoft/hcsshim v0.9.10 h1:TxXGNmcbQxBKVWvjvTocNb6jrPyeHlk5EiDhhgHgggs= -github.com/Microsoft/hcsshim v0.9.10/go.mod h1:7pLA8lDk46WKDWlVsENo92gC0XFa8rbKfyFRBqxEbCc= -github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78= -github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk= github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/adrg/strutil v0.2.3 h1:WZVn3ItPBovFmP4wMHHVXUr8luRaHrbyIuLlHt32GZQ= github.com/adrg/strutil v0.2.3/go.mod h1:+SNxbiH6t+O+5SZqIj5n/9i5yUjR+S3XXVrjEcN2mxg= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/algolia/algoliasearch-client-go/v3 v3.18.1 h1:FP2Xtqqs/sefR5Qluygp+jVV+juXzEdJaPrZTCDLhDQ= github.com/algolia/algoliasearch-client-go/v3 v3.18.1/go.mod h1:i7tLoP7TYDmHX3Q7vkIOL4syVse/k5VJ+k0i8WqFiJk= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aws/aws-sdk-go v1.42.27/go.mod h1:OGr6lGMAKGlG9CVrYnWYDKIyb829c6EVBRjxqjmPepc= @@ -87,30 +77,29 @@ github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8b github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 h1:/P9/RL0xgWE+ehnCUUN5h3RpG3dmoMCOONO1CCvq23Y= github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013/go.mod h1:pccXHIvs3TV/TUqSNyEvF99sxjX2r4FFRIyw6TZY9+w= -github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/carlescere/scheduler v0.0.0-20170109141437-ee74d2f83d82 h1:9bAydALqAjBfPHd/eAiJBHnMZUYov8m2PkXVr+YGQeI= github.com/carlescere/scheduler v0.0.0-20170109141437-ee74d2f83d82/go.mod h1:tyA14J0sA3Hph4dt+AfCjPrYR13+vVodshQSM7km9qw= github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo= github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/containerd/containerd v1.6.26 h1:VVfrE6ZpyisvB1fzoY8Vkiq4sy+i5oF4uk7zu03RaHs= -github.com/containerd/containerd v1.6.26/go.mod h1:I4TRdsdoo5MlKob5khDJS2EPT1l1oMNaE2MBm6FrwxM= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= -github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= -github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo= github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -118,30 +107,26 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v26.1.5+incompatible h1:NEAxTwEjxV6VbBMBoGG3zPqbiJosIApZjxlbrG9q3/g= -github.com/docker/docker v26.1.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v27.5.0+incompatible h1:um++2NcQtGRTz5eEgO6aJimo6/JxrTXC941hd05JO6U= github.com/docker/docker v27.5.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= -github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy v1.2.1 h1:njjgvO6cRG9rIqN2ebkqy6cQz2Njkx7Fsfv/zIZqgug= +github.com/elazarl/goproxy v1.2.1/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/frikky/kin-openapi v0.42.0 h1:d5Z6vnuQ6RnCCPIxZaDL+TH2ODLxT8abytOt+Zh+Kd0= github.com/frikky/kin-openapi v0.42.0/go.mod h1:ev9OZAw7Bv5p0w93j91++6a1ElPzGcCofst+kmrWsj4= github.com/frikky/schemaless v0.0.13 h1:ARiN9V7wr2VZXAr9JK5wvTbyPgpGrgeiL1VhR5MlgaQ= @@ -150,28 +135,24 @@ github.com/fsouza/go-dockerclient v1.11.0 h1:4ZAk6W7rPAtPXm7198EFqA5S68rwnNQORxl github.com/fsouza/go-dockerclient v1.11.0/go.mod h1:0I3TQCRseuPTzqlY4Y3ajfsg2VAdMQoazrkxJTiJg8s= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= -github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8= +github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= +github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= -github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8= github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= -github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/go-git/go-git/v5 v5.13.0 h1:vLn5wlGIh/X78El6r3Jr+30W16Blk0CTcxTYcYPWi5E= github.com/go-git/go-git/v5 v5.13.0/go.mod h1:Wjo7/JyVKtQgUNdXYXIepzWfJQkUEIGvkvVkiXRR/zw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -206,6 +187,7 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= @@ -222,6 +204,7 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -267,7 +250,6 @@ github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= @@ -276,7 +258,6 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -288,7 +269,6 @@ github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -296,7 +276,6 @@ github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= @@ -307,8 +286,6 @@ github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= -github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -322,12 +299,10 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= -github.com/onsi/gomega v1.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE= -github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8= -github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= github.com/opensearch-project/opensearch-go v1.1.0 h1:eG5sh3843bbU1itPRjA9QXbxcg8LaZ+DjEzQH9aLN3M= @@ -336,18 +311,17 @@ github.com/opensearch-project/opensearch-go/v2 v2.3.0 h1:nQIEMr+A92CkhHrZgUhcfsr github.com/opensearch-project/opensearch-go/v2 v2.3.0/go.mod h1:8LDr9FCgUTVoT+5ESjc2+iaZuldqE+23Iq0r1XeNue8= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/sashabaranov/go-openai v1.19.2 h1:+dkuCADSnwXV02YVJkdphY8XD9AyHLUWwk6V7LB6EL8= github.com/sashabaranov/go-openai v1.19.2/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= @@ -357,31 +331,20 @@ github.com/sendgrid/rest v2.6.9+incompatible h1:1EyIcsNdn9KIisLW50MKwmSRSK+ekuei github.com/sendgrid/rest v2.6.9+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE= github.com/sendgrid/sendgrid-go v3.14.0+incompatible h1:KDSasSTktAqMJCYClHVE94Fcif2i7P7wzISv1sU6DUA= github.com/sendgrid/sendgrid-go v3.14.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= -github.com/shuffle/shuffle-shared v0.6.77 h1:KKtM50xW2DLuRHINxhp3uXrNH0AhiwkeiiU93a8fB3A= -github.com/shuffle/shuffle-shared v0.6.77/go.mod h1:RAJiSFjmuKmijKTbbEf9A6Ojb+3/te7g71lED7JjPus= -github.com/shuffle/shuffle-shared v0.6.90 h1:FzIYtEt44eWgEsW/9tj2ki7qq8FEm/HWXUok+THp72M= -github.com/shuffle/shuffle-shared v0.6.90/go.mod h1:RAJiSFjmuKmijKTbbEf9A6Ojb+3/te7g71lED7JjPus= -github.com/shuffle/shuffle-shared v0.7.0 h1:T7nbC5An/K9ePx1pwvYqSnnNZuafwK3GVy6wPDuog18= -github.com/shuffle/shuffle-shared v0.7.0/go.mod h1:bBXhEsPKjxln0mFnSeri7gIJ3tL/636Sh5NyTyNrvIQ= +github.com/shuffle/shuffle-shared v0.8.19 h1:HXqU62sPhVzv9MeJnA5ZpPYwwbitVz1EtMMABbY3t74= +github.com/shuffle/shuffle-shared v0.8.19/go.mod h1:NruHSAscDsW595wpK2r7MeHPGspUEKRNvBpcN1iGbHI= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= -github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= -github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -393,9 +356,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -411,49 +373,38 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs= go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0 h1:R/OBkMoGgfy2fLhs2QhkCI1w4HLEQX92GCcJB6SSdNk= go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0 h1:giGm8w67Ja7amYNfYMdme7xSp2pIxThWopw8+QP51Yk= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0 h1:Ydage/P0fRrSPpZeCVxzjqGcI6iVmG2xb43+IR8cjqM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 h1:wpMfgF8E1rkrT1Z6meFh1NDtownE9Ii3n3X2GJYjsaU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0/go.mod h1:wAy0T/dUbs468uOlkT31xjvqQgEVXv58BRFWEgn5v/0= go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= -go.opentelemetry.io/otel/sdk v1.22.0 h1:6coWHw9xw7EfClIC/+O31R8IY3/+EiRFHevmHafB2Gw= -go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs= +go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM= +go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= +go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk= go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v0.11.0 h1:cLDgIBTf4lLOlztkhzAEdQsJ4Lj+i5Wc9k6Nn0K1VyU= go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ= go4.org v0.0.0-20201209231011-d4a079459e60 h1:iqAGo78tVOJXELHQFRjR6TMwItrvXH4hrGJ32I/NFF8= go4.org v0.0.0-20201209231011-d4a079459e60/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -462,6 +413,8 @@ golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -481,9 +434,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -501,6 +451,7 @@ golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= @@ -508,21 +459,14 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= +golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= -golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -533,14 +477,10 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -553,34 +493,27 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -591,11 +524,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -611,9 +541,7 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -629,9 +557,6 @@ golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -670,15 +595,12 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= -google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c h1:kaI7oewGK5YnVwj+Y+EJBO/YN1ht8iTL9XkFHtVZLsc= -google.golang.org/genproto/googleapis/api v0.0.0-20240314234333-6e1732d8331c/go.mod h1:VQW3tUculP/D4B+xVCo+VgSq8As6wA9ZjHl//pmk+6s= google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q= google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be h1:LG9vZxsWGOmUKieR8wPAUR3u3MpnYFQZROPIMaXh7/A= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY= google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -689,9 +611,10 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= -google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0= google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -705,8 +628,7 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -717,15 +639,10 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= -gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= -gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= @@ -733,9 +650,8 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -gotest.tools/v3 v3.5.0 h1:Ljk6PdHdOhAb5aDMWXjDLMMhph+BpztA4v1QdqEW2eY= -gotest.tools/v3 v3.5.0/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/backend/go-app/main.go b/backend/go-app/main.go index e1f0defa..6df286b9 100755 --- a/backend/go-app/main.go +++ b/backend/go-app/main.go @@ -31,12 +31,13 @@ import ( "github.com/frikky/kin-openapi/openapi2conv" "github.com/frikky/kin-openapi/openapi3" - //"github.com/go-git/go-billy/v5" "github.com/go-git/go-billy/v5/memfs" + "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" - gitProxy "github.com/go-git/go-git/v5/plumbing/transport" "github.com/go-git/go-git/v5/storage/memory" + gitProxy "github.com/go-git/go-git/v5/plumbing/transport" + http2 "github.com/go-git/go-git/v5/plumbing/transport/http" // Random xj "github.com/basgys/goxml2json" @@ -46,7 +47,8 @@ import ( // Web "github.com/gorilla/mux" - http2 "gopkg.in/src-d/go-git.v4/plumbing/transport/http" + //http2 "gopkg.in/src-d/go-git.v5/plumbing/transport/http" + //http2 "github.com/go-git/go-git/plumbing/transport/http" ) // This is used to handle onprem vs offprem databases etc @@ -3079,8 +3081,9 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User, s return } - // FIXME: Check whether it's in use. - if user.Id != app.Owner && user.Role != "admin" { + if user.Id == app.Owner || (user.Role == "admin" && user.ActiveOrg.Id == app.ReferenceOrg) || shuffle.ArrayContains(app.Contributors, user.Id) { + log.Printf("[DEBUG] Editing app %s with user %s (%s) in org %s", test.Id, user.Username, user.Id, user.ActiveOrg.Id) + } else { log.Printf("[WARNING] Wrong user (%s) for app %s when verifying swagger", user.Username, app.Name) resp.WriteHeader(403) resp.Write([]byte(`{"success": false, "reason": "You don't have permissions to edit this app. Contact support@shuffler.io if this persists."}`)) @@ -3154,7 +3157,18 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User, s } } - api.Owner = user.Id + if api.Owner == "" { + api.Owner = user.Id + } + + if len(api.ReferenceOrg) == 0 { + api.ReferenceOrg = user.ActiveOrg.Id + } + + if len(test.Image) > 0 { + api.SmallImage = test.Image + api.LargeImage = test.Image + } err = shuffle.DumpApi(basePath, api) if err != nil { @@ -3279,6 +3293,12 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User, s Body: string(body), } + if !shuffle.ArrayContains(api.Contributors, user.Id) { + api.Contributors = append(api.Contributors, user.Id) + } + + shuffle.SetAppRevision(ctx, api) + log.Printf("[INFO] API LENGTH FOR %s: %d, ID: %s", api.Name, len(parsed.Body), newmd5) // FIXME: Might cause versioning issues if we re-use the same!! // FIXME: Need a way to track different versions of the same app properly. @@ -3349,11 +3369,27 @@ func buildSwaggerApp(resp http.ResponseWriter, body []byte, user shuffle.User, s } } + log.Printf("[DEBUG] Successfully built app %s (%s)", api.Name, api.ID) if len(user.Id) > 0 { resp.WriteHeader(200) resp.Write([]byte(fmt.Sprintf(`{"success": true, "id": "%s"}`, api.ID))) } + + org, err := shuffle.GetOrg(ctx, user.ActiveOrg.Id) + if err != nil { + log.Printf("[ERROR] Failed getting org during image build (%s): %s", user.ActiveOrg.Id, err) + } else { + imagenames := []string{ + fmt.Sprintf("%s_%s", api.Name, api.AppVersion), + fmt.Sprintf("%s_%s", api.Name, api.ID), + } + + err = shuffle.DistributeAppToEnvironments(ctx, *org, imagenames) + if err != nil { + log.Printf("[ERROR] Failed distributing app to environments: %s", err) + } + } } // Creates an app from the app builder @@ -4343,15 +4379,15 @@ func runInitEs(ctx context.Context) { } if os.Getenv("SHUFFLE_HEALTHCHECK_DISABLED") != "true" { - healthcheckInterval := 30 - log.Printf("[INFO] Starting healthcheck job every %d minute. Stats available on /api/v1/health/stats. Disable with SHUFFLE_HEALTHCHECK_DISABLED=true", healthcheckInterval) + healthcheckInterval := 60 + log.Printf("[INFO] Starting healthcheck job every %d minute. Stats available on /api/v1/health/stats, and dashboard on /health. Disable with SHUFFLE_HEALTHCHECK_DISABLED=true", healthcheckInterval) job := func() { // Prepare a fake http.responsewriter resp := httptest.NewRecorder() request := http.Request{} // Add the "force=true" query to the fake request - request.URL, err = url.Parse("/api/v1/health/stats?force=true") + request.URL, err = url.Parse("/api/v1/health?force=true") if err != nil { log.Printf("[ERROR] Failed to parse test url for healthstats: %s", err) } @@ -4422,7 +4458,7 @@ func handleStopCloudSync(syncUrl string, org shuffle.Org) (*shuffle.Org, error) return &org, errors.New(fmt.Sprintf("Couldn't find any sync key to disable org %s", org.Id)) } - log.Printf("[INFO] Should run cloud sync disable for org %s with URL %s and sync key %s", org.Id, syncUrl, org.SyncConfig.Apikey) + log.Printf("[INFO] Should run cloud sync disable for org %s with URL %s", org.Id, syncUrl) client := shuffle.GetExternalClient(syncUrl) req, err := http.NewRequest( @@ -5185,6 +5221,16 @@ func initHandlers() { r.HandleFunc("/api/v1/hooks/{key}/delete", shuffle.HandleDeleteHook).Methods("DELETE", "OPTIONS") r.HandleFunc("/api/v1/hooks/{key}", shuffle.HandleDeleteHook).Methods("DELETE", "OPTIONS") + // This structure is horrendous. Needs fixing after we got the prototype up + r.HandleFunc("/api/v1/detections", shuffle.HandleListDetectionCategories).Methods("GET", "OPTIONS") + r.HandleFunc("/api/v1/detections/{detectionType}/connect", shuffle.HandleDetectionAutoConnect).Methods("GET", "OPTIONS") + r.HandleFunc("/api/v1/detections/{detection_type}", shuffle.HandleGetDetectionRules).Methods("GET", "OPTIONS") + r.HandleFunc("/api/v1/detections/{detection_type}/selected_rules/{action}", shuffle.HandleFolderToggle).Methods("PUT", "OPTIONS") + + r.HandleFunc("/api/v1/detections/{triggerId}/selected_rules", shuffle.HandleGetSelectedRules).Methods("GET", "OPTIONS") + r.HandleFunc("/api/v1/detections/{triggerId}/selected_rules/save", shuffle.HandleSaveSelectedRules).Methods("POST", "OPTIONS") + r.HandleFunc("/api/v1/detections/{detection_type}/{fileId}/{action}", shuffle.HandleToggleRule).Methods("PUT", "OPTIONS") + // OpenAPI configuration r.HandleFunc("/api/v1/verify_swagger", verifySwagger).Methods("POST", "OPTIONS") r.HandleFunc("/api/v1/verify_openapi", verifySwagger).Methods("POST", "OPTIONS") diff --git a/backend/go-app/walkoff.go b/backend/go-app/walkoff.go index df7addb8..434b5a42 100755 --- a/backend/go-app/walkoff.go +++ b/backend/go-app/walkoff.go @@ -33,9 +33,11 @@ import ( "github.com/go-git/go-billy/v5" "github.com/go-git/go-billy/v5/memfs" "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/storage/memory" - http2 "gopkg.in/src-d/go-git.v4/plumbing/transport/http" + "github.com/go-git/go-git/v5/plumbing" + http2 "github.com/go-git/go-git/v5/plumbing/transport/http" + //http2 "gopkg.in/src-d/go-git.v5/plumbing/transport/http" + //http2 "github.com/go-git/go-git/plumbing/transport/http" //"github.com/gorilla/websocket" //"google.golang.org/appengine" @@ -1032,10 +1034,14 @@ func deleteWorkflow(resp http.ResponseWriter, request *http.Request) { log.Printf("[INFO] Should have deleted workflow %s (%s)", workflow.Name, fileId) - cacheKey := fmt.Sprintf("%s_workflows", user.Id) - shuffle.DeleteCache(ctx, cacheKey) + shuffle.DeleteCache(ctx, fmt.Sprintf("%s_workflows", user.Id)) shuffle.DeleteCache(ctx, fmt.Sprintf("%s_workflows", user.ActiveOrg.Id)) + shuffle.DeleteCache(ctx, fmt.Sprintf("%s_%s", user.Username, fileId)) log.Printf("[DEBUG] Cleared workflow cache for %s (%s)", user.Username, user.Id) + shuffle.DeleteCache(ctx, fmt.Sprintf("workflow_%s_childworkflows", workflow.ID)) + if len(workflow.ParentWorkflowId) > 0 { + shuffle.DeleteCache(ctx, fmt.Sprintf("workflow_%s_childworkflows", workflow.ParentWorkflowId)) + } resp.WriteHeader(200) resp.Write([]byte(`{"success": true}`)) @@ -1050,7 +1056,7 @@ func handleExecution(id string, workflow shuffle.Workflow, request *http.Request ctx := context.Background() if workflow.ID == "" || workflow.ID != id { - tmpworkflow, err := shuffle.GetWorkflow(ctx, id) + tmpworkflow, err := shuffle.GetWorkflow(ctx, id, true) if err != nil { //log.Printf("[WARNING] Failed getting the workflow locally (execution setup): %s", err) return shuffle.WorkflowExecution{}, "Failed getting workflow", err @@ -1094,10 +1100,12 @@ func handleExecution(id string, workflow shuffle.Workflow, request *http.Request workflow.Errors = []string{} } + /* if !workflow.IsValid { log.Printf("[ERROR] Stopped execution as workflow %s is not valid.", workflow.ID) return shuffle.WorkflowExecution{}, fmt.Sprintf(`workflow %s is invalid`, workflow.ID), errors.New("Failed getting workflow") } + */ maxExecutionDepth := 10 if os.Getenv("SHUFFLE_MAX_EXECUTION_DEPTH") != "" { @@ -1133,507 +1141,6 @@ func handleExecution(id string, workflow shuffle.Workflow, request *http.Request return shuffle.WorkflowExecution{}, "Failed unmarshal during execution", err } - /* - makeNew := true - start, startok := request.URL.Query()["start"] - if request.Method == "POST" { - body, err := ioutil.ReadAll(request.Body) - if err != nil { - log.Printf("[ERROR] Failed request POST read: %s", err) - return shuffle.WorkflowExecution{}, "Failed getting body", err - } - - // This one doesn't really matter. - log.Printf("[INFO] Running POST execution with body of length %d for workflow %s", len(string(body)), workflowExecution.Workflow.ID) - - if len(body) >= 4 { - if body[0] == 34 && body[len(body)-1] == 34 { - body = body[1 : len(body)-1] - } - if body[0] == 34 && body[len(body)-1] == 34 { - body = body[1 : len(body)-1] - } - } - - sourceAuth, sourceAuthOk := request.URL.Query()["source_auth"] - if sourceAuthOk { - //log.Printf("\n\n\nSETTING SOURCE WORKFLOW AUTH TO %s!!!\n\n\n", sourceAuth[0]) - workflowExecution.ExecutionSourceAuth = sourceAuth[0] - } else { - //log.Printf("Did NOT get source workflow") - } - - sourceNode, sourceNodeOk := request.URL.Query()["source_node"] - if sourceNodeOk { - //log.Printf("\n\n\nSETTING SOURCE WORKFLOW NODE TO %s!!!\n\n\n", sourceNode[0]) - workflowExecution.ExecutionSourceNode = sourceNode[0] - } else { - //log.Printf("Did NOT get source workflow") - } - - //workflowExecution.ExecutionSource = "default" - sourceWorkflow, sourceWorkflowOk := request.URL.Query()["source_workflow"] - if sourceWorkflowOk { - //log.Printf("Got source workflow %s", sourceWorkflow) - workflowExecution.ExecutionSource = sourceWorkflow[0] - } else { - //log.Printf("Did NOT get source workflow") - } - - sourceExecution, sourceExecutionOk := request.URL.Query()["source_execution"] - if sourceExecutionOk { - //log.Printf("[INFO] Got source execution%s", sourceExecution) - workflowExecution.ExecutionParent = sourceExecution[0] - } else { - //log.Printf("Did NOT get source execution") - } - - if len(string(body)) < 50 { - //log.Println(body) - // String in string - //log.Println(body) - - //if string(body)[0] == "\"" && string(body)[string(body) - log.Printf("[DEBUG] Body: %s", string(body)) - } - - var execution shuffle.ExecutionRequest - err = json.Unmarshal(body, &execution) - if err != nil { - log.Printf("[WARNING] Failed execution POST unmarshalling for execution %s - continuing anyway: %s", execution.ExecutionId, err) - //return shuffle.WorkflowExecution{}, "", err - } - - if execution.Start == "" && len(body) > 0 { - execution.ExecutionArgument = string(body) - } - - // FIXME - this should have "execution_argument" from executeWorkflow frontend - //log.Printf("EXEC: %#v", execution) - if len(execution.ExecutionArgument) > 0 { - workflowExecution.ExecutionArgument = execution.ExecutionArgument - } - - if len(execution.ExecutionSource) > 0 { - workflowExecution.ExecutionSource = execution.ExecutionSource - } - - //log.Printf("Execution data: %#v", execution) - if len(execution.Start) == 36 && len(workflow.Actions) > 0 { - log.Printf("[INFO] Should start execution on node %s", execution.Start) - workflowExecution.Start = execution.Start - - found := false - for _, action := range workflow.Actions { - if action.ID == execution.Start { - found = true - break - } - } - - if !found { - log.Printf("[ERROR] Action %s was NOT found! Exiting execution.", execution.Start) - return shuffle.WorkflowExecution{}, fmt.Sprintf("Startnode %s was not found in actions", workflow.Start), errors.New(fmt.Sprintf("Startnode %s was not found in actions", workflow.Start)) - } - } else if len(execution.Start) > 0 { - //log.Printf("[INFO] !") - //log.Printf("[ERROR] START ACTION %s IS WRONG ID LENGTH %d!", execution.Start, len(execution.Start)) - //return shuffle.WorkflowExecution{}, fmt.Sprintf("Startnode %s was not found in actions", execution.Start), errors.New(fmt.Sprintf("Startnode %s was not found in actions", execution.Start)) - } - - if len(execution.ExecutionId) == 36 { - workflowExecution.ExecutionId = execution.ExecutionId - } else { - sessionToken := uuid.NewV4() - workflowExecution.ExecutionId = sessionToken.String() - } - } else { - // Check for parameters of start and ExecutionId - // This is mostly used for user input trigger - - answer, answerok := request.URL.Query()["answer"] - referenceId, referenceok := request.URL.Query()["reference_execution"] - if answerok && referenceok && len(answer) > 0 && len(referenceId) > 0 { - // If answer is false, reference execution with result - log.Printf("[INFO] Answer is OK AND reference is OK!") - if answer[0] == "false" { - log.Printf("Should update reference and return, no need for further execution!") - - // Get the reference execution - oldExecution, err := shuffle.GetWorkflowExecution(ctx, referenceId[0]) - if err != nil { - log.Printf("Failed getting execution (execution) %s: %s", referenceId[0], err) - return shuffle.WorkflowExecution{}, fmt.Sprintf("Failed getting execution ID %s because it doesn't exist.", referenceId[0]), err - } - - if oldExecution.Workflow.ID != id { - log.Println("Wrong workflowid!") - return shuffle.WorkflowExecution{}, fmt.Sprintf("Bad ID %s", referenceId), errors.New("Bad ID") - } - - newResults := []shuffle.ActionResult{} - //log.Printf("%#v", oldExecution.Results) - for _, result := range oldExecution.Results { - log.Printf("%s - %s", result.Action.ID, start[0]) - if result.Action.ID == start[0] { - note, noteok := request.URL.Query()["note"] - if noteok && len(note) > 0 { - result.Result = fmt.Sprintf("User note: %s", note[0]) - } else { - result.Result = fmt.Sprintf("User clicked %s", answer[0]) - } - - // Stopping the whole thing - result.CompletedAt = int64(time.Now().Unix()) - result.Status = "ABORTED" - oldExecution.Status = result.Status - oldExecution.Result = result.Result - oldExecution.LastNode = result.Action.ID - } - - newResults = append(newResults, result) - } - - oldExecution.Results = newResults - err = shuffle.SetWorkflowExecution(ctx, *oldExecution, true) - if err != nil { - log.Printf("Error saving workflow execution actionresult setting: %s", err) - return shuffle.WorkflowExecution{}, fmt.Sprintf("Failed setting workflowexecution actionresult in execution: %s", err), err - } - - return shuffle.WorkflowExecution{}, "", nil - } - } - - if referenceok { - log.Printf("Handling an old execution continuation!") - // Will use the old name, but still continue with NEW ID - oldExecution, err := shuffle.GetWorkflowExecution(ctx, referenceId[0]) - if err != nil { - log.Printf("Failed getting execution (execution) %s: %s", referenceId[0], err) - return shuffle.WorkflowExecution{}, fmt.Sprintf("Failed getting execution ID %s because it doesn't exist.", referenceId[0]), err - } - - workflowExecution = *oldExecution - } - - if len(workflowExecution.ExecutionId) == 0 { - sessionToken := uuid.NewV4() - workflowExecution.ExecutionId = sessionToken.String() - } else { - log.Printf("Using the same executionId as before: %s", workflowExecution.ExecutionId) - makeNew = false - } - - // Don't override workflow defaults - } - - if startok { - //log.Printf("\n\n[INFO] Setting start to %s based on query!\n\n", start[0]) - //workflowExecution.Workflow.Start = start[0] - workflowExecution.Start = start[0] - } - - // FIXME - regex uuid, and check if already exists? - if len(workflowExecution.ExecutionId) != 36 { - log.Printf("Invalid uuid: %s", workflowExecution.ExecutionId) - return shuffle.WorkflowExecution{}, "Invalid uuid", err - } - - // FIXME - find owner of workflow - // FIXME - get the actual workflow itself and build the request - // MAYBE: Don't send the workflow within the pubsub, as this requires more data to be sent - // Check if a worker already exists for company, else run one with: - // locations, project IDs and subscription names - - // When app is executed: - // Should update with status execution (somewhere), which will trigger the next node - // IF action.type == internal, we need the internal watcher to be running and executing - // This essentially means the WORKER has to be the responsible party for new actions in the INTERNAL landscape - // Results are ALWAYS posted back to cloud@execution_id? - if makeNew { - workflowExecution.Type = "workflow" - //workflowExecution.Stream = "tmp" - //workflowExecution.WorkflowQueue = "tmp" - //workflowExecution.SubscriptionNameNodestream = "testcompany-nodestream" - //workflowExecution.Locations = []string{"europe-west2"} - workflowExecution.ProjectId = gceProject - workflowExecution.WorkflowId = workflow.ID - workflowExecution.StartedAt = int64(time.Now().Unix()) - workflowExecution.CompletedAt = 0 - workflowExecution.Authorization = uuid.NewV4().String() - - // Status for the entire workflow. - workflowExecution.Status = "EXECUTING" - } - - if len(workflowExecution.ExecutionSource) == 0 { - log.Printf("[INFO] No execution source (trigger) specified. Setting to default") - workflowExecution.ExecutionSource = "default" - } else { - log.Printf("[INFO] Execution source is %s for execution ID %s in workflow %s", workflowExecution.ExecutionSource, workflowExecution.ExecutionId, workflowExecution.Workflow.ID) - } - - workflowExecution.ExecutionVariables = workflow.ExecutionVariables - if len(workflowExecution.Start) == 0 && len(workflowExecution.Workflow.Start) > 0 { - workflowExecution.Start = workflowExecution.Workflow.Start - } - - startnodeFound := false - newStartnode := "" - for _, item := range workflowExecution.Workflow.Actions { - if item.ID == workflowExecution.Start { - startnodeFound = true - } - - if item.IsStartNode { - newStartnode = item.ID - } - } - - if !startnodeFound { - log.Printf("[INFO] Couldn't find startnode %s. Remapping to %#v", workflowExecution.Start, newStartnode) - - if len(newStartnode) > 0 { - workflowExecution.Start = newStartnode - } else { - return shuffle.WorkflowExecution{}, fmt.Sprintf("Startnode couldn't be found"), errors.New("Startnode isn't defined in this workflow..") - } - } - - childNodes := shuffle.FindChildNodes(workflowExecution.Workflow, workflowExecution.Start, []string{}, []string{}) - - startFound := false - newActions := []shuffle.Action{} - defaultResults := []shuffle.ActionResult{} - - for _, action := range workflowExecution.Workflow.Actions { - //action.LargeImage = "" - if action.ID == workflowExecution.Start { - startFound = true - } - //log.Println(action.Environment) - - if action.Environment == "" { - return shuffle.WorkflowExecution{}, fmt.Sprintf("Environment is not defined for %s", action.Name), errors.New("Environment not defined!") - } - - action.LargeImage = "" - if len(action.Label) == 0 { - action.Label = action.ID - } - //log.Printf("LABEL: %s", action.Label) - newActions = append(newActions, action) - - // If the node is NOT found, it's supposed to be set to SKIPPED, - // as it's not a childnode of the startnode - // This is a configuration item for the workflow itself. - if len(workflowExecution.Results) > 0 { - defaultResults = []shuffle.ActionResult{} - for _, result := range workflowExecution.Results { - if result.Status == "WAITING" { - result.Status = "FINISHED" - result.Result = "Continuing" - } - - defaultResults = append(defaultResults, result) - } - } else if len(workflowExecution.Results) == 0 && !workflowExecution.Workflow.Configuration.StartFromTop { - found := false - for _, nodeId := range childNodes { - if nodeId == action.ID { - //log.Printf("Found %s", action.ID) - found = true - } - } - - if !found { - if action.ID == workflowExecution.Start { - continue - } - - //log.Printf("[WARNING] Set %s to SKIPPED as it's NOT a childnode of the startnode.", action.ID) - curaction := shuffle.Action{ - AppName: action.AppName, - AppVersion: action.AppVersion, - Label: action.Label, - Name: action.Name, - ID: action.ID, - } - //action - //curaction.Parameters = [] - defaultResults = append(defaultResults, shuffle.ActionResult{ - Action: curaction, - ExecutionId: workflowExecution.ExecutionId, - Authorization: workflowExecution.Authorization, - Result: "Skipped because it's not under the startnode", - StartedAt: 0, - CompletedAt: 0, - Status: "SKIPPED", - }) - } - } - } - - removeTriggers := []string{} - for triggerIndex, trigger := range workflowExecution.Workflow.Triggers { - //log.Printf("[INFO] ID: %s vs %s", trigger.ID, workflowExecution.Start) - if trigger.ID == workflowExecution.Start { - if trigger.AppName == "User Input" { - startFound = true - break - } - } - - if trigger.AppName == "User Input" || trigger.AppName == "Shuffle Workflow" { - found := false - for _, node := range childNodes { - if node == trigger.ID { - found = true - break - } - } - - if !found { - //log.Printf("SHOULD SET TRIGGER %s TO BE SKIPPED", trigger.ID) - - curaction := shuffle.Action{ - AppName: "shuffle-subflow", - AppVersion: trigger.AppVersion, - Label: trigger.Label, - Name: trigger.Name, - ID: trigger.ID, - } - - defaultResults = append(defaultResults, shuffle.ActionResult{ - Action: curaction, - ExecutionId: workflowExecution.ExecutionId, - Authorization: workflowExecution.Authorization, - Result: "Skipped because it's not under the startnode", - StartedAt: 0, - CompletedAt: 0, - Status: "SKIPPED", - }) - } else { - // Replaces trigger with the subflow - //if trigger.AppName == "Shuffle Workflow" { - // replaceActions := false - // workflowAction := "" - // for _, param := range trigger.Parameters { - // if param.Name == "argument" && !strings.Contains(param.Value, ".#") { - // replaceActions = true - // } - - // if param.Name == "startnode" { - // workflowAction = param.Value - // } - // } - - // if replaceActions { - // replacementNodes, newBranches, lastnode := shuffle.GetReplacementNodes(ctx, workflowExecution, trigger, trigger.Label) - // log.Printf("REPLACEMENTS: %d, %d", len(replacementNodes), len(newBranches)) - // if len(replacementNodes) > 0 { - // for _, action := range replacementNodes { - // found := false - - // for subActionIndex, subaction := range newActions { - // if subaction.ID == action.ID { - // found = true - // //newActions[subActionIndex].Name = action.Name - // newActions[subActionIndex].Label = action.Label - // break - // } - // } - - // if !found { - // action.SubAction = true - // newActions = append(newActions, action) - // } - - // // Check if it's already set to have a value - // for resultIndex, result := range defaultResults { - // if result.Action.ID == action.ID { - // defaultResults = append(defaultResults[:resultIndex], defaultResults[resultIndex+1:]...) - // break - // } - // } - // } - - // for _, branch := range newBranches { - // workflowExecution.Workflow.Branches = append(workflowExecution.Workflow.Branches, branch) - // } - - // // Append branches: - // // parent -> new inner node (FIRST one) - // for branchIndex, branch := range workflowExecution.Workflow.Branches { - // if branch.DestinationID == trigger.ID { - // log.Printf("REPLACE DESTINATION WITH %s!!", workflowAction) - // workflowExecution.Workflow.Branches[branchIndex].DestinationID = workflowAction - // } - - // if branch.SourceID == trigger.ID { - // log.Printf("REPLACE SOURCE WITH LASTNODE %s!!", lastnode) - // workflowExecution.Workflow.Branches[branchIndex].SourceID = lastnode - // } - // } - - // // Remove the trigger - // removeTriggers = append(removeTriggers, workflowExecution.Workflow.Triggers[triggerIndex].ID) - // } - - // log.Printf("NEW ACTION LENGTH %d, RESULT: %d, Triggers: %d, BRANCHES: %d", len(newActions), len(defaultResults), len(workflowExecution.Workflow.Triggers), len(workflowExecution.Workflow.Branches)) - // } - //} - _ = triggerIndex - } - } - } - - //newTriggers := []shuffle.Trigger{} - //for _, trigger := range workflowExecution.Workflow.Triggers { - // found := false - // for _, triggerId := range removeTriggers { - // if trigger.ID == triggerId { - // found = true - // break - // } - // } - - // if found { - // log.Printf("[WARNING] Removed trigger %s during execution", trigger.ID) - // continue - // } - - // newTriggers = append(newTriggers, trigger) - //} - //workflowExecution.Workflow.Triggers = newTriggers - - if !startFound { - if len(workflowExecution.Start) == 0 && len(workflowExecution.Workflow.Start) > 0 { - workflowExecution.Start = workflow.Start - } else if len(workflowExecution.Workflow.Actions) > 0 { - workflowExecution.Start = workflowExecution.Workflow.Actions[0].ID - } else { - log.Printf("[ERROR] Startnode %s doesn't exist!!", workflowExecution.Start) - return shuffle.WorkflowExecution{}, fmt.Sprintf("Workflow action %s doesn't exist in workflow", workflowExecution.Start), errors.New(fmt.Sprintf(`Workflow start node "%s" doesn't exist. Exiting!`, workflowExecution.Start)) - } - } - - //log.Printf("EXECUTION START: %s", workflowExecution.Start) - - // Verification for execution environments - workflowExecution.Results = defaultResults - workflowExecution.Workflow.Actions = newActions - onpremExecution := true - _ = onpremExecution - environments := []string{} - - if len(workflowExecution.ExecutionOrg) == 0 && len(workflow.ExecutingOrg.Id) > 0 { - workflowExecution.ExecutionOrg = workflow.ExecutingOrg.Id - } - */ - - //workflowExecution, execInfo, _, workflowExecErr := shuffle.PrepareWorkflowExecution(ctx, workflow, request, int64(maxExecutionDepth)) err = shuffle.SetWorkflowExecution(ctx, workflowExecution, true) if err != nil { log.Printf("[ERROR] Failed setting workflow execution during init (2): %s", err) @@ -1644,7 +1151,6 @@ func handleExecution(id string, workflow shuffle.Workflow, request *http.Request environments := execInfo.Environments var allEnvs []shuffle.Environment if len(workflowExecution.ExecutionOrg) > 0 { - //log.Printf("[INFO] Executing ORG: %s", workflowExecution.ExecutionOrg) allEnvironments, err := shuffle.GetEnvironments(ctx, workflowExecution.ExecutionOrg) if err != nil { @@ -1897,7 +1403,7 @@ func executeWorkflow(resp http.ResponseWriter, request *http.Request) { log.Printf("[INFO] Inside execute workflow for ID %s", fileId) ctx := context.Background() - workflow, err := shuffle.GetWorkflow(ctx, fileId) + workflow, err := shuffle.GetWorkflow(ctx, fileId, true) if err != nil && workflow.ID == "" { log.Printf("[WARNING] Failed getting the workflow locally (execute workflow): %s", err) resp.WriteHeader(401) diff --git a/docker-compose.yml b/docker-compose.yml index 11838a86..adf6b533 100755 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: frontend: - image: ghcr.io/shuffle/shuffle-frontend:1.4.2 + image: ghcr.io/shuffle/shuffle-frontend:latest container_name: shuffle-frontend hostname: shuffle-frontend ports: @@ -14,7 +14,7 @@ services: depends_on: - backend backend: - image: ghcr.io/shuffle/shuffle-backend:1.4.2 + image: ghcr.io/shuffle/shuffle-backend:latest container_name: shuffle-backend hostname: ${BACKEND_HOSTNAME} # Here for debugging: @@ -33,7 +33,7 @@ services: - SHUFFLE_FILE_LOCATION=/shuffle-files restart: unless-stopped orborus: - image: ghcr.io/shuffle/shuffle-orborus:1.4.0 + image: ghcr.io/shuffle/shuffle-orborus:latest container_name: shuffle-orborus hostname: shuffle-orborus networks: @@ -53,15 +53,15 @@ services: - SHUFFLE_PASS_WORKER_PROXY=${SHUFFLE_PASS_WORKER_PROXY} - SHUFFLE_PASS_APP_PROXY=${SHUFFLE_PASS_APP_PROXY} - SHUFFLE_STATS_DISABLED=true - - SHUFFLE_SWARM_CONFIG=run - SHUFFLE_LOGS_DISABLED=true - - SHUFFLE_WORKER_IMAGE=ghcr.io/shuffle/shuffle-worker:1.4.2 + - SHUFFLE_SWARM_CONFIG=run + - SHUFFLE_WORKER_IMAGE=ghcr.io/shuffle/shuffle-worker:latest env_file: .env restart: unless-stopped security_opt: - seccomp:unconfined opensearch: - image: opensearchproject/opensearch:2.14.0 + image: opensearchproject/opensearch:2.19.1 hostname: shuffle-opensearch container_name: shuffle-opensearch environment: diff --git a/frontend/frontend-testing.sh b/frontend/frontend-testing.sh new file mode 100644 index 00000000..c25c3618 --- /dev/null +++ b/frontend/frontend-testing.sh @@ -0,0 +1,74 @@ + +SERVER_URL="http://localhost:3000" + +declare -a Routes=($(grep -oP '(?<=path=")[^"]*' src/App.jsx | grep -E '^[a-zA-Z0-9/_:-]+$' | grep -vE '^/$')) + +for i in "${!Routes[@]}"; do + Routes[$i]="${Routes[$i]#/}" +done + +# # Add all tab routes and unique routes here +Routes+=( +'workflows?tab=org_workflows' +'workflows?tab=my_workflows' +'workflows?tab=all_workflows' +'apps/gmail' +'apis/gmail' +'apps?tab=my_apps' +'apps?tab=all_apps' +'search?tab=org_apps' +'search?tab=my_apps' +'search?tab=workflows' +'search?tab=docs' +'search?tab=creators' +'search?tab=discord' +"admin?tab=organization" +"admin?tab=users" +"admin?tab=app_auth" +"admin?tab=datastore" +"admin?tab=files" +"admin?tab=triggers" +"admin?tab=locations" +"admin?tab=tenants" +"admin?admin_tab=org_config" +"admin?admin_tab=sso" +"admin?admin_tab=notifications" +"admin?admin_tab=billingstats" +"admin?admin_tab=branding(beta)" +) + +# Stop frontend container so it test unpushed changes +docker stop shuffle-frontend + +# # Install all frontend dependencies +yarn add selenium-webdriver --dev && yarn install +echo "Starting frontend..." + +BROWSER=none yarn start & +SERVER_PID=$! +echo "Frontend started with PID: $SERVER_PID" + +echo "Waiting for 1 minute to ensure the server is fully up..." +sleep 60 + +echo "Server is up! Starting Selenium tests..." + +echo "Starting frontend tests..." +node selenium-test.js "$SERVER_URL" "${Routes[@]}" + +TEST_EXIT_CODE=$? + +if [[ $TEST_EXIT_CODE -ne 0 ]]; then +echo "Selenium tests failed. Exiting..." +kill $SERVER_PID +exit 1 +fi + +kill $SERVER_PID +echo "Testing complete. See above logs for errors if any." + +# Starting shuffle-frontend container +echo "Starting shuffle-frontend container..." +docker start shuffle-frontend +echo "shuffle-frontend started successfully." +exit 0 diff --git a/frontend/package.json b/frontend/package.json old mode 100755 new mode 100644 index 7426ee23..db88fae3 --- a/frontend/package.json +++ b/frontend/package.json @@ -21,7 +21,7 @@ "@uiw/codemirror-themes": "^4.21.9", "@uiw/react-codemirror": "^4.21.21", "algoliasearch": "^4.8.3", - "class-transformer": "^0.2.0", + "class-transformer": "^0.5.1", "codemirror": "^6.0.1", "cpx": "^1.5.0", "create-react-app": "^5.0.1", @@ -128,6 +128,7 @@ "babel-preset-es2015": "^6.24.1", "postcss": "^8.4.38", "promise-window": "^1.2.1", + "selenium-webdriver": "^4.29.0", "webpack-cli": "^5.1.4" } } diff --git a/frontend/public/images/ProfessionalServices.svg b/frontend/public/images/ProfessionalServices.svg new file mode 100644 index 00000000..164b6917 --- /dev/null +++ b/frontend/public/images/ProfessionalServices.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/public/images/SecurityConsultation.svg b/frontend/public/images/SecurityConsultation.svg new file mode 100644 index 00000000..05614a4d --- /dev/null +++ b/frontend/public/images/SecurityConsultation.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/public/images/Support.svg b/frontend/public/images/Support.svg new file mode 100644 index 00000000..83a18f00 --- /dev/null +++ b/frontend/public/images/Support.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/public/images/Training.svg b/frontend/public/images/Training.svg new file mode 100644 index 00000000..b01a9901 --- /dev/null +++ b/frontend/public/images/Training.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/public/images/icons/API.svg b/frontend/public/images/icons/API.svg new file mode 100644 index 00000000..447b94de --- /dev/null +++ b/frontend/public/images/icons/API.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/public/images/icons/about_us.svg b/frontend/public/images/icons/about_us.svg new file mode 100644 index 00000000..c77e7e8e --- /dev/null +++ b/frontend/public/images/icons/about_us.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/public/images/icons/about_us_hover.svg b/frontend/public/images/icons/about_us_hover.svg new file mode 100644 index 00000000..2c693ca9 --- /dev/null +++ b/frontend/public/images/icons/about_us_hover.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/public/images/icons/articles.svg b/frontend/public/images/icons/articles.svg new file mode 100644 index 00000000..763d960f --- /dev/null +++ b/frontend/public/images/icons/articles.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/public/images/icons/articles_hover.svg b/frontend/public/images/icons/articles_hover.svg new file mode 100644 index 00000000..6b51f294 --- /dev/null +++ b/frontend/public/images/icons/articles_hover.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/public/images/icons/contact_us.svg b/frontend/public/images/icons/contact_us.svg new file mode 100644 index 00000000..5fbc3568 --- /dev/null +++ b/frontend/public/images/icons/contact_us.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/public/images/icons/contact_us_hover.svg b/frontend/public/images/icons/contact_us_hover.svg new file mode 100644 index 00000000..0da02b7c --- /dev/null +++ b/frontend/public/images/icons/contact_us_hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/public/images/icons/discord.svg b/frontend/public/images/icons/discord.svg new file mode 100644 index 00000000..b982260b --- /dev/null +++ b/frontend/public/images/icons/discord.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/public/images/icons/docs.svg b/frontend/public/images/icons/docs.svg new file mode 100644 index 00000000..a568538d --- /dev/null +++ b/frontend/public/images/icons/docs.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/public/images/icons/docs_hover.svg b/frontend/public/images/icons/docs_hover.svg new file mode 100644 index 00000000..a711ba59 --- /dev/null +++ b/frontend/public/images/icons/docs_hover.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/public/images/icons/faq.svg b/frontend/public/images/icons/faq.svg new file mode 100644 index 00000000..7345040f --- /dev/null +++ b/frontend/public/images/icons/faq.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/public/images/icons/faq_hover.svg b/frontend/public/images/icons/faq_hover.svg new file mode 100644 index 00000000..4d29215a --- /dev/null +++ b/frontend/public/images/icons/faq_hover.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/public/images/icons/github.svg b/frontend/public/images/icons/github.svg new file mode 100644 index 00000000..de6c0200 --- /dev/null +++ b/frontend/public/images/icons/github.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/public/images/icons/linkedIn.svg b/frontend/public/images/icons/linkedIn.svg new file mode 100644 index 00000000..605e7804 --- /dev/null +++ b/frontend/public/images/icons/linkedIn.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/public/images/icons/usecases.svg b/frontend/public/images/icons/usecases.svg new file mode 100644 index 00000000..cc96e086 --- /dev/null +++ b/frontend/public/images/icons/usecases.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/public/images/icons/usecases_hover.svg b/frontend/public/images/icons/usecases_hover.svg new file mode 100644 index 00000000..6841b21e --- /dev/null +++ b/frontend/public/images/icons/usecases_hover.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/public/images/icons/x.svg b/frontend/public/images/icons/x.svg new file mode 100644 index 00000000..815e4e30 --- /dev/null +++ b/frontend/public/images/icons/x.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/public/images/logos/singul.svg b/frontend/public/images/logos/singul.svg new file mode 100644 index 00000000..5f27d7a3 --- /dev/null +++ b/frontend/public/images/logos/singul.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/selenium-test.js b/frontend/selenium-test.js new file mode 100644 index 00000000..42b6b801 --- /dev/null +++ b/frontend/selenium-test.js @@ -0,0 +1,253 @@ +const { Builder, By, until } = require('selenium-webdriver'); +const chrome = require('selenium-webdriver/chrome'); +const fs = require('fs'); +const path = require('path'); + +console.log('Starting Selenium script for testing pages...'); + +(async () => { + const userDataDir = path.join(__dirname, 'chrome-user-data', `${Date.now()}-${Math.random().toString(36).substring(2, 8)}`); + fs.mkdirSync(userDataDir, { recursive: true }); + + let options = new chrome.Options(); + options.addArguments('--no-sandbox'); + options.addArguments('--headless'); + + let driver = await new Builder() + .forBrowser('chrome') + .setChromeOptions(options) + .build(); + + const SuccessfullyLoadedPath = []; + const FailedToLoadPath = []; + + try { + await driver.manage().window().setRect({ width: 1600, height: 1200 }); + await driver.manage().window().maximize() + await driver.manage().setTimeouts({ implicit: 15000 }); + + const frontendURL = process.argv[2]; + const routes = process.argv.slice(3); + + console.log('Frontend URL:', frontendURL); + const isCloud = frontendURL === 'http://localhost:3002' || frontendURL === 'https://sandbox.shuffler.io' || frontendURL === 'https://shuffler.io'; + + if (isCloud) { + // Login Credentials + const LOGIN_URL = `${frontendURL}/login`; + // put your login credentials here + const USERNAME = ''; + const PASSWORD = ''; + + console.log('Logging in...'); + await driver.get(LOGIN_URL); + + try { + await driver.wait(until.elementLocated(By.css('#emailfield')), 10000); + await driver.findElement(By.css('#emailfield')).sendKeys(USERNAME); + + await driver.wait(until.elementLocated(By.css('#outlined-password-input')), 10000); + await driver.findElement(By.css('#outlined-password-input')).sendKeys(PASSWORD); + + await driver.wait(until.elementLocated(By.css('#loginButton')), 10000); + await driver.findElement(By.css('#loginButton')).click(); + + // Ensure login success by checking URL change + await driver.wait(async () => { + const url = await driver.getCurrentUrl(); + return url.includes('welcome'); + }, 20000); + + console.log('Successfully logged in!'); + } catch (error) { + console.error('Login failed:', error.message); + FailedToLoadPath.push(LOGIN_URL); + await driver.quit(); + process.exit(1); + } + }else { + // Steps for onprem testing + // 1. Login + // 2. Create new workflow + + // Write your own login credentials here if you are testing onprem locally + const USERNAME = 'demo@demo.io'; + const PASSWORD = 'supercoolpassword'; + const WORKFLOW_URL = `${frontendURL}/workflows`; + + try { + // Login + console.log('Logging in...'); + await driver.get(`${frontendURL}/login`); + + await driver.wait(until.elementLocated(By.css('#emailfield')), 10000); + await driver.findElement(By.css('#emailfield')).sendKeys(USERNAME); + + await driver.wait(until.elementLocated(By.css('#outlined-password-input')), 10000); + await driver.findElement(By.css('#outlined-password-input')).sendKeys(PASSWORD); + + const loginButton = await driver.findElement(By.css('#loginButton')); + await driver.executeScript("arguments[0].scrollIntoView(true);", loginButton); + await loginButton.click(); + + + + // Ensure signup success by checking URL change + await driver.wait(async () => { + const url = await driver.getCurrentUrl(); + return url.includes('welcome') || url.includes('workflows'); + }, 20000); + + + const isParentPresent = await driver.wait(async () => { + return await driver.executeScript( + "return document.querySelector('.parent-component') !== null;" + ); + }, 5000).catch(() => false); + + if (!isParentPresent) { + const logs = await driver.manage().logs().get('browser'); + const severeErrors = logs.filter(log => log.level.name === 'SEVERE'); + if (severeErrors.length > 0) { + const crashCausingErrors = severeErrors.filter(err => { + return !err.message.includes('Warning:') && + !err.message.includes('MUI:') + }); + + console.error(`Page (${frontendURL}/login) did not load correctly:`, crashCausingErrors); + FailedToLoadPath.push(`${frontendURL}/login`); + } + } + + console.log('Successfully logged in!'); + + } catch (error) { + console.error('Failed to login:', error.message); + FailedToLoadPath.push(WORKFLOW_URL); + await driver.quit(); + process.exit(1); + } + + try { + // Create new workflow + console.log('Creating new workflow...'); + await driver.get(WORKFLOW_URL); + + await driver.sleep(1000); + + await driver.wait(until.elementLocated(By.css('#create_workflow_button')), 10000); + const create_workflow_button = await driver.findElement(By.css('#create_workflow_button')); + + await driver.sleep(1000); + await create_workflow_button.click(); + + await driver.sleep(1500); + + await driver.wait(until.elementLocated(By.css('#Enter-Workflow-Name')), 10000); + const enter_workflow_name_field = await driver.findElement(By.css('#Enter-Workflow-Name')); + + await driver.sleep(1000); + await enter_workflow_name_field.sendKeys("Test Workflow"); + + // Wait before saving + await driver.sleep(1500); + + await driver.wait(until.elementLocated(By.css('#save_workflow_button')), 10000); + const save_workflow_button = await driver.findElement(By.css('#save_workflow_button')); + + await driver.sleep(1000); // Delay before clicking + await save_workflow_button.click(); + + // Wait for the parent component to appear + await driver.sleep(2000); + + const isParentPresent = await driver.wait(async () => { + return await driver.executeScript( + "return document.querySelector('.parent-component') !== null;" + ); + }, 5000).catch(() => false); + + if (!isParentPresent) { + const logs = await driver.manage().logs().get('browser'); + const severeErrors = logs.filter(log => log.level.name === 'SEVERE'); + if (severeErrors.length > 0) { + const crashCausingErrors = severeErrors.filter(err => { + return !err.message.includes('Warning:') && + !err.message.includes('MUI:'); + }); + + console.error(`Page (${WORKFLOW_URL}) did not load correctly:`, crashCausingErrors); + FailedToLoadPath.push(`${WORKFLOW_URL}`); + } + } + + } catch (error) { + console.error('Failed to create new workflow:', error.message); + FailedToLoadPath.push(WORKFLOW_URL); + await driver.quit(); + process.exit(1); + } + } + + // Get routes from command line arguments + if (routes.length === 0) { + console.error('No routes found to test.'); + await driver.quit(); + process.exit(1); + } + console.log(`Found ${routes.length} routes to test.`); + + for (const route of routes) { + const url = `${frontendURL}/${route}`; + console.log(`Testing route: ${url}`); + + try { + await driver.get(url); + await driver.sleep(3000); + + // Wait for document readiness + await driver.wait(async () => { + return await driver.executeScript('return document.readyState') === 'complete'; + }, 10000); + + const isParentPresent = await driver.wait(async () => { + return await driver.executeScript( + "return document.querySelector('.parent-component') !== null;" + ); + }, 5000).catch(() => false); + + if (!isParentPresent) { + const logs = await driver.manage().logs().get('browser'); + const severeErrors = logs.filter(log => log.level.name === 'SEVERE'); + if (severeErrors.length > 0) { + const crashCausingErrors = severeErrors.filter(err => { + return !err.message.includes('Warning:') && + !err.message.includes('MUI:') + }); + + console.error(`Page (${url}) did not load correctly:`, crashCausingErrors); + FailedToLoadPath.push(url); + } + continue; + } + + console.log(`Successfully loaded: ${url}`); + SuccessfullyLoadedPath.push(url); + } catch (error) { + console.error(`Failed to load ${url}:`, error.message); + } + } + } finally { + console.log("Total pages tested: ", SuccessfullyLoadedPath.length + FailedToLoadPath.length); + console.log("Successfully loaded pages: ", SuccessfullyLoadedPath.length); + if (FailedToLoadPath.length > 0) { + console.log("Failed to load pages: ", FailedToLoadPath.length); + console.log("Failed to load pages paths: ", FailedToLoadPath); + process.exit(1); + }else { + console.log("No pages failed to load. Congrats!"); + } + await driver.quit(); + fs.rmSync(userDataDir, { recursive: true, force: true }); + } +})(); \ No newline at end of file diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 8c0e8870..7fa7c847 100755 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -25,6 +25,7 @@ import AdminSetup from "./views/AdminSetup.jsx"; import Admin from "./views/Admin.jsx"; import Docs from "./views/Docs.jsx"; import Usecases2 from "./views/Usecases2.jsx"; +import DashboardViews from "./views/DashboardViews.jsx"; //import Introduction from "./views/Introduction"; import SetAuthentication from "./views/SetAuthentication.jsx"; import SetAuthenticationSSO from "./views/SetAuthenticationSSO.jsx"; @@ -33,9 +34,10 @@ import RunWorkflow from "./views/RunWorkflow.jsx"; import Admin2 from "./views/Admin2.jsx"; import LoginPage from "./views/LoginPage.jsx"; +import LoginPageOld from "./views/LoginPageOld.jsx"; + import SettingsPage from "./views/SettingsPage.jsx"; import KeepAlive from "./views/KeepAlive.jsx"; - import { ThemeProvider } from "@mui/material/styles"; import CssBaseline from '@mui/material/CssBaseline'; @@ -58,6 +60,7 @@ import 'react-toastify/dist/ReactToastify.css'; import Drift from "react-driftjs"; import { AppContext } from './context/ContextApi.jsx'; +import Navbar from "./components/Navbar.jsx"; import Workflows2 from "./views/Workflows2.jsx"; import AppExplorer from "./views/AppExplorer.jsx"; @@ -186,6 +189,7 @@ const App = (message, props) => { color: "rgba(255, 255, 255, 0.65)", minHeight: "100vh", }} + className='parent-component' > { { window?.location?.pathname === "/" || window?.location?.pathname === "/training" || !(isLoggedIn && isLoaded) ? (
-
*/} + {
*/} + { { /> } /> + + + } + /> + + + } + /> + + + } + /> + { element={ { } /> ) : null} + { /> } /> + { } /> } /> + + } + /> + + } + /> { exact path="/docs" element={ - //navigate(`/docs/about`) { /> } /> - - } - /> + + } + /> + + } + /> + + } + /> + + } + /> { return (
-
-
+ +
+ + + */} + + + ); }); diff --git a/frontend/src/components/AppCreationModal.jsx b/frontend/src/components/AppCreationModal.jsx index f5a25169..a9f8f598 100644 --- a/frontend/src/components/AppCreationModal.jsx +++ b/frontend/src/components/AppCreationModal.jsx @@ -22,7 +22,6 @@ import CreateIcon from '@mui/icons-material/Create' import { toast } from 'react-toastify' import YAML from "yaml"; - const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => { const [openApiModal, setOpenApiModal] = useState(false) const [generateAppModal, setGenerateAppModal] = useState(false) @@ -59,6 +58,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => { : "1px solid rgba(255,255,255,0.3)", borderImage: makeFancy ? "linear-gradient(to right, #ff8544 0%, #ec517c 50%, #9c5af2 100%) 1" : "none", transition: 'all 0.2s ease-in-out', + paddingBottom: isCloud ? 0 : 175, } return ( @@ -256,26 +256,27 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => { body: openApidata, credentials: "include", }) - .then((response) => { + .then((response) => { - setValidation(false); - return response.json(); - }) - .then((responseJson) => { - if (responseJson.success) { - setAppValidation(responseJson.id); - } else { - if (responseJson.reason !== undefined) { - setOpenApiError(responseJson.reason); - } - toast("An error occurred in the response"); - } - }) - .catch((error) => { - setValidation(false); - toast(error.toString()); - setOpenApiError(error.toString()); - }); + setValidation(false); + return response.json(); + }) + .then((responseJson) => { + if (responseJson?.success === true) { + setAppValidation(responseJson?.id) + navigate(`/apps/new?id=${responseJson?.id}`) + } else { + if (responseJson.reason !== undefined) { + setOpenApiError(responseJson.reason) + } + toast("An error occurred in the response"); + } + }) + .catch((error) => { + setValidation(false); + toast(error.toString()); + setOpenApiError(error.toString()); + }); }; const redirectOpenApi = () => { @@ -416,7 +417,7 @@ const AppCreationModal = ({ open, onClose, theme, globalUrl, isCloud }) => { -
+
{ diff --git a/frontend/src/components/AppFramework.jsx b/frontend/src/components/AppFramework.jsx index c65cf1cf..d6fc1f42 100644 --- a/frontend/src/components/AppFramework.jsx +++ b/frontend/src/components/AppFramework.jsx @@ -198,7 +198,7 @@ export const findSpecificApp = (framework, inputcategory) => { id: "", } } else { - console.log("findSpecificApp: unknown category: ", category) + //console.log("findSpecificApp: unknown category: ", category) } return null diff --git a/frontend/src/components/AppGrid.jsx b/frontend/src/components/AppGrid.jsx index 1f758a7e..8a5d9a18 100644 --- a/frontend/src/components/AppGrid.jsx +++ b/frontend/src/components/AppGrid.jsx @@ -116,7 +116,7 @@ const AppGrid = (props) => { }) .then((response) => response.json()) .then((response) => { - if (response.success === true) { + if (response?.success === true) { setFormMessage(response.reason); //toast("Thanks for submitting!") } else { @@ -307,7 +307,7 @@ const AppGrid = (props) => { }) .then(response => response.json()) .then(responseJson => { - if (responseJson.success) { + if (responseJson?.success) { setUserdata(responseJson); setAllActivatedAppIds(responseJson.active_apps) setIsLoggedIn(true); @@ -350,7 +350,7 @@ const AppGrid = (props) => { }) .then((response) => response.json()) .then((responseJson) => { - if (responseJson.success === false) { + if (responseJson?.success === false) { toast.error(responseJson.reason); } else { //toast.success(`App ${type}d Successfully!`); @@ -414,7 +414,7 @@ const AppGrid = (props) => { scrollbarColor: "#494949 #2f2f2f", }} > - {hits.map((data, index) => { + {hits?.map((data, index) => { const appUrl = isCloud === true ? `/apps/${data.objectID}` @@ -556,7 +556,7 @@ const AppGrid = (props) => { }} > - {data.tags.slice(0, 1).map((tag, tagIndex) => ( + {data?.tags?.slice(0, 1)?.map((tag, tagIndex) => ( {normalizedString(tag)} {tagIndex < 1 ? ", " : ""} @@ -569,7 +569,7 @@ const AppGrid = (props) => { ) : (
{data.tags && - data.tags.map((tag, tagIndex) => ( + data?.tags?.map((tag, tagIndex) => ( {normalizedString(tag)} {tagIndex < data.tags.length - 1 ? ", " : ""} @@ -760,7 +760,7 @@ const AppGrid = (props) => { }; const transformRefinementListItems = items => - items.map(item => ({ + items?.map(item => ({ ...item, label: item.label === 'true' ? 'App Editor' : 'Python', })); @@ -1103,7 +1103,7 @@ const AppGrid = (props) => { } }); - const categoryArray = Object.keys(categoryCountMap).map((category) => ({ + const categoryArray = Object.keys(categoryCountMap)?.map((category) => ({ category, count: categoryCountMap[category], })); @@ -1169,7 +1169,7 @@ const AppGrid = (props) => { {!isLoading && (
- {topCategories.map((data, index) => ( + {topCategories?.map((data, index) => (
- {topTags && topTags.length > 0 && topTags.map((data, index) => ( + {topTags && topTags.length > 0 && topTags?.map((data, index) => (
{top_text === "Base Cloud Access" && userdata.has_card_available === true ? { { }} @@ -857,6 +860,7 @@ const Billing = memo((props) => { "Add Card Details" } + {userdata.has_card_available === true ? + + {fileCategories !== undefined && + fileCategories !== null && + fileCategories.length > 1 ? ( + + + { + setShowFileCategoryPopup(false) + }} + > + File Categories + + Please note that your selected files ({selectedFileId?.length}) will be moved to the {updateToThisCategory} category. + + + + + + + + ) : null} + +
+ {renderTextBox ? + + + + : + + + + } + + {renderTextBox && { + handleKeyDown(event); + if(event.key === 'Enter' && selectedFileId.length > 0){ + //setShowFileCategoryPopup(true) + setUpdateToThisCategory(event.target.value) + } + + }} + style={{ + height: 35, + width: 200, + marginTop: 0, + }} + InputProps={{ + style: { + color: "white", + height: 35, + fontSize: 16, + borderRadius: 4, + paddingTop: 0, + }, + }} + color="primary" + placeholder="Category name" + required + margin="dense" + defaultValue={""} + autoFocus + />}
{isSelectedDataStore? null : { ): listCache?.map((data, index) => { + var category = selectedCategory + if (selectedCategory === "default") { + category = "" + } + + if (data?.category === undefined && category === "") { + } else if (data?.category !== category) { + return null + } + var bgColor = isSelectedDataStore? "#212121":"#27292d"; if (index % 2 === 0) { bgColor = isSelectedDataStore? "#1A1A1A":"#1f2023"; diff --git a/frontend/src/components/DashboardBarchart.jsx b/frontend/src/components/DashboardBarchart.jsx index 58f20708..74970549 100644 --- a/frontend/src/components/DashboardBarchart.jsx +++ b/frontend/src/components/DashboardBarchart.jsx @@ -65,80 +65,83 @@ export const LoadStats = (globalUrl, cachekey) => { } const DashboardBarchart = (props) => { - const { timelineData, title, height, } = props; - var inputHeight = 15 - if (height !== undefined && height !== null) { - inputHeight = height - } + // this is clearly unfinished and not worth my time. + // refer to health page to see how i made it work there w/o using chartjs - const barOptions = { - plugins: { - tooltip: { - enabled: true, // Ensure tooltips are enabled - }, - }, - tooltips: { - mode: 'index', - intersect: false, - }, - legend: { - display: false - }, - layout: { - padding: { - top: 0, // Adjust the top padding as needed - bottom: -10, // Adjust the bottom padding as needed - left: 0, // Adjust the left padding as needed - right: 0, // Adjust the right padding as needed - }, - }, - scales: { - y: { - beginAtZero: false, - }, - yAxes: [{ - ticks: { - display: false - }, - beginAtZero: false, - }], - xAxes: [{ - ticks: { - display: false - }, - beginAtZero: false, - }] - }, - tooltips: { - callbacks: { - label: function (tooltipItem, data) { - const label = data.labels[tooltipItem.index] - return label.split('\n')[0] - }, - afterLabel: function (tooltipItem, data) { - const amount = tooltipItem.value === undefined || tooltipItem.value === null ? 0 : tooltipItem.value - return `Amount: ${amount}` - }, - title: function () { - return title === undefined ? '' : title - } - } - } - } + // const { timelineData, title, height, } = props; + // var inputHeight = 15 + // if (height !== undefined && height !== null) { + // inputHeight = height + // } - return ( - { - if (elements && elements.length > 0) { - //toast("Click event") - console.log("Clicked: ", elements) - } - }} - /> - ) + // const barOptions = { + // plugins: { + // tooltip: { + // enabled: true, // Ensure tooltips are enabled + // }, + // }, + // tooltips: { + // mode: 'index', + // intersect: false, + // }, + // legend: { + // display: false + // }, + // layout: { + // padding: { + // top: 0, // Adjust the top padding as needed + // bottom: -10, // Adjust the bottom padding as needed + // left: 0, // Adjust the left padding as needed + // right: 0, // Adjust the right padding as needed + // }, + // }, + // scales: { + // y: { + // beginAtZero: false, + // }, + // yAxes: [{ + // ticks: { + // display: false + // }, + // beginAtZero: false, + // }], + // xAxes: [{ + // ticks: { + // display: false + // }, + // beginAtZero: false, + // }] + // }, + // tooltips: { + // callbacks: { + // label: function (tooltipItem, data) { + // const label = data.labels[tooltipItem.index] + // return label.split('\n')[0] + // }, + // afterLabel: function (tooltipItem, data) { + // const amount = tooltipItem.value === undefined || tooltipItem.value === null ? 0 : tooltipItem.value + // return `Amount: ${amount}` + // }, + // title: function () { + // return title === undefined ? '' : title + // } + // } + // } + // } + + // return ( + // { + // if (elements && elements.length > 0) { + // //toast("Click event") + // console.log("Clicked: ", elements) + // } + // }} + // /> + // ) } export default DashboardBarchart; diff --git a/frontend/src/components/EditOrgTab.jsx b/frontend/src/components/EditOrgTab.jsx index 6a5e1662..c1cd11fc 100644 --- a/frontend/src/components/EditOrgTab.jsx +++ b/frontend/src/components/EditOrgTab.jsx @@ -1,8 +1,8 @@ import React, { useEffect, useState, useContext } from 'react'; -import OrgHeaderexpanded from "./OrgHeaderexpandedNew.jsx"; -import OrgHeader from './OrgHeaderNew.jsx'; +import OrgHeaderexpanded from "../components/OrgHeaderexpandedNew.jsx"; +import OrgHeader from '../components/OrgHeaderNew.jsx'; import { toast } from "react-toastify"; -import CloudSyncTab from './CloudSyncTab.jsx'; +import CloudSyncTab from '../components/CloudSyncTab.jsx'; import { FileCopy as FileCopyIcon, } from "@mui/icons-material"; @@ -443,4 +443,4 @@ If you're interested, please let me know a time that works for you, or set up a ) } -export default EditOrgTab; \ No newline at end of file +export default EditOrgTab; diff --git a/frontend/src/components/EditWorkflow.jsx b/frontend/src/components/EditWorkflow.jsx index cf51720b..5f571110 100644 --- a/frontend/src/components/EditWorkflow.jsx +++ b/frontend/src/components/EditWorkflow.jsx @@ -88,6 +88,8 @@ const EditWorkflow = (props) => { const [inputMarkdown, setInputMarkdown] = React.useState(workflow?.form_control?.input_markdown !== undefined && workflow?.form_control?.input_markdown !== null ? workflow?.form_control?.input_markdown : "") const [scrollDone, setScrollDone] = React.useState(false) const [selectedYieldActions, setSelectedYieldActions] = React.useState(workflow?.form_control?.output_yields !== undefined && workflow?.form_control?.output_yields !== null ? JSON.parse(JSON.stringify(workflow?.form_control?.output_yields)) : []) + const [selectedCleanupActions, setSelectedCleanupActions] = React.useState(workflow?.form_control?.cleanup_actions !== undefined && workflow?.form_control?.cleanup_actions !== null ? JSON.parse(JSON.stringify(workflow?.form_control?.cleanup_actions)) : []) + const [formWidth, setFormWidth] = React.useState(boxWidth === undefined || boxWidth === null ? 500 : boxWidth) const classes = useStyles(); @@ -189,6 +191,10 @@ const EditWorkflow = (props) => { var upload = ""; var total_count = 0 + const isCloud = + window.location.host === "localhost:3002" || + window.location.host === "shuffler.io"; + return ( {
@@ -1586,6 +1610,18 @@ useEffect(() => { marginLeft: 5, }} > + + {expandLeftNav && + + } { }; export default LeftSideBar; - - -const ModalView = memo(({searchBarModalOpen, setSearchBarModalOpen, globalUrl, serverside, userdata}) => { +const ModalView = memo(({searchBarModalOpen, setSearchBarModalOpen, globalUrl, serverside, userdata, isDocSearchModalOpen}) => { return ( ( { setSearchBarModalOpen(false); }} diff --git a/frontend/src/components/LicencePopup.jsx b/frontend/src/components/LicencePopup.jsx index c29095e4..67fb07b4 100644 --- a/frontend/src/components/LicencePopup.jsx +++ b/frontend/src/components/LicencePopup.jsx @@ -46,7 +46,7 @@ import { handlePayasyougo } from "../views/HandlePaymentNew.jsx" import Billing from "./Billing.jsx"; const LicencePopup = (props) => { - const { globalUrl, userdata, serverside, billingInfo, stripeKey, setModalOpen, isLoggedIn, isMobile, selectedOrganization, isCloud } = props; + const { globalUrl, userdata, serverside, billingInfo, stripeKey, setModalOpen, isScale, isLoggedIn, isMobile, selectedOrganization, isCloud } = props; //const alert = useAlert(); let navigate = useNavigate(); const [selectedDealModalOpen, setSelectedDealModalOpen] = React.useState(false); @@ -165,11 +165,25 @@ const LicencePopup = (props) => { ] } + if (userdata?.app_execution_limit >= 300000) { + subscription.name = "Enterprise" + subscription.currency_text = "$" + subscription.price = typecost_single + subscription.limit = userdata?.app_execution_limit + subscription.interval = "app run / month" + subscription.features = [ + "Includes " + (userdata?.app_execution_limit/1000) + "K app runs/month. ", + "Multi-Tenancy and Region-Selection", + "And all other features from /pricing", + ] + } + + var newPaperstyle = JSON.parse(JSON.stringify(paperStyle)) if (subscription.name === "Enterprise" && subscription.active === true) { - top_text = "Current Plan" + top_text = "Enterprise Plan" - newPaperstyle.border = "1px solid #f85a3e" + // newPaperstyle.border = "1px solid #f85a3e" } var showSupport = false @@ -255,7 +269,7 @@ const LicencePopup = (props) => { style={{ borderRadius: theme.palette?.borderRadius, }} placement="bottom" > -
+
setHovered(true)} @@ -343,9 +357,9 @@ const LicencePopup = (props) => {
- + {subscription.active === true && !isScale && }
- {top_text === "Base Cloud Access" && userdata.has_card_available === true ? + {top_text === "Base Cloud Access" && userdata.has_card_available === true && !isScale ? { "While you have a card attached to your account, Shuffle will no longer prevent workflows from running. Billing will occur at the start of each month." : isCloud ? - `You are not subscribed to any plan and are using the free plan with max 10,000 app runs per month. Upgrade to deactivate this limit.` + userdata?.app_execution_limit && userdata?.app_execution_limit >= 300000 ? + "You have subscribed to the Enterprise plan, which includes " + (userdata?.app_execution_limit/1000) + "K app runs/month. You can increase the limit by upgrading current plan. Contact support@shuffler.io for more information." : + `You are not subscribed to any plan and are using the free plan with max 10,000 app runs per month. Upgrade to deactivate this limit.` + : `You are not subscribed to any plan and are using the free, open source plan. This plan has no enforced limits, but scale issues may occur due to CPU congestion.` } @@ -699,8 +716,33 @@ const LicencePopup = (props) => { setCalculatedCost("$960") setSelectedValue(8) } else { - setCalculatedCost("$960") - setSelectedValue(300) + if (userdata && userdata?.app_execution_limit) { + if (userdata.app_execution_limit >= 300000 && userdata.app_execution_limit < 400000) { + setSelectedValue(400) + setCalculatedCost("$1280") + }else if (userdata?.app_execution_limit >= 400000 && userdata?.app_execution_limit < 500000) { + setSelectedValue(500) + setCalculatedCost("$1600") + } else if (userdata?.app_execution_limit >= 500000 && userdata?.app_execution_limit < 600000) { + setSelectedValue(600) + setCalculatedCost("$1920") + } else if (userdata?.app_execution_limit >= 600000 && userdata?.app_execution_limit < 700000) { + setSelectedValue(700) + setCalculatedCost("$2240") + } else if (userdata?.app_execution_limit >= 700000 && userdata?.app_execution_limit < 800000) { + setSelectedValue(800) + setCalculatedCost("$2560") + } else if (userdata?.app_execution_limit >= 800000 && userdata?.app_execution_limit < 900000) { + setSelectedValue(900) + setCalculatedCost("$2880") + }else { + setCalculatedCost("$960") + setSelectedValue(300) + } + }else { + setCalculatedCost("$960") + setSelectedValue(300) + } } }, [shuffleVariant]) @@ -864,20 +906,26 @@ const LicencePopup = (props) => { return } - const priceItem = window.location.origin === "https://shuffler.io" ? - shuffleVariant === 0 ? "app_executions" : "cores" - : - shuffleVariant === 0 ? "price_1PZPSSEJjT17t98NLJoTMYja" : "price_1PZPQuEJjT17t98N3yORUtd9" + const priceItem = + window.location.origin === "https://shuffler.io/" || "https://sandbox.shuffler.io/" + ? shuffleVariant === 0 + ? "price_1PWI3uDzMUgUjxHSffUBwWCy" + : "price_1PWI8EDzMUgUjxHSfEhUB7oL" + + : shuffleVariant === 0 + ? "price_1PZPSSEJjT17t98NLJoTMYja" + : "price_1PZPQuEJjT17t98N3yORUtd9"; const successUrl = `${window.location.origin}/admin?admin_tab=billingstats&payment=success` const failUrl = `${window.location.origin}/admin?admin_tab=billingstats&payment=failure` + const quantity = shuffleVariant === 0 ? selectedValue / 100 : selectedValue - console.log("Priceitem: ", priceItem, shuffleVariant) + console.log("Priceitem: ", priceItem, quantity, shuffleVariant) var checkoutObject = { lineItems: [ { price: priceItem, - quantity: shuffleVariant === 0 ? selectedValue / 100 : selectedValue, + quantity: quantity, }, ], mode: "subscription", @@ -973,7 +1021,7 @@ const LicencePopup = (props) => { : null} - {isCloud && + {/* {isCloud && selectedOrganization.subscriptions !== undefined && selectedOrganization.subscriptions !== null && selectedOrganization.subscriptions.length > 0 ? @@ -994,7 +1042,7 @@ const LicencePopup = (props) => { /> ) }) - : null} + : null} */} @@ -1002,12 +1050,12 @@ const LicencePopup = (props) => {
- + color="primary">Recommended }
{shuffleVariant === 1 ? "Scale" : "Enterprise"} @@ -1095,6 +1143,7 @@ const LicencePopup = (props) => { > View all plans + + + + {section === 'Resources' ? ( + + {menuData.Resources.columns.map((column, index) => ( + + + {column.title} + + + {column.social ? ( + <> + + {column.platforms.map((platform) => ( + { + if (isCloud) { + ReactGA.event(platform.gaData); + } + window.open(platform.link, '_blank') + return; + }} + // onClick={() => showDesktopToast()} + > + {platform.name} + + ))} + + + Follow Us + + + {column.followUs.map((platform) => ( + { + if (isCloud) { + ReactGA.event(platform.gaData); + } + window.open(platform.link, '_blank') + return; + }} + > + {platform.name} + + ))} + + + ) : ( + column.items.map((item) => ( + + )) + )} + + ))} + + ) : ( + + {menuData[section].map((item) => ( + + ))} + + )} + + + ))} + + {/* Static menu items */} + + + + {/* Action buttons */} + + + + + + + ); +}; + +const Navbar = (props) => { + const { + globalUrl, + isLoaded, + isLoggedIn, + removeCookie, + homePage, + userdata, + // isMobile, + serverside, + billingInfo, + + notifications, + } = props; + + const topbar_var = "topbar_closed10" + + const theme = useTheme(); + const {searchBarModalOpen, setSearchBarModalOpen, isDocSearchModalOpen} = useContext(Context) + const [pricingModalOpen, setPricingModalOpen] = useState(false); + const isTabletOrMobile = useMediaQuery(theme.breakpoints.down("lg")); + const isMobile = useMediaQuery(theme.breakpoints.down("md")); + const [anchorElNav, setAnchorElNav] = useState(null); + const [openMenu, setOpenMenu] = useState(null); + const [selectedOrganization, setSelectedOrganization] = useState({}); + const navigate = useNavigate(); + const [anchorElUser, setAnchorElUser] = useState(null); + const [anchorElOrg, setAnchorElOrg] = useState(null); + const [isOrgChanging, setIsOrgChanging] = useState(false); + const [isHovered, setIsHovered] = useState(""); + const [orgSelectOpen, setOrgSelectOpen] = useState(false); + const [showTopbar, setShowTopbar] = useState(true) // Set to true to show top bar + const isCloud = + serverside === true || typeof window === "undefined" + ? true + : window.location.host === "localhost:3002" || + window.location.host === "shuffler.io" || + window.location.host === "localhost:5002"; + + + const stripeKey = typeof window === 'undefined' || window.location === undefined ? "" : window.location.origin === "https://shuffler.io" ? "pk_live_51PXYYMEJjT17t98N20qEqItyt1fLQjrnn41lPeG2PjnSlZHTDNKHuisAbW00s4KAn86nGuqB9uSVU4ds8MutbnMU00DPXpZ8ZD" : "pk_test_51PXYYMEJjT17t98NbDkojZ3DRvsFUQBs35LGMx3i436BXwEBVFKB9nCvHt0Q3M4MG3dz4mHheuWvfoYvpaL3GmsG00k1Rb2ksO" + + useEffect(() => { + // Manually setShowTopbar(true) to show topbar by default + const topbar = localStorage.getItem(topbar_var) + if (topbar === "true") { + setShowTopbar(false) + } + }, []) + + const pricingModal = + { + setPricingModalOpen(false); + }} + PaperProps={{ + style: { + color: "white", + minWidth: 850, + minHeight: 370, + padding: 20, + backgroundColor: "rgba(0, 0, 0, 1)", + borderRadius: theme.palette?.borderRadius, + }, + }} + > + + + Upgrade your plan + + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "close_upgrade_modal", + label: "navbar_upgrade_modal", + }) + }; + setPricingModalOpen(false); + }} + style={{ + marginLeft: "auto", + position: "absolute", + top: 20, + right: 20, + }} + > + + + +
+ +
+
+ + + const modalView = ( + { + setSearchBarModalOpen(false); + }} + PaperProps={{ + style: { + color: "white", + minWidth: 750, + height: 785, + borderRadius: 16, + border: "1px solid var(--Container-Stroke, #494949)", + background: "var(--Container, #000000)", + boxShadow: "0px 16px 24px 8px rgba(0, 0, 0, 0.25)", + }, + }} + sx={{ + zIndex: 50005, + '& .MuiBackdrop-root': { + backgroundColor: 'rgba(0, 0, 0, 0.8)', + }, + }} + > + + + Search for Docs, Apps, Workflows and more + + setSearchBarModalOpen(false)} + sx={{ + color: 'white', + '&:hover': { + backgroundColor: 'rgba(255, 255, 255, 0.1)' + } + }} + > + + + + + + + + + + + ); + + const handleOpenNavMenu = (event) => { + setAnchorElNav(event.currentTarget); + }; + + const handleCloseNavMenu = () => { + setAnchorElNav(null); + }; + + const handleMenuOpen = (menu) => { + setOpenMenu(menu); + }; + + const handleMenuClose = () => { + setOpenMenu(null); + }; + + const handleOpenUserMenu = (event) => { + setAnchorElUser(event.currentTarget); + }; + + const handleCloseUserMenu = () => { + setAnchorElUser(null); + }; + + const handleOpenOrgMenu = (event) => { + setAnchorElOrg(event.currentTarget); + }; + + const handleCloseOrgMenu = () => { + setAnchorElOrg(null); + }; + + const menuStyles = { + "& .MuiPaper-root": { + backgroundColor: "#212121", + marginTop: 1, + backdropFilter: "blur(10px)", + fontFamily: theme.typography.fontFamily, + }, + }; + + const menuItemBox = { + display: "flex", + alignItems: "flex-start", + padding: 2, + paddingTop: "20px", + paddingBottom: "20px", + paddingLeft: "20px", + gap: 2, + width: "100%", + backgroundColor: "#212121", + transition: "all 0.2s ease-in-out", + borderBottom: "1px solid #494949", + }; + + const buttonStyles = { + fontFamily: theme.typography.fontFamily, + color: "white", + textTransform: "none", + fontSize: "16px", + fontWeight: 400, + padding: "6px 12px", + "& .MuiSvgIcon-root": { + transition: "transform 0.2s ease-in-out", + }, + "&:hover": { + backgroundColor: "transparent", + color: theme.palette.primary.main, + "& .MuiSvgIcon-root": { + transform: "rotate(180deg)", + }, + }, + }; + + // Render menu content based on type + const renderMenuContent = (item, isCloud) => { + if (item === "Resources") { + return ( + + {menuData.Resources.columns.map((column, index) => ( + + + {column.title} + + + {column.social ? ( + <> + + {column.platforms.map((platform) => ( + { + if (isCloud) { + ReactGA.event(platform.gaData); + } + handleMenuClose(); + }} + sx={{ + padding: 0, + width: 48, + height: 48, + "&:hover": { + backgroundColor: "transparent", + opacity: 0.8, + }, + }} + > + {platform.name} + + ))} + + + Follow Us + + + {column.followUs.map((platform) => ( + { + if (isCloud) { + ReactGA.event(platform.gaData); + } + handleMenuClose(); + }} + sx={{ + padding: 0, + width: 48, + height: 48, + "&:hover": { + backgroundColor: "transparent", + opacity: 0.8, + }, + }} + > + {platform.name} + + ))} + + + ) : ( + + {column.items.map((item) => ( + + ))} + + )} + + ))} + + ); + } + + return menuData[item].map((menuItem, index) => ( + { + if (menuItem.title === "Singul") { + window.open(menuItem.path, '_blank'); + return; + } + if(isCloud) { + ReactGA.event(menuItem.gaData); + } + handleCloseNavMenu(); + handleMenuClose(); + if(isCloud) { + navigate(menuItem.path); + } else { + if(menuItem.path.includes("docs")){ + navigate(menuItem.path); + handleMenuClose(); + }else{ + window.open("https://shuffler.io" + menuItem.path, '_blank'); + return; + } + } + }} + sx={{ + padding: 0, + backgroundColor: "#212121", + "&:hover": { + backgroundColor: "#212121", + }, + "&:last-child": { + borderBottomLeftRadius: "4px", + borderBottomRightRadius: "4px", + }, + "&:first-of-type": { + paddingTop: "4px", + }, + }} + > + + + + + + {menuItem.title} + + {menuItem.title === "Singul" && ( + + Coming Soon + + )} + + + {menuItem.description} + + + + + )); + }; + + const renderDesktopMenu = () => ( + + {Object.keys(menuData).map((item) => ( + + + + {/* Custom Dropdown */} + handleMenuOpen(item)} + onMouseLeave={handleMenuClose} + sx={{ + position: "absolute", + top: "130%", + left: + item === "Products" + ? 0 + : item === "Services" + ? -50 + : item === "Resources" + ? isTabletOrMobile ? -330 : -250 + : 0, + backgroundColor: "#212121", + borderTopLeftRadius: 0, + borderTopRightRadius: 0, + borderBottomLeftRadius: "4px", + borderBottomRightRadius: "4px", + boxShadow: + "0 8px 16px rgba(0, 0, 0, 0.25), 0 2px 4px rgba(0, 0, 0, 0.1)", + backdropFilter: "blur(10px)", + zIndex: -20, + opacity: openMenu === item ? 1 : 0, + visibility: openMenu === item ? "visible" : "hidden", + transform: openMenu === item ? "translateY(0)" : "translateY(-8px)", + transition: "transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease", + pointerEvents: openMenu === item ? "auto" : "none", + ...(item === "Resources" && { + width: "900px", + padding: 3, + }), + }} + > + {renderMenuContent(item, isCloud)} + + + ))} + + + + ); + + const menuItemStyles = { + fontFamily: theme.typography.fontFamily, + color: "white", + "&:hover": { + backgroundColor: "rgba(255, 133, 68, 0.1)", + }, + }; + + const searchButtonStyles = { + fontFamily: theme.typography.fontFamily, + color: "rgba(255, 255, 255, 0.7)", + border: "1px solid rgba(26, 26, 26, 0.8)", + backgroundColor: "#2F2F2F", + textTransform: "none", + borderRadius: "8px", + fontSize: "14px", + padding: "6px 12px", + display: "flex", + alignItems: "center", + height: "42px", + gap: 1, + minWidth: "110px", + justifyContent: "space-between", + "&:hover": { + borderColor: "rgba(255, 255, 255, 0.1)", + }, + }; + + const searchIconButtonStyles = { + color: "rgba(255, 255, 255, 0.7)", + padding: "8px", + minWidth: "unset", + height: "42px", + "&:hover": { + backgroundColor: "#3F3F3F", + }, + }; + + // Add this shared button style + const sharedButtonStyles = { + fontFamily: theme.typography.fontFamily, + textTransform: "none", + fontSize: "16px", + fontWeight: 600, + padding: "6px 24px", + }; + + + useEffect(() => { + Mousetrap.bind(['command+k', 'ctrl+k'], () => { + setSearchBarModalOpen(true); + return false; // Prevent the default action + }); + Mousetrap.bind(['esc'], () => { + setSearchBarModalOpen(false); + return false; // Prevent the default action + }); + + return () => { + Mousetrap.unbind(['command+k', 'ctrl+k']); + }; + }, []); + + useEffect(() => { + if (isLoggedIn && userdata?.active_org?.id?.length > 0) { + handleGetOrg(userdata.active_org.id); + } + }, [isLoggedIn]); + + const handleGetOrg = (orgId) => { + fetch(`${globalUrl}/api/v1/orgs/${orgId}`, { + method: "GET", + credentials: "include", + headers: { + "Content-Type": "application/json", + }, + }) + .then((response) => { + if (response.status === 401) { + } + + return response.json(); + }) + .then((responseJson) => { + if (responseJson["success"] === false) { + console.log("Error getting org: ", responseJson); + } else { + setSelectedOrganization(responseJson); + } + }) + .catch((error) => { + console.log("Error getting org: ", error); + }); + }; + + const handleClickLogout = () => { + console.log("SHOULD LOG OUT"); + + toast.info("Logging out..."); + // Don't really care about the logout + fetch(globalUrl + "/api/v1/logout", { + credentials: "include", + method: "POST", + headers: { + "Content-Type": "application/json", + }, + }) + .then(() => { + // Log out anyway + removeCookie("session_token", { path: "/" }); + removeCookie("session_token", { path: "/" }); + removeCookie("session_token", { path: "/" }); + + removeCookie("__session", { path: "/" }); + removeCookie("__session", { path: "/" }); + removeCookie("__session", { path: "/" }); + + removeCookie("__session", { path: "/" }); + + window.location.pathname = "/"; + + localStorage.setItem("globalUrl", "") + + // Delete userinfo from localstorage + localStorage.removeItem("apps") + localStorage.removeItem("workflows") + localStorage.removeItem("userinfo") + }) + .catch((error) => { + console.log(error); + }); + }; + + const topbarHeight = showTopbar ? 40 : 0 + const topbar = !isCloud || !showTopbar ? null : + curpath === "/" || curpath.includes("/docs") || curpath === "/pricing" || curpath === "/contact" || curpath === "/search" || curpath === "/usecases" || curpath === "/training" || curpath === "/professional-services" ? + +
+ + {/* Shuffle 1.4.0 is out! Read more about  */} + Shuffle 2.0.0 is out now!  + + { + ReactGA.event({ + category: "landingpage", + action: "click_header_training", + label: "", + }) + + navigate("/articles/2.0_release") + + }} style={{ cursor: "pointer", textDecoration: "none", fontWeight: 600, color: "rgba(255,255,255,0.9)" }}> + Read about it here. + + + + { + setShowTopbar(false) + + // Set storage that it's clicked + localStorage.setItem(topbar_var, "true") + }}> + + +
+
+ : + null + + const handleClickChangeOrg = (orgId) => { + setIsOrgChanging(true); + const data = { org_id: orgId }; + + localStorage.setItem("globalUrl", ""); + localStorage.setItem("getting_started_sidebar", "open"); + toast.info("Changing organization..."); + fetch(`${globalUrl}/api/v1/orgs/${orgId}/change`, { + mode: "cors", + credentials: "include", + crossDomain: true, + method: "POST", + body: JSON.stringify(data), + withCredentials: true, + headers: { + "Content-Type": "application/json; charset=utf-8", + }, + }) + .then(function (response) { + if (response.status !== 200) { + console.log("Error in response"); + } else { + localStorage.removeItem("apps"); + localStorage.removeItem("workflows"); + localStorage.removeItem("userinfo"); + } + + return response.json(); + }) + .then(function (responseJson) { + if (responseJson.success === true) { + if ( + responseJson.region_url !== undefined && + responseJson.region_url !== null && + responseJson.region_url.length > 0 + ) { + console.log("Region Change: ", responseJson.region_url); + localStorage.setItem("globalUrl", responseJson.region_url); + //globalUrl = responseJson.region_url + } + + if (responseJson["reason"] === "SSO_REDIRECT") { + toast.info("Redirecting to SSO login page as SSO is required for this organization."); + setTimeout(() => { + window.location.href = responseJson["url"]; + }, 2000); + } else { + toast("Successfully changed active organization - refreshing!"); + setTimeout(() => { + window.location.reload(); + }, 2000); + } + } else { + setIsOrgChanging(false); + if ( + responseJson.reason !== undefined && + responseJson.reason !== null && + responseJson.reason.length > 0 + ) { + toast(responseJson.reason); + } else { + toast("Failed changing org. Try again or contact support@shuffler.io if this persists."); + } + } + }) + .catch((error) => { + console.log("error changing: ", error); + setIsOrgChanging(false); + }); + }; + + // Add these helper functions from LeftSideBar + const getRegionTag = (region_url) => { + let regiontag = "EU"; + if (region_url !== undefined && region_url !== null && region_url.length > 0) { + const regionsplit = region_url.split("."); + if (regionsplit.length > 2 && !regionsplit[0].includes("shuffler")) { + const namesplit = regionsplit[0].split("/"); + regiontag = namesplit[namesplit.length - 1]; + + if (regiontag === "california") { + regiontag = "US"; + } else if (regiontag === "frankfurt") { + regiontag = "EU-2"; + } else if (regiontag === "ca") { + regiontag = "CA"; + } + } + } + return regiontag; + }; + + const getRegionFlag = (region_url) => { + const regionTag = getRegionTag(region_url); + const regionMapping = { + "US": "us", + "EU": "eu", + "EU-2": "de", + "CA": "ca", + "UK": "gb" + }; + + const region = regionMapping[regionTag] || "eu"; + return `https://flagcdn.com/48x36/${region}.png`; + }; + + // Add this useEffect to prevent scroll locking + useEffect(() => { + // Remove modal classes that cause scroll locking + const removeModalClasses = () => { + document.body.style.overflow = 'auto'; + document.body.style.paddingRight = '0px'; + }; + + // Create observer to watch for class changes + const observer = new MutationObserver((mutations) => { + mutations.forEach((mutation) => { + if (mutation.attributeName === 'class') { + if (document.body.classList.contains('MuiModal-open')) { + removeModalClasses(); + } + } + }); + }); + + // Start observing + observer.observe(document.body, { + attributes: true, + attributeFilter: ['class'], + }); + + // Cleanup + return () => { + observer.disconnect(); + removeModalClasses(); + }; + }, []); + + const handleOrgSelectClick = (event) => { + // Prevent the default Select behavior + event.preventDefault(); + if(isCloud){ + ReactGA.event({ + category: "navbar", + action: "org_dropdown_click", + label: "org_dropdown_click", + }) + } + // Toggle the select open state + setOrgSelectOpen(!orgSelectOpen); + }; + + return ( + + {topbar} + + + + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "home_click", + label: "shuffle_logo", + }); + } + }} + > + shuffle logo + + + + {isMobile ? ( + /* Mobile Navigation Icons */ + + setSearchBarModalOpen(true)} + > + + + { + if(Boolean(anchorElNav)) { + handleCloseNavMenu(); + }else{ + handleOpenNavMenu(e); + } + } + } + sx={{ color: "white" }} + > + {Boolean(anchorElNav) ? ( + + ) : ( + + )} + + + + ) : ( + <> + {modalView} + {pricingModal} + {renderDesktopMenu()} + {/* Right Side Buttons */} + + {!isLoaded ? ( + + ) : isLoggedIn ? ( + <> + {isOrgChanging ? ( + + ) : ( + <> + + + + K +
+ } + placement="bottom" + arrow + componentsProps={{ + tooltip: { + sx: { + backgroundColor: "rgba(33, 33, 33, 1)", + color: "rgba(241, 241, 241, 1)", + fontSize: 12, + border: "1px solid rgba(73, 73, 73, 1)", + fontFamily: theme?.typography?.fontFamily, + } + }, + popper: { + sx: { + zIndex: 1000019, + } + } + }} + > + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "search_icon_click", + label: "search_icon_click", + }) + } + setSearchBarModalOpen(true); + }} + > + + + + {isCloud && (userdata.org_status === undefined || userdata.org_status === null || userdata.org_status.length === 0) ? + + : null} + + + {/* Organization Dropdown */} + {/* */} + + {/* User Avatar Menu */} + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "click_user_menu", + label: "open_user_dropdown" + }); + } + handleOpenUserMenu(e); + }} + sx={{ + padding: 0, + "&:hover": { + backgroundColor: "rgba(47, 47, 47, 0.5)", + }, + }} + > + + + + + + + {/* User Info Section */} + + + + + + {userdata?.username} + + + + + + + + {/* Menu Items */} + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "user_dropdown_click", + label: "go_to_admin" + }); + } + handleCloseUserMenu(); + navigate("/admin"); + }} + onMouseEnter={() => setIsHovered("organization")} + onMouseLeave={() => setIsHovered("")} + sx={{ + py: 1.5, + px: 2, + fontFamily: theme.typography.fontFamily, + transition: "color 0.1s ease", + '&:hover': { + backgroundColor: 'rgba(255, 255, 255, 0.1)', + color: isHovered === "organization" ? "#FF8544" : "white", + }, + }} + > + + + + Organization + + + + + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "user_dropdown_click", + label: "go_to_settings", + }) + } + handleCloseUserMenu(); + navigate("/settings"); + }} + onMouseEnter={() => setIsHovered("settings")} + onMouseLeave={() => setIsHovered("")} + sx={{ + py: 1.5, + px: 2, + fontFamily: theme.typography.fontFamily, + transition: "color 0.1s ease", + '&:hover': { + backgroundColor: 'rgba(255, 255, 255, 0.1)', + color: isHovered === "settings" ? "#FF8544" : "white", + }, + }} + > + + + + Settings + + + + + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "user_dropdown_click", + label: "go_to_notifications", + }) + } + handleCloseUserMenu(); + navigate("/admin?admin_tab=notifications"); + }} + onMouseEnter={() => setIsHovered("notifications")} + onMouseLeave={() => setIsHovered("")} + sx={{ + py: 1.5, + px: 2, + fontFamily: theme.typography.fontFamily, + transition: "color 0.1s ease", + '&:hover': { + backgroundColor: 'rgba(255, 255, 255, 0.1)', + color: isHovered === "notifications" ? "#FF8544" : "white", + }, + }} + > + + + + Notifications ({notifications === undefined || notifications === null ? 0 : + notifications?.filter((notification) => notification.read === false).length}) + + + + + + + + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "user_dropdown_click", + label: "go_to_about", + }) + } + handleCloseUserMenu(); + navigate("/docs/about"); + }} + onMouseEnter={() => setIsHovered("about")} + onMouseLeave={() => setIsHovered("")} + sx={{ + py: 1.5, + px: 2, + fontFamily: theme.typography.fontFamily, + transition: "color 0.1s ease", + '&:hover': { + backgroundColor: 'rgba(255, 255, 255, 0.1)', + color: isHovered === "about" ? "#FF8544" : "white", + }, + }} + > + + + + About + + + + + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "user_dropdown_click", + label: "logout_click", + }) + } + handleCloseUserMenu(); + handleClickLogout(); + }} + onMouseEnter={() => setIsHovered("logout")} + onMouseLeave={() => setIsHovered("")} + sx={{ + py: 1.5, + px: 2, + fontFamily: theme.typography.fontFamily, + '&:hover': { + backgroundColor: 'rgba(255, 255, 255, 0.1)', + color: isHovered === "logout" ? "#FD4C62" : "white", + }, + }} + > + + + + Logout + + + + + + + + + Version 1.4.5 + + + + + )} + + ) : ( + <> + + + + K +
+ } + placement="bottom" + arrow + componentsProps={{ + tooltip: { + sx: { + backgroundColor: "rgba(33, 33, 33, 1)", + color: "rgba(241, 241, 241, 1)", + fontSize: 12, + border: "1px solid rgba(73, 73, 73, 1)", + fontFamily: theme?.typography?.fontFamily, + } + }, + popper: { + sx: { + zIndex: 1000019, + } + } + }} + > + { + if (isCloud) { + ReactGA.event({ + category: "navbar", + action: "search_icon_click", + label: "search_icon_click", + }) + } + setSearchBarModalOpen(true); + }} + > + + + + + + + {isCloud && + + } + + + + )} + + + )} + + + + ); +}; + +export default Navbar; diff --git a/frontend/src/components/OrgHeaderexpandedNew.jsx b/frontend/src/components/OrgHeaderexpandedNew.jsx index 63adc751..e5317da3 100644 --- a/frontend/src/components/OrgHeaderexpandedNew.jsx +++ b/frontend/src/components/OrgHeaderexpandedNew.jsx @@ -74,7 +74,7 @@ const OrgHeaderexpandedNew = (props) => { getContentAnchorEl: () => null, }; -const [orgName, setOrgName] = useState(selectedOrganization?.name); + const [orgName, setOrgName] = useState(selectedOrganization?.name); const [orgDescription, setOrgDescription] = React.useState( selectedOrganization.description ); @@ -180,41 +180,41 @@ const [orgName, setOrgName] = useState(selectedOrganization?.name); const [uploadUsername, setUploadUsername] = React.useState(selectedOrganization.defaults === undefined ? "" : selectedOrganization.defaults.workflow_upload_username === undefined || selectedOrganization.defaults.workflow_upload_username.length === 0 ? "" : selectedOrganization.defaults.workflow_upload_username) const [uploadToken, setUploadToken] = React.useState(selectedOrganization.defaults === undefined ? "" : selectedOrganization.defaults.workflow_upload_token === undefined || selectedOrganization.defaults.workflow_upload_token.length === 0 ? "" : selectedOrganization.defaults.workflow_upload_token) const [regionStatus, setRegionStatus] = useState(); - + useEffect(() => { if (documentationReference !== selectedOrganization?.defaults?.documentation_reference) { setDocumentationReference(selectedOrganization?.defaults?.documentation_reference) } - - if (uploadRepo !== selectedOrganization?.defaults?.workflow_upload_repo){ + + if (uploadRepo !== selectedOrganization?.defaults?.workflow_upload_repo) { setUploadRepo(selectedOrganization?.defaults?.workflow_upload_repo) } - if (uploadBranch !== selectedOrganization?.defaults?.workflow_upload_branch){ + if (uploadBranch !== selectedOrganization?.defaults?.workflow_upload_branch) { setUploadBranch(selectedOrganization?.defaults?.workflow_upload_branch) } - if (uploadUsername !== selectedOrganization?.defaults?.workflow_upload_username){ + if (uploadUsername !== selectedOrganization?.defaults?.workflow_upload_username) { setUploadUsername(selectedOrganization?.defaults?.workflow_upload_username) } - if (uploadToken !== selectedOrganization?.defaults?.workflow_upload_token){ + if (uploadToken !== selectedOrganization?.defaults?.workflow_upload_token) { setUploadToken(selectedOrganization?.defaults?.workflow_upload_token) } }, [selectedOrganization]) useEffect(() => { if (selectedOrganization !== undefined && selectedOrganization !== null) { - if((orgName === undefined || orgName === null || orgName.length === 0) && selectedOrganization?.name !== orgName) { + if ((orgName === undefined || orgName === null || orgName.length === 0) && selectedOrganization?.name !== orgName) { setOrgName(selectedOrganization?.name) } - if((orgDescription === undefined || orgDescription === null || orgDescription.length === 0) && selectedOrganization?.description !== orgDescription) { + if ((orgDescription === undefined || orgDescription === null || orgDescription.length === 0) && selectedOrganization?.description !== orgDescription) { setOrgDescription(selectedOrganization?.description) } } }, [selectedOrganization]) - + const handleEditOrg = ( name, description, @@ -262,21 +262,21 @@ const [orgName, setOrgName] = useState(selectedOrganization?.name); }); } - const handleSendChangeRegionMail = (region)=> { - if(selectedOrganization === undefined || selectedOrganization === null){ + const handleSendChangeRegionMail = (region) => { + if (selectedOrganization === undefined || selectedOrganization === null) { toast.error("Failed to send request for changing region. Please contact support@shuffler.io.") return } - let destinationRegion = region; - if (region === "US") { - destinationRegion = "us-west2"; - } else if (region === "EU") { - destinationRegion = "europe-west3"; - } else if (region === "CA") { - destinationRegion = "northamerica-northeast1"; - } else if (region === "UK") { - destinationRegion = "europe-west2"; - } + + const regionToCloudRegion = { + 'US': 'us-west2', + 'EU': 'europe-west3', + 'CA': 'northamerica-northeast1', + 'UK': 'europe-west2', + 'EU-2': 'europe-west3' + }; + + const destinationRegion = regionToCloudRegion[region] || region; var data = { dst_region: destinationRegion @@ -284,7 +284,7 @@ const [orgName, setOrgName] = useState(selectedOrganization?.name); toast.info("Sending request for changing region to " + region) - fetch(`${globalUrl}/api/v1/orgs/${selectedOrganization?.id}/change/region/request`,{ + fetch(`${globalUrl}/api/v1/orgs/${selectedOrganization?.id}/change/region/request`, { method: "POST", headers: { "Content-Type": "application/json", @@ -292,13 +292,13 @@ const [orgName, setOrgName] = useState(selectedOrganization?.name); }, credentials: "include", body: JSON.stringify(data), - }).then((response)=>{ - if(response.status !== 200){ + }).then((response) => { + if (response.status !== 200) { toast.error("Failed to send request for changing region. Please contact support@shuffler.io.") - }else{ - toast.success("successfully send request for changing region. We will contact you shortly.") + } else { + toast.success("Successfully sent request for region change. We will process the move and contact you shortly.") } - }).catch((err)=>{ + }).catch((err) => { console.log(err) toast.error("Failed to send request for changing region. Please contact support@shuffler.io.") }) @@ -307,17 +307,16 @@ const [orgName, setOrgName] = useState(selectedOrganization?.name); const setSelectedRegion = (region) => { // send a POST request to /api/v1/orgs/{org_id}/region with the region as the body - if(region === "US") { - region = "us-west2" - } else if(region === "EU") { - region = "europe-west2" - } else if(region === "CA") { - region = "northamerica-northeast1" - } else if(region === "UK") { - region = "europe-west2" - } else if (region === "EU-2") { - region = "europe-west3" - } + const regionMap = { + "US": "us-west2", + "EU": "europe-west2", + "CA": "northamerica-northeast1", + "UK": "europe-west2", + "EU-2": "europe-west3", + "AUS": "australia-southeast1" + }; + + region = regionMap[region] || region; var data = { dst_region: region @@ -336,7 +335,11 @@ const [orgName, setOrgName] = useState(selectedOrganization?.name); timeOut: 1000 }).then((response) => { if (response.status !== 200) { - toast("Failed to change region!") + response.json().then((reason) => { + toast.error("Failed to change region: " + reason.reason) + }).catch((err) => { + toast.error("Failed to change region") + }); } else { toast("Region changed successfully! Reloading in 5 seconds..") @@ -347,7 +350,7 @@ const [orgName, setOrgName] = useState(selectedOrganization?.name); } - return response.json(); + // return responseJson }) } @@ -355,7 +358,7 @@ const [orgName, setOrgName] = useState(selectedOrganization?.name); const orgSaveButton = (
- + Preferences @@ -647,9 +653,9 @@ const [orgName, setOrgName] = useState(selectedOrganization?.name); - Org Documentation reference + Org Documentation reference - + Add a URL that is added as a link, pointing to any external documentation page you want. @@ -672,7 +678,7 @@ const [orgName, setOrgName] = useState(selectedOrganization?.name); placeholder="Paste a URL to an external reference for this implementation" value={documentationReference} onBlur={() => { - if(documentationReference !== selectedOrganization?.defaults?.documentation_reference) { + if (documentationReference !== selectedOrganization?.defaults?.documentation_reference) { handleEditOrg( orgName, orgDescription, @@ -714,7 +720,7 @@ const [orgName, setOrgName] = useState(selectedOrganization?.name); }, style: { color: "white", - + fontWeight: 400, fontSize: 16, borderRadius: 4, @@ -728,16 +734,16 @@ const [orgName, setOrgName] = useState(selectedOrganization?.name); globalUrl={globalUrl} userdata={userdata} serverside={false} - /> + /> - Workflow Backup Repository - - Decide where workflows are backed up in a Git repository. Will create logs and notifications if upload fails. The repository and branch must already have been initialized. Files will show up in the repo root in the /orgId/workflow-status/workflowId.json format. MSSP: If suborg exists, this will automatically be applied for them as well (not retroactive). Credentials are encrypted. + Workflow Backup Repository + + Decide where workflows are backed up in a Git repository. Will create logs and notifications if upload fails. The repository and branch must already have been initialized. Files will show up in the repo root in the /orgId/workflow-status/workflowId.json format. MSSP: If suborg exists, this will automatically be applied for them as well (not retroactive). Credentials are encrypted. - Repository for workflow backup + Repository for workflow backup - Branch + Branch - Username for backup of workflows + Username for backup of workflows - Git token/password + Git token/password { +const RegionChangeModal = memo(({ selectedOrganization, setSelectedRegion, userdata, handleSendChangeRegionMail }) => { // Show from options: "us-west2", "europe-west2", "europe-west3", "northamerica-northeast1" // var regions = ["us-west2", "europe-west2", "europe-west3", "northamerica-northeast1"] const regionMapping = { "US": "us", "EU-2": "eu", "CA": "ca", - "UK": "gb" + "UK": "gb", + "AUS": "au", }; //let regiontag = "UK"; @@ -1095,6 +1102,7 @@ const RegionChangeModal = memo(({selectedOrganization, setSelectedRegion, userda let regionCode = "gb"; const regionsplit = selectedOrganization?.region_url?.split("."); + if (regionsplit?.length > 2 && !regionsplit[0]?.includes("shuffler")) { const namesplit = regionsplit[0]?.split("/"); regiontag = namesplit[namesplit.length - 1]; @@ -1103,58 +1111,67 @@ const RegionChangeModal = memo(({selectedOrganization, setSelectedRegion, userda regiontag = "US"; regionCode = "us"; } else if (regiontag === "frankfurt") { - regiontag = "EU"; + regiontag = "EU-2"; regionCode = "eu"; } else if (regiontag === "ca") { regiontag = "CA"; regionCode = "ca"; + } else if (regiontag === "austrailia") { + regiontag = "AUS"; + regionCode = "au" } } -return ( - - {/* Region */} - { + // if (userdata?.support) { + // setSelectedRegion(e.target.value) + // } else { + // handleSendChangeRegionMail(e.target.value) + // } + setSelectedRegion(e.target.value) + }} + > + {Object.keys(regionMapping).map((region, index) => { + const regionImageCode = regionMapping[region]; + // Set the default region if selectedOrganization.region is not set + if (selectedOrganization.region === undefined) { + selectedOrganization.region = "europe-west2"; + } + + if (region === "AUS") { + region = "AUS (test)" + } + + // Check if the current region matches the selected region + if (region === selectedOrganization.region) { + // If the region matches, set the MenuItem as selected + return ( + + {/* show region image through cdn */} + {region} + {region} + + ); + } else { + return + {region} {region} - - ); - } else { - return - {region} - {region} ; - } - })} - - -); + } + })} + + + ); }) diff --git a/frontend/src/components/OrganizationTab.jsx b/frontend/src/components/OrganizationTab.jsx index 3fc2cbee..1911bfad 100644 --- a/frontend/src/components/OrganizationTab.jsx +++ b/frontend/src/components/OrganizationTab.jsx @@ -3,7 +3,6 @@ import { Link, useNavigate, useLocation } from "react-router-dom"; import Billing from "../components/Billing.jsx"; import Priorities from "../components/Priorities.jsx"; import Branding from "../components/Branding.jsx"; -import AnalyticsTab from '../components/AnalyticsTab.jsx'; import EditOrgTab from '../components/EditOrgTab.jsx'; import CloudSyncTab from '../components/CloudSyncTab.jsx'; import SSOTab from "../components/ssoTab.jsx" diff --git a/frontend/src/components/ParsedAction.jsx b/frontend/src/components/ParsedAction.jsx index 10d506ac..35bc0ea4 100755 --- a/frontend/src/components/ParsedAction.jsx +++ b/frontend/src/components/ParsedAction.jsx @@ -214,6 +214,20 @@ const ParsedAction = (props) => { } }, [expansionModalOpen]) + /* + useEffect(() => { + // This will have the OLD selectedAction, not the new one huh? + // How do we map the fields correctly? + if (selectedAction === undefined || selectedAction === null) { + console.log("Selected action is undefined") + return + } + + console.log("Selected action: ", selectedAction?.name, selectedAction) + + }, [selectedAction]) + */ + useEffect(() => { // Changes the order of params to show in order: // auth, required, optional @@ -347,7 +361,7 @@ const ParsedAction = (props) => { } if (keyorder.join(",") !== newkeyorder.join(",")) { - //toast("KEYORDER CHANGED!") + //console.log("KEYORDER CHANGED! DID ACTION AS WELL?", keyorder, newkeyorder) setSelectedActionParameters(newparams) selectedAction.parameters = newparams @@ -688,7 +702,7 @@ const ParsedAction = (props) => { if (newActionList.find((item) => item.type === "Shuffle DB") === undefined) { let cacheKey = { type: "Shuffle DB", - name: "Shuffle DB", + name: "Shuffle Datastore", value: "$shuffle_cache", highlight: "shuffle_cache", autocomplete: "shuffle_cache", @@ -753,44 +767,78 @@ const ParsedAction = (props) => { if (parents.length > 1) { const labels = []; for (let parentNode of parents) { - if (parentNode.label !== "Runtime Argument" && !labels.includes(parentNode.label)) { - labels.push(parentNode.label); - let exampleData = parentNode.example ?? ""; - if (!exampleData && workflowExecutions.length > 0) { - for (let exec of workflowExecutions) { - const foundResult = exec.results?.find(result => result.action.id === parentNode.id); - if (foundResult) { - const valid = validateJson(foundResult.result); - if (valid.valid && valid.result.success !== false) { - exampleData = valid.result; - break; - } + if (parentNode.label === "Runtime Argument" || labels.includes(parentNode.label)) { + continue + } + + labels.push(parentNode.label); + let exampleData = parentNode.example ?? ""; + if (parentNode?.app_name === "http") { + exampleData = "" + } + + if (workflowExecutions.length > 0) { + for (let exec of workflowExecutions) { + const foundResult = exec.results?.find(result => result?.action?.id === parentNode?.id); + if (foundResult) { + const valid = validateJson(foundResult.result); + if (valid.valid && valid.result.success !== false) { + exampleData = valid.result + break } } } - - if (parentNode.label === undefined) { - parentNode.label = "" - } - - newActionList.push({ - type: "action", - id: parentNode.id, - name: parentNode.label, - autocomplete: parentNode.label.split(" ").join("_"), - example: exampleData, - }); - - parentActionList.push({ - type: "action", - id: parentNode.id, - name: parentNode.label, - autocomplete: parentNode.label.split(" ").join("_"), - example: exampleData, - }); - - } + + if (exampleData === "" && apps !== undefined && apps !== null && apps?.length > 0) { + // Check apps if it exists, then if it + const foundApp = apps?.find(app => app?.id === parentNode?.app_id) + if (foundApp !== undefined && foundApp !== null) { + if (foundApp?.generated === true || foundApp?.name === "http") { + const validationData = validateJson(`{ + "status": 200, + "body": { + "example": "json", + "values": "json" + }, + "url": "https://example.com", + "headers": { + "Content-Type": "application/json", + "Example-Header": "two" + }, + "cookies": { + "example": "session", + "__session": "sessionid" + }, + "success": true + }`) + + if (validationData.valid) { + exampleData = validationData.result + } + } + } + } + + if (parentNode.label === undefined) { + parentNode.label = "" + } + + newActionList.push({ + type: "action", + id: parentNode.id, + name: parentNode.label, + autocomplete: parentNode.label.split(" ").join("_"), + example: exampleData, + }); + + parentActionList.push({ + type: "action", + id: parentNode.id, + name: parentNode.label, + autocomplete: parentNode.label.split(" ").join("_"), + example: exampleData, + }); } } } @@ -838,10 +886,10 @@ const ParsedAction = (props) => { } } return { ...param, value: paramvalue, error: message } - }); + }) - setSelectedActionParameters(newParameters); - setActionlist(newActionList); + setSelectedActionParameters(newParameters) + setActionlist(newActionList) }, [workflow.execution_variables, paramUpdate, workflow.workflow_variables, workflowExecutions, workflow, selectedAction, listCache, getParents, setNewSelectedAction]); useEffect(() => { @@ -1112,6 +1160,12 @@ const ParsedAction = (props) => { selectedActionParameters[1].value = splitparsed[1] selectedAction.parameters[1].value = splitparsed[1] + + if (splitparsed.length > 2) { + toast.warn("Filter list only supports filtering at the first level. If you want multi-level filtering, please use the 'execute python' action with the 'filter a list' function in the code editor.") + } else if (selectedAction.parameters[1].value.includes(".#")) { + toast.warn("This filter may not work due to using .# indexing. Please use the 'execute python' action and try the 'filter a list' function in the code editor.") + } } else { // Remove .# and after const splitparsed = parsedvalue.split(".#") @@ -2497,7 +2551,7 @@ const ParsedAction = (props) => { {workflow.execution_variables !== undefined && workflow.execution_variables !== null && workflow.execution_variables.length > 0 ? (
- Execution variable (optional) + Runtime variable (optional) { }} labelId="suborg-changer" value={workflow.org_id} - disabled={savingState !== 0 || suborgWorkflows?.length === 0} + disabled={savingState !== 0 || suborgWorkflows?.length === 0 || allTriggers === undefined} onChange={(e) => { + if (cy !== undefined && cy !== null) { + cy.nodes().unselect() + } + if (lastSaved === false && originalWorkflow.id === workflow.id) { setSuborgWorkflows([]) + saveWorkflow(workflow, undefined, undefined, e.target.value) - toast.warn("Saving workflow first due to detected changes. Please try to change workflow again when it is finished.", { + + /* Standard re-loads */ + setAllTriggers(undefined) + setSelectedTriggerIndex(-1) + + getEnvironments(e.target.value) + getAppAuthentication(undefined, undefined, undefined, e.target.value) + getFiles(e.target.value) + listOrgCache(e.target.value) + /* Standard re-loads */ + + toast.warn(`Saving workflow first due to detected changes.`, { autoClose: 2000, }) + + return } @@ -17693,11 +18302,14 @@ const AngularWorkflow = (defaultprops) => { } ReactDOM.unstable_batchedUpdates(() => { + /* Standard re-loads */ + setAllTriggers(undefined) setSelectedTriggerIndex(-1) getEnvironments(e.target.value) getAppAuthentication(undefined, undefined, undefined, e.target.value) getFiles(e.target.value) listOrgCache(e.target.value) + /* Standard re-loads */ // Reset the save button to ensure random saves don't occur during move setLastSaved(true) @@ -18966,7 +19578,7 @@ const AngularWorkflow = (defaultprops) => { {workflow.public || userdata.support == true ? @@ -19687,7 +20299,6 @@ const AngularWorkflow = (defaultprops) => { src={validate.result} theme={theme.palette.jsonTheme} style={theme.palette.reactJsonStyle} - collapsed={false} shouldCollapse={(jsonField) => { return collapseField(jsonField) }} @@ -19969,7 +20580,8 @@ const AngularWorkflow = (defaultprops) => { } } - to_be_copied.replaceAll(" ", "_"); + to_be_copied = to_be_copied.replaceAll(" ", "_"); + console.log("COPY: ", to_be_copied); const elementName = "copy_element_shuffle"; var copyText = document.getElementById(elementName); if (copyText !== null && copyText !== undefined) { @@ -20030,7 +20642,6 @@ const AngularWorkflow = (defaultprops) => { src={validate.result} theme={theme.palette.jsonTheme} style={theme.palette.reactJsonStyle} - collapsed={parsedCollapse} shouldCollapse={(jsonField) => { return collapseField(jsonField) }} @@ -21239,13 +21850,23 @@ const AngularWorkflow = (defaultprops) => { const cursearch = typeof window === "undefined" || window.location === undefined ? "" : window.location.search; const chosenNodeId = new URLSearchParams(cursearch).get("node"); const highlightNode = chosenNodeId !== null && chosenNodeId !== undefined && chosenNodeId !== "" && chosenNodeId === data.action.id + var relevant_errors = [] + if (data?.action?.parameters !== undefined && data?.action?.parameters !== null && data?.action?.parameters.length > 0) { + for (var i = 0; i < data.action.parameters.length; i++) { + // Specific error patterns in params + const param = data.action.parameters[i] + if (param?.name?.endsWith("_error") && (param?.name?.startsWith("shuffle_") || param?.name?.startsWith("liquid_"))) { + relevant_errors.push(param) + } + } + } return (
{ > + Expand result window. Errors: {relevant_errors.length} + + } placement="top" style={{ zIndex: 50000 }} > - + 0 ? yellow : "rgba(255,255,255,0.7)", + }} /> {actionimg} @@ -21406,7 +22033,6 @@ const AngularWorkflow = (defaultprops) => { src={validate.result} theme={theme.palette.jsonTheme} style={theme.palette.reactJsonStyle} - collapsed={false} shouldCollapse={(jsonField) => { return collapseField(jsonField) }} @@ -21493,19 +22119,24 @@ const AngularWorkflow = (defaultprops) => { const checked = validateJson(data.value.trim()) if (data.name === "shuffle_action_logs" && data.value !== undefined && data.value !== null && data.value.length > 0 && data.value.includes("add env SHUFFLE_LOGS_DISABLED")) { - return ( -
- - Action Logs - - - Logs for an action are not available without an onprem environment with the SHUFFLE_LOGS_DISABLED environment variable set to false: SHUFFLE_LOGS_DISABLED=false. Logs are enabled by default, except in scale mode. - -
- ) + + if (isCloud) { + return null + } + + return ( +
+ + Action Logs + + + More log details for this action are not available without an onprem environment with the SHUFFLE_LOGS_DISABLED environment variable set to false: SHUFFLE_LOGS_DISABLED=false. Logs are enabled by default, except in scale mode. + +
+ ) } var showlink = false @@ -21568,7 +22199,6 @@ const AngularWorkflow = (defaultprops) => { src={checked.result} theme={theme.palette.jsonTheme} style={theme.palette.reactJsonStyle} - collapsed={data.value.length < 10000 ? false : true} shouldCollapse={(jsonField) => { return collapseField(jsonField) }} @@ -21994,7 +22624,6 @@ const AngularWorkflow = (defaultprops) => { src={validate.result} theme={theme.palette.jsonTheme} style={theme.palette.reactJsonStyle} - collapsed={selectedResult.result.length < 10000 ? false : true} shouldCollapse={(jsonField) => { return collapseField(jsonField) }} @@ -22055,6 +22684,7 @@ const AngularWorkflow = (defaultprops) => {
)} +
{selectedResult.action.parameters !== null && selectedResult.action.parameters !== undefined ? ( @@ -22070,9 +22700,9 @@ const AngularWorkflow = (defaultprops) => { variant="h6" style={{ marginBottom: 0, marginTop: 0 }} > - Variables (click to expand) + Variable & Debug info ({selectedResult?.action?.parameters?.length}) - {selectedResult.action.parameters.map((data, index) => { + {selectedResult?.action?.parameters?.map((data, index) => { if (data.value.length === 0) { return null; } diff --git a/frontend/src/views/ApiExplorerWrapper.jsx b/frontend/src/views/ApiExplorerWrapper.jsx index 72dc93ca..96298437 100644 --- a/frontend/src/views/ApiExplorerWrapper.jsx +++ b/frontend/src/views/ApiExplorerWrapper.jsx @@ -663,7 +663,7 @@ const ApiExplorerWrapper = (props) => { } } } else if (validate.result.status === 404) { - toast.error("Page not found. Please try a different URL.") + //toast.error("Page not found. Please try a different URL.") } else if (validate.result.error !== undefined && validate.result.error !== null && validate.result.error.length > 0) { if (validate.result.error.toLowerCase().includes("max retries")) { toast.error("Are you sure the URL is correct? It seems like the server is not responding.") diff --git a/frontend/src/views/AppCreator.jsx b/frontend/src/views/AppCreator.jsx index af2cc2ad..50106831 100755 --- a/frontend/src/views/AppCreator.jsx +++ b/frontend/src/views/AppCreator.jsx @@ -281,7 +281,7 @@ export const appCategories = [ "name": "AI", "color": "#FFC107", "icon": "AI", - "action_labels": ["Answer Question", "Run Action"], + "action_labels": ["Answer Question", "Run Action", "Run LLM",], }, { "name": "Other", @@ -2657,12 +2657,12 @@ const AppCreator = (defaultprops) => { if (responseJson.reason !== undefined) { setErrorCode(responseJson.reason); - if (responseJson.extra === undefined && responseJson.extra === null) { - toast("Failed to verify: " + responseJson.reason); - } + toast.error("Failed to build: " + responseJson.reason, { + autoClose: 10000 + }) } } else { - toast("Successfully uploaded openapi"); + toast.success("Successfully built openapi app! Added job to rebuild it in your hybrid runtime locations (Orborus)."); if (window.location.pathname.includes("/new")) { if (responseJson.id !== undefined && responseJson.id !== null) { window.location = `/apps/edit/${responseJson.id}`; diff --git a/frontend/src/views/AppExplorer.jsx b/frontend/src/views/AppExplorer.jsx index 93bc9f89..d37709ee 100644 --- a/frontend/src/views/AppExplorer.jsx +++ b/frontend/src/views/AppExplorer.jsx @@ -2906,7 +2906,7 @@ const AppExplorer = (props) => { const deduplicateByName = (array) => { const uniqueNames = {}; return array.filter(item => { - if (!item.hasOwnProperty('name') || !item.name.length) { + if (!item?.hasOwnProperty('name') || !item?.name?.length) { return true } if (!uniqueNames[item.name]) { @@ -3866,13 +3866,13 @@ const AppExplorer = (props) => { } }} > - +
Are you sure you want to PUBLISH this app?
@@ -4120,7 +4120,7 @@ const AppExplorer = (props) => { )} {appType === 1 ? null : - creatorProfile.self === true || userdata.support === true ? + userdata?.support || userdata?.id === app?.owner || (userdata?.admin === "true" && userdata?.active_org?.id === app?.reference_org) || app?.contributors?.includes(userdata?.id) || creatorProfile?.self === true ? - {(appdata?.owner === userdata?.id) ? ( - ): null }
) : ( { } if (typeof inputdata !== "object") { - return parsedValues; + return parsedValues } - for (const [key, value] of Object.entries(inputdata)) { + for (var [key, value] of Object.entries(inputdata)) { + key = key.replaceAll(" ", "_") + // Check if loop or JSON const extra = basekey.length > 0 ? splitkey : ""; const basekeyname = `${basekey .slice(1, basekey.length) .split(".") - .join(splitkey)}${extra}${key}`; + .join(splitkey)}${extra}${key}` // Handle direct loop! if (!isNaN(key) && basekey === "") { @@ -205,7 +207,8 @@ export const GetParsedPaths = (inputdata, basekey) => { type: "list", name: `${splitkey}list`, autocomplete: `${basekey.replaceAll(" ", "_")}.#`, - }); + }) + const returnValues = GetParsedPaths(value, `${basekey}.#`); for (var subkey in returnValues) { parsedValues.push(returnValues[subkey]); diff --git a/frontend/src/views/Apps2.jsx b/frontend/src/views/Apps2.jsx index d56e3469..c5fb9d38 100644 --- a/frontend/src/views/Apps2.jsx +++ b/frontend/src/views/Apps2.jsx @@ -1,6 +1,7 @@ import React, { useState, useEffect, useContext, useCallback, memo, useMemo, useRef } from "react"; import theme from "../theme.jsx"; import { isMobile } from "react-device-detect"; + import { useLocation, useNavigate } from "react-router-dom"; import { TextField, Button, Typography, MenuItem, Select, Tabs, Tab, Zoom, @@ -49,15 +50,14 @@ const searchClient = algoliasearch( ); // AppCard Component -const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl, deactivatedIndexes, currTab, handleAppClick, leftSideBarOpenByClick, userdata, fetchApps }) => { +const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl, deactivatedIndexes, currTab, handleAppClick, leftSideBarOpenByClick, userdata, fetchApps, appsToShow, setAppsToShow, setUserApps, }) => { const navigate = useNavigate(); const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io" || window.location.host === "localhost:3000"; - const appUrl = isCloud ? `/apps/${data.id}` : `https://shuffler.io/apps/${data.id}`; + //const appUrl = isCloud ? `/apps/${data.id}` : `https://shuffler.io/apps/${data.id}`; + const appUrl = `/apps/${data.id}` - var canEditApp = userdata?.support || - userdata?.id === data?.owner || - (userdata?.admin === "true" && userdata?.active_org?.id === data?.reference_org) || - data?.contributors?.includes(userdata?.id) + var canEditApp = userdata?.support || userdata?.id === data?.owner || + (userdata?.admin === "true" && userdata?.active_org?.id === data?.reference_org) || data?.contributors?.includes(userdata?.id) const paperStyle = { backgroundColor: mouseHoverIndex === index ? "rgba(26, 26, 26, 1)" : "#212121", @@ -71,7 +71,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl, boxShadow: "0px 0px 10px 0px rgba(0, 0, 0, 0.1)", marginBottom: 20, transition: "width 0.3s ease", - }; + } return ( @@ -133,6 +133,7 @@ const AppCard = ({ data, index, mouseHoverIndex, setMouseHoverIndex, globalUrl, margin: "12px 0", fontFamily: theme?.typography?.fontFamily, }}> +
+
{data.name.replace(/_/g, ' ').replace(/\b\w/g, char => char.toUpperCase())}
+
{data.categories ? data.categories.join(", ") : "NA"}
+
))}
+ {/* Deactivate button */} {(currTab === 0 || currTab === 1) && !deactivatedIndexes.includes(index) && mouseHoverIndex === index && data.generated === true && (
) } + + ) : ( +
diff --git a/frontend/src/views/DashboardViews.jsx b/frontend/src/views/DashboardViews.jsx index 9de1db29..7905a21a 100644 --- a/frontend/src/views/DashboardViews.jsx +++ b/frontend/src/views/DashboardViews.jsx @@ -6,9 +6,6 @@ import classNames from "classnames"; import theme from '../theme.jsx'; import { useNavigate, Link, useParams } from "react-router-dom"; -// react plugin used to create charts -//import { Line, Bar } from "react-chartjs-2"; -//import { useAlert import { ToastContainer, toast } from "react-toastify" import Draggable from "react-draggable"; import DashboardBarchart, { LoadStats } from '../components/DashboardBarchart.jsx'; @@ -311,9 +308,13 @@ const RadialChart = ({keys, setSelectedCategory}) => { //axis={} } + +// 0x0elliot: not cleaning this up. this seems clearly experimental. not worth my time. + // This is the start of a dashboard that can be used. // What data do we fill in here? Idk const Dashboard = (props) => { + const { globalUrl, isLoggedIn } = props; //const alert = useAlert(); const [bigChartData, setBgChartData] = useState("data1"); @@ -397,7 +398,7 @@ const Dashboard = (props) => { if (foundQuery !== null && foundQuery !== undefined) { setSelectedUsecaseCategory(foundQuery) - const newitem = removeParam("selected", cursearch); + const newitem = removeParam("selected", cursearch); navigate(curpath + newitem) } diff --git a/frontend/src/views/Docs.jsx b/frontend/src/views/Docs.jsx index 7d55acaf..8b56b2ce 100755 --- a/frontend/src/views/Docs.jsx +++ b/frontend/src/views/Docs.jsx @@ -5,7 +5,7 @@ import theme from '../theme.jsx'; import ReactJson from "react-json-view-ssr"; import { isMobile } from "react-device-detect"; import { BrowserView, MobileView } from "react-device-detect"; -import { useParams, useNavigate, Link } from "react-router-dom"; +import { useParams, useNavigate, Link, useLocation } from "react-router-dom"; import { validateJson, GetIconInfo } from "../views/Workflows.jsx"; import remarkGfm from 'remark-gfm' import { Context } from "../context/ContextApi.jsx"; @@ -23,16 +23,26 @@ import { List, Collapse, ListItemButton, - ListItemText + ListItemText, + Dialog, + DialogTitle, + Box, + DialogContent, + InputAdornment } from "@mui/material"; import { Link as LinkIcon, Edit as EditIcon, KeyboardArrowRight as KeyboardArrowRightIcon, ExpandMore as ExpandMoreIcon, - FileCopy as FileCopyIcon + FileCopy as FileCopyIcon, + ChevronLeft, + ChevronRight, + Search as SearchIcon, + Close as CloseIcon } from "@mui/icons-material"; import { fontGrid } from "@mui/material/styles/cssUtils.js"; +import SearchBox from "../components/SearchData.jsx"; const Body = { //maxWidth: 1000, @@ -51,6 +61,7 @@ const dividerColor = "rgb(225, 228, 232)"; const hrefStyle = { color: "rgba(255, 255, 255, 0.8)", textDecoration: "none", + marginRight: window.location.pathname.includes("/articles/") ? "0.8em" : undefined, }; @@ -152,11 +163,34 @@ export const OuterLink = (props) => { } + export const Img = (props) => { // Find parent container and check width - + const isArticlePage = window.location.pathname.includes("/articles/") + const isFormPage = window.location.pathname.includes("/forms/") var height = "auto" - var width = 750 + var width = isArticlePage ? 1000 : isFormPage ? 400: 750 + + const docsImageStyle = { + border: isFormPage ? null : "1px solid rgba(255,255,255,0.3)", + borderRadius: theme.palette?.borderRadius, + width: width, + maxWidth: width, + margin: "auto", + marginTop: 10, + marginBottom: 10 + } + + const articleImageStyle = { + borderRadius: theme.palette?.borderRadius, + minWidth: 350, + maxWidth: "100%", + textAlign: "center", + margin: "auto", + marginTop: 20, + marginBottom: 20, + } + if (props.height !== undefined && props.height !== null) { height = props.height } @@ -166,11 +200,13 @@ export const Img = (props) => { } return( - {props.alt} +
+ {props.alt} +
) } @@ -251,8 +287,12 @@ export const CodeHandler = (props) => { } const Docs = (defaultprops) => { - const { globalUrl, selectedDoc, serverside, serverMobile, isLoggedIn, isLoaded } = defaultprops; + const { globalUrl, selectedDoc, serverside, serverMobile, isLoggedIn, isLoaded, userdata } = defaultprops; + + const { searchBarModalOpen, setSearchBarModalOpen, isDocSearchModalOpen, setIsDocSearchModalOpen, leftSideBarOpenByClick } = useContext(Context); + let navigate = useNavigate(); + const location = useLocation(); // Quickfix for react router 5 -> 6 const params = useParams(); //var props = JSON.parse(JSON.stringify(defaultprops)) @@ -283,16 +323,40 @@ const Docs = (defaultprops) => { serverside === true ? "" : window.location.href ); const [hashRendered, setHashRendered] = React.useState(false) - + const [sidebarOpen, setSidebarOpen] = useState(false); + const [activeSubItem, setActiveSubItem] = useState(false); const headingElementsRef = useRef({}) + var isArticlePage = window.location.pathname.includes("/articles/") || window.location.pathname === "/articles" ? true : false; + const searchFieldRef = useRef(null); + useEffect(() => { - //if (params["key"] === undefined) { - // navigate("/docs/about") - // return - //} - }, []) + fetchDocList(); + setSidebarOpen(false); + if (props.match.params === undefined || props.match.params === null) { + return + } + + const propkey = props.match.params.key + if (propkey === undefined || propkey === null) { + return + } + + if (location.pathname.includes("/docs/")) { + if (propkey === "cookie_policy" || propkey === "compliance" || propkey === "privacy_policy" || propkey === "terms_of_service") { + navigate(`/legal/${propkey}`) + } + } + }, [location]); + + useEffect(() => { + return () => { + setIsDocSearchModalOpen(false); + setSearchBarModalOpen(false); + }; + }, []); + const handleClick = (event) => { setAnchorEl(event.currentTarget); } @@ -422,6 +486,71 @@ const Docs = (defaultprops) => { return headings; }; + const modalView = ( + { + setSearchBarModalOpen(false); + if (searchFieldRef.current) { + searchFieldRef.current.blur(); + } + }} + PaperProps={{ + style: { + color: "white", + minWidth: 750, + minHeight: "180px", + maxHeight: "85vh", + borderRadius: 16, + border: "1px solid var(--Container-Stroke, #494949)", + background: "var(--Container, #000000)", + boxShadow: "0px 16px 24px 8px rgba(0, 0, 0, 0.25)", + position: "fixed", + top: "70px", + left: "50%", + transform: "translateX(-50%)", + }, + }} + sx={{ + zIndex: 50005, + '& .MuiBackdrop-root': { + backgroundColor: 'rgba(0, 0, 0, 0.8)', + }, + }} + > + + + Search for Documentation + + setSearchBarModalOpen(false)} + sx={{ + color: 'white', + '&:hover': { + backgroundColor: 'rgba(255, 255, 255, 0.1)' + } + }} + > + + + + + + + + + + + ); + // extract TOC from actual markdown const tocvalue = (markdown) => { @@ -460,8 +589,13 @@ const Docs = (defaultprops) => { } const SidebarPaperStyle = { - backgroundColor: "rgb(26,26,26)", + backgroundColor: isArticlePage ? "transparent" : "rgb(26,26,26)", + border: isArticlePage ? "none" : undefined, + borderRadius: isArticlePage ? "none" : undefined, + boxShadow: isArticlePage ? "none" : undefined, backgroundImage: "none", + width: isArticlePage ? "100%" : undefined, + height: isArticlePage ? "100%" : undefined, overflowX: "hidden", position: "relative", paddingLeft: 15, @@ -527,7 +661,7 @@ const Docs = (defaultprops) => { backgroundColor: theme.palette.inputColor, padding: 15, borderRadius: theme.palette?.borderRadius, - marginBottom: 25, + marginBottom: isArticlePage ? 25 : 30, display: "flex", }} > @@ -620,7 +754,7 @@ const Docs = (defaultprops) => { style={{ width: "90%", marginTop: 60, - marginBottom: 20, + marginBottom: isArticlePage ? 40 : 20, backgroundColor: theme.palette.inputColor, }} /> @@ -630,7 +764,21 @@ const Docs = (defaultprops) => { marginBlock: "0.85em", alignItems: "center" }}> {element} - { + e.preventDefault(); // Prevent default navigation + document.getElementById(id)?.scrollIntoView({ + behavior: 'smooth' + }); + + const url = `${window.location.origin}${window.location.pathname}#${id}`; + navigator.clipboard.writeText(url); + toast("Link copied to clipboard", { + position: "bottom-center", + autoClose: 2000, + }); + }} + style={{ textDecoration: "none", color: "white", paddingLeft: "0.3em", rotate: "-30deg", paddingTop: "0.9em", display: props.level === 1 ? "none" : "block", @@ -638,8 +786,7 @@ const Docs = (defaultprops) => {
- - {extraInfo} + {isArticlePage ? (userdata?.support ? extraInfo : "") : extraInfo} ) } @@ -647,21 +794,56 @@ const Docs = (defaultprops) => { const SideBar = { width: "17%", + borderRight: !isArticlePage ? "1px solid rgba(255,255,255,0.3)" : undefined, + minWidth: isArticlePage ? "250px" : "17%", + maxWidth: isArticlePage ? "250px" : "17%", + marginLeft: isArticlePage ? sidebarOpen ? 40 : 50 : undefined, position: "sticky", - top: 50, - paddingTop: "0.25em", - minHeight: "95vh", - maxHeight: "95vh", + top: isArticlePage ? 120 : 50, + paddingTop: isArticlePage ? "0.65em" : "0.25em", + paddingRight: isArticlePage ? "1em" : undefined, + minHeight: isArticlePage ? "80vh" : "95vh", + maxHeight: isArticlePage ? "80vh" : "95vh", overflowX: "hidden", overflowY: "auto", zIndex: 1000, - //borderRight: "1px solid rgba(255,255,255,0.3)", + backgroundColor: isArticlePage ? "#212121" : undefined, + borderRadius: isArticlePage ? theme.palette?.borderRadius : undefined, + transition: isArticlePage ? "width 0.3s ease, min-width 0.3s ease" : undefined, + }; + + const sideBarToggleButton = { + position: "absolute", + bottom: sidebarOpen ? 20 : "50%", + right: sidebarOpen ? 30 : 21, + zIndex: 1000, + backgroundColor: "#212121", + border: "1px solid rgba(255,255,255,0.3)", + borderRadius: "50%", + width: 40, + height: 40, + display: "flex", + alignItems: "center", + justifyContent: "center", + cursor: "pointer", + transition: "transform 0.3s ease", + "&:hover": { + backgroundColor: "#2c2c2c", + } + }; + + const collapsedSideBar = { + ...SideBar, + width: "40px", + minWidth: "40px", + maxWidth: "40px", + overflow: "hidden", }; const IndexBar = { alignSelf: "flex-start", position: "sticky", - top: 80, + top: 120, overflowY: "auto", minHeight: "93vh", maxHeight: "93vh", @@ -670,8 +852,15 @@ const Docs = (defaultprops) => { overflow: "hidden", } - const fetchDocList = () => { - fetch(`${globalUrl}/api/v1/docs`, { + const fetchDocList = (resetCache = false) => { + var url = `${globalUrl}/api/v1/docs` + if (location.pathname.includes("/legal")) { + url = `${globalUrl}/api/v1/docs?folder=legal&resetCache=${resetCache}` + } else if (location.pathname.includes("/articles")) { + url = `${globalUrl}/api/v1/docs?folder=articles&resetCache=${resetCache}` + } + + fetch(url, { method: "GET", headers: { "Content-Type": "application/json", @@ -691,8 +880,19 @@ const Docs = (defaultprops) => { .catch((error) => { }); }; - const fetchDocs = (docId) => { - fetch(`${globalUrl}/api/v1/docs/${docId}`, { + const fetchDoc = (docId) => { + if (docId === undefined) { + return + } + + var url = `${globalUrl}/api/v1/docs/${docId}` + if (location.pathname.includes("/legal")) { + url = `${globalUrl}/api/v1/docs/${docId}?folder=legal` + } else if (location.pathname.includes("/articles")) { + url = `${globalUrl}/api/v1/docs/${docId}?folder=articles` + } + + fetch(url, { method: "GET", headers: { "Content-Type": "application/json", @@ -706,18 +906,32 @@ const Docs = (defaultprops) => { } if (responseJson.success && responseJson.reason !== undefined) { + + if(isArticlePage && window.location.pathname.includes("/articles/")) { + if (responseJson.reason !== undefined && responseJson.reason !== null && responseJson.reason.includes("404: Not Found")) { + setData("# Error\nThis page doesn't exist."); + toast("This page doesn't exist. Redirecting to the latest article...", { + position: "bottom-center", + autoClose: 2000, + }); + setTimeout(() => { + navigate(`/articles/2.0_release`) + }, 2000) + return + } + } // Find tags and translate them into ![]() format const imgRegex = / { .catch((error) => { }); }; + const handleResetCache = () => { + fetchDocList(true); + toast("Cache has been reset"); + } + if (firstrequest) { setFirstrequest(false); if (!serverside) { @@ -769,11 +988,29 @@ const Docs = (defaultprops) => { // return null //} // - if (props.match.params.key === undefined) { - + if (props.match.params.key === undefined && isArticlePage) { + fetch(`${globalUrl}/api/v1/articles`, { + method: "GET", + headers: { + "Content-Type": "application/json", + Accept: "application/json", + }, + }) + .then((response) => response.json()) + .then((responseJson) => { + if (responseJson.success && responseJson.list && responseJson.list.length > 0) { + // Navigate to the latest article + if (responseJson?.list[0]?.name) { + navigate(`/articles/${responseJson?.list[0].name}`); + } + } + }) + .catch((error) => { + console.error("Error fetching articles:", error); + }); } else { console.log("DOCID: ", props.match.params.key) - fetchDocs(props.match.params.key) + fetchDoc(props.match.params.key) } } } @@ -782,7 +1019,7 @@ const Docs = (defaultprops) => { // Handles search-based changes that origin from outside this file if (serverside !== true && window.location.href !== baseUrl) { setBaseUrl(window.location.href); - fetchDocs(props.match.params.key); + fetchDoc(props.match.params.key); } const markdownStyle = { @@ -793,7 +1030,7 @@ const Docs = (defaultprops) => { maxWidth: "100%", minWidth: "100%", overflow: "hidden", - fontSize: isMobile ? "1.3rem" : "1rem", + fontSize: isMobile ? "1.3rem" : "1.1rem", }; const alertNote = { @@ -940,20 +1177,92 @@ const Docs = (defaultprops) => { } + const activeHrefStyleToc2 = { + ...hrefStyleToc2, + color: "#f86a3e", + }; + + const activeListItemStyle = { + backgroundColor: "rgba(248, 106, 62, 0.08)", // Slight orange tint + marginRight: window.location.pathname.includes("/articles/") ? "0.8em" : undefined, + borderLeft: "3px solid #f86a3e", + paddingLeft: "13px", // Compensate for the border + }; + + const toggleSidebar = () => { + setSidebarOpen(!sidebarOpen); + }; + + // PostDataBrowser Section const postDataBrowser = list === undefined || list === null ? null : (
-
+
- + {modalView} + { + !isArticlePage && ( + { + setIsDocSearchModalOpen(true) + setSearchBarModalOpen(true) + }} + inputRef={searchFieldRef} + InputProps={{ + endAdornment: ( + + + + ), + style: { + backgroundColor: "#212121", + borderRadius: 4, + color: "white", + }, + }} + style={{ + marginTop: 10, + marginLeft: 10, + borderRadius: 4, + width: !isLoggedIn ? "14%" : !leftSideBarOpenByClick ? "12%" : "11%", + maxWidth: "285px", + position: "fixed", + zIndex: 1100, + }} + inputProps={{ + readOnly: true, + }} + /> + ) + } + {list.map((data, index) => { const item = data.name; if (item === undefined) { return null; } - const path = "/docs/" + item; + + var path = "/docs/" + item; + if (location.pathname.includes("/legal")) { + path = "/legal/" + item + } else if (location.pathname.includes("/articles")) { + path = "/articles/" + item + } + const newname = item.charAt(0).toUpperCase() + item.substring(1).split("_").join(" ").split("-").join(" "); @@ -965,23 +1274,62 @@ const Docs = (defaultprops) => { - {newname} - + style={{ + color: itemMatching ? "#f86a3e" : "inherit", + flex: 1, + }} + primary={ + + {newname} + + } + /> + ); })} + { + isArticlePage && ( + + {sidebarOpen ? : } + + ) + }
-
+
{props.match.params.key === undefined ? mainpageInfo : @@ -1003,12 +1351,26 @@ const Docs = (defaultprops) => { }
+ {userdata?.support && isArticlePage && ( + + )} {tocLines.length > 0 ? ( -

Table of Content

+

Table Of Content

) : null} - +
@@ -1083,7 +1452,7 @@ const Docs = (defaultprops) => { color="primary" onClick={handleClick} > -
More docs
+
More {isArticlePage ? "articles" : "docs"}
{ return null; } - const path = "/docs/" + item; + const path = isArticlePage ? "/articles/" + item : "/docs/" + item; const newname = item.charAt(0).toUpperCase() + item.substring(1).split("_").join(" ").split("-").join(" "); @@ -1108,7 +1477,8 @@ const Docs = (defaultprops) => { key={index} style={{ color: "white" }} onClick={() => { - window.location.pathname = path; + navigate(path) + handleClose() }} > {newname} @@ -1140,8 +1510,22 @@ const Docs = (defaultprops) => { { + console.log(`Scrolling to: ${data.id}`); + setTimeout(() => { + const element = document.getElementById(data?.id); + if (element) { + element.scrollIntoView({ behavior: 'smooth' }); + } else { + console.error(`Element with id ${data.id} not found.`); + } + }, 100); // Delay to ensure the content is loaded + handleCloseToc(); + }} > - {data.title} + {data.title} ) })} @@ -1178,7 +1562,7 @@ const Docs = (defaultprops) => { color="primary" onClick={handleClick} > -
More docs
+
More {isArticlePage ? "articles" : "docs"}
); @@ -1198,7 +1582,7 @@ export default Docs; const DocsContent = memo(({postDataBrowser, postDataMobile}) => { return( -
+
{postDataBrowser} {postDataMobile}
@@ -1210,12 +1594,14 @@ const DocsWrapper = memo(({isLoggedIn, isLoaded, children })=>{ return (
{children} diff --git a/frontend/src/views/LoginPage.jsx b/frontend/src/views/LoginPage.jsx index 719a4717..9bcc6966 100755 --- a/frontend/src/views/LoginPage.jsx +++ b/frontend/src/views/LoginPage.jsx @@ -1,546 +1,1007 @@ /* eslint-disable react/no-multi-comp */ -import React, { useState, useEffect } from "react"; -import { makeStyles } from "@mui/styles"; +import React, { useState, useEffect, } from 'react'; +import { makeStyles } from '@mui/styles'; +import { useNavigate, Link, useParams } from "react-router-dom"; +import { isMobile } from "react-device-detect"; +import { toast } from 'react-toastify'; import { useInterval } from "react-powerhooks"; -import theme from '../theme.jsx'; +import VisibilityOutlinedIcon from '@mui/icons-material/VisibilityOutlined'; +import VisibilityOffOutlinedIcon from '@mui/icons-material/VisibilityOffOutlined'; +import { + ConnectingAirportsOutlined, + ConstructionOutlined, + DoneRounded, + Done as DoneIcon +} from '@mui/icons-material'; import { - CircularProgress, - TextField, - Button, - Paper, - Typography, -} from "@mui/material"; - -import { useNavigate } from "react-router-dom"; + Checkbox, + CircularProgress, + TextField, + Button, + Paper, + Typography, + Tooltip, + TableHead, + TableRow, + TableContainer, + TableCell, + TableBody, + Table, +} from '@mui/material'; const hrefStyle = { - color: "white", - textDecoration: "none", -}; + color: "#FF8444", + fontSize: "14px", + textDecoration: "none", + display: "flex", +} -const bodyDivStyle = { - margin: "auto", - marginTop: 150, - width: "500px", -}; +const googleLoginIcon = { + boxSizing: "border-box", + display: "flex", + flexDirection: "row", + justifyContent: "center", + alignItems: "center", + padding: "16px", + gap: "8px", + // position: "sticky", + width: 171, + height: "51px", + left: "352px", + top: "725px", + background: "#1A1A1A", + border: "1px solid #494949", + borderRadius: "8px", + +} + +const githubLoginIcon = { + boxSizing: "border-box", + display: "flex", + flexDirection: "row", + justifyContent: "center", + alignItems: "center", + padding: "16px", + gap: "8px", + position: "sticky", + width: "173px", + height: "51px", + left: "539px", + top: "725px", + backgroundColor: "#1A1A1A", + border: "1px solid #494949", + borderRadius: "8px", +} + +const surfaceColor = "#27292D" +const inputColor = "#383B40" const useStyles = makeStyles({ - notchedOutline: { - borderColor: "#f85a3e !important", - }, + notchedOutline: { + borderColor: "#f85a3e !important" + }, + marketplaceIcon: { + width: 28, + height: 28, + marginRight: 12 + }, + divider: { + display: "flex", + alignItems: "center", + margin: "0 20px", + '&::before, &::after': { + content: '""', + flex: 1, + borderBottom: "1px solid #494949" + }, + '& span': { + margin: "0 10px", + color: "#9E9E9E" + } + }, + freePlanCard: { + padding: "40px", + background: "#212121", + borderRadius: "12px", + width: "100%", + maxWidth: "500px" + }, + freePlanTitle: { + fontSize: "28px", + fontWeight: 600, + color: "white", + marginTop: 0, + marginBottom: "32px" + }, + featureItem: { + display: "flex", + alignItems: "center", + marginBottom: "20px", + color: "white", + fontSize: "16px", + fontWeight: 500 + }, + checkIcon: { + color: "#4CAF50", + marginRight: "16px", + width: "24px", + height: "24px" + } }); -const LoginDialog = (props) => { - const { - globalUrl, - isLoaded, - isLoggedIn, - setIsLoggedIn, - setCookie, - register, - checkLogin, - } = props; +const FreePlanCard = ({ classes }) => { + const features = [ + "Access to All Apps", + "10,000 App Runs", + "Monthly Runs Refresh", + "Unlimited Users & Workflows", + "Multi-Tenancy & -Region", + "Support & Discord Access" + ]; + + return ( +
+

+ The free plan includes: +

+ + {features.map((feature, index) => ( +
+ + {feature} +
+ ))} +
+ ); +}; + +const MarketplaceCard = ({ classes }) => { + const marketplaceOptions = [ + { + name: "Open Source Install", + logo: "https://static.cdnlogo.com/logos/g/69/github-icon.svg", + tooltipText: "Click to install!", + valid: true, + + link: "https://github.com/shuffle/shuffle/blob/main/.github/install-guide.md" + }, + { + name: "Amazon Web Services", + logo: "https://cdn.cdnlogo.com/logos/a/19/aws.svg", + tooltipText: "Coming soon to AWS Marketplace!", + valid: false, + }, + { + name: "Microsoft Azure", + logo: "https://cdn.cdnlogo.com/logos/a/12/azure.svg", + tooltipText: "Coming soon to Azure Marketplace!", + valid: false, + }, + { + name: "Google Cloud Platform", + logo: "https://cdn.cdnlogo.com/logos/g/75/google-cloud.svg", + tooltipText: "Coming soon to Google Cloud Marketplace!", + valid: false, + } + ]; + + return ( +
+

+ Self Host +

+ + {marketplaceOptions.map((option, index) => { + return ( + + + + ) + })} + + + +
+ ); +}; + + +const LoginPage = props => { + const { globalUrl, isLoaded, isLoggedIn, setIsLoggedIn, setCookie, inregister, serverside, checkLogin, } = props; let navigate = useNavigate(); - const classes = useStyles(); + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [message, setMessage] = useState(""); + const [loginLoading, setLoginLoading] = useState(false); - const [username, setUsername] = useState(""); - const [password, setPassword] = useState(""); - const [firstRequest, setFirstRequest] = useState(true); - const [loginLoading, setLoginLoading] = useState(false); - const [loginViewLoading, setLoginViewLoading] = useState(false); - const [ssoUrl, setSSOUrl] = useState(""); + const [MFAField, setMFAField] = useState(false); + const [MFAValue, setMFAValue] = useState(""); + const [register, setRegister] = useState(inregister); + const [checkboxClicked, setCheckboxClicked] = useState(false); + const [loginWithSSO, setLoginWithSSO] = useState(false) + const [showPassword, setShowPassword] = useState(false) + const [ssoUrl, setSSOUrl] = useState(""); - const [MFAField, setMFAField] = useState(false); - const [MFAValue, setMFAValue] = useState(""); - - - // Used to swap from login to register. True = login, false = register + const isCloud = window.location.host === "localhost:3002" || window.location.host === "shuffler.io" || window.location.host === "migration.shuffler.io"; + const parsedsearch = serverside === true ? "" : window.location.search useEffect(() => { - checkAdmin() - }, [loginViewLoading]) + if (!isCloud) { + checkAdmin() + } + }, []) - // Error messages etc - const [loginInfo, setLoginInfo] = useState(""); - - const handleValidateForm = () => { - return username.length > 1 && password.length > 1; - }; - - if (isLoggedIn === true) { - //window.location.pathname = "/workflows"; - navigate("/workflows") - } - - const checkAdmin = () => { - const url = globalUrl + "/api/v1/checkusers"; - fetch(url, { - method: "GET", - headers: { - "Content-Type": "application/json", + const { start, stop } = useInterval({ + duration: 3000, + startImmediate: false, + callback: () => { + checkAdmin() }, }) + + if (serverside !== true) { + const tmpMessage = new URLSearchParams(window.location.search).get("message") + if (tmpMessage !== undefined && tmpMessage !== null && message !== tmpMessage) { + setMessage(tmpMessage) + } + } + + if (document !== undefined) { + if (register) { + document.title = "Login to Shuffle SaaS" + } else { + document.title = "Register to Shuffle SaaS" + } + } + + useEffect(() => { + + if (loginWithSSO && window?.location?.pathname === "/register") { + setLoginWithSSO(false) + } + + },[window?.location?.pathname]) + + // Just a way to force location loading properly + // Register & login should be split :3 + if (window !== undefined) { + const path = window.location.pathname; + if (path.includes("/login") && register === false) { + console.log("Should register instead of login!") + setRegister(!register) + } else if (path.includes("/register") && register === true) { + if (!isCloud) { + setRegister(true) + navigate("/login") + } + + console.log("Should login instead of register!") + setRegister(!register) + } else { + console.log("Path: " + path, "Register: " + register) + } + } + + const bodyDivStyle = { + marginTop: 100, + width: isMobile ? "100%" : "100%", + maxWidth: "1200px", // Increased max-width to accommodate larger cards + background: "#1A1A1A", + margin: "auto", + display: isMobile ? "block" : "flex", + padding: "40px", + gap: "40px", + overflow: "hidden", + alignItems: "center" + }; + + const boxStyle = { + color: "white", + padding: "40px", + flex: 1, + maxWidth: isMobile ? "100%" : 410, + minWidth: 410, + background: "#212121", + borderRadius: "12px", + display: "flex", + // flexDirection: "column", + }; + + + + const paperStyleReg = { + width: 300, + height: 350, + background: "#212121", + borderRadius: "8px", + marginLeft: isMobile ? 80 : register ? "455px" : "485px", + marginTop: isMobile ? 10 : 110, + position: isMobile ? "" : "absolute", + + } + const paperStyleLog = { + position: "absolute", + width: isMobile ? "400px" : "532px", + padding: "0px 30px 0px", + // marginTop: "135px", + // background: "#212121", + borderRadius: "8px", + } + const createData = (icon, title) => { + return { + icon, + title, + } + } + + // Used to swap from login to register. True = login, false = register + const activeIcon = + const rows = [ + createData(activeIcon, "Access to All Apps"), + createData(activeIcon, "10,000 App Runs"), + createData(activeIcon, "Monthly Runs Refresh"), + createData(activeIcon, "Unlimited Users & Workflows"), + createData(activeIcon, "Multi-Tenancy & -Region"), + createData(activeIcon, "Support & Discord Access"), + ]; + const classes = useStyles(); + // Error messages etc + const [loginInfo, setLoginInfo] = useState(""); + + const handleValidateForm = (username, password) => { + if (loginWithSSO) { + return username.length > 1 + } + + if (!isCloud) { + return (username.length > 0 && password.length > 0); + } + + return (username.length > 1 && password.length > 8); + } + + if (isLoggedIn === true && serverside !== true) { + const tmpView = new URLSearchParams(window.location.search).get("view") + if (tmpView !== undefined && tmpView !== null && tmpView === "pricing") { + window.location.pathname = "/pricing" + return + } else if (tmpView !== undefined && tmpView !== null) { + window.location.pathname = tmpView + return + } + + window.location.pathname = "/workflows" + } + + const checkAdmin = () => { + const url = globalUrl + "/api/v1/checkusers"; + fetch(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }) .then((response) => response.json().then((responseJson) => { if (responseJson["success"] === false) { setLoginInfo(responseJson["reason"]); } else { - if (responseJson.sso_url !== undefined && responseJson.sso_url !== null) { setSSOUrl(responseJson.sso_url); } - if (loginViewLoading) { - setLoginViewLoading(false); - checkLogin(); - stop(); - - if ( - responseJson.reason !== undefined && - responseJson.reason !== null - ) { - setLoginInfo(responseJson.reason); - } - } - + // Stay = 0 users + // Redirect = >1 user if (responseJson.reason === "stay") { - navigate("/adminsetup") - } + setTimeout(() => { + navigate("/adminsetup") + }, 2500) + } } }) ) .catch((error) => { - if (!loginViewLoading) { - setLoginViewLoading(true); - start(); - } - }); - }; - - const { start, stop } = useInterval({ - duration: 3000, - startImmediate: false, - callback: () => { - checkAdmin(); - }, - }); - - if (firstRequest) { - setFirstRequest(false); - checkAdmin(); - } - - const onSubmit = (e) => { - setLoginLoading(true); - e.preventDefault(); - setLoginInfo(""); - // FIXME - add some check here ROFL - - // Just use this one? - var data = { username: username, password: password }; - if (MFAValue !== undefined && MFAValue !== null && MFAValue.length > 0) { - data["mfa_code"] = MFAValue; + setTimeout(() => { + navigate("/adminsetup") + }, 2500) + }) } - var baseurl = globalUrl; - if (register) { - var url = baseurl + "/api/v1/login"; - fetch(url, { - mode: "cors", - method: "POST", - body: JSON.stringify(data), - credentials: "include", - crossDomain: true, - withCredentials: true, - headers: { - "Content-Type": "application/json; charset=utf-8", - }, - }) - .then((response) => - response.json().then((responseJson) => { - setLoginLoading(false); - if (responseJson["success"] === false) { - setLoginInfo(responseJson["reason"]); - } else { - if (responseJson["reason"] === "MFA_REDIRECT") { - setLoginInfo( - "MFA required. Please enter the 6-digit code from your authenticator" - ); - setMFAField(true); - return; - } else if (responseJson["reason"] === "MFA_SETUP") { - window.location.href = `/login/${responseJson.url}/mfa-setup`; - return; - } + const onSubmit = (e) => { + //toast("Testing from login page") - setLoginInfo("Successful login, rerouting"); - for (var key in responseJson["cookies"]) { - setCookie( - responseJson["cookies"][key].key, - responseJson["cookies"][key].value, - { path: "/" } - ); - } + setMessage("") + setLoginLoading(true) + e.preventDefault() - if (responseJson.tutorials === undefined || responseJson.tutorials === null || !responseJson.tutorials.includes("welcome")) { - console.log("RUN Welcome!!") - setTimeout(() => { - navigate("/welcome?tab=2") - },200) - // window.location.pathname = "" - return - } + // Just use this one? + var data = { "username": username, "password": password } + if (MFAValue !== undefined && MFAValue !== null && MFAValue.length > 0) { + data["mfa_code"] = MFAValue + } - const tmpView = new URLSearchParams(window.location.search).get("view") - if (tmpView !== undefined && tmpView !== null) { - //const newUrl = `/${tmpView}${decodeURIComponent(window.location.search)}` - const newUrl = `/${tmpView}` - window.location.pathname = newUrl - } else { - window.location.pathname = "/workflows" - } + localStorage.setItem("globalUrl", "") - setIsLoggedIn(true); - } - }) - ) - .catch((error) => { - setLoginLoading(false); - setLoginInfo("Error logging in: " + error); - }); - } else { - url = baseurl + "/api/v1/users/register"; - fetch(url, { - method: "POST", - body: JSON.stringify(data), - headers: { - "Content-Type": "application/json", - }, - }) - .then((response) => - response.json().then((responseJson) => { - if (responseJson["success"] === false) { - setLoginInfo(responseJson["reason"]); - } else { - setLoginInfo("Successful register!"); - } - }) - ) - .catch((error) => { - setLoginInfo("Error in from backend: ", error); - }); - } - }; + var baseurl = globalUrl + if (register) { + var url = baseurl + '/api/v1/login'; - const onChangeUser = (e) => { - setUsername(e.target.value); - }; - - const onChangePass = (e) => { - setPassword(e.target.value); - }; - - //const onClickRegister = () => { - // if (props.location.pathname === "/login") { - // window.location.pathname = "/register" - // } else { - // window.location.pathname = "/login" - // } - - // setLoginCheck(!register) - //} - - //var loginChange = register ? (

Want to register? Click here.

) : (

Go back to login? Click here.

); - var formtitle = register ?
Login
:
Register
; - const imgsize = 100; - const basedata = ( -
- -
- -
- - {loginViewLoading ? ( -
- - Waiting for the Shuffle database to become available. This may - take up to a minute. - - - {loginInfo === undefined || - loginInfo === null || - loginInfo.length === 0 ? null : ( -
Database Response: {loginInfo}
- )} - - - - - - Are you sure Shuffle is{" "} - - installed correctly - - ? - - - - 1. Make sure shuffle-database folder has correct access, and that you have a minimum of 2Gb of RAM available:{" "} -
-
- sudo chown -R 1000:1000 shuffle-database -
- - 2. Disable memory swap on the host: -
-
- sudo swapoff -a -
- - 3. Restart the database: -
-
- sudo docker restart shuffle-opensearch -
-
- - Need help?{" "} - - Join the Discord! - - -
- ) : ( -
-

{formtitle}

- Username -
- -
- Password -
- -
- {MFAField === true ? ( -
- 2-factor code - { - setMFAValue(event.target.value); - }} - /> -
- ) : null} -
- -
-
{loginInfo}
- {ssoUrl !== undefined && ssoUrl !== null && ssoUrl.length > 0 ? ( -
- Or -
- -
-
- ) : null} -
- )} -
-
- ); - - const loadedCheck = isLoaded ?
{basedata}
:
; - - useEffect(() => { - setTimeout(() => { - if (ssoUrl !== undefined && ssoUrl !== null && ssoUrl.length > 0) { - //id="sso_button" - const ssoBtn = document.getElementById("sso_button"); - if (ssoBtn !== undefined && ssoBtn !== null) { - //console.log("SSO BTN: ", ssoBtn) - const cursearch = typeof window === "undefined" || window.location === undefined ? "" : window.location.search; - var tmpView = new URLSearchParams(cursearch).get("autologin"); - if (tmpView !== undefined && tmpView !== null) { - if (tmpView === "true") { - console.log("Tmp: ", tmpView) - ssoBtn.click() - } - } - } + if (loginWithSSO === true) { + url = baseurl + '/api/v1/login/sso' + setLoginInfo("Logging in with SSO. Please wait while we find a relevant org...") } - }, 200); - }, [ssoUrl]) - return
{loadedCheck}
; -}; + fetch(url, { + mode: 'cors', + method: 'POST', + body: JSON.stringify(data), + credentials: 'include', + crossDomain: true, + withCredentials: true, + headers: { + 'Content-Type': 'application/json; charset=utf-8', + }, + }) + .then((response) => { + if (response.status !== 200) { + console.log("Status not 200 for login:O!"); + } -export default LoginDialog; + return response.json(); + }) + .then((responseJson) => { + + setLoginLoading(false) + + console.log("Resp from backend: ", responseJson) + + if (responseJson["success"] === false) { + setLoginInfo(responseJson["reason"]) + } + else { + + if (responseJson["reason"] === "MFA_REDIRECT") { + setLoginInfo("Enter the 6-digit MFA code.") + setMFAField(true) + return + + } + else if (responseJson["reason"] === "MFA_SETUP") { + window.location.href = `/login/${responseJson.url}/mfa-setup`; + return; + } + else if (responseJson["reason"] === "SSO_REDIRECT") { + //navigate(responseJson["url"]) + window.location.href = responseJson["url"] + return + + } + else if (responseJson["reason"] !== undefined && responseJson["reason"] !== null && responseJson["reason"].includes("error")) { + setLoginInfo(responseJson["reason"]) + return + } + + + setLoginInfo("Successful login! Redirecting you in 3 seconds...") + for (var key in responseJson["cookies"]) { + setCookie(responseJson["cookies"][key].key, responseJson["cookies"][key].value, { path: "/" }) + } + + const tmpView = new URLSearchParams(window.location.search).get("view") + if (tmpView !== undefined && tmpView !== null) { + //const newUrl = `/${tmpView}${decodeURIComponent(window.location.search)}` + // Check if slash in the url + + var newUrl = `/${tmpView}` + if (tmpView.startsWith("/")) { + newUrl = `${tmpView}` + } + + console.log("Found url: ", newUrl) + + window.location.pathname = newUrl + return + } + + console.log("LOGIN DATA: ", responseJson) + if (responseJson.tutorials !== undefined && responseJson.tutorials !== null) { + // Find welcome in responseJson.tutorials under key name + const welcome = responseJson.tutorials.find(function (element) { + return element.name === "welcome"; + }) + + console.log("Welcome: ", welcome) + if (welcome === undefined || welcome === null) { + console.log("RUN login Welcome!!") + // window.location.pathname = "/welcome?tab=2" + // window.location = "/welcome?tab=2" + window.location.href = "/welcome?tab=2" + return + } + } + + window.location.pathname = "/workflows" + } + }) + .catch(error => { + setLoginInfo("Error from login API: " + error) + setLoginLoading(false) + }); + } else { + url = baseurl + '/api/v1/register'; + fetch(url, { + method: 'POST', + body: JSON.stringify(data), + headers: { + 'Content-Type': 'application/json', + }, + }) + .then(response => + response.json().then(responseJson => { + if (responseJson["success"] === false) { + setLoginInfo(responseJson["reason"]) + } else { + if (responseJson["reason"] === "shuffle_account") { + window.location.href = "/login?message=Please+login+with+your+Shuffle+account" + return + } + + //setLoginInfo("Successful register!") + //var newpath = "/login?message=Successfully signed up. You can now sign in." + //const tmpMessage = new URLSearchParams(window.location.search).get("message") + setLoginInfo("Successful registration! Redirecting in 3 seconds...") + for (var key in responseJson["cookies"]) { + setCookie(responseJson["cookies"][key].key, responseJson["cookies"][key].value, { path: "/" }) + } + + setTimeout(() => { + console.log("LOGIN DATA: ", responseJson) + + const tmpView = new URLSearchParams(window.location.search).get("view") + if (tmpView !== undefined && tmpView !== null) { + //const newUrl = `/${tmpView}${decodeURIComponent(window.location.search)}` + const newUrl = `/${tmpView}` + window.location.pathname = newUrl + return + } + + //if (responseJson.tutorials === undefined || responseJson.tutorials === null || !responseJson.tutorials.includes("welcome")) { + console.log("RUN Welcome!!") + //window.location.pathname = "/welcome?tab=2" + window.location.href = "/welcome" + }, 1500); + } + setLoginLoading(false) + }), + ) + .catch(error => { + setLoginInfo("Error in login. Please try again, or contact support@shuffler.io if the problem persists.") + setLoginLoading(false) + }); + } + } + + const onChangeUser = (e) => { + setUsername(e.target.value) + } + + const onChangePass = (e) => { + setPassword(e.target.value) + } + + const HandleLoginWithSSO = () => { + setPassword("") + setLoginInfo("") + setLoginWithSSO(true) + } + + var formtitle = register ?
Welcome Back!
:
Create your account
+ var formButton = !isCloud ? "" : register ?
Don’t have an account yet?
Register here
: <> + +
Already have an account?
Login here
+ + //
Click here to Login
+ + // {formtitle} + + const buttonBackground = "linear-gradient(89.83deg, #FF8444 0.13%, #F2643B 99.84%)" + + const buttonStyle = { borderRadius: 25, height: 50, fontSize: 18, backgroundImage: handleValidateForm(username, password) || loginLoading || (checkboxClicked && register) ? buttonBackground : "grey", color: "white" } + // +
+ +
+
+ {formButton} +
+
+ +
+ {loginInfo} +
+ + {( + ssoUrl !== undefined && ssoUrl !== null && ssoUrl.length) > 0 + //|| (isCloud && !loginWithSSO && window?.location?.pathname !== "/register") + ? ( +
+ Or +
+ +
+
+ ) : null} + {isCloud && loginWithSSO && ( + + )} + + + + {isMobile ? null : ( + <> +
+ OR +
+ + + )} +
+ ); + + const loadedCheck = isLoaded ? +
+ {basedata} +
+ : +
+
+ + return ( +
+ {loadedCheck} +
+ ) +} + +export default LoginPage; diff --git a/frontend/src/views/LoginPageOld.jsx b/frontend/src/views/LoginPageOld.jsx new file mode 100755 index 00000000..541cd903 --- /dev/null +++ b/frontend/src/views/LoginPageOld.jsx @@ -0,0 +1,548 @@ +/* eslint-disable react/no-multi-comp */ +import React, { useState, useEffect } from "react"; +import { makeStyles } from "@mui/styles"; +import { useInterval } from "react-powerhooks"; +import theme from '../theme.jsx'; + +import { + CircularProgress, + TextField, + Button, + Paper, + Typography, +} from "@mui/material"; + +import { useNavigate } from "react-router-dom"; + +const hrefStyle = { + color: "white", + textDecoration: "none", +}; + +const bodyDivStyle = { + margin: "auto", + marginTop: 150, + width: "500px", +}; + +const useStyles = makeStyles({ + notchedOutline: { + borderColor: "#f85a3e !important", + }, +}); + +const LoginDialog = (props) => { + const { + globalUrl, + isLoaded, + isLoggedIn, + setIsLoggedIn, + setCookie, + register, + checkLogin, + } = props; + + let navigate = useNavigate(); + const classes = useStyles(); + + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const [firstRequest, setFirstRequest] = useState(true); + const [loginLoading, setLoginLoading] = useState(false); + const [loginViewLoading, setLoginViewLoading] = useState(false); + const [ssoUrl, setSSOUrl] = useState(""); + + const [MFAField, setMFAField] = useState(false); + const [MFAValue, setMFAValue] = useState(""); + + + // Used to swap from login to register. True = login, false = register + + useEffect(() => { + checkAdmin() + }, [loginViewLoading]) + + // Error messages etc + const [loginInfo, setLoginInfo] = useState(""); + + const handleValidateForm = () => { + return username.length > 1 && password.length > 1; + }; + + if (isLoggedIn === true) { + //window.location.pathname = "/workflows"; + navigate("/workflows") + } + + const checkAdmin = () => { + const url = globalUrl + "/api/v1/checkusers"; + fetch(url, { + method: "GET", + headers: { + "Content-Type": "application/json", + }, + }) + .then((response) => + response.json().then((responseJson) => { + if (responseJson["success"] === false) { + setLoginInfo(responseJson["reason"]); + } else { + + if (responseJson.sso_url !== undefined && responseJson.sso_url !== null) { + setSSOUrl(responseJson.sso_url); + } + + navigate("/login") + + if (loginViewLoading) { + setLoginViewLoading(false); + checkLogin(); + stop(); + + if ( + responseJson.reason !== undefined && + responseJson.reason !== null + ) { + setLoginInfo(responseJson.reason); + } + } + + if (responseJson.reason === "stay") { + navigate("/adminsetup") + } + } + }) + ) + .catch((error) => { + if (!loginViewLoading) { + setLoginViewLoading(true); + start(); + } + }); + }; + + const { start, stop } = useInterval({ + duration: 3000, + startImmediate: false, + callback: () => { + checkAdmin(); + }, + }) + + if (firstRequest) { + setFirstRequest(false); + checkAdmin(); + } + + const onSubmit = (e) => { + setLoginLoading(true); + e.preventDefault(); + setLoginInfo(""); + // FIXME - add some check here ROFL + + // Just use this one? + var data = { username: username, password: password }; + if (MFAValue !== undefined && MFAValue !== null && MFAValue.length > 0) { + data["mfa_code"] = MFAValue; + } + + var baseurl = globalUrl; + if (register) { + var url = baseurl + "/api/v1/login"; + fetch(url, { + mode: "cors", + method: "POST", + body: JSON.stringify(data), + credentials: "include", + crossDomain: true, + withCredentials: true, + headers: { + "Content-Type": "application/json; charset=utf-8", + }, + }) + .then((response) => + response.json().then((responseJson) => { + setLoginLoading(false); + if (responseJson["success"] === false) { + setLoginInfo(responseJson["reason"]); + } else { + if (responseJson["reason"] === "MFA_REDIRECT") { + setLoginInfo( + "MFA required. Please enter the 6-digit code from your authenticator" + ); + setMFAField(true); + return; + } else if (responseJson["reason"] === "MFA_SETUP") { + window.location.href = `/login/${responseJson.url}/mfa-setup`; + return; + } + + setLoginInfo("Successful login, rerouting"); + for (var key in responseJson["cookies"]) { + setCookie( + responseJson["cookies"][key].key, + responseJson["cookies"][key].value, + { path: "/" } + ); + } + + if (responseJson.tutorials === undefined || responseJson.tutorials === null || !responseJson.tutorials.includes("welcome")) { + console.log("RUN Welcome!!") + setTimeout(() => { + navigate("/welcome?tab=2") + },200) + // window.location.pathname = "" + return + } + + const tmpView = new URLSearchParams(window.location.search).get("view") + if (tmpView !== undefined && tmpView !== null) { + //const newUrl = `/${tmpView}${decodeURIComponent(window.location.search)}` + const newUrl = `/${tmpView}` + window.location.pathname = newUrl + } else { + window.location.pathname = "/workflows" + } + + setIsLoggedIn(true); + } + }) + ) + .catch((error) => { + setLoginLoading(false); + setLoginInfo("Error logging in: " + error); + }); + } else { + url = baseurl + "/api/v1/users/register"; + fetch(url, { + method: "POST", + body: JSON.stringify(data), + headers: { + "Content-Type": "application/json", + }, + }) + .then((response) => + response.json().then((responseJson) => { + if (responseJson["success"] === false) { + setLoginInfo(responseJson["reason"]); + } else { + setLoginInfo("Successful register!"); + } + }) + ) + .catch((error) => { + setLoginInfo("Error in from backend: ", error); + }); + } + }; + + const onChangeUser = (e) => { + setUsername(e.target.value); + }; + + const onChangePass = (e) => { + setPassword(e.target.value); + }; + + //const onClickRegister = () => { + // if (props.location.pathname === "/login") { + // window.location.pathname = "/register" + // } else { + // window.location.pathname = "/login" + // } + + // setLoginCheck(!register) + //} + + //var loginChange = register ? (

Want to register? Click here.

) : (

Go back to login? Click here.

); + var formtitle = register ?
Login
:
Register
; + const imgsize = 100; + const basedata = ( +
+ +
+ +
+ + {loginViewLoading ? ( +
+ + Waiting for the Shuffle database to become available. This may + take up to two minutes. + + + {loginInfo === undefined || + loginInfo === null || + loginInfo.length === 0 ? null : ( +
Database Response: {loginInfo}
+ )} + + + + + + Are you sure Shuffle is{" "} + + installed correctly + + ? + + + + 1. Make sure shuffle-database folder has correct access, and that you have a minimum of 2Gb of RAM available:{" "} +
+
+ sudo chown -R 1000:1000 shuffle-database +
+ + 2. Disable memory swap on the host: +
+
+ sudo swapoff -a +
+ + 3. Restart the database: +
+
+ sudo docker restart shuffle-opensearch +
+
+ + Need help?{" "} + + Join the Discord! + + +
+ ) : ( +
+

{formtitle}

+ Username +
+ +
+ Password +
+ +
+ {MFAField === true ? ( +
+ 2-factor code + { + setMFAValue(event.target.value); + }} + /> +
+ ) : null} +
+ +
+
{loginInfo}
+ {ssoUrl !== undefined && ssoUrl !== null && ssoUrl.length > 0 ? ( +
+ Or +
+ +
+
+ ) : null} +
+ )} +
+
+ ); + + const loadedCheck = isLoaded ?
{basedata}
:
; + + useEffect(() => { + setTimeout(() => { + if (ssoUrl !== undefined && ssoUrl !== null && ssoUrl.length > 0) { + //id="sso_button" + const ssoBtn = document.getElementById("sso_button"); + if (ssoBtn !== undefined && ssoBtn !== null) { + //console.log("SSO BTN: ", ssoBtn) + const cursearch = typeof window === "undefined" || window.location === undefined ? "" : window.location.search; + var tmpView = new URLSearchParams(cursearch).get("autologin"); + if (tmpView !== undefined && tmpView !== null) { + if (tmpView === "true") { + console.log("Tmp: ", tmpView) + ssoBtn.click() + } + } + } + } + }, 200); + }, [ssoUrl]) + + return
{loadedCheck}
; +}; + +export default LoginDialog; diff --git a/frontend/src/views/RunWorkflow.jsx b/frontend/src/views/RunWorkflow.jsx index 34b8c38c..919d3551 100644 --- a/frontend/src/views/RunWorkflow.jsx +++ b/frontend/src/views/RunWorkflow.jsx @@ -77,6 +77,24 @@ const RunWorkflow = (defaultprops) => { const [boxWidth, setBoxWidth] = React.useState(500) const [inputQuestions, setInputQuestions] = React.useState([]) + + useEffect(() => { + if (workflow === undefined || workflow === null || Object.keys(workflow).length === 0) { + return + } + + if (workflow.input_questions === undefined || workflow.input_questions === null) { + return + } + + // Checks if it's a user input-node based or not + if ((answer !== undefined && answer !== null) || (foundSourcenode !== undefined && foundSourcenode !== null)) { + } else { + setInputQuestions(workflow.input_questions) + setUpdate(Math.random()) + } + }, [workflow]) + const IframeWrapper = (props) => { var propsCopy = JSON.parse(JSON.stringify(props)) propsCopy.width = 400 @@ -1179,6 +1197,7 @@ const RunWorkflow = (defaultprops) => {
{onSubmit(e)}} style={{margin: "25px 0px 15px 0px",}}> {workflowQuestion !== "" || (workflow.form_control.input_markdown !== undefined && workflow.form_control.input_markdown !== null && workflow.form_control.input_markdown.length > 0) ? null :
+ {/* {workflow.name} { left: 200, }} /> + */} {organization} diff --git a/frontend/src/views/Usecases2.jsx b/frontend/src/views/Usecases2.jsx index 9648881e..886427b3 100644 --- a/frontend/src/views/Usecases2.jsx +++ b/frontend/src/views/Usecases2.jsx @@ -23,6 +23,7 @@ import { Chip, Checkbox, Fade, + Skeleton, } from "@mui/material"; import { @@ -140,12 +141,166 @@ const UsecaseListComponent = (props) => { const [firstLoad, setFirstLoad] = useState(true) const [apps, setApps] = useState([]) + const [autoOpenUsecase, setAutoOpenUsecase] = useState(null); const classes = useStyles(); let navigate = useNavigate(); const [mitreTags, setMitreTags] = useState([]); + // Add loading state + const [isLoading, setIsLoading] = useState(true); + + // Add this useEffect to handle URL parameters on load + useEffect(() => { + const urlSearchParams = new URLSearchParams(window.location.search); + const params = Object.fromEntries(urlSearchParams.entries()); + + const selectedUsecase = params["selected_object"]; + if (selectedUsecase && keys.length > 0) { + const usecaseName = selectedUsecase.toLowerCase().replaceAll("_", " "); + + // Find the matching usecase in the keys + for (const category of keys) { + const foundUsecase = category.list.find( + usecase => usecase.name.toLowerCase().replaceAll("_", " ") === usecaseName + ); + + if (foundUsecase) { + setAutoOpenUsecase(foundUsecase); + + // Wait for render then scroll + setTimeout(() => { + const element = document.getElementById(usecaseName); + if (element) { + element.scrollIntoView({ + behavior: "smooth", + block: "center", + inline: "center" + }); + } + }, 1000); + + break; + } + } + } + }, [keys]); + + // Add useEffect to handle auto-opening + useEffect(() => { + if (autoOpenUsecase) { + getUsecase(autoOpenUsecase, 0, 0); + setAutoOpenUsecase(null); + } + }, [autoOpenUsecase]); + + // Loading skeleton component + const LoadingSkeleton = () => ( +
+ {/* Header skeleton */} + + + + {/* Apps selection skeleton */} + + + {/* App icons skeleton */} +
+ {[1, 2, 3, 4, 5].map((app) => ( + + ))} +
+ {/* Add more apps button skeleton */} + +
+ + {/* Usecase categories skeleton - 3 sections: Collect, Enrich, Detect */} + {[1, 2, 3,4,5].map((category) => ( +
+ {/* Category title with color indicator */} + + + + + {[1, 2, 3].map((item) => ( + + + {/* App icons container */} +
+ + +
+ {/* Usecase title */} + +
+
+ ))} +
+
+ ))} +
+ ); + + const parseUsecase = (subcase, inputFramework) => { var useFramework = frameworkData @@ -187,6 +342,7 @@ const UsecaseListComponent = (props) => { }, [frameworkData]) const loadApps = () => { + setIsLoading(true); fetch(`${globalUrl}/api/v1/apps`, { method: "GET", headers: { @@ -220,9 +376,11 @@ const UsecaseListComponent = (props) => { } setApps(responseJson); + setIsLoading(false); }) .catch((error) => { console.log("App loading error: " + error.toString()); + setIsLoading(false); }) } @@ -231,15 +389,23 @@ const UsecaseListComponent = (props) => { }, []) if (keys === undefined || keys === null || keys.length === 0) { - return null + return ; } // Timeout 50ms to delay it slightly const getUsecase = (subcase, index, subindex) => { - subcase = parseUsecase(subcase) - setPrevSubcase(subcase) + // Update URL with selected usecase + const usecaseName = subcase.name.toLowerCase().replaceAll(" ", "_") + const newUrl = `?selected_object=${usecaseName}` + + // Force URL update even if it's the same usecase + navigate(newUrl, { replace: true }) + + // Parse and fetch usecase data + subcase = parseUsecase(subcase) + setPrevSubcase(subcase) fetch(`${globalUrl}/api/v1/workflows/usecases/${escape(subcase.name.replaceAll(" ", "_"))}`, { method: "GET", @@ -415,6 +581,19 @@ const UsecaseListComponent = (props) => { } } + // Then, add a cleanup function for URL params when drawer closes + const handleUsecaseClose = () => { + // Remove the selected_object parameter from URL + navigate("/usecases", { replace: true }) + + // Reset relevant state + setInputUsecase({}) + setExpandedIndex(-1) + setExpandedItem(-1) + setFirstLoad(false) + setSelectedWorkflows([]) + } + return (
@@ -645,10 +824,10 @@ const UsecaseListComponent = (props) => { return ( { - if (fixedName === "reporting") { - getUsecase(subcase, index, subindex) - return - } + // if (fixedName === "reporting") { + // getUsecase(subcase, index, subindex) + // return + // } //setSelectedWorkflows([]) if (selectedItem) { @@ -678,6 +857,8 @@ const UsecaseListComponent = (props) => { workflowBuilt={workflowBuilt} inputWorkflowId={workflowBuilt} usecaseDetails={usecaseDetails} + isModalOpenDefault={autoOpenUsecase?.name === subcase.name} + onClose={handleUsecaseClose} /> @@ -717,6 +898,7 @@ const Usecases2 = (props) => { window.location.host === "localhost:3002" || window.location.host === "shuffler.io"; + const [isLoading, setIsLoading] = useState(true); useEffect(() => { if (selectedUsecaseCategory.length === 0) { @@ -729,71 +911,8 @@ const Usecases2 = (props) => { } }, [selectedUsecaseCategory]) - const checkSelectedParams = () => { - const urlSearchParams = new URLSearchParams(window.location.search) - const params = Object.fromEntries(urlSearchParams.entries()) - - const curpath = typeof window === "undefined" || window.location === undefined ? "" : window.location.pathname; - const cursearch = typeof window === "undefined" || window.location === undefined ? "" : window.location.search; - - const foundQuery = params["selected"] - if (foundQuery !== null && foundQuery !== undefined) { - setSelectedUsecaseCategory(foundQuery) - - const newitem = removeParam("selected", cursearch); - navigate(curpath + newitem) - } - - const baseItem = document.getElementById("reporting") - if (baseItem !== undefined && baseItem !== null) { - baseItem.click() - - // Find close window button -> go to top - const foundButton = document.getElementById("close_selection") - if (foundButton !== undefined && foundButton !== null) { - foundButton.click() - } - - // Scroll back to top - window.scrollTo(0, 0) - } - - const foundQuery2 = params["selected_object"] - if (foundQuery2 !== null && foundQuery2 !== undefined) { - // Take a random object, quickly click it, then go to this one - // Something is weird with loading apps without it - - const queryName = foundQuery2.toLowerCase().replaceAll("_", " ") - // Waiting a bit for it to render - setTimeout(() => { - const foundItem = document.getElementById(queryName) - if (foundItem !== undefined && foundItem !== null) { - foundItem.click() - // Scroll to it - - setTimeout(() => { - foundItem.scrollIntoView({ - behavior: "smooth", - block: "center", - inline: "center" - }) - }, 100) - } else { - //console.log("Couldn't find item with name ", queryName) - } - }, 1000) - } - - } - - useEffect(() => { - if (usecases.length > 0) { - //console.log(usecases) - checkSelectedParams() - } - }, [usecases]) - const getFramework = () => { + setIsLoading(true); fetch(globalUrl + "/api/v1/apps/frameworkConfiguration", { method: "GET", headers: { @@ -831,6 +950,7 @@ const Usecases2 = (props) => { }) .catch((error) => { toast(error.toString()); + setIsLoading(false); }) } diff --git a/frontend/src/views/Welcome.jsx b/frontend/src/views/Welcome.jsx index 7dd21dea..cb5c24c5 100644 --- a/frontend/src/views/Welcome.jsx +++ b/frontend/src/views/Welcome.jsx @@ -447,6 +447,7 @@ const Welcome = (props) => { } navigate("/welcome?tab=2") + setActiveStep(1) setShowWelcome(true) }}> diff --git a/frontend/src/views/Workflows.jsx b/frontend/src/views/Workflows.jsx index b9baf567..100eed13 100755 --- a/frontend/src/views/Workflows.jsx +++ b/frontend/src/views/Workflows.jsx @@ -427,11 +427,15 @@ const chipStyle = { color: "white", }; -export const collapseField = (field) => { +export const collapseField = (field, inputdata) => { if (field === undefined || field === null) { return true } + if (field.namespace !== undefined && field.namespace !== null && field.namespace.length === 1) { + return false + } + if (field.name === "headers" || field.name === "cookies") { return true } @@ -451,44 +455,44 @@ export const collapseField = (field) => { } export const validateJson = (showResult) => { - if (showResult === undefined || showResult === null) { - return { - valid: false, - result: "", - } - } + if (showResult === undefined || showResult === null) { + return { + valid: false, + result: "", + } + } - if (typeof showResult === 'string') { - showResult = showResult.split(" False").join(" false") - showResult = showResult.split(" True").join(" true") + if (typeof showResult === 'string') { + showResult = showResult.split(" False").join(" false") + showResult = showResult.split(" True").join(" true") - showResult.replaceAll("False,", "false,") - showResult.replaceAll("True,", "true,") - } + showResult.replaceAll("False,", "false,") + showResult.replaceAll("True,", "true,") + } - if (typeof showResult === "object" || typeof showResult === "array") { - return { - valid: true, - result: showResult, - } - } + if (typeof showResult === "object" || typeof showResult === "array") { + return { + valid: true, + result: showResult, + } + } - if (showResult[0] === "\"") { - return { - valid: false, - result: showResult, - } - } + if (showResult[0] === "\"") { + return { + valid: false, + result: showResult, + } + } var jsonvalid = true try { if (!showResult.includes("{") && !showResult.includes("[")) { jsonvalid = false - return { - valid: jsonvalid, - result: showResult, - }; + return { + valid: jsonvalid, + result: showResult, + }; } } catch (e) { @@ -505,94 +509,94 @@ export const validateJson = (showResult) => { var result = showResult; try { - result = jsonvalid ? JSON.parse(showResult, { "storeAsString": true }) : showResult; + result = jsonvalid ? JSON.parse(showResult, {"storeAsString": true}) : showResult; } catch (e) { ////console.log("Failed parsing JSON even though its valid: ", e) jsonvalid = false; } - if (jsonvalid === false) { + if (jsonvalid === false) { - if (typeof showResult === 'string') { - showResult = showResult.trim() - } + if (typeof showResult === 'string') { + showResult = showResult.trim() + } - try { - var newstr = showResult.replaceAll("'", '"') + try { + var newstr = showResult.replaceAll("'", '"') - // Basic workarounds for issues with Python Dicts -> JSON - if (newstr.includes(": None")) { - newstr = newstr.replaceAll(": None", ': null') - } + // Basic workarounds for issues with Python Dicts -> JSON + if (newstr.includes(": None")) { + newstr = newstr.replaceAll(": None", ': null') + } - if (newstr.includes("[\"{") && newstr.includes("}\"]")) { - newstr = newstr.replaceAll("[\"{", '[{') - newstr = newstr.replaceAll("}\"]", '}]') - } + if (newstr.includes("[\"{") && newstr.includes("}\"]")) { + newstr = newstr.replaceAll("[\"{", '[{') + newstr = newstr.replaceAll("}\"]", '}]') + } - if (newstr.includes("{\"[") && newstr.includes("]\"}")) { - newstr = newstr.replaceAll("{\"[", '[{') - newstr = newstr.replaceAll("]\"}", '}]') - } + if (newstr.includes("{\"[") && newstr.includes("]\"}")) { + newstr = newstr.replaceAll("{\"[", '[{') + newstr = newstr.replaceAll("]\"}", '}]') + } - result = JSON.parse(newstr) - jsonvalid = true - } catch (e) { + result = JSON.parse(newstr) + jsonvalid = true + } catch (e) { - //console.log("Failed parsing JSON even though its valid (2): ", e) - jsonvalid = false - } - } + //console.log("Failed parsing JSON even though its valid (2): ", e) + jsonvalid = false + } + } - if (jsonvalid && typeof result === "number") { - jsonvalid = false - } + if (jsonvalid && typeof result === "number") { + jsonvalid = false + } - // This is where we start recursing - if (jsonvalid) { - // Check fields if they can be parsed too - try { - for (const [key, value] of Object.entries(result)) { - if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) { - //console.log("CHECKING STRING: ", value) + // This is where we start recursing + if (jsonvalid) { + // Check fields if they can be parsed too + try { + for (const [key, value] of Object.entries(result)) { + if (typeof value === "string" && (value.startsWith("{") || value.startsWith("["))) { + //console.log("CHECKING STRING: ", value) - const inside_result = validateJson(value) - if (inside_result.valid) { - //console.log("INSIDE RESULT: ", inside_result.result) + const inside_result = validateJson(value) + if (inside_result.valid) { + //console.log("INSIDE RESULT: ", inside_result.result) - if (typeof inside_result.result === "string") { - const newres = JSON.parse(inside_result.result) + if (typeof inside_result.result === "string") { + const newres = JSON.parse(inside_result.result) - result[key] = newres - } else { - result[key] = inside_result.result - } - } - } else { + result[key] = newres + } else { + result[key] = inside_result.result + } + } + } else { - // Usually only reaches here if raw array > dict > value - if (typeof showResult !== "array") { - for (const [subkey, subvalue] of Object.entries(value)) { - if (typeof subvalue === "string" && (subvalue.startsWith("{") || subvalue.startsWith("["))) { - const inside_result = validateJson(subvalue) - if (inside_result.valid) { - if (typeof inside_result.result === "string") { - const newres = JSON.parse(inside_result.result) - result[key][subkey] = newres - } else { - result[key][subkey] = inside_result.result - } - } - } + // Usually only reaches here if raw array > dict > value + if (typeof showResult !== "array") { + for (const [subkey, subvalue] of Object.entries(value)) { + if (typeof subvalue === "string" && (subvalue.startsWith("{") || subvalue.startsWith("["))) { + const inside_result = validateJson(subvalue) + if (inside_result.valid) { + if (typeof inside_result.result === "string") { + const newres = JSON.parse(inside_result.result) + result[key][subkey] = newres + } else { + result[key][subkey] = inside_result.result + } + } + } - } - } - } - } - } catch (e) { - //console.log("Failed parsing inside json subvalues: ", e) - } - } + } + } + } + } + } catch (e) { + //console.log("Failed parsing inside json subvalues: ", e) + } + } return { valid: jsonvalid, @@ -600,6 +604,7 @@ export const validateJson = (showResult) => { }; }; + //Custom hook for handling styling of the dropzone const useDropzoneStyles = () => { const { leftSideBarOpenByClick } = useContext(Context); @@ -1841,9 +1846,13 @@ const Workflows = (props) => { var parsedworkflows = []; for (var key in newSubflows) { + if (key === data.id) { + continue + } + const foundWorkflow = workflows.find( (workflow) => workflow.id === newSubflows[key] - ); + ) if (foundWorkflow !== undefined && foundWorkflow !== null) { parsedworkflows.push(foundWorkflow); } @@ -1854,7 +1863,7 @@ const Workflows = (props) => { "Appending subflows during export: ", parsedworkflows.length ); - data.subflows = parsedworkflows; + data.subflows = parsedworkflows } } @@ -1937,7 +1946,10 @@ const Workflows = (props) => { .then((response) => { if (response.status !== 200) { console.log("Status not 200 for setting workflows :O!"); - toast("Failed deleting workflow. Do you have access?"); + + if (bulk !== true) { + toast(`Failed deleting workflow ${id}. Do you have access?`); + } } else { if (bulk !== true) { toast(`Deleted workflow ${id}. Child Workflows in Suborgs were also removed.`) diff --git a/frontend/src/views/Workflows2.jsx b/frontend/src/views/Workflows2.jsx index 40aaf42d..45d598ee 100644 --- a/frontend/src/views/Workflows2.jsx +++ b/frontend/src/views/Workflows2.jsx @@ -724,6 +724,8 @@ const Workflows2 = (props) => { const [apps, setApps] = React.useState([]); + const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); + document.title = "Shuffle - Workflows"; useEffect(() => { @@ -1758,9 +1760,17 @@ const Workflows2 = (props) => { let exportFileDefaultName = data.name + ".json"; data["owner"] = ""; + data["updated_by"] = ""; data["org"] = []; data["org_id"] = ""; data["execution_org"] = {}; + data["created"] = 0 + data["due_date"] = 0 + data["edited"] = 0 + + data["validation"] = {}; + data["suborg_distribution"] = [] + data["parentorg_workflow"] = "" // These are backwards.. True = saved before. Very confuse. data["previously_saved"] = false; @@ -1935,6 +1945,10 @@ const Workflows2 = (props) => { var parsedworkflows = []; for (var key in newSubflows) { + if (key === data.id) { + continue + } + const foundWorkflow = workflows.find( (workflow) => workflow.id === newSubflows[key] ); @@ -2031,7 +2045,10 @@ const Workflows2 = (props) => { .then((response) => { if (response.status !== 200) { console.log("Status not 200 for setting workflows :O!"); - toast("Failed deleting workflow. Do you have access?"); + + if (bulk !== true) { + toast("Failed deleting workflow. Do you have access?"); + } } else { if (bulk !== true) { toast(`Deleted workflow ${id}. Child Workflows in Suborgs were also removed.`) @@ -2312,7 +2329,7 @@ const Workflows2 = (props) => { key={"explore forms"} > - {"Create Form"} + {"Edit Form"} @@ -2362,7 +2379,6 @@ const Workflows2 = (props) => { { setDeleteModalOpen(true); setSelectedWorkflowId(data.id); @@ -2810,7 +2826,7 @@ const Workflows2 = (props) => { {(data.sharing !== undefined && data.sharing !== null && data.sharing === "form") || (data?.form_control?.input_markdown !== undefined && data?.form_control?.input_markdown !== null && data?.form_control?.input_markdown !== "") && type !== "public" ? -
+
{ : null} {(data?.validation?.validation_ran === true && data?.validation?.valid === false && data?.validation?.errors?.length > 0 ) ? - -
+ +
{
- : null} +
@@ -3224,6 +3240,7 @@ const Workflows2 = (props) => {
} + { display: "flex", flexDirection: "column", width: "100%", - maxWidth: "70%", + maxWidth: isSafari ? "100%" : "70%", margin: "auto", }}> @@ -4601,6 +4618,7 @@ const Workflows2 = (props) => { variant="contained" color="primary" onClick={handleCreateWorkflow} + id="create_workflow_button" style={{ borderRadius: 4, flex: 0.8, @@ -5045,8 +5063,9 @@ const Workflows2 = (props) => { + //isLoaded && isLoggedIn && workflowDone ? ( const loadedCheck = - isLoaded && isLoggedIn && workflowDone ? ( + workflowDone ? (
{/* @@ -5113,8 +5132,14 @@ const Workflows2 = (props) => {
); + const safariStyle = { + transform: 'scale(0.7)', + transformOrigin: 'top', + width: '100%', + height: '100%', + } // Maybe use gridview or something, idk - return
{loadedCheck}
; + return
{loadedCheck}
; }; diff --git a/functions/kubernetes/charts/shuffle/.gitignore b/functions/kubernetes/charts/shuffle/.gitignore new file mode 100644 index 00000000..1fab0544 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/.gitignore @@ -0,0 +1,3 @@ +.DS_Store +*.tgz +charts/ diff --git a/functions/kubernetes/charts/shuffle/.helmignore b/functions/kubernetes/charts/shuffle/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/functions/kubernetes/charts/shuffle/.yamllint b/functions/kubernetes/charts/shuffle/.yamllint new file mode 100644 index 00000000..8b3ce4aa --- /dev/null +++ b/functions/kubernetes/charts/shuffle/.yamllint @@ -0,0 +1,11 @@ +--- +extends: default + +rules: + line-length: disable + braces: disable + comments: + require-starting-space: true + ignore-shebangs: true + min-spaces-from-content: 1 + diff --git a/functions/kubernetes/charts/shuffle/Chart.yaml b/functions/kubernetes/charts/shuffle/Chart.yaml new file mode 100644 index 00000000..f11f1726 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/Chart.yaml @@ -0,0 +1,14 @@ +apiVersion: v2 +name: shuffle +description: A Helm chart for deploying Shuffle on Kubernetes +type: application +version: 0.0.0 +appVersion: 0.0.0 +dependencies: + - name: common + version: ^2.23.0 + repository: oci://registry-1.docker.io/bitnamicharts + - name: opensearch + version: ^1.3.0 + repository: oci://registry-1.docker.io/bitnamicharts + condition: opensearch.enabled diff --git a/functions/kubernetes/charts/shuffle/README.md b/functions/kubernetes/charts/shuffle/README.md new file mode 100644 index 00000000..495d2690 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/README.md @@ -0,0 +1,607 @@ +# Shuffle Helm chart + +## Chart Template + +The Bitnami Chart Template was used for creating this chart: + +https://github.com/bitnami/charts/tree/7e44e64626f5b1fc6d56889cdfdeadc1f62c7cf1/template/CHART_NAME + +Original license text: + +``` +Copyright Broadcom, Inc. All Rights Reserved. + +SPDX-License-Identifier: APACHE-2.0 +``` + +## Usage + +```sh +# Install shuffle via helm (the shuffle namespace is hardcoded into the shuffle source code) +helm install shuffle oci://ghcr.io/shuffle/shuffle/charts/shuffle --namespace shuffle --create-namespace +``` + +Make sure that no other application is deployed to the shuffle namespace, as shuffle deletes kubernetes resources in this namespace. + +Only a single deployment of shuffle is supported per namespace. + +## Uninstallation + +```sh +# Uninstall shuffle via helm +helm uninstall shuffle --namespace shuffle + +# Remove additional resources created by shuffle (such as workers and apps) +kubectl delete svc --namespace shuffle -l "app.kubernetes.io/managed-by in (shuffle-orborus,shuffle-worker)" +kubectl delete deploy --namespace shuffle -l "app.kubernetes.io/managed-by in (shuffle-orborus,shuffle-worker)" +``` + +## Secret Parameters + +The helm chart was designed to not contain any secret data and does not allow configuring secret data using helm values. +Instead, secret values must be passed to services using `extraEnvVarsSecret` or `extraEnvVars`. + +The secrets need to be manually created. It is possible to run this helm chart without specifying any secrets. +You will be prompted to create an admin user when visiting the shuffle dashboard for the first time. +Note that information will not be encrypted without specifying the `SHUFFLE_ENCRYPTION_MODIFIER` value. + +### Mounting env variables into a service + +After creating secrets which hold sensitive information, you can mount them as environment variables into a +service via the `extraEnvVarsSecret` or `extraEnvVars` values. + +```yaml +backend: + # Use a single secret, which holds environment variables. + # Remember that the secret keys must exactly match the environment variable names. + extraEnvVarsSecret: shuffle-backend-env + + # Or mount each value explicitly + extraEnvVars: + - name: SHUFFLE_DEFAULT_USERNAME + valueFrom: + secretKeyRef: + name: "shuffle-initial-user" + key: username + - name: SHUFFLE_DEFAULT_PASSWORD + valueFrom: + secretKeyRef: + name: "shuffle-initial-user" + key: password + - name: SHUFFLE_DEFAULT_APIKEY + valueFrom: + secretKeyRef: + name: "shuffle-initial-user" + key: apikey + - name: SHUFFLE_ENCRYPTION_MODIFIER + valueFrom: + secretKeyRef: + name: "shuffle-encryption" + key: modifier +``` + +### Backend + +A list of environment variables containing secret values for the backend. + +```yaml +# OpenSearch password +SHUFFLE_OPENSEARCH_PASSWORD: "" + +# Basic auth credentials for downloading apps from git +SHUFFLE_DOWNLOAD_AUTH_USERNAME: "" +SHUFFLE_DOWNLOAD_AUTH_PASSWORD: "" + +# Automatically create the initial admin user. Username and password have a min length of 3. +# If not set, you are prompted with an admin user creation dialog when visiting the shuffle frontend for the first time. +SHUFFLE_DEFAULT_USERNAME: admin +SHUFFLE_DEFAULT_PASSWORD: MySecretAdminPassword1234! +SHUFFLE_DEFAULT_APIKEY: "72E41083-A6F6-4A1B-8538-B06B577F47F0" # Shuffle uses uuid v4 + +# Encryption modifier. This HAS to be set to encrypt any authentication being used in Shuffle. +# This is put together with other relevant values to ensure multiple parts are needed to decrypt. +# If this key is lost or changed, you will have to reauthenticate all apps. +# The encryption modifier is added to encrypted values to prevent rainbow table attacks. It can be any random string. +SHUFFLE_ENCRYPTION_MODIFIER: "MyShuffleEncryptionModifier" +``` + +## Parameters + +### Global parameters + +| Name | Description | Value | +| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | +| `global.imageRegistry` | Global Docker image registry | `""` | +| `global.imagePullSecrets` | Global Docker registry secret names as an array | `[]` | +| `global.defaultStorageClass` | Global default StorageClass for Persistent Volume(s) | `""` | +| `global.compatibility.openshift.adaptSecurityContext` | Adapt the securityContext sections of the deployment to make them compatible with Openshift restricted-v2 SCC: remove runAsUser, runAsGroup and fsGroup and let the platform use their allowed default IDs. Possible values: auto (apply if the detected running cluster is Openshift), force (perform the adaptation always), disabled (do not perform adaptation) | `auto` | +| `global.compatibility.omitEmptySeLinuxOptions` | If set to true, removes the seLinuxOptions from the securityContexts when it is set to an empty object | `false` | + +### Common parameters + +| Name | Description | Value | +| ------------------------ | --------------------------------------------------------------------------------------- | --------------- | +| `kubeVersion` | Override Kubernetes version | `""` | +| `nameOverride` | String to partially override common.names.name | `""` | +| `fullnameOverride` | String to fully override common.names.fullname | `""` | +| `namespaceOverride` | String to fully override common.names.namespace | `""` | +| `commonLabels` | Labels to add to all deployed objects | `{}` | +| `commonAnnotations` | Annotations to add to all deployed objects | `{}` | +| `clusterDomain` | Kubernetes cluster domain name | `cluster.local` | +| `extraDeploy` | Array of extra objects to deploy with the release | `[]` | +| `diagnosticMode.enabled` | Enable diagnostic mode (all probes will be disabled and the command will be overridden) | `false` | +| `diagnosticMode.command` | Command to override all containers in the chart release | `["sleep"]` | +| `diagnosticMode.args` | Args to override all containers in the chart release | `["infinity"]` | + +### Shared Shuffle Parameters + +| Name | Description | Value | +| --------------------- | ------------------------------------------------------------- | --------------- | +| `shuffle.baseUrl` | The external base URL under which Shuffle is reachable. | `""` | +| `shuffle.org` | Default shuffle organization | `Shuffle` | +| `shuffle.appRegistry` | The registry from / to which shuffle apps are pulled / pushed | `""` | +| `shuffle.timezone` | The timezone used by Shuffle | `Europe/Berlin` | + +### backend Parameters + +| Name | Description | Value | +| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | +| `backend.image.registry` | backend image registry | `ghcr.io` | +| `backend.image.repository` | backend image repository | `shuffle/shuffle-backend` | +| `backend.image.digest` | backend image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag image tag (immutable tags are recommended) | `""` | +| `backend.image.pullPolicy` | backend image pull policy | `IfNotPresent` | +| `backend.image.pullSecrets` | backend image pull secrets | `[]` | +| `backend.replicaCount` | Number of backend replicas to deploy | `1` | +| `backend.containerPorts.http` | backend HTTP container port | `5001` | +| `backend.extraContainerPorts` | Optionally specify extra list of additional ports for backend containers | `[]` | +| `backend.livenessProbe.enabled` | Enable livenessProbe on backend containers | `false` | +| `backend.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `0` | +| `backend.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `15` | +| `backend.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `1` | +| `backend.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `4` | +| `backend.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | +| `backend.readinessProbe.enabled` | Enable readinessProbe on backend containers | `false` | +| `backend.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `0` | +| `backend.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `5` | +| `backend.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `1` | +| `backend.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `3` | +| `backend.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | +| `backend.startupProbe.enabled` | Enable startupProbe on backend containers | `false` | +| `backend.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `0` | +| `backend.startupProbe.periodSeconds` | Period seconds for startupProbe | `1` | +| `backend.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `1` | +| `backend.startupProbe.failureThreshold` | Failure threshold for startupProbe | `60` | +| `backend.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | +| `backend.customLivenessProbe` | Custom livenessProbe that overrides the default one | `{}` | +| `backend.customReadinessProbe` | Custom readinessProbe that overrides the default one | `{}` | +| `backend.customStartupProbe` | Custom startupProbe that overrides the default one | `{}` | +| `backend.resourcesPreset` | Set backend container resources according to one common preset (allowed values: none, nano, small, medium, large, xlarge, 2xlarge). This is ignored if backend.resources is set (backend.resources is recommended for production). | `small` | +| `backend.resources` | Set backend container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | +| `backend.podSecurityContext.enabled` | Enable backend pods' Security Context | `true` | +| `backend.podSecurityContext.fsGroupChangePolicy` | Set filesystem group change policy for backend pods | `Always` | +| `backend.podSecurityContext.sysctls` | Set kernel settings using the sysctl interface for backend pods | `[]` | +| `backend.podSecurityContext.supplementalGroups` | Set filesystem extra groups for backend pods | `[]` | +| `backend.podSecurityContext.fsGroup` | Set fsGroup in backend pods' Security Context | `1001` | +| `backend.containerSecurityContext.enabled` | Enabled backend container' Security Context | `true` | +| `backend.containerSecurityContext.seLinuxOptions` | Set SELinux options in backend container | `{}` | +| `backend.containerSecurityContext.runAsUser` | Set runAsUser in backend container' Security Context | `1000` | +| `backend.containerSecurityContext.runAsGroup` | Set runAsGroup in backend container' Security Context | `1000` | +| `backend.containerSecurityContext.runAsNonRoot` | Set runAsNonRoot in backend container' Security Context | `true` | +| `backend.containerSecurityContext.readOnlyRootFilesystem` | Set readOnlyRootFilesystem in backend container' Security Context | `true` | +| `backend.containerSecurityContext.privileged` | Set privileged in backend container' Security Context | `false` | +| `backend.containerSecurityContext.allowPrivilegeEscalation` | Set allowPrivilegeEscalation in backend container' Security Context | `false` | +| `backend.containerSecurityContext.capabilities.drop` | List of capabilities to be dropped in backend container | `["ALL"]` | +| `backend.containerSecurityContext.seccompProfile.type` | Set seccomp profile in backend container | `RuntimeDefault` | +| `backend.command` | Override default backend container command (useful when using custom images) | `[]` | +| `backend.args` | Override default backend container args (useful when using custom images) | `[]` | +| `backend.automountServiceAccountToken` | Mount Service Account token in backend pods | `true` | +| `backend.hostAliases` | backend pods host aliases | `[]` | +| `backend.daemonsetAnnotations` | Annotations for backend daemonset | `{}` | +| `backend.deploymentAnnotations` | Annotations for backend deployment | `{}` | +| `backend.statefulsetAnnotations` | Annotations for backend statefulset | `{}` | +| `backend.podLabels` | Extra labels for backend pods | `{}` | +| `backend.podAnnotations` | Annotations for backend pods | `{}` | +| `backend.podAffinityPreset` | Pod affinity preset. Ignored if `backend.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `backend.podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `backend.affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `backend.nodeAffinityPreset.type` | Node affinity preset type. Ignored if `backend.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `backend.nodeAffinityPreset.key` | Node label key to match. Ignored if `backend.affinity` is set | `""` | +| `backend.nodeAffinityPreset.values` | Node label values to match. Ignored if `backend.affinity` is set | `[]` | +| `backend.affinity` | Affinity for backend pods assignment | `{}` | +| `backend.nodeSelector` | Node labels for backend pods assignment | `{}` | +| `backend.tolerations` | Tolerations for backend pods assignment | `[]` | +| `backend.updateStrategy.type` | backend deployment strategy type | `RollingUpdate` | +| `backend.updateStrategy.type` | backend statefulset strategy type | `RollingUpdate` | +| `backend.podManagementPolicy` | Pod management policy for backend statefulset | `OrderedReady` | +| `backend.priorityClassName` | backend pods' priorityClassName | `""` | +| `backend.topologySpreadConstraints` | Topology Spread Constraints for backend pod assignment spread across your cluster among failure-domains | `[]` | +| `backend.schedulerName` | Name of the k8s scheduler (other than default) for backend pods | `""` | +| `backend.terminationGracePeriodSeconds` | Seconds backend pods need to terminate gracefully | `""` | +| `backend.lifecycleHooks` | for backend containers to automate configuration before or after startup | `{}` | +| `backend.extraEnvVars` | Array with extra environment variables to add to backend containers | `[]` | +| `backend.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for backend containers | `""` | +| `backend.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for backend containers | `""` | +| `backend.extraVolumes` | Optionally specify extra list of additional volumes for the backend pods | `[]` | +| `backend.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the backend containers | `[]` | +| `backend.sidecars` | Add additional sidecar containers to the backend pods | `[]` | +| `backend.initContainers` | Add additional init containers to the backend pods | `[]` | +| `backend.pdb.create` | Enable/disable a Pod Disruption Budget creation | `true` | +| `backend.pdb.minAvailable` | Minimum number/percentage of pods that should remain scheduled | `""` | +| `backend.pdb.maxUnavailable` | Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `backend.pdb.minAvailable` and `backend.pdb.maxUnavailable` are empty. | `""` | +| `backend.autoscaling.vpa.enabled` | Enable VPA for backend pods | `false` | +| `backend.autoscaling.vpa.annotations` | Annotations for VPA resource | `{}` | +| `backend.autoscaling.vpa.controlledResources` | VPA List of resources that the vertical pod autoscaler can control. Defaults to cpu and memory | `[]` | +| `backend.autoscaling.vpa.maxAllowed` | VPA Max allowed resources for the pod | `{}` | +| `backend.autoscaling.vpa.minAllowed` | VPA Min allowed resources for the pod | `{}` | +| `backend.autoscaling.vpa.updatePolicy.updateMode` | Autoscaling update policy | `Auto` | +| `backend.autoscaling.hpa.enabled` | Enable HPA for backend pods | `false` | +| `backend.autoscaling.hpa.minReplicas` | Minimum number of replicas | `""` | +| `backend.autoscaling.hpa.maxReplicas` | Maximum number of replicas | `""` | +| `backend.autoscaling.hpa.targetCPU` | Target CPU utilization percentage | `""` | +| `backend.autoscaling.hpa.targetMemory` | Target Memory utilization percentage | `""` | +| `backend.serviceAccount.create` | Specifies whether a ServiceAccount should be created | `true` | +| `backend.serviceAccount.name` | The name of the ServiceAccount to use. | `""` | +| `backend.serviceAccount.annotations` | Additional Service Account annotations (evaluated as a template) | `{}` | +| `backend.serviceAccount.automountServiceAccountToken` | Automount service account token for the backend service account | `true` | +| `backend.serviceAccount.imagePullSecrets` | Add image pull secrets to the backend service account | `[]` | +| `backend.rbac.create` | Specifies whether RBAC resources should be created | `true` | +| `backend.networkPolicy.enabled` | Specifies whether a NetworkPolicy should be created | `true` | +| `backend.networkPolicy.allowExternal` | Don't require server label for connections | `true` | +| `backend.networkPolicy.allowExternalEgress` | Allow the pod to access any range of port and all destinations. | `true` | +| `backend.networkPolicy.extraIngress` | Add extra ingress rules to the NetworkPolicy | `[]` | +| `backend.networkPolicy.extraEgress` | Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true) | `[]` | +| `backend.cleanupSchedule` | The interval in seconds at which the cleanup job runs | `300` | +| `backend.openSearch.url` | The URL at which OpenSearch is available | `http://{{ .Release.Name }}-opensearch:9200` | +| `backend.openSearch.username` | The username that is used for authenticating with OpenSearch | `admin` | +| `backend.openSearch.certificateFile` | The path to a custom OpenSearch certificate file | `""` | +| `backend.openSearch.skipSSLVerify` | Skip SSL verification | `false` | +| `backend.openSearch.indexPrefix` | A prefix for OpenSearch indices | `""` | +| `backend.apps.downloadLocation` | The location to a git repository from which default appps are downloaded on startup. | `https://github.com/shuffle/python-apps` | +| `backend.apps.downloadBranch` | The branch from which apps should be downloaded on startup. | `master` | +| `backend.apps.forceUpdate` | Force an update of apps on startup. | `false` | + +### frontend Parameters + +| Name | Description | Value | +| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- | +| `frontend.image.registry` | frontend image registry | `ghcr.io` | +| `frontend.image.repository` | frontend image repository | `shuffle/shuffle-frontend` | +| `frontend.image.digest` | frontend image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag image tag (immutable tags are recommended) | `""` | +| `frontend.image.pullPolicy` | frontend image pull policy | `IfNotPresent` | +| `frontend.image.pullSecrets` | frontend image pull secrets | `[]` | +| `frontend.replicaCount` | Number of frontend replicas to deploy | `1` | +| `frontend.containerPorts.http` | frontend HTTP container port | `80` | +| `frontend.containerPorts.https` | frontend HTTPS container port | `443` | +| `frontend.extraContainerPorts` | Optionally specify extra list of additional ports for frontend containers | `[]` | +| `frontend.livenessProbe.enabled` | Enable livenessProbe on frontend containers | `false` | +| `frontend.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `0` | +| `frontend.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `15` | +| `frontend.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `1` | +| `frontend.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `4` | +| `frontend.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | +| `frontend.readinessProbe.enabled` | Enable readinessProbe on frontend containers | `false` | +| `frontend.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `0` | +| `frontend.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `5` | +| `frontend.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `1` | +| `frontend.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `3` | +| `frontend.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | +| `frontend.startupProbe.enabled` | Enable startupProbe on frontend containers | `false` | +| `frontend.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `0` | +| `frontend.startupProbe.periodSeconds` | Period seconds for startupProbe | `1` | +| `frontend.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `1` | +| `frontend.startupProbe.failureThreshold` | Failure threshold for startupProbe | `60` | +| `frontend.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | +| `frontend.customLivenessProbe` | Custom livenessProbe that overrides the default one | `{}` | +| `frontend.customReadinessProbe` | Custom readinessProbe that overrides the default one | `{}` | +| `frontend.customStartupProbe` | Custom startupProbe that overrides the default one | `{}` | +| `frontend.resourcesPreset` | Set frontend container resources according to one common preset (allowed values: none, nano, small, medium, large, xlarge, 2xlarge). This is ignored if frontend.resources is set (frontend.resources is recommended for production). | `nano` | +| `frontend.resources` | Set frontend container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | +| `frontend.podSecurityContext.enabled` | Enable frontend pods' Security Context | `false` | +| `frontend.podSecurityContext.fsGroupChangePolicy` | Set filesystem group change policy for frontend pods | `Always` | +| `frontend.podSecurityContext.sysctls` | Set kernel settings using the sysctl interface for frontend pods | `[]` | +| `frontend.podSecurityContext.supplementalGroups` | Set filesystem extra groups for frontend pods | `[]` | +| `frontend.podSecurityContext.fsGroup` | Set fsGroup in frontend pods' Security Context | `1001` | +| `frontend.containerSecurityContext.enabled` | Enabled frontend container' Security Context | `false` | +| `frontend.containerSecurityContext.seLinuxOptions` | Set SELinux options in frontend container | `{}` | +| `frontend.containerSecurityContext.runAsUser` | Set runAsUser in frontend container' Security Context | `101` | +| `frontend.containerSecurityContext.runAsGroup` | Set runAsGroup in frontend container' Security Context | `101` | +| `frontend.containerSecurityContext.runAsNonRoot` | Set runAsNonRoot in frontend container' Security Context | `true` | +| `frontend.containerSecurityContext.readOnlyRootFilesystem` | Set readOnlyRootFilesystem in frontend container' Security Context | `true` | +| `frontend.containerSecurityContext.privileged` | Set privileged in frontend container' Security Context | `false` | +| `frontend.containerSecurityContext.allowPrivilegeEscalation` | Set allowPrivilegeEscalation in frontend container' Security Context | `false` | +| `frontend.containerSecurityContext.capabilities.drop` | List of capabilities to be dropped in frontend container | `["ALL"]` | +| `frontend.containerSecurityContext.seccompProfile.type` | Set seccomp profile in frontend container | `RuntimeDefault` | +| `frontend.command` | Override default frontend container command (useful when using custom images) | `[]` | +| `frontend.args` | Override default frontend container args (useful when using custom images) | `[]` | +| `frontend.automountServiceAccountToken` | Mount Service Account token in frontend pods | `false` | +| `frontend.hostAliases` | frontend pods host aliases | `[]` | +| `frontend.daemonsetAnnotations` | Annotations for frontend daemonset | `{}` | +| `frontend.deploymentAnnotations` | Annotations for frontend deployment | `{}` | +| `frontend.statefulsetAnnotations` | Annotations for frontend statefulset | `{}` | +| `frontend.podLabels` | Extra labels for frontend pods | `{}` | +| `frontend.podAnnotations` | Annotations for frontend pods | `{}` | +| `frontend.podAffinityPreset` | Pod affinity preset. Ignored if `frontend.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `frontend.podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `frontend.affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `frontend.nodeAffinityPreset.type` | Node affinity preset type. Ignored if `frontend.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `frontend.nodeAffinityPreset.key` | Node label key to match. Ignored if `frontend.affinity` is set | `""` | +| `frontend.nodeAffinityPreset.values` | Node label values to match. Ignored if `frontend.affinity` is set | `[]` | +| `frontend.affinity` | Affinity for frontend pods assignment | `{}` | +| `frontend.nodeSelector` | Node labels for frontend pods assignment | `{}` | +| `frontend.tolerations` | Tolerations for frontend pods assignment | `[]` | +| `frontend.updateStrategy.type` | frontend deployment strategy type | `RollingUpdate` | +| `frontend.updateStrategy.type` | frontend statefulset strategy type | `RollingUpdate` | +| `frontend.podManagementPolicy` | Pod management policy for frontend statefulset | `OrderedReady` | +| `frontend.priorityClassName` | frontend pods' priorityClassName | `""` | +| `frontend.topologySpreadConstraints` | Topology Spread Constraints for frontend pod assignment spread across your cluster among failure-domains | `[]` | +| `frontend.schedulerName` | Name of the k8s scheduler (other than default) for frontend pods | `""` | +| `frontend.terminationGracePeriodSeconds` | Seconds frontend pods need to terminate gracefully | `""` | +| `frontend.lifecycleHooks` | for frontend containers to automate configuration before or after startup | `{}` | +| `frontend.extraEnvVars` | Array with extra environment variables to add to frontend containers | `[]` | +| `frontend.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for frontend containers | `""` | +| `frontend.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for frontend containers | `""` | +| `frontend.extraVolumes` | Optionally specify extra list of additional volumes for the frontend pods | `[]` | +| `frontend.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the frontend containers | `[]` | +| `frontend.sidecars` | Add additional sidecar containers to the frontend pods | `[]` | +| `frontend.initContainers` | Add additional init containers to the frontend pods | `[]` | +| `frontend.pdb.create` | Enable/disable a Pod Disruption Budget creation | `true` | +| `frontend.pdb.minAvailable` | Minimum number/percentage of pods that should remain scheduled | `""` | +| `frontend.pdb.maxUnavailable` | Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `frontend.pdb.minAvailable` and `frontend.pdb.maxUnavailable` are empty. | `""` | +| `frontend.autoscaling.vpa.enabled` | Enable VPA for frontend pods | `false` | +| `frontend.autoscaling.vpa.annotations` | Annotations for VPA resource | `{}` | +| `frontend.autoscaling.vpa.controlledResources` | VPA List of resources that the vertical pod autoscaler can control. Defaults to cpu and memory | `[]` | +| `frontend.autoscaling.vpa.maxAllowed` | VPA Max allowed resources for the pod | `{}` | +| `frontend.autoscaling.vpa.minAllowed` | VPA Min allowed resources for the pod | `{}` | +| `frontend.autoscaling.vpa.updatePolicy.updateMode` | Autoscaling update policy | `Auto` | +| `frontend.autoscaling.hpa.enabled` | Enable HPA for frontend pods | `false` | +| `frontend.autoscaling.hpa.minReplicas` | Minimum number of replicas | `""` | +| `frontend.autoscaling.hpa.maxReplicas` | Maximum number of replicas | `""` | +| `frontend.autoscaling.hpa.targetCPU` | Target CPU utilization percentage | `""` | +| `frontend.autoscaling.hpa.targetMemory` | Target Memory utilization percentage | `""` | +| `frontend.serviceAccount.create` | Specifies whether a ServiceAccount should be created | `true` | +| `frontend.serviceAccount.name` | The name of the ServiceAccount to use. | `""` | +| `frontend.serviceAccount.annotations` | Additional Service Account annotations (evaluated as a template) | `{}` | +| `frontend.serviceAccount.automountServiceAccountToken` | Automount service account token for the frontend service account | `true` | +| `frontend.serviceAccount.imagePullSecrets` | Add image pull secrets to the frontend service account | `[]` | +| `frontend.networkPolicy.enabled` | Specifies whether a NetworkPolicy should be created | `true` | +| `frontend.networkPolicy.allowExternal` | Don't require server label for connections | `true` | +| `frontend.networkPolicy.allowExternalEgress` | Allow the pod to access any range of port and all destinations. | `true` | +| `frontend.networkPolicy.extraIngress` | Add extra ingress rules to the NetworkPolicy | `[]` | +| `frontend.networkPolicy.extraEgress` | Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true) | `[]` | + +### orborus Parameters + +| Name | Description | Value | +| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | +| `orborus.image.registry` | orborus image registry | `ghcr.io` | +| `orborus.image.repository` | orborus image repository | `shuffle/shuffle-orborus` | +| `orborus.image.digest` | orborus image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag image tag (immutable tags are recommended) | `""` | +| `orborus.image.pullPolicy` | orborus image pull policy | `IfNotPresent` | +| `orborus.image.pullSecrets` | orborus image pull secrets | `[]` | +| `orborus.replicaCount` | Number of orborus replicas to deploy | `1` | +| `orborus.containerPorts.http` | orborus HTTP container port | `8080` | +| `orborus.extraContainerPorts` | Optionally specify extra list of additional ports for orborus containers | `[]` | +| `orborus.livenessProbe.enabled` | Enable livenessProbe on orborus containers | `false` | +| `orborus.livenessProbe.initialDelaySeconds` | Initial delay seconds for livenessProbe | `0` | +| `orborus.livenessProbe.periodSeconds` | Period seconds for livenessProbe | `15` | +| `orborus.livenessProbe.timeoutSeconds` | Timeout seconds for livenessProbe | `1` | +| `orborus.livenessProbe.failureThreshold` | Failure threshold for livenessProbe | `4` | +| `orborus.livenessProbe.successThreshold` | Success threshold for livenessProbe | `1` | +| `orborus.readinessProbe.enabled` | Enable readinessProbe on orborus containers | `false` | +| `orborus.readinessProbe.initialDelaySeconds` | Initial delay seconds for readinessProbe | `0` | +| `orborus.readinessProbe.periodSeconds` | Period seconds for readinessProbe | `5` | +| `orborus.readinessProbe.timeoutSeconds` | Timeout seconds for readinessProbe | `1` | +| `orborus.readinessProbe.failureThreshold` | Failure threshold for readinessProbe | `3` | +| `orborus.readinessProbe.successThreshold` | Success threshold for readinessProbe | `1` | +| `orborus.startupProbe.enabled` | Enable startupProbe on orborus containers | `false` | +| `orborus.startupProbe.initialDelaySeconds` | Initial delay seconds for startupProbe | `0` | +| `orborus.startupProbe.periodSeconds` | Period seconds for startupProbe | `1` | +| `orborus.startupProbe.timeoutSeconds` | Timeout seconds for startupProbe | `1` | +| `orborus.startupProbe.failureThreshold` | Failure threshold for startupProbe | `60` | +| `orborus.startupProbe.successThreshold` | Success threshold for startupProbe | `1` | +| `orborus.customLivenessProbe` | Custom livenessProbe that overrides the default one | `{}` | +| `orborus.customReadinessProbe` | Custom readinessProbe that overrides the default one | `{}` | +| `orborus.customStartupProbe` | Custom startupProbe that overrides the default one | `{}` | +| `orborus.resourcesPreset` | Set orborus container resources according to one common preset (allowed values: none, nano, small, medium, large, xlarge, 2xlarge). This is ignored if orborus.resources is set (orborus.resources is recommended for production). | `nano` | +| `orborus.resources` | Set orborus container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | +| `orborus.podSecurityContext.enabled` | Enable orborus pods' Security Context | `true` | +| `orborus.podSecurityContext.fsGroupChangePolicy` | Set filesystem group change policy for orborus pods | `Always` | +| `orborus.podSecurityContext.sysctls` | Set kernel settings using the sysctl interface for orborus pods | `[]` | +| `orborus.podSecurityContext.supplementalGroups` | Set filesystem extra groups for orborus pods | `[]` | +| `orborus.podSecurityContext.fsGroup` | Set fsGroup in orborus pods' Security Context | `1001` | +| `orborus.containerSecurityContext.enabled` | Enabled orborus container' Security Context | `true` | +| `orborus.containerSecurityContext.seLinuxOptions` | Set SELinux options in orborus container | `{}` | +| `orborus.containerSecurityContext.runAsUser` | Set runAsUser in orborus container' Security Context | `101` | +| `orborus.containerSecurityContext.runAsGroup` | Set runAsGroup in orborus container' Security Context | `101` | +| `orborus.containerSecurityContext.runAsNonRoot` | Set runAsNonRoot in orborus container' Security Context | `true` | +| `orborus.containerSecurityContext.readOnlyRootFilesystem` | Set readOnlyRootFilesystem in orborus container' Security Context | `true` | +| `orborus.containerSecurityContext.privileged` | Set privileged in orborus container' Security Context | `false` | +| `orborus.containerSecurityContext.allowPrivilegeEscalation` | Set allowPrivilegeEscalation in orborus container' Security Context | `false` | +| `orborus.containerSecurityContext.capabilities.drop` | List of capabilities to be dropped in orborus container | `["ALL"]` | +| `orborus.containerSecurityContext.seccompProfile.type` | Set seccomp profile in orborus container | `RuntimeDefault` | +| `orborus.command` | Override default orborus container command (useful when using custom images) | `[]` | +| `orborus.args` | Override default orborus container args (useful when using custom images) | `[]` | +| `orborus.automountServiceAccountToken` | Mount Service Account token in orborus pods | `true` | +| `orborus.hostAliases` | orborus pods host aliases | `[]` | +| `orborus.daemonsetAnnotations` | Annotations for orborus daemonset | `{}` | +| `orborus.deploymentAnnotations` | Annotations for orborus deployment | `{}` | +| `orborus.statefulsetAnnotations` | Annotations for orborus statefulset | `{}` | +| `orborus.podLabels` | Extra labels for orborus pods | `{}` | +| `orborus.podAnnotations` | Annotations for orborus pods | `{}` | +| `orborus.podAffinityPreset` | Pod affinity preset. Ignored if `orborus.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `orborus.podAntiAffinityPreset` | Pod anti-affinity preset. Ignored if `orborus.affinity` is set. Allowed values: `soft` or `hard` | `soft` | +| `orborus.nodeAffinityPreset.type` | Node affinity preset type. Ignored if `orborus.affinity` is set. Allowed values: `soft` or `hard` | `""` | +| `orborus.nodeAffinityPreset.key` | Node label key to match. Ignored if `orborus.affinity` is set | `""` | +| `orborus.nodeAffinityPreset.values` | Node label values to match. Ignored if `orborus.affinity` is set | `[]` | +| `orborus.affinity` | Affinity for orborus pods assignment | `{}` | +| `orborus.nodeSelector` | Node labels for orborus pods assignment | `{}` | +| `orborus.tolerations` | Tolerations for orborus pods assignment | `[]` | +| `orborus.updateStrategy.type` | orborus deployment strategy type | `RollingUpdate` | +| `orborus.updateStrategy.type` | orborus statefulset strategy type | `RollingUpdate` | +| `orborus.podManagementPolicy` | Pod management policy for orborus statefulset | `OrderedReady` | +| `orborus.priorityClassName` | orborus pods' priorityClassName | `""` | +| `orborus.topologySpreadConstraints` | Topology Spread Constraints for orborus pod assignment spread across your cluster among failure-domains | `[]` | +| `orborus.schedulerName` | Name of the k8s scheduler (other than default) for orborus pods | `""` | +| `orborus.terminationGracePeriodSeconds` | Seconds orborus pods need to terminate gracefully | `""` | +| `orborus.lifecycleHooks` | for orborus containers to automate configuration before or after startup | `{}` | +| `orborus.extraEnvVars` | Array with extra environment variables to add to orborus containers | `[]` | +| `orborus.extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for orborus containers | `""` | +| `orborus.extraEnvVarsSecret` | Name of existing Secret containing extra env vars for orborus containers | `""` | +| `orborus.extraVolumes` | Optionally specify extra list of additional volumes for the orborus pods | `[]` | +| `orborus.extraVolumeMounts` | Optionally specify extra list of additional volumeMounts for the orborus containers | `[]` | +| `orborus.sidecars` | Add additional sidecar containers to the orborus pods | `[]` | +| `orborus.initContainers` | Add additional init containers to the orborus pods | `[]` | +| `orborus.pdb.create` | Enable/disable a Pod Disruption Budget creation | `true` | +| `orborus.pdb.minAvailable` | Minimum number/percentage of pods that should remain scheduled | `""` | +| `orborus.pdb.maxUnavailable` | Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `orborus.pdb.minAvailable` and `orborus.pdb.maxUnavailable` are empty. | `""` | +| `orborus.autoscaling.vpa.enabled` | Enable VPA for orborus pods | `false` | +| `orborus.autoscaling.vpa.annotations` | Annotations for VPA resource | `{}` | +| `orborus.autoscaling.vpa.controlledResources` | VPA List of resources that the vertical pod autoscaler can control. Defaults to cpu and memory | `[]` | +| `orborus.autoscaling.vpa.maxAllowed` | VPA Max allowed resources for the pod | `{}` | +| `orborus.autoscaling.vpa.minAllowed` | VPA Min allowed resources for the pod | `{}` | +| `orborus.autoscaling.vpa.updatePolicy.updateMode` | Autoscaling update policy | `Auto` | +| `orborus.autoscaling.hpa.enabled` | Enable HPA for orborus pods | `false` | +| `orborus.autoscaling.hpa.minReplicas` | Minimum number of replicas | `""` | +| `orborus.autoscaling.hpa.maxReplicas` | Maximum number of replicas | `""` | +| `orborus.autoscaling.hpa.targetCPU` | Target CPU utilization percentage | `""` | +| `orborus.autoscaling.hpa.targetMemory` | Target Memory utilization percentage | `""` | +| `orborus.serviceAccount.create` | Specifies whether a ServiceAccount should be created | `true` | +| `orborus.serviceAccount.name` | The name of the ServiceAccount to use. | `""` | +| `orborus.serviceAccount.annotations` | Additional Service Account annotations (evaluated as a template) | `{}` | +| `orborus.serviceAccount.automountServiceAccountToken` | Automount service account token for the orborus service account | `true` | +| `orborus.serviceAccount.imagePullSecrets` | Add image pull secrets to the orborus service account | `[]` | +| `orborus.rbac.create` | Specifies whether RBAC resources should be created | `true` | +| `orborus.networkPolicy.enabled` | Specifies whether a NetworkPolicy should be created | `true` | +| `orborus.networkPolicy.allowExternal` | Don't require server label for connections | `true` | +| `orborus.networkPolicy.allowExternalEgress` | Allow the pod to access any range of port and all destinations. | `true` | +| `orborus.networkPolicy.extraIngress` | Add extra ingress rules to the NetworkPolicy | `[]` | +| `orborus.networkPolicy.extraEgress` | Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true) | `[]` | + +### worker Parameters + +| Name | Description | Value | +| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | +| `worker.image.registry` | worker image registry | `ghcr.io` | +| `worker.image.repository` | worker image repository | `shuffle/shuffle-worker` | +| `worker.image.digest` | worker image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag image tag (immutable tags are recommended) | `""` | +| `worker.serviceAccount.create` | Specifies whether a ServiceAccount should be created | `true` | +| `worker.serviceAccount.name` | The name of the ServiceAccount to use. | `""` | +| `worker.serviceAccount.annotations` | Additional Service Account annotations (evaluated as a template) | `{}` | +| `worker.serviceAccount.automountServiceAccountToken` | Automount service account token for the worker service account | `true` | +| `worker.serviceAccount.imagePullSecrets` | Add image pull secrets to the worker service account | `[]` | +| `worker.rbac.create` | Specifies whether RBAC resources should be created | `true` | +| `worker.networkPolicy.enabled` | Specifies whether a NetworkPolicy should be created | `true` | +| `worker.networkPolicy.allowExternal` | Don't require server label for connections | `true` | +| `worker.networkPolicy.allowExternalEgress` | Allow the pod to access any range of port and all destinations. | `true` | +| `worker.networkPolicy.extraIngress` | Add extra ingress rules to the NetworkPolicy | `[]` | +| `worker.networkPolicy.extraEgress` | Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true) | `[]` | + +### app Parameters + +| Name | Description | Value | +| ------------------------------------------------- | ---------------------------------------------------------------------------------- | ------ | +| `app.serviceAccount.create` | Specifies whether a ServiceAccount should be created | `true` | +| `app.serviceAccount.name` | The name of the ServiceAccount to use. | `""` | +| `app.serviceAccount.annotations` | Additional Service Account annotations (evaluated as a template) | `{}` | +| `app.serviceAccount.automountServiceAccountToken` | Automount service account token for the app service account | `true` | +| `app.serviceAccount.imagePullSecrets` | Add image pull secrets to the app service account | `[]` | +| `app.rbac.create` | Specifies whether RBAC resources should be created | `true` | +| `app.networkPolicy.enabled` | Specifies whether a NetworkPolicy should be created | `true` | +| `app.networkPolicy.allowExternal` | Don't require server label for connections | `true` | +| `app.networkPolicy.allowExternalEgress` | Allow the pod to access any range of port and all destinations. | `true` | +| `app.networkPolicy.extraIngress` | Add extra ingress rules to the NetworkPolicy | `[]` | +| `app.networkPolicy.extraEgress` | Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true) | `[]` | + +### Traffic Exposure Parameters + +| Name | Description | Value | +| -------------------------- | ----------------------------------------------------------------------------------------------------- | --------------- | +| `ingress.enabled` | Enable ingress record generation for frontend and backend | `false` | +| `ingress.pathType` | Ingress path type for the frontend path | `Prefix` | +| `ingress.backendPathType` | Ingress path type for the backend path | `Prefix` | +| `ingress.apiVersion` | Force Ingress API version (automatically detected if not set) | `""` | +| `ingress.hostname` | Default host for the ingress record | `shuffle.local` | +| `ingress.ingressClassName` | IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+) | `nginx` | +| `ingress.path` | Ingress path for Shuffle frontend | `"/"` | +| `ingress.backendPath` | Ingress path for Shuffle backend | `"/api/"` | +| `ingress.annotations` | Additional annotations for the Ingress resource. | `{}` | +| `ingress.tls` | Enable TLS configuration for the host defined at `ingress.hostname` parameter | `false` | +| `ingress.selfSigned` | Create a TLS secret for this ingress record using self-signed certificates generated by Helm | `false` | +| `ingress.extraHosts` | An array with additional hostname(s) to be covered with the ingress record | `[]` | +| `ingress.extraPaths` | An array with additional arbitrary paths that may need to be added to the ingress under the main host | `[]` | +| `ingress.extraTls` | TLS configuration for additional hostname(s) to be covered with this ingress record | `[]` | +| `ingress.secrets` | Custom TLS certificates as secrets | `[]` | +| `ingress.extraRules` | Additional rules to be covered with this ingress record | `[]` | + +### Istio Parameters + +| Name | Description | Value | +| --------------------------------------- | ------------------------------------------------------------------------------- | ------------------------ | +| `istio.enabled` | Enable creation of an Istio Gateway and VirtualService for frontend and backend | `false` | +| `istio.apiVersion` | The istio apiVersion to use for Gateway and VirtualService resources | `networking.istio.io/v1` | +| `istio.hosts` | One or more hosts exposed by Istio | `[]` | +| `istio.gateway.annotations` | Additional annotations for the Gateway resource | `{}` | +| `istio.gateway.selector` | The selector matches the ingress gateway pod labels | `{ istio: ingress }` | +| `istio.gateway.http.enabled` | Enable HTTP server port 80 | `true` | +| `istio.gateway.http.httpsRedirect` | If set to true, a 301 redirect is send for all HTTP connections | `false` | +| `istio.gateway.https.enabled` | Enable HTTPS server on port 443 | `false` | +| `istio.gateway.https.tlsCredentialName` | The name of the secret that holds the TLS certs including the CA certificates. | `""` | +| `istio.gateway.https.tlsCipherSuites` | If specified, only support the specified cipher list. | `[]` | +| `istio.gateway.extraServers` | Additional servers for the Gateway resource | `[]` | +| `istio.virtualService.annotations` | Additional annotations for the VirtualService resource. | `{}` | +| `istio.virtualService.backendHeaders` | Header manipulation rules for backend traffic | `{}` | +| `istio.virtualService.frontendHeaders` | Header manipulation rules for frontend traffic | `{}` | + +### Persistence Parameters + +| Name | Description | Value | +| ------------------------------------- | ------------------------------------------------- | ------------------- | +| `persistence.enabled` | Enable persistence using Persistent Volume Claims | `true` | +| `persistence.apps.existingClaim` | Name of an existing PVC to use | `""` | +| `persistence.apps.storageClass` | PVC Storage Class for shuffle-apps volume | `""` | +| `persistence.apps.subPath` | The sub path used in the volume | `""` | +| `persistence.apps.accessModes` | The access mode of the volume | `["ReadWriteOnce"]` | +| `persistence.apps.size` | The size of the volume | `5Gi` | +| `persistence.apps.annotations` | Annotations for the PVC | `{}` | +| `persistence.apps.selector` | Selector to match an existing Persistent Volume | `{}` | +| `persistence.appBuilder.storageClass` | PVC Storage Class for backend-apps-claim volume | `""` | +| `persistence.appBuilder.accessModes` | The access mode of the volume | `["ReadWriteOnce"]` | +| `persistence.appBuilder.size` | The size of the volume | `5Gi` | +| `persistence.appBuilder.annotations` | Annotations for the PVC | `{}` | +| `persistence.appBuilder.selector` | Selector to match an existing Persistent Volume | `{}` | +| `persistence.files.existingClaim` | Name of an existing PVC to use | `""` | +| `persistence.files.storageClass` | PVC Storage Class for shuffle-files volume | `""` | +| `persistence.files.subPath` | The sub path used in the volume | `""` | +| `persistence.files.accessModes` | The access mode of the volume | `["ReadWriteOnce"]` | +| `persistence.files.size` | The size of the volume | `5Gi` | +| `persistence.files.annotations` | Annotations for the PVC | `{}` | +| `persistence.files.selector` | Selector to match an existing Persistent Volume | `{}` | + +### Init Container Parameters + +| Name | Description | Value | +| ----------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | +| `volumePermissions.enabled` | Enable init container that changes the owner/group of the PV mount point to `runAsUser:fsGroup` | `false` | +| `volumePermissions.image.registry` | OS Shell + Utility image registry | `docker.io` | +| `volumePermissions.image.repository` | OS Shell + Utility image repository | `bitnami/os-shell` | +| `volumePermissions.image.pullPolicy` | OS Shell + Utility image pull policy | `IfNotPresent` | +| `volumePermissions.image.pullSecrets` | OS Shell + Utility image pull secrets | `[]` | +| `volumePermissions.resourcesPreset` | Set init container resources according to one common preset (allowed values: none, nano, small, medium, large, xlarge, 2xlarge). This is ignored if volumePermissions.resources is set (volumePermissions.resources is recommended for production). | `nano` | +| `volumePermissions.resources` | Set init container requests and limits for different resources like CPU or memory (essential for production workloads) | `{}` | +| `volumePermissions.containerSecurityContext.enabled` | Enabled init container' Security Context | `true` | +| `volumePermissions.containerSecurityContext.seLinuxOptions` | Set SELinux options in init container | `{}` | +| `volumePermissions.containerSecurityContext.runAsUser` | Set init container's Security Context runAsUser | `0` | + +### OpenSearch Parameters + +| Name | Description | Value | +| -------------------- | ----------------------------------------------------- | ------ | +| `opensearch.enabled` | Switch to enable or disable the opensearch helm chart | `true` | + +### Vault Parameters + +| Name | Description | Value | +| --------------- | -------------------------------------------------------------------------- | ----- | +| `vault.role` | Specify the Vault role, which should be used to get the secret from Vault. | `""` | +| `vault.secrets` | A list of VaultSecrets to create | `[]` | + +### Other Parameters + diff --git a/functions/kubernetes/charts/shuffle/templates/NOTES.txt b/functions/kubernetes/charts/shuffle/templates/NOTES.txt new file mode 100644 index 00000000..10e38886 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/NOTES.txt @@ -0,0 +1,27 @@ +CHART NAME: {{ .Chart.Name }} +CHART VERSION: {{ .Chart.Version }} +APP VERSION: {{ .Chart.AppVersion }} + +** Please be patient while the chart is being deployed ** + +{{- if .Values.diagnosticMode.enabled }} +The chart has been deployed in diagnostic mode. All probes have been disabled and the command has been overwritten with: + + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 4 }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 4 }} + +Get the list of pods by executing: + + kubectl get pods --namespace {{ include "common.names.namespace" . | quote }} -l app.kubernetes.io/instance={{ .Release.Name }} + +Access the pod you want to debug by executing + + kubectl exec --namespace {{ include "common.names.namespace" . | quote }} -ti -- bash + +{{- end }} + +To access shuffle using port-forwarding: + +1. Run `kubectl port-forward -n shuffle svc/shuffle-frontend 8080:http` +2. Visit http://localhost:8080 with your browser + diff --git a/functions/kubernetes/charts/shuffle/templates/_helpers.tpl b/functions/kubernetes/charts/shuffle/templates/_helpers.tpl new file mode 100644 index 00000000..6bd29238 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/_helpers.tpl @@ -0,0 +1,377 @@ +{{/* +Return the common name for backend componentes +*/}} +{{- define "shuffle.backend.name" -}} + {{- printf "%s-backend" (include "common.names.fullname" .) | trunc 63 -}} +{{- end -}} + +{{/* +Return the common name for frontend components +*/}} +{{- define "shuffle.frontend.name" -}} + {{- printf "%s-frontend" (include "common.names.fullname" .) | trunc 63 -}} +{{- end -}} + +{{/* +Return the common name for orborus components +*/}} +{{- define "shuffle.orborus.name" -}} + {{- printf "%s-orborus" (include "common.names.fullname" .) | trunc 63 -}} +{{- end -}} + +{{/* +Return the common name for worker components +*/}} +{{- define "shuffle.worker.name" -}} + {{- printf "%s-worker" (include "common.names.fullname" .) | trunc 63 -}} +{{- end -}} + +{{/* +Return the common name for app components +*/}} +{{- define "shuffle.app.name" -}} + {{- printf "%s-app" (include "common.names.fullname" .) | trunc 63 -}} +{{- end -}} + +{{/* +Return the common labels for backend components +The shuffle app builder requires the io.kompose.service=backend label to be set on the backend pod. +*/}} +{{- define "shuffle.backend.labels" -}} +{{- include "common.labels.standard" . }} +app.kubernetes.io/component: backend +io.kompose.service: backend +{{- end -}} + +{{/* +Return the common labels for frontend components +*/}} +{{- define "shuffle.frontend.labels" -}} +{{- include "common.labels.standard" . }} +app.kubernetes.io/component: frontend +{{- end -}} + +{{/* +Return the common labels for orborus components +*/}} +{{- define "shuffle.orborus.labels" -}} +{{- include "common.labels.standard" . }} +app.kubernetes.io/component: orborus +{{- end -}} + +{{/* +Return the common labels for worker components +*/}} +{{- define "shuffle.worker.labels" -}} +{{- include "common.labels.standard" . }} +app.kubernetes.io/component: worker +{{- end -}} + +{{/* +Return the common labels for app components +*/}} +{{- define "shuffle.app.labels" -}} +{{- include "common.labels.standard" . }} +app.kubernetes.io/component: app +{{- end -}} + +{{/* +Return the match labels for backend components +*/}} +{{- define "shuffle.backend.matchLabels" -}} +{{- include "common.labels.matchLabels" . }} +app.kubernetes.io/component: backend +{{- end -}} + +{{/* +Return the match labels for frontend components +*/}} +{{- define "shuffle.frontend.matchLabels" -}} +{{- include "common.labels.matchLabels" . }} +app.kubernetes.io/component: frontend +{{- end -}} + +{{/* +Return the match labels for orborus components +*/}} +{{- define "shuffle.orborus.matchLabels" -}} +{{- include "common.labels.matchLabels" . }} +app.kubernetes.io/component: orborus +{{- end -}} + +{{/* +Return the match labels for worker components +NOTE: This does not match the labels from shuffle.worker.labels, but the labels set by the orborus GoLang app. +*/}} +{{- define "shuffle.worker.matchLabels" -}} +app.kubernetes.io/name: shuffle-worker +{{- end -}} + +{{/* +Return the match labels for app components +NOTE: This does not match the labels from shuffle.worker.labels, but the labels set by the orborus GoLang app. +*/}} +{{- define "shuffle.app.matchLabels" -}} +app.kubernetes.io/name: shuffle-app +{{- end -}} + +{{/* +Return the proper image name (for the init container volume-permissions image) +*/}} +{{- define "shuffle.volumePermissions.image" -}} +{{- include "common.images.image" ( dict "imageRoot" .Values.volumePermissions.image "global" .Values.global ) -}} +{{- end -}} + +{{/* +Return the proper Shuffle backend image name +*/}} +{{- define "shuffle.backend.image" -}} +{{- include "common.images.image" ( dict "imageRoot" .Values.backend.image "global" .Values.global ) -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names for the backend pod +*/}} +{{- define "shuffle.backend.imagePullSecrets" -}} +{{- include "common.images.renderPullSecrets" (dict "images" (list .Values.backend.image) "context" $) -}} +{{- end -}} + +{{/* +Return the proper Shuffle frontend image name +*/}} +{{- define "shuffle.frontend.image" -}} +{{- include "common.images.image" ( dict "imageRoot" .Values.frontend.image "global" .Values.global ) -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names for the frontend pod +*/}} +{{- define "shuffle.frontend.imagePullSecrets" -}} +{{- include "common.images.renderPullSecrets" (dict "images" (list .Values.frontend.image) "context" $) -}} +{{- end -}} + +{{/* +Return the proper Shuffle orborus image name +*/}} +{{- define "shuffle.orborus.image" -}} +{{- include "common.images.image" ( dict "imageRoot" .Values.orborus.image "global" .Values.global ) -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names for the orborus pod +*/}} +{{- define "shuffle.orborus.imagePullSecrets" -}} +{{- include "common.images.renderPullSecrets" (dict "images" (list .Values.orborus.image) "context" $) -}} +{{- end -}} + +{{/* +Return the proper Shuffle worker image name +*/}} +{{- define "shuffle.worker.image" -}} +{{- include "common.images.image" ( dict "imageRoot" .Values.worker.image "global" .Values.global ) -}} +{{- end -}} + +{{/* +Create the name of the service account to use for the Shuffle backend +*/}} +{{- define "shuffle.backend.serviceAccount.name" -}} +{{- if .Values.backend.serviceAccount.create -}} + {{ default (include "shuffle.backend.name" .) .Values.backend.serviceAccount.name | trunc 63 | trimSuffix "-" }} +{{- else -}} + {{ default "default" .Values.backend.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names for the backend service account +*/}} +{{- define "shuffle.backend.serviceAccount.imagePullSecrets" -}} +{{- $pullSecrets := list }} + +{{- range .Values.global.imagePullSecrets -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" .)) -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" .)) -}} + {{- end -}} +{{- end -}} + +{{- range .Values.backend.serviceAccount.imagePullSecrets -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" .)) -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" .)) -}} + {{- end -}} +{{- end -}} + +{{- if (not (empty $pullSecrets)) -}} +imagePullSecrets: +{{- range $pullSecrets | uniq }} + - name: {{ . }} +{{- end }} +{{- end }} +{{- end -}} + +{{/* +Create the name of the service account to use for the Shuffle frontend +*/}} +{{- define "shuffle.frontend.serviceAccount.name" -}} +{{- if .Values.frontend.serviceAccount.create -}} + {{ default (include "shuffle.frontend.name" .) .Values.frontend.serviceAccount.name | trunc 63 | trimSuffix "-" }} +{{- else -}} + {{ default "default" .Values.frontend.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names for the frontend service account +*/}} +{{- define "shuffle.frontend.serviceAccount.imagePullSecrets" -}} +{{- $pullSecrets := list }} + +{{- range .Values.global.imagePullSecrets -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" .)) -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" .)) -}} + {{- end -}} +{{- end -}} + +{{- range .Values.frontend.serviceAccount.imagePullSecrets -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" .)) -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" .)) -}} + {{- end -}} +{{- end -}} + +{{- if (not (empty $pullSecrets)) -}} +imagePullSecrets: +{{- range $pullSecrets | uniq }} + - name: {{ . }} +{{- end }} +{{- end }} +{{- end -}} + +{{/* +Create the name of the service account to use for Shuffle orborus +*/}} +{{- define "shuffle.orborus.serviceAccount.name" -}} +{{- if .Values.orborus.serviceAccount.create -}} + {{ default (include "shuffle.orborus.name" .) .Values.orborus.serviceAccount.name | trunc 63 | trimSuffix "-" }} +{{- else -}} + {{ default "default" .Values.orborus.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names for the orborus service account +*/}} +{{- define "shuffle.orborus.serviceAccount.imagePullSecrets" -}} +{{- $pullSecrets := list }} + +{{- range .Values.global.imagePullSecrets -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" .)) -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" .)) -}} + {{- end -}} +{{- end -}} + +{{- range .Values.orborus.serviceAccount.imagePullSecrets -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" .)) -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" .)) -}} + {{- end -}} +{{- end -}} + +{{- if (not (empty $pullSecrets)) -}} +imagePullSecrets: +{{- range $pullSecrets | uniq }} + - name: {{ . }} +{{- end }} +{{- end }} +{{- end -}} + +{{/* +Create the name of the service account to use for Shuffle workers +*/}} +{{- define "shuffle.worker.serviceAccount.name" -}} +{{- if .Values.worker.serviceAccount.create -}} + {{ default (include "shuffle.worker.name" .) .Values.worker.serviceAccount.name | trunc 63 | trimSuffix "-" }} +{{- else -}} + {{ default "default" .Values.worker.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names for the worker service account +*/}} +{{- define "shuffle.worker.serviceAccount.imagePullSecrets" -}} +{{- $pullSecrets := list }} + +{{- range .Values.global.imagePullSecrets -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" .)) -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" .)) -}} + {{- end -}} +{{- end -}} + +{{- range .Values.worker.serviceAccount.imagePullSecrets -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" .)) -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" .)) -}} + {{- end -}} +{{- end -}} + +{{- if (not (empty $pullSecrets)) -}} +imagePullSecrets: +{{- range $pullSecrets | uniq }} + - name: {{ . }} +{{- end }} +{{- end }} +{{- end -}} + +{{/* +Create the name of the service account to use for Shuffle apps +*/}} +{{- define "shuffle.app.serviceAccount.name" -}} +{{- if .Values.app.serviceAccount.create -}} + {{ default (include "shuffle.app.name" .) .Values.app.serviceAccount.name | trunc 63 | trimSuffix "-" }} +{{- else -}} + {{ default "default" .Values.app.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names for the app service account +*/}} +{{- define "shuffle.app.serviceAccount.imagePullSecrets" -}} +{{- $pullSecrets := list }} + +{{- range .Values.global.imagePullSecrets -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" .)) -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" .)) -}} + {{- end -}} +{{- end -}} + +{{- range .Values.app.serviceAccount.imagePullSecrets -}} + {{- if kindIs "map" . -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" .name "context" .)) -}} + {{- else -}} + {{- $pullSecrets = append $pullSecrets (include "common.tplvalues.render" (dict "value" . "context" .)) -}} + {{- end -}} +{{- end -}} + +{{- if (not (empty $pullSecrets)) -}} +imagePullSecrets: +{{- range $pullSecrets | uniq }} + - name: {{ . }} +{{- end }} +{{- end }} +{{- end -}} diff --git a/functions/kubernetes/charts/shuffle/templates/backend/backend-apps-claim-pvc.yaml b/functions/kubernetes/charts/shuffle/templates/backend/backend-apps-claim-pvc.yaml new file mode 100644 index 00000000..e0e8ef7d --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/backend/backend-apps-claim-pvc.yaml @@ -0,0 +1,28 @@ +# This PVC is always enabled, regardless of .Values.persistence.enabled, +# as app building does not work without it. +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: backend-apps-claim # Hardcoded by shuffle-app-builder + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.backend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + annotations: + {{- if eq .Values.persistence.resourcePolicy "keep" }} + helm.sh/resource-policy: keep + {{- end }} + {{- if or .Values.persistence.appBuilder.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.persistence.appBuilder.annotations .Values.commonAnnotations ) "context" . ) }} + {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} + {{- end }} +spec: + accessModes: + {{- range .Values.persistence.appBuilder.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.appBuilder.size }} + {{- if .Values.persistence.appBuilder.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.appBuilder.selector "context" $) | nindent 2 }} + {{- end }} + {{- include "common.storage.class" ( dict "persistence" .Values.persistence.appBuilder "global" .Values.global ) | nindent 2 }} diff --git a/functions/kubernetes/charts/shuffle/templates/backend/backend-apps-pvc.yaml b/functions/kubernetes/charts/shuffle/templates/backend/backend-apps-pvc.yaml new file mode 100644 index 00000000..b26dfdf3 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/backend/backend-apps-pvc.yaml @@ -0,0 +1,30 @@ +{{- if .Values.persistence.enabled }} +{{- if (not .Values.persistence.apps.existingClaim) }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ printf "%s-apps" (include "shuffle.backend.name" .) }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.backend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + annotations: + {{- if eq .Values.persistence.resourcePolicy "keep" }} + helm.sh/resource-policy: keep + {{- end }} + {{- if or .Values.persistence.apps.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.persistence.apps.annotations .Values.commonAnnotations ) "context" . ) }} + {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} + {{- end }} +spec: + accessModes: + {{- range .Values.persistence.apps.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.apps.size }} + {{- if .Values.persistence.apps.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.apps.selector "context" $) | nindent 2 }} + {{- end }} + {{- include "common.storage.class" ( dict "persistence" .Values.persistence.apps "global" .Values.global ) | nindent 2 }} +{{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/backend/backend-cm-env.yaml b/functions/kubernetes/charts/shuffle/templates/backend/backend-cm-env.yaml new file mode 100644 index 00000000..e7138dc0 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/backend/backend-cm-env.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "shuffle.backend.name" . }}-env + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.backend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: + BACKEND_PORT: "5001" + {{- if .Values.shuffle.baseUrl }} + BASE_URL: "{{ .Values.shuffle.baseUrl }}" + SSO_REDIRECT_URL: "{{ .Values.shuffle.baseUrl }}" + {{- else }} + BASE_URL: "http://{{ include "shuffle.backend.name" . }}:5001" + {{- end }} + ORG_ID: "{{ .Values.shuffle.org }}" + SHUFFLE_APP_DOWNLOAD_LOCATION: "{{ .Values.backend.apps.downloadLocation }}" + SHUFFLE_DOWNLOAD_AUTH_BRANCH: "{{ .Values.backend.apps.downloadBranch }}" + SHUFFLE_APP_FORCE_UPDATE: "{{ .Values.backend.apps.forceUpdate }}" + SHUFFLE_CHAT_DISABLED: "true" + SHUFFLE_OPENSEARCH_URL: {{ include "common.tplvalues.render" (dict "value" .Values.backend.openSearch.url "context" $) }} + SHUFFLE_OPENSEARCH_USERNAME: "{{ .Values.backend.openSearch.username }}" + SHUFFLE_OPENSEARCH_CERTIFICATE_FILE: "{{ .Values.backend.openSearch.certificateFile }}" + SHUFFLE_OPENSEARCH_SKIPSSL_VERIFY: "{{ .Values.backend.openSearch.skipSSLVerify }}" + SHUFFLE_OPENSEARCH_INDEX_PREFIX: "{{ .Values.backend.openSearch.indexPrefix }}" + SHUFFLE_RERUN_SCHEDULE: "{{ .Values.backend.cleanupSchedule }}" + TZ: "{{ .Values.shuffle.timezone }}" + REGISTRY_URL: "{{ .Values.shuffle.appRegistry }}" diff --git a/functions/kubernetes/charts/shuffle/templates/backend/backend-dpl.yaml b/functions/kubernetes/charts/shuffle/templates/backend/backend-dpl.yaml new file mode 100644 index 00000000..b1cc606c --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/backend/backend-dpl.yaml @@ -0,0 +1,224 @@ +apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} +kind: Deployment +metadata: + name: {{ template "shuffle.backend.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.backend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.backend.deploymentAnnotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" (dict "values" (list .Values.backend.deploymentAnnotations .Values.commonAnnotations) "context" .) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- if not .Values.backend.autoscaling.hpa.enabled }} + replicas: {{ .Values.backend.replicaCount }} + {{- end }} + {{- if .Values.backend.updateStrategy }} + strategy: {{- toYaml .Values.backend.updateStrategy | nindent 4 }} + {{- end }} + {{- $podLabels := include "common.tplvalues.merge" (dict "values" (list .Values.backend.podLabels .Values.commonLabels) "context" .) }} + selector: + matchLabels: {{- include "shuffle.backend.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} + template: + metadata: + {{- if .Values.backend.podAnnotations }} + annotations: {{- include "common.tplvalues.render" (dict "value" .Values.backend.podAnnotations "context" $) | nindent 8 }} + {{- end }} + labels: {{- include "shuffle.backend.labels" ( dict "customLabels" $podLabels "context" $ ) | nindent 8 }} + spec: + {{- include "shuffle.backend.imagePullSecrets" . | nindent 6 }} + serviceAccountName: {{ template "shuffle.backend.serviceAccount.name" . }} + automountServiceAccountToken: {{ .Values.backend.automountServiceAccountToken }} + {{- if .Values.backend.hostAliases }} + hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.backend.hostAliases "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.backend.affinity }} + affinity: {{- include "common.tplvalues.render" ( dict "value" .Values.backend.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.backend.podAffinityPreset "component" "backend" "customLabels" $podLabels "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.backend.podAntiAffinityPreset "component" "backend" "customLabels" $podLabels "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.backend.nodeAffinityPreset.type "key" .Values.backend.nodeAffinityPreset.key "values" .Values.backend.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.backend.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" ( dict "value" .Values.backend.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.backend.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.backend.tolerations "context" .) | nindent 8 }} + {{- end }} + {{- if .Values.backend.priorityClassName }} + priorityClassName: {{ .Values.backend.priorityClassName | quote }} + {{- end }} + {{- if .Values.backend.schedulerName }} + schedulerName: {{ .Values.backend.schedulerName | quote }} + {{- end }} + {{- if .Values.backend.topologySpreadConstraints }} + topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.backend.topologySpreadConstraints "context" .) | nindent 8 }} + {{- end }} + {{- if .Values.backend.podSecurityContext.enabled }} + securityContext: {{- omit .Values.backend.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.backend.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.backend.terminationGracePeriodSeconds }} + {{- end }} + initContainers: + {{- if and .Values.volumePermissions.enabled .Values.persistence.enabled }} + - name: volume-permissions + image: {{ include "shuffle.volumePermissions.image" . }} + imagePullPolicy: {{ .Values.volumePermissions.image.pullPolicy | quote }} + command: + - /bin/bash + - -ec + - | + chown -vR {{ .Values.backend.containerSecurityContext.runAsUser }}:{{ .Values.backend.podSecurityContext.fsGroup }} /app/generated && \ + chown -vR {{ .Values.backend.containerSecurityContext.runAsUser }}:{{ .Values.backend.podSecurityContext.fsGroup }} /shuffle-apps && \ + chown -vR {{ .Values.backend.containerSecurityContext.runAsUser }}:{{ .Values.backend.podSecurityContext.fsGroup }} /shuffle-files + {{- if .Values.volumePermissions.containerSecurityContext.enabled }} + securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.volumePermissions.containerSecurityContext "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.volumePermissions.resources }} + resources: {{- toYaml .Values.volumePermissions.resources | nindent 12 }} + {{- else if ne .Values.volumePermissions.resourcesPreset "none" }} + resources: {{- include "common.resources.preset" (dict "type" .Values.volumePermissions.resourcesPreset) | nindent 12 }} + {{- end }} + volumeMounts: + - name: shuffle-app-builder + mountPath: /app/generated + - name: shuffle-apps + mountPath: /shuffle-apps + {{- if .Values.persistence.apps.subPath }} + subPath: {{ .Values.persistence.apps.subPath }} + {{- end }} + - name: shuffle-files + mountPath: /shuffle-files + {{- if .Values.persistence.files.subPath }} + subPath: {{ .Values.persistence.apps.subPath }} + {{- end }} + {{- end }} + {{- if .Values.backend.initContainers }} + {{- include "common.tplvalues.render" (dict "value" .Values.backend.initContainers "context" $) | nindent 8 }} + {{- end }} + containers: + - name: backend + image: {{ template "shuffle.backend.image" . }} + imagePullPolicy: {{ .Values.backend.image.pullPolicy }} + {{- if .Values.backend.containerSecurityContext.enabled }} + securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.backend.containerSecurityContext "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} + {{- else if .Values.backend.command }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.backend.command "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} + {{- else if .Values.backend.args }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.backend.args "context" $) | nindent 12 }} + {{- end }} + env: + - name: RUNNING_MODE + value: kubernetes + - name: IS_KUBERNETES + value: "true" + - name: SHUFFLE_APP_HOTLOAD_FOLDER + value: /shuffle-apps + - name: SHUFFLE_FILE_LOCATION + value: /shuffle-files + {{- if .Values.backend.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.backend.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + envFrom: + - configMapRef: + name: {{ include "shuffle.backend.name" . }}-env + {{- if .Values.backend.extraEnvVarsCM }} + - configMapRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.backend.extraEnvVarsCM "context" $) }} + {{- end }} + {{- if .Values.backend.extraEnvVarsSecret }} + - secretRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.backend.extraEnvVarsSecret "context" $) }} + {{- end }} + {{- if .Values.backend.resources }} + resources: {{- toYaml .Values.backend.resources | nindent 12 }} + {{- else if ne .Values.backend.resourcesPreset "none" }} + resources: {{- include "common.resources.preset" (dict "type" .Values.backend.resourcesPreset) | nindent 12 }} + {{- end }} + ports: + - name: http + containerPort: {{ .Values.backend.containerPorts.http }} + {{- if .Values.backend.extraContainerPorts }} + {{- include "common.tplvalues.render" (dict "value" .Values.backend.extraContainerPorts "context" $) | nindent 12 }} + {{- end }} + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.backend.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.backend.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.backend.livenessProbe.enabled }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.backend.livenessProbe "enabled") "context" $) | nindent 12 }} + httpGet: + path: /api/v1/health + port: {{ .Values.backend.containerPorts.http }} + {{- end }} + {{- if .Values.backend.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.backend.customReadinessProbe "context" $) | nindent 12 }} + {{- else if .Values.backend.readinessProbe.enabled }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.backend.readinessProbe "enabled") "context" $) | nindent 12 }} + httpGet: + path: /api/v1/health + port: {{ .Values.backend.containerPorts.http }} + {{- end }} + {{- if .Values.backend.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.backend.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.backend.startupProbe.enabled }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.backend.startupProbe "enabled") "context" $) | nindent 12 }} + httpGet: + path: /api/v1/health + port: {{ .Values.backend.containerPorts.http }} + {{- end }} + {{- end }} + {{- if .Values.backend.lifecycleHooks }} + lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.backend.lifecycleHooks "context" $) | nindent 12 }} + {{- end }} + volumeMounts: + - name: shuffle-app-builder + mountPath: /app/generated + - name: shuffle-apps + mountPath: /shuffle-apps + {{- if .Values.persistence.apps.subPath }} + subPath: {{ .Values.persistence.apps.subPath }} + {{- end }} + - name: shuffle-files + mountPath: /shuffle-files + {{- if .Values.persistence.files.subPath }} + subPath: {{ .Values.persistence.apps.subPath }} + {{- end }} + - name: empty-dir + mountPath: /tmp + subPath: tmp-dir + {{- if .Values.backend.extraVolumeMounts }} + {{- include "common.tplvalues.render" (dict "value" .Values.backend.extraVolumeMounts "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.backend.sidecars }} + {{- include "common.tplvalues.render" ( dict "value" .Values.backend.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + - name: empty-dir + emptyDir: {} + - name: shuffle-app-builder + persistentVolumeClaim: + claimName: backend-apps-claim + - name: shuffle-apps + {{- if .Values.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ default (printf "%s-apps" (include "shuffle.backend.name" .)) .Values.persistence.apps.existingClaim }} + {{- else }} + emptyDir: {} + {{- end }} + - name: shuffle-files + {{- if .Values.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ default (printf "%s-files" (include "shuffle.backend.name" .)) .Values.persistence.apps.existingClaim }} + {{- else }} + emptyDir: {} + {{- end }} + {{- if .Values.backend.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.backend.extraVolumes "context" $) | nindent 8 }} + {{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/backend/backend-files-pvc.yaml b/functions/kubernetes/charts/shuffle/templates/backend/backend-files-pvc.yaml new file mode 100644 index 00000000..86faac82 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/backend/backend-files-pvc.yaml @@ -0,0 +1,30 @@ +{{- if .Values.persistence.enabled }} +{{- if (not .Values.persistence.files.existingClaim) }} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ printf "%s-files" (include "shuffle.backend.name" .) }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.backend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + annotations: + {{- if eq .Values.persistence.resourcePolicy "keep" }} + helm.sh/resource-policy: keep + {{- end }} + {{- if or .Values.persistence.files.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.persistence.files.annotations .Values.commonAnnotations ) "context" . ) }} + {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} + {{- end }} +spec: + accessModes: + {{- range .Values.persistence.files.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.files.size }} + {{- if .Values.persistence.files.selector }} + selector: {{- include "common.tplvalues.render" (dict "value" .Values.persistence.files.selector "context" $) | nindent 2 }} + {{- end }} + {{- include "common.storage.class" ( dict "persistence" .Values.persistence.files "global" .Values.global ) | nindent 2 }} +{{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/backend/backend-hpa.yaml b/functions/kubernetes/charts/shuffle/templates/backend/backend-hpa.yaml new file mode 100644 index 00000000..bd099242 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/backend/backend-hpa.yaml @@ -0,0 +1,43 @@ +{{- if .Values.backend.autoscaling.hpa.enabled }} +apiVersion: {{ include "common.capabilities.hpa.apiVersion" . }} +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "shuffle.backend.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.backend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + scaleTargetRef: + apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} + kind: Deployment + name: {{ include "shuffle.backend.name" . }} + minReplicas: {{ .Values.backend.autoscaling.hpa.minReplicas }} + maxReplicas: {{ .Values.backend.autoscaling.hpa.maxReplicas }} + metrics: + {{- if .Values.backend.autoscaling.hpa.targetMemory }} + - type: Resource + resource: + name: memory + {{- if semverCompare "<1.23-0" (include "common.capabilities.kubeVersion" .) }} + targetAverageUtilization: {{ .Values.backend.autoscaling.hpa.targetMemory }} + {{- else }} + target: + type: Utilization + averageUtilization: {{ .Values.worker.autoscaling.hpa.targetMemory }} + {{- end }} + {{- end }} + {{- if .Values.backend.autoscaling.hpa.targetCPU }} + - type: Resource + resource: + name: cpu + {{- if semverCompare "<1.23-0" (include "common.capabilities.kubeVersion" .) }} + targetAverageUtilization: {{ .Values.backend.autoscaling.hpa.targetCPU }} + {{- else }} + target: + type: Utilization + averageUtilization: {{ .Values.worker.autoscaling.hpa.targetCPU }} + {{- end }} + {{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/backend/backend-network-policy.yaml b/functions/kubernetes/charts/shuffle/templates/backend/backend-network-policy.yaml new file mode 100644 index 00000000..48010706 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/backend/backend-network-policy.yaml @@ -0,0 +1,66 @@ +{{- if .Values.backend.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} +metadata: + name: {{ template "shuffle.backend.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.backend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.backend.podLabels .Values.commonLabels ) "context" . ) }} + podSelector: + matchLabels: {{- include "shuffle.backend.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} + policyTypes: + - Ingress + - Egress + egress: + {{- if .Values.backend.networkPolicy.allowExternalEgress }} + - {} + {{- else }} + # Allow DNS resolution with an in-cluster DNS server + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: kube-system + {{- if .Values.backend.networkPolicy.extraEgress }} + {{- include "common.tplvalues.render" ( dict "value" .Values.backend.networkPolicy.extraEgress "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} + ingress: + - ports: + - port: {{ .Values.backend.containerPorts.http }} + protocol: TCP + {{- if not .Values.backend.networkPolicy.allowExternal }} + from: + # Allow traffic from orborus + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ .Release.Namespace }} + podSelector: + matchLabels: {{ include "shuffle.orborus.matchLabels" . | nindent 14 }} + + # Allow traffic from workers + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ .Release.Namespace }} + podSelector: + matchLabels: {{ include "shuffle.worker.matchLabels" . | nindent 14 }} + + # Allow traffic from apps + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ .Release.Namespace }} + podSelector: + matchLabels: {{ include "shuffle.app.matchLabels" . | nindent 14 }} + {{- end }} + {{- if .Values.backend.networkPolicy.extraIngress }} + {{- include "common.tplvalues.render" ( dict "value" .Values.backend.networkPolicy.extraIngress "context" $ ) | nindent 4 }} + {{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/backend/backend-pdb.yaml b/functions/kubernetes/charts/shuffle/templates/backend/backend-pdb.yaml new file mode 100644 index 00000000..5b253ca6 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/backend/backend-pdb.yaml @@ -0,0 +1,21 @@ +{{- if .Values.backend.pdb.create }} +apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ include "shuffle.backend.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.backend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- if .Values.backend.pdb.minAvailable }} + minAvailable: {{ .Values.backend.pdb.minAvailable }} + {{- end }} + {{- if or .Values.backend.pdb.maxUnavailable ( not .Values.backend.pdb.minAvailable ) }} + maxUnavailable: {{ .Values.backend.pdb.maxUnavailable | default 1 }} + {{- end }} + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.backend.podLabels .Values.commonLabels ) "context" . ) }} + selector: + matchLabels: {{- include "shuffle.backend.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/backend/backend-role-binding.yaml b/functions/kubernetes/charts/shuffle/templates/backend/backend-role-binding.yaml new file mode 100644 index 00000000..171e2c98 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/backend/backend-role-binding.yaml @@ -0,0 +1,18 @@ +{{ if .Values.backend.rbac.create }} +kind: RoleBinding +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: {{ include "shuffle.backend.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.backend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +subjects: + - kind: ServiceAccount + name: {{ include "shuffle.backend.serviceAccount.name" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "shuffle.backend.name" . }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/backend/backend-role.yaml b/functions/kubernetes/charts/shuffle/templates/backend/backend-role.yaml new file mode 100644 index 00000000..790ea462 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/backend/backend-role.yaml @@ -0,0 +1,18 @@ +{{ if .Values.backend.rbac.create }} +kind: Role +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: {{ include "shuffle.backend.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.backend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: ["list"] + - apiGroups: ["batch"] + resources: ["jobs"] + verbs: ["get", "create", "delete"] +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/backend/backend-service-account.yaml b/functions/kubernetes/charts/shuffle/templates/backend/backend-service-account.yaml new file mode 100644 index 00000000..5a49ba3a --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/backend/backend-service-account.yaml @@ -0,0 +1,14 @@ +{{- if .Values.backend.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "shuffle.backend.serviceAccount.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.backend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.backend.serviceAccount.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" (dict "values" (list .Values.backend.serviceAccount.annotations .Values.commonAnnotations) "context" .) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $ ) | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.backend.serviceAccount.automountServiceAccountToken }} +{{- include "shuffle.backend.serviceAccount.imagePullSecrets" . | nindent 0 }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/backend/backend-svc.yaml b/functions/kubernetes/charts/shuffle/templates/backend/backend-svc.yaml new file mode 100644 index 00000000..18328899 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/backend/backend-svc.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "shuffle.backend.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.backend.labels" (dict "customLabels" .Values.commonLabels "context" $) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} +spec: + type: ClusterIP + ports: + - name: http + port: {{ .Values.backend.containerPorts.http }} + targetPort: http + protocol: TCP + {{- $podLabels := include "common.tplvalues.merge" (dict "values" (list .Values.backend.podLabels .Values.commonLabels) "context" .) }} + selector: {{- include "shuffle.backend.matchLabels" (dict "customLabels" $podLabels "context" $) | nindent 4 }} diff --git a/functions/kubernetes/charts/shuffle/templates/backend/backend-vpa.yaml b/functions/kubernetes/charts/shuffle/templates/backend/backend-vpa.yaml new file mode 100644 index 00000000..dfdd0bf5 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/backend/backend-vpa.yaml @@ -0,0 +1,38 @@ +{{- if and (.Capabilities.APIVersions.Has "autoscaling.k8s.io/v1/VerticalPodAutoscaler") .Values.backend.autoscaling.vpa.enabled }} +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: {{ include "shuffle.backend.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.backend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.backend.autoscaling.vpa.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.backend.autoscaling.vpa.annotations .Values.commonAnnotations ) "context" . ) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} + {{- end }} +spec: + resourcePolicy: + containerPolicies: + - containerName: backend + {{- with .Values.backend.autoscaling.vpa.controlledResources }} + controlledResources: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.backend.autoscaling.vpa.maxAllowed }} + maxAllowed: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.backend.autoscaling.vpa.minAllowed }} + minAllowed: + {{- toYaml . | nindent 8 }} + {{- end }} + targetRef: + apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} + kind: Deployment + name: {{ include "backend.names.name" . }} + {{- if .Values.backend.autoscaling.vpa.updatePolicy }} + updatePolicy: + {{- with .Values.backend.autoscaling.vpa.updatePolicy.updateMode }} + updateMode: {{ . }} + {{- end }} + {{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/extra-list.yaml b/functions/kubernetes/charts/shuffle/templates/extra-list.yaml new file mode 100644 index 00000000..9ac65f9e --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/extra-list.yaml @@ -0,0 +1,4 @@ +{{- range .Values.extraDeploy }} +--- +{{ include "common.tplvalues.render" (dict "value" . "context" $) }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/frontend/frontend-cm-env.yaml b/functions/kubernetes/charts/shuffle/templates/frontend/frontend-cm-env.yaml new file mode 100644 index 00000000..9d9f8e72 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/frontend/frontend-cm-env.yaml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "shuffle.frontend.name" . }}-env + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.frontend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: diff --git a/functions/kubernetes/charts/shuffle/templates/frontend/frontend-dpl.yaml b/functions/kubernetes/charts/shuffle/templates/frontend/frontend-dpl.yaml new file mode 100644 index 00000000..1a984eaf --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/frontend/frontend-dpl.yaml @@ -0,0 +1,158 @@ +apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} +kind: Deployment +metadata: + name: {{ template "shuffle.frontend.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.frontend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.frontend.deploymentAnnotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" (dict "values" (list .Values.frontend.deploymentAnnotations .Values.commonAnnotations) "context" .) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- if not .Values.frontend.autoscaling.hpa.enabled }} + replicas: {{ .Values.frontend.replicaCount }} + {{- end }} + {{- if .Values.frontend.updateStrategy }} + strategy: {{- toYaml .Values.frontend.updateStrategy | nindent 4 }} + {{- end }} + {{- $podLabels := include "common.tplvalues.merge" (dict "values" (list .Values.frontend.podLabels .Values.commonLabels) "context" .) }} + selector: + matchLabels: {{- include "shuffle.frontend.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} + template: + metadata: + {{- if .Values.frontend.podAnnotations }} + annotations: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.podAnnotations "context" $) | nindent 8 }} + {{- end }} + labels: {{- include "shuffle.frontend.labels" ( dict "customLabels" $podLabels "context" $ ) | nindent 8 }} + spec: + {{- include "shuffle.frontend.imagePullSecrets" . | nindent 6 }} + serviceAccountName: {{ template "shuffle.frontend.serviceAccount.name" . }} + automountServiceAccountToken: {{ .Values.frontend.automountServiceAccountToken }} + {{- if .Values.frontend.hostAliases }} + hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.hostAliases "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.frontend.affinity }} + affinity: {{- include "common.tplvalues.render" ( dict "value" .Values.frontend.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.frontend.podAffinityPreset "component" "frontend" "customLabels" $podLabels "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.frontend.podAntiAffinityPreset "component" "frontend" "customLabels" $podLabels "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.frontend.nodeAffinityPreset.type "key" .Values.frontend.nodeAffinityPreset.key "values" .Values.frontend.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.frontend.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" ( dict "value" .Values.frontend.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.frontend.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.tolerations "context" .) | nindent 8 }} + {{- end }} + {{- if .Values.frontend.priorityClassName }} + priorityClassName: {{ .Values.frontend.priorityClassName | quote }} + {{- end }} + {{- if .Values.frontend.schedulerName }} + schedulerName: {{ .Values.frontend.schedulerName | quote }} + {{- end }} + {{- if .Values.frontend.topologySpreadConstraints }} + topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.topologySpreadConstraints "context" .) | nindent 8 }} + {{- end }} + {{- if .Values.frontend.podSecurityContext.enabled }} + securityContext: {{- omit .Values.frontend.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.frontend.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.frontend.terminationGracePeriodSeconds }} + {{- end }} + initContainers: + {{- if .Values.frontend.initContainers }} + {{- include "common.tplvalues.render" (dict "value" .Values.frontend.initContainers "context" $) | nindent 8 }} + {{- end }} + containers: + - name: frontend + image: {{ template "shuffle.frontend.image" . }} + imagePullPolicy: {{ .Values.frontend.image.pullPolicy }} + {{- if .Values.frontend.containerSecurityContext.enabled }} + securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.frontend.containerSecurityContext "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} + {{- else if .Values.frontend.command }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.command "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} + {{- else if .Values.frontend.args }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.args "context" $) | nindent 12 }} + {{- end }} + env: + {{- if .Values.frontend.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.frontend.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + envFrom: + - configMapRef: + name: {{ include "shuffle.frontend.name" . }}-env + {{- if .Values.frontend.extraEnvVarsCM }} + - configMapRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.frontend.extraEnvVarsCM "context" $) }} + {{- end }} + {{- if .Values.frontend.extraEnvVarsSecret }} + - secretRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.frontend.extraEnvVarsSecret "context" $) }} + {{- end }} + {{- if .Values.frontend.resources }} + resources: {{- toYaml .Values.frontend.resources | nindent 12 }} + {{- else if ne .Values.frontend.resourcesPreset "none" }} + resources: {{- include "common.resources.preset" (dict "type" .Values.frontend.resourcesPreset) | nindent 12 }} + {{- end }} + ports: + - name: http + containerPort: {{ .Values.frontend.containerPorts.http }} + {{- if .Values.frontend.containerPorts.https }} + - name: https + containerPort: {{ .Values.frontend.containerPorts.https }} + {{- end }} + {{- if .Values.frontend.extraContainerPorts }} + {{- include "common.tplvalues.render" (dict "value" .Values.frontend.extraContainerPorts "context" $) | nindent 12 }} + {{- end }} + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.frontend.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.frontend.livenessProbe.enabled }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.frontend.livenessProbe "enabled") "context" $) | nindent 12 }} + httpGet: + path: / + port: {{ .Values.frontend.containerPorts.http }} + {{- end }} + {{- if .Values.frontend.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.customReadinessProbe "context" $) | nindent 12 }} + {{- else if .Values.frontend.readinessProbe.enabled }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.frontend.readinessProbe "enabled") "context" $) | nindent 12 }} + httpGet: + path: / + port: {{ .Values.frontend.containerPorts.http }} + {{- end }} + {{- if .Values.frontend.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.frontend.startupProbe.enabled }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.frontend.startupProbe "enabled") "context" $) | nindent 12 }} + httpGet: + path: / + port: {{ .Values.frontend.containerPorts.http }} + {{- end }} + {{- end }} + {{- if .Values.frontend.lifecycleHooks }} + lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.frontend.lifecycleHooks "context" $) | nindent 12 }} + {{- end }} + volumeMounts: + - name: empty-dir + mountPath: /tmp + subPath: tmp-dir + {{- if .Values.frontend.extraVolumeMounts }} + {{- include "common.tplvalues.render" (dict "value" .Values.frontend.extraVolumeMounts "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.frontend.sidecars }} + {{- include "common.tplvalues.render" ( dict "value" .Values.frontend.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + - name: empty-dir + emptyDir: {} + {{- if .Values.frontend.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.frontend.extraVolumes "context" $) | nindent 8 }} + {{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/frontend/frontend-hpa.yaml b/functions/kubernetes/charts/shuffle/templates/frontend/frontend-hpa.yaml new file mode 100644 index 00000000..d1b31e11 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/frontend/frontend-hpa.yaml @@ -0,0 +1,43 @@ +{{- if .Values.frontend.autoscaling.hpa.enabled }} +apiVersion: {{ include "common.capabilities.hpa.apiVersion" . }} +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "shuffle.frontend.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.frontend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + scaleTargetRef: + apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} + kind: Deployment + name: {{ include "shuffle.frontend.name" . }} + minReplicas: {{ .Values.frontend.autoscaling.hpa.minReplicas }} + maxReplicas: {{ .Values.frontend.autoscaling.hpa.maxReplicas }} + metrics: + {{- if .Values.frontend.autoscaling.hpa.targetMemory }} + - type: Resource + resource: + name: memory + {{- if semverCompare "<1.23-0" (include "common.capabilities.kubeVersion" .) }} + targetAverageUtilization: {{ .Values.frontend.autoscaling.hpa.targetMemory }} + {{- else }} + target: + type: Utilization + averageUtilization: {{ .Values.worker.autoscaling.hpa.targetMemory }} + {{- end }} + {{- end }} + {{- if .Values.frontend.autoscaling.hpa.targetCPU }} + - type: Resource + resource: + name: cpu + {{- if semverCompare "<1.23-0" (include "common.capabilities.kubeVersion" .) }} + targetAverageUtilization: {{ .Values.frontend.autoscaling.hpa.targetCPU }} + {{- else }} + target: + type: Utilization + averageUtilization: {{ .Values.worker.autoscaling.hpa.targetCPU }} + {{- end }} + {{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/frontend/frontend-network-policy.yaml b/functions/kubernetes/charts/shuffle/templates/frontend/frontend-network-policy.yaml new file mode 100644 index 00000000..9082535b --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/frontend/frontend-network-policy.yaml @@ -0,0 +1,47 @@ +{{- if .Values.frontend.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} +metadata: + name: {{ template "shuffle.frontend.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.frontend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.frontend.podLabels .Values.commonLabels ) "context" . ) }} + podSelector: + matchLabels: {{- include "shuffle.frontend.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} + policyTypes: + - Ingress + - Egress + egress: + {{- if .Values.frontend.networkPolicy.allowExternalEgress }} + - {} + {{- else }} + # Allow DNS resolution with an in-cluster DNS server + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: kube-system + {{- if .Values.frontend.networkPolicy.extraEgress }} + {{- include "common.tplvalues.render" ( dict "value" .Values.frontend.networkPolicy.extraEgress "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} + ingress: + {{ if .Values.frontend.networkPolicy.allowExternal }} + - ports: + - port: {{ .Values.frontend.containerPorts.http }} + {{- if .Values.frontend.containerPorts.https }} + - port: {{ .Values.frontend.containerPorts.https }} + {{- end }} + {{- end }} + {{- if .Values.frontend.networkPolicy.extraIngress }} + {{- include "common.tplvalues.render" ( dict "value" .Values.frontend.networkPolicy.extraIngress "context" $ ) | nindent 4 }} + {{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/frontend/frontend-pdb.yaml b/functions/kubernetes/charts/shuffle/templates/frontend/frontend-pdb.yaml new file mode 100644 index 00000000..b1c2eb28 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/frontend/frontend-pdb.yaml @@ -0,0 +1,21 @@ +{{- if .Values.frontend.pdb.create }} +apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ include "shuffle.frontend.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.frontend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- if .Values.frontend.pdb.minAvailable }} + minAvailable: {{ .Values.frontend.pdb.minAvailable }} + {{- end }} + {{- if or .Values.frontend.pdb.maxUnavailable ( not .Values.frontend.pdb.minAvailable ) }} + maxUnavailable: {{ .Values.frontend.pdb.maxUnavailable | default 1 }} + {{- end }} + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.frontend.podLabels .Values.commonLabels ) "context" . ) }} + selector: + matchLabels: {{- include "shuffle.frontend.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/frontend/frontend-service-account.yaml b/functions/kubernetes/charts/shuffle/templates/frontend/frontend-service-account.yaml new file mode 100644 index 00000000..d580dd3e --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/frontend/frontend-service-account.yaml @@ -0,0 +1,14 @@ +{{- if .Values.frontend.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "shuffle.frontend.serviceAccount.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.frontend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.frontend.serviceAccount.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" (dict "values" (list .Values.frontend.serviceAccount.annotations .Values.commonAnnotations) "context" .) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $ ) | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.frontend.serviceAccount.automountServiceAccountToken }} +{{- include "shuffle.frontend.serviceAccount.imagePullSecrets" . | nindent 0 }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/frontend/frontend-svc.yaml b/functions/kubernetes/charts/shuffle/templates/frontend/frontend-svc.yaml new file mode 100644 index 00000000..76851c0a --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/frontend/frontend-svc.yaml @@ -0,0 +1,24 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "shuffle.frontend.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.frontend.labels" (dict "customLabels" .Values.commonLabels "context" $) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" (dict "value" .Values.commonAnnotations "context" $) | nindent 4 }} + {{- end }} +spec: + type: ClusterIP + ports: + - name: http + port: {{ .Values.frontend.containerPorts.http }} + targetPort: http + protocol: TCP + {{- if .Values.frontend.containerPorts.https }} + - name: https + port: {{ .Values.frontend.containerPorts.https }} + targetPort: https + protocol: TCP + {{- end }} + {{- $podLabels := include "common.tplvalues.merge" (dict "values" (list .Values.frontend.podLabels .Values.commonLabels) "context" .) }} + selector: {{- include "shuffle.frontend.matchLabels" (dict "customLabels" $podLabels "context" $) | nindent 4 }} diff --git a/functions/kubernetes/charts/shuffle/templates/frontend/frontend-vpa.yaml b/functions/kubernetes/charts/shuffle/templates/frontend/frontend-vpa.yaml new file mode 100644 index 00000000..8dd26333 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/frontend/frontend-vpa.yaml @@ -0,0 +1,38 @@ +{{- if and (.Capabilities.APIVersions.Has "autoscaling.k8s.io/v1/VerticalPodAutoscaler") .Values.frontend.autoscaling.vpa.enabled }} +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: {{ include "shuffle.frontend.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.frontend.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.frontend.autoscaling.vpa.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.frontend.autoscaling.vpa.annotations .Values.commonAnnotations ) "context" . ) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} + {{- end }} +spec: + resourcePolicy: + containerPolicies: + - containerName: frontend + {{- with .Values.frontend.autoscaling.vpa.controlledResources }} + controlledResources: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.frontend.autoscaling.vpa.maxAllowed }} + maxAllowed: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.frontend.autoscaling.vpa.minAllowed }} + minAllowed: + {{- toYaml . | nindent 8 }} + {{- end }} + targetRef: + apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} + kind: Deployment + name: {{ include "frontend.names.name" . }} + {{- if .Values.frontend.autoscaling.vpa.updatePolicy }} + updatePolicy: + {{- with .Values.frontend.autoscaling.vpa.updatePolicy.updateMode }} + updateMode: {{ . }} + {{- end }} + {{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/ingress/ingress.yaml b/functions/kubernetes/charts/shuffle/templates/ingress/ingress.yaml new file mode 100644 index 00000000..cd08c0f9 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/ingress/ingress.yaml @@ -0,0 +1,60 @@ +{{- if .Values.ingress.enabled }} +apiVersion: {{ include "common.capabilities.ingress.apiVersion" . }} +kind: Ingress +metadata: + name: {{ template "common.names.fullname" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.ingress.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" (dict "values" (list .Values.ingress.annotations .Values.commonAnnotations) "context" .) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.ingressClassName (eq "true" (include "common.ingress.supportsIngressClassname" .)) }} + ingressClassName: {{ .Values.ingress.ingressClassName | quote }} + {{- end }} + rules: + {{- if .Values.ingress.hostname }} + - host: {{ .Values.ingress.hostname }} + http: + paths: + {{- if .Values.ingress.extraPaths }} + {{- toYaml .Values.ingress.extraPaths | nindent 10 }} + {{- end }} + - path: {{ .Values.ingress.path }} + {{- if eq "true" (include "common.ingress.supportsPathType" .) }} + pathType: {{ .Values.ingress.pathType }} + {{- end }} + backend: {{- include "common.ingress.backend" (dict "serviceName" (include "shuffle.frontend.name" .) "servicePort" "http" "context" $) | nindent 14 }} + - path: {{ .Values.ingress.backendPath }} + {{- if eq "true" (include "common.ingress.supportsPathType" .) }} + pathType: {{ .Values.ingress.backendPathType }} + {{- end }} + backend: {{- include "common.ingress.backend" (dict "serviceName" (include "shuffle.backend.name" .) "servicePort" "http" "context" $) | nindent 14 }} + + {{- end }} + {{- range .Values.ingress.extraHosts }} + - host: {{ .name | quote }} + http: + paths: + - path: {{ default "/" .path }} + {{- if eq "true" (include "common.ingress.supportsPathType" $) }} + pathType: {{ default "ImplementationSpecific" .pathType }} + {{- end }} + backend: {{- include "common.ingress.backend" (dict "serviceName" (include "common.names.fullname" $) "servicePort" "http" "context" $) | nindent 14 }} + {{- end }} + {{- if .Values.ingress.extraRules }} + {{- include "common.tplvalues.render" (dict "value" .Values.ingress.extraRules "context" $) | nindent 4 }} + {{- end }} + {{- if or (and .Values.ingress.tls (or (include "common.ingress.certManagerRequest" ( dict "annotations" .Values.ingress.annotations )) .Values.ingress.selfSigned)) .Values.ingress.extraTls }} + tls: + {{- if and .Values.ingress.tls (or (include "common.ingress.certManagerRequest" ( dict "annotations" .Values.ingress.annotations )) .Values.ingress.selfSigned) }} + - hosts: + - {{ .Values.ingress.hostname | quote }} + secretName: {{ printf "%s-tls" .Values.ingress.hostname }} + {{- end }} + {{- if .Values.ingress.extraTls }} + {{- include "common.tplvalues.render" (dict "value" .Values.ingress.extraTls "context" $) | nindent 4 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/ingress/tls-secret.yaml b/functions/kubernetes/charts/shuffle/templates/ingress/tls-secret.yaml new file mode 100644 index 00000000..4e35a9aa --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/ingress/tls-secret.yaml @@ -0,0 +1,39 @@ +{{- if .Values.ingress.enabled }} +{{- if .Values.ingress.secrets }} +{{- range .Values.ingress.secrets }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .name }} + namespace: {{ include "common.names.namespace" $ | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" $.Values.commonLabels "context" $ ) | nindent 4 }} + {{- if $.Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $.Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +type: kubernetes.io/tls +data: + tls.crt: {{ .certificate | b64enc }} + tls.key: {{ .key | b64enc }} +--- +{{- end }} +{{- end }} +{{- if and .Values.ingress.tls .Values.ingress.selfSigned }} +{{- $secretName := printf "%s-tls" .Values.ingress.hostname }} +{{- $ca := genCA "shuffle-ca" 365 }} +{{- $cert := genSignedCert .Values.ingress.hostname nil (list .Values.ingress.hostname) 365 $ca }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ $secretName }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +type: kubernetes.io/tls +data: + tls.crt: {{ include "common.secrets.lookup" (dict "secret" $secretName "key" "tls.crt" "defaultValue" $cert.Cert "context" $) }} + tls.key: {{ include "common.secrets.lookup" (dict "secret" $secretName "key" "tls.key" "defaultValue" $cert.Key "context" $) }} + ca.crt: {{ include "common.secrets.lookup" (dict "secret" $secretName "key" "ca.crt" "defaultValue" $ca.Cert "context" $) }} +{{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/istio/gateway.yaml b/functions/kubernetes/charts/shuffle/templates/istio/gateway.yaml new file mode 100644 index 00000000..f30a5ecb --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/istio/gateway.yaml @@ -0,0 +1,42 @@ +{{- if .Values.istio.enabled }} +apiVersion: "{{ .Values.istio.apiVersion }}" +kind: Gateway +metadata: + name: {{ template "common.names.fullname" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.istio.gateway.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" (dict "values" (list .Values.istio.gateway.annotations .Values.commonAnnotations) "context" .) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + selector: {{- include "common.tplvalues.render" ( dict "value" .Values.istio.gateway.selector "context" $ ) | nindent 4 }} + servers: + {{- if .Values.istio.gateway.http.enabled }} + - name: "{{ include "common.names.fullname" . }}-http" + port: + number: 80 + name: http + protocol: HTTP + hosts: {{ .Values.istio.hosts }} + tls: + httpsRedirect: {{ .Values.istio.gateway.http.httpsRedirect }} + {{- end }} + {{- if .Values.istio.gateway.https.enabled }} + - name: "{{ include "common.names.fullname" . }}-https" + port: + number: 443 + name: https + protocol: HTTPS + hosts: {{ .Values.istio.hosts }} + tls: + credentialName: {{ .Values.istio.gateway.https.tlsCredentialName }} + mode: SIMPLE + {{- with .Values.istio.gateway.https.tlsCipherSuites }} + cipherSuites: {{- include "common.tplvalues.render" ( dict "value" . "context" $ ) | nindent 10 }} + {{- end }} + {{- end }} + {{- if .Values.istio.gateway.extraServers }} + {{- include "common.tplvalues.render" (dict "value" .Values.istio.gateway.extraServers "context" $) | nindent 4 }} + {{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/istio/virtual-service.yaml b/functions/kubernetes/charts/shuffle/templates/istio/virtual-service.yaml new file mode 100644 index 00000000..aae37e77 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/istio/virtual-service.yaml @@ -0,0 +1,38 @@ +{{- if .Values.istio.enabled }} +apiVersion: "{{ .Values.istio.apiVersion }}" +kind: VirtualService +metadata: + name: {{ template "common.names.fullname" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.istio.gateway.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" (dict "values" (list .Values.istio.virtualService.annotations .Values.commonAnnotations) "context" .) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + hosts: {{ .Values.istio.hosts }} + gateways: + - {{ include "common.names.fullname" . }} + http: + - name: backend + match: + - uri: + prefix: /api + route: + - destination: + host: {{ include "shuffle.backend.name" . }} + port: + number: {{ .Values.backend.containerPorts.http }} + {{- with .Values.istio.virtualService.backendHeaders }} + headers: {{- include "common.tplvalues.render" ( dict "value" . "context" $ ) | nindent 8 }} + {{- end }} + - name: frontend + route: + - destination: + host: {{ include "shuffle.frontend.name" . }} + port: + number: {{ .Values.frontend.containerPorts.http }} + {{- with .Values.istio.virtualService.frontendHeaders }} + headers: {{- include "common.tplvalues.render" ( dict "value" . "context" $ ) | nindent 8 }} + {{- end }} + {{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/orborus/orborus-cm-env.yaml b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-cm-env.yaml new file mode 100644 index 00000000..57b020a7 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-cm-env.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "shuffle.orborus.name" . }}-env + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.orborus.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +data: + ENVIRONMENT_NAME: "{{ .Values.shuffle.org }}" + ORG_ID: "{{ .Values.shuffle.org }}" + TZ: "{{ .Values.shuffle.timezone }}" + BASE_URL: "http://{{ include "shuffle.backend.name" . }}.{{ .Release.Namespace }}.svc.cluster.local:5001" + KUBERNETES_NAMESPACE: "{{ .Release.Namespace }}" + KUBERNETES_SERVICE_ACCOUNT: {{ include "shuffle.orborus.serviceAccount.name" . }} + SHUFFLE_WORKER_IMAGE: "{{ include "shuffle.worker.image" . }}" + REGISTRY_URL: "{{ .Values.shuffle.appRegistry }}" + SHUFFLE_SWARM_CONFIG: run diff --git a/functions/kubernetes/charts/shuffle/templates/orborus/orborus-dpl.yaml b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-dpl.yaml new file mode 100644 index 00000000..a2d9c278 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-dpl.yaml @@ -0,0 +1,162 @@ +apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} +kind: Deployment +metadata: + name: {{ template "shuffle.orborus.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.orborus.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.orborus.deploymentAnnotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" (dict "values" (list .Values.orborus.deploymentAnnotations .Values.commonAnnotations) "context" .) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- if not .Values.orborus.autoscaling.hpa.enabled }} + replicas: {{ .Values.orborus.replicaCount }} + {{- end }} + {{- if .Values.orborus.updateStrategy }} + strategy: {{- toYaml .Values.orborus.updateStrategy | nindent 4 }} + {{- end }} + {{- $podLabels := include "common.tplvalues.merge" (dict "values" (list .Values.orborus.podLabels .Values.commonLabels) "context" .) }} + selector: + matchLabels: {{- include "shuffle.orborus.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} + template: + metadata: + {{- if .Values.orborus.podAnnotations }} + annotations: {{- include "common.tplvalues.render" (dict "value" .Values.orborus.podAnnotations "context" $) | nindent 8 }} + {{- end }} + labels: {{- include "shuffle.orborus.labels" ( dict "customLabels" $podLabels "context" $ ) | nindent 8 }} + spec: + {{- include "shuffle.orborus.imagePullSecrets" . | nindent 6 }} + serviceAccountName: {{ template "shuffle.orborus.serviceAccount.name" . }} + automountServiceAccountToken: {{ .Values.orborus.automountServiceAccountToken }} + {{- if .Values.orborus.hostAliases }} + hostAliases: {{- include "common.tplvalues.render" (dict "value" .Values.orborus.hostAliases "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.orborus.affinity }} + affinity: {{- include "common.tplvalues.render" ( dict "value" .Values.orborus.affinity "context" $) | nindent 8 }} + {{- else }} + affinity: + podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.orborus.podAffinityPreset "component" "orborus" "customLabels" $podLabels "context" $) | nindent 10 }} + podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.orborus.podAntiAffinityPreset "component" "orborus" "customLabels" $podLabels "context" $) | nindent 10 }} + nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.orborus.nodeAffinityPreset.type "key" .Values.orborus.nodeAffinityPreset.key "values" .Values.orborus.nodeAffinityPreset.values) | nindent 10 }} + {{- end }} + {{- if .Values.orborus.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" ( dict "value" .Values.orborus.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.orborus.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.orborus.tolerations "context" .) | nindent 8 }} + {{- end }} + {{- if .Values.orborus.priorityClassName }} + priorityClassName: {{ .Values.orborus.priorityClassName | quote }} + {{- end }} + {{- if .Values.orborus.schedulerName }} + schedulerName: {{ .Values.orborus.schedulerName | quote }} + {{- end }} + {{- if .Values.orborus.topologySpreadConstraints }} + topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.orborus.topologySpreadConstraints "context" .) | nindent 8 }} + {{- end }} + {{- if .Values.orborus.podSecurityContext.enabled }} + securityContext: {{- omit .Values.orborus.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.orborus.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.orborus.terminationGracePeriodSeconds }} + {{- end }} + initContainers: + {{- if .Values.orborus.initContainers }} + {{- include "common.tplvalues.render" (dict "value" .Values.orborus.initContainers "context" $) | nindent 8 }} + {{- end }} + containers: + - name: orborus + image: {{ template "shuffle.orborus.image" . }} + imagePullPolicy: {{ .Values.orborus.image.pullPolicy }} + {{- if .Values.orborus.containerSecurityContext.enabled }} + securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.orborus.containerSecurityContext "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.command "context" $) | nindent 12 }} + {{- else if .Values.orborus.command }} + command: {{- include "common.tplvalues.render" (dict "value" .Values.orborus.command "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.diagnosticMode.enabled }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.diagnosticMode.args "context" $) | nindent 12 }} + {{- else if .Values.orborus.args }} + args: {{- include "common.tplvalues.render" (dict "value" .Values.orborus.args "context" $) | nindent 12 }} + {{- end }} + env: + - name: RUNNING_MODE + value: kubernetes + - name: IS_KUBERNETES + value: "true" + - name: SHUFFLE_WORKER_SERVICE_ACCOUNT_NAME + value: {{ include "shuffle.worker.serviceAccount.name" . }} + - name: SHUFFLE_APP_SERVICE_ACCOUNT_NAME + value: {{ include "shuffle.app.serviceAccount.name" . }} + {{- if .Values.orborus.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.orborus.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + envFrom: + - configMapRef: + name: {{ include "shuffle.orborus.name" . }}-env + {{- if .Values.orborus.extraEnvVarsCM }} + - configMapRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.orborus.extraEnvVarsCM "context" $) }} + {{- end }} + {{- if .Values.orborus.extraEnvVarsSecret }} + - secretRef: + name: {{ include "common.tplvalues.render" (dict "value" .Values.orborus.extraEnvVarsSecret "context" $) }} + {{- end }} + {{- if .Values.orborus.resources }} + resources: {{- toYaml .Values.orborus.resources | nindent 12 }} + {{- else if ne .Values.orborus.resourcesPreset "none" }} + resources: {{- include "common.resources.preset" (dict "type" .Values.orborus.resourcesPreset) | nindent 12 }} + {{- end }} + ports: + - name: http + containerPort: {{ .Values.orborus.containerPorts.http }} + {{- if .Values.orborus.extraContainerPorts }} + {{- include "common.tplvalues.render" (dict "value" .Values.orborus.extraContainerPorts "context" $) | nindent 12 }} + {{- end }} + {{- if not .Values.diagnosticMode.enabled }} + {{- if .Values.orborus.customLivenessProbe }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.orborus.customLivenessProbe "context" $) | nindent 12 }} + {{- else if .Values.orborus.livenessProbe.enabled }} + livenessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.orborus.livenessProbe "enabled") "context" $) | nindent 12 }} + httpGet: + path: / + port: {{ .Values.orborus.containerPorts.http }} + {{- end }} + {{- if .Values.orborus.customReadinessProbe }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" .Values.orborus.customReadinessProbe "context" $) | nindent 12 }} + {{- else if .Values.orborus.readinessProbe.enabled }} + readinessProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.orborus.readinessProbe "enabled") "context" $) | nindent 12 }} + httpGet: + path: / + port: {{ .Values.orborus.containerPorts.http }} + {{- end }} + {{- if .Values.orborus.customStartupProbe }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" .Values.orborus.customStartupProbe "context" $) | nindent 12 }} + {{- else if .Values.orborus.startupProbe.enabled }} + startupProbe: {{- include "common.tplvalues.render" (dict "value" (omit .Values.orborus.startupProbe "enabled") "context" $) | nindent 12 }} + httpGet: + path: / + port: {{ .Values.orborus.containerPorts.http }} + {{- end }} + {{- end }} + {{- if .Values.orborus.lifecycleHooks }} + lifecycle: {{- include "common.tplvalues.render" (dict "value" .Values.orborus.lifecycleHooks "context" $) | nindent 12 }} + {{- end }} + volumeMounts: + - name: empty-dir + mountPath: /tmp + subPath: tmp-dir + {{- if .Values.orborus.extraVolumeMounts }} + {{- include "common.tplvalues.render" (dict "value" .Values.orborus.extraVolumeMounts "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.orborus.sidecars }} + {{- include "common.tplvalues.render" ( dict "value" .Values.orborus.sidecars "context" $) | nindent 8 }} + {{- end }} + volumes: + - name: empty-dir + emptyDir: {} + {{- if .Values.orborus.extraVolumes }} + {{- include "common.tplvalues.render" (dict "value" .Values.orborus.extraVolumes "context" $) | nindent 8 }} + {{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/orborus/orborus-hpa.yaml b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-hpa.yaml new file mode 100644 index 00000000..12bf073f --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-hpa.yaml @@ -0,0 +1,43 @@ +{{- if .Values.orborus.autoscaling.hpa.enabled }} +apiVersion: {{ include "common.capabilities.hpa.apiVersion" . }} +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "shuffle.orborus.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.orborus.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + scaleTargetRef: + apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} + kind: Deployment + name: {{ include "shuffle.orborus.name" . }} + minReplicas: {{ .Values.orborus.autoscaling.hpa.minReplicas }} + maxReplicas: {{ .Values.orborus.autoscaling.hpa.maxReplicas }} + metrics: + {{- if .Values.orborus.autoscaling.hpa.targetMemory }} + - type: Resource + resource: + name: memory + {{- if semverCompare "<1.23-0" (include "common.capabilities.kubeVersion" .) }} + targetAverageUtilization: {{ .Values.orborus.autoscaling.hpa.targetMemory }} + {{- else }} + target: + type: Utilization + averageUtilization: {{ .Values.worker.autoscaling.hpa.targetMemory }} + {{- end }} + {{- end }} + {{- if .Values.orborus.autoscaling.hpa.targetCPU }} + - type: Resource + resource: + name: cpu + {{- if semverCompare "<1.23-0" (include "common.capabilities.kubeVersion" .) }} + targetAverageUtilization: {{ .Values.orborus.autoscaling.hpa.targetCPU }} + {{- else }} + target: + type: Utilization + averageUtilization: {{ .Values.worker.autoscaling.hpa.targetCPU }} + {{- end }} + {{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/orborus/orborus-network-policy.yaml b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-network-policy.yaml new file mode 100644 index 00000000..f6a22339 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-network-policy.yaml @@ -0,0 +1,72 @@ +{{- if .Values.orborus.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} +metadata: + name: {{ template "shuffle.orborus.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.orborus.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.orborus.podLabels .Values.commonLabels ) "context" . ) }} + podSelector: + matchLabels: {{- include "shuffle.orborus.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} + policyTypes: + - Ingress + - Egress + egress: + {{- if .Values.orborus.networkPolicy.allowExternalEgress }} + - {} + {{- else }} + # Allow DNS resolution with an in-cluster DNS server + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: kube-system + # Allow access to backend + - ports: + - port: {{ .Values.backend.containerPorts.http }} + protocol: TCP + to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ .Release.Namespace }} + podSelector: + matchLabels: {{ include "shuffle.backend.matchLabels" . | nindent 14 }} + # Allow access to workers + - ports: + - port: 33333 + protocol: TCP + to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ .Release.Namespace }} + podSelector: + matchLabels: {{ include "shuffle.worker.matchLabels" . | nindent 14 }} + {{- if .Values.orborus.networkPolicy.extraEgress }} + {{- include "common.tplvalues.render" ( dict "value" .Values.orborus.networkPolicy.extraEgress "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} + ingress: + - ports: + - port: {{ .Values.orborus.containerPorts.http }} + protocol: TCP + {{- if not .Values.orborus.networkPolicy.allowExternal }} + from: + # Allow traffic from workers + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ .Release.Namespace }} + podSelector: + matchLabels: {{ include "shuffle.worker.matchLabels" . | nindent 14 }} + {{- end }} + {{- if .Values.orborus.networkPolicy.extraIngress }} + {{- include "common.tplvalues.render" ( dict "value" .Values.orborus.networkPolicy.extraIngress "context" $ ) | nindent 4 }} + {{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/orborus/orborus-pdb.yaml b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-pdb.yaml new file mode 100644 index 00000000..827b01bc --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-pdb.yaml @@ -0,0 +1,21 @@ +{{- if .Values.orborus.pdb.create }} +apiVersion: {{ include "common.capabilities.policy.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + name: {{ include "shuffle.orborus.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.orborus.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- if .Values.orborus.pdb.minAvailable }} + minAvailable: {{ .Values.orborus.pdb.minAvailable }} + {{- end }} + {{- if or .Values.orborus.pdb.maxUnavailable ( not .Values.orborus.pdb.minAvailable ) }} + maxUnavailable: {{ .Values.orborus.pdb.maxUnavailable | default 1 }} + {{- end }} + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.orborus.podLabels .Values.commonLabels ) "context" . ) }} + selector: + matchLabels: {{- include "shuffle.orborus.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/orborus/orborus-role-binding.yaml b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-role-binding.yaml new file mode 100644 index 00000000..feb73887 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-role-binding.yaml @@ -0,0 +1,18 @@ +{{ if .Values.orborus.rbac.create }} +kind: RoleBinding +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: {{ include "shuffle.orborus.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.orborus.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +subjects: + - kind: ServiceAccount + name: {{ include "shuffle.orborus.serviceAccount.name" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "shuffle.orborus.name" . }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/orborus/orborus-role.yaml b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-role.yaml new file mode 100644 index 00000000..90041d89 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-role.yaml @@ -0,0 +1,29 @@ +{{ if .Values.orborus.rbac.create }} +kind: Role +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: {{ include "shuffle.orborus.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.orborus.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +rules: + - verbs: + - list + - create + - delete + apiGroups: + - '' + resources: + - pods + - services + - verbs: + - list + - create + - delete + apiGroups: + - apps + resources: + - deployments +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/orborus/orborus-service-account.yaml b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-service-account.yaml new file mode 100644 index 00000000..27c4b9f6 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-service-account.yaml @@ -0,0 +1,14 @@ +{{- if .Values.orborus.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "shuffle.orborus.serviceAccount.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.orborus.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.orborus.serviceAccount.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" (dict "values" (list .Values.orborus.serviceAccount.annotations .Values.commonAnnotations) "context" .) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $ ) | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.orborus.serviceAccount.automountServiceAccountToken }} +{{- include "shuffle.orborus.serviceAccount.imagePullSecrets" . | nindent 0 }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/orborus/orborus-vpa.yaml b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-vpa.yaml new file mode 100644 index 00000000..a1a7c386 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/orborus/orborus-vpa.yaml @@ -0,0 +1,38 @@ +{{- if and (.Capabilities.APIVersions.Has "autoscaling.k8s.io/v1/VerticalPodAutoscaler") .Values.orborus.autoscaling.vpa.enabled }} +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + name: {{ include "shuffle.orborus.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.orborus.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.orborus.autoscaling.vpa.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" ( dict "values" ( list .Values.orborus.autoscaling.vpa.annotations .Values.commonAnnotations ) "context" . ) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $) | nindent 4 }} + {{- end }} +spec: + resourcePolicy: + containerPolicies: + - containerName: orborus + {{- with .Values.orborus.autoscaling.vpa.controlledResources }} + controlledResources: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.orborus.autoscaling.vpa.maxAllowed }} + maxAllowed: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.orborus.autoscaling.vpa.minAllowed }} + minAllowed: + {{- toYaml . | nindent 8 }} + {{- end }} + targetRef: + apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} + kind: Deployment + name: {{ include "orborus.names.name" . }} + {{- if .Values.orborus.autoscaling.vpa.updatePolicy }} + updatePolicy: + {{- with .Values.orborus.autoscaling.vpa.updatePolicy.updateMode }} + updateMode: {{ . }} + {{- end }} + {{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/shuffle-app/shuffle-app-network-policy.yaml b/functions/kubernetes/charts/shuffle/templates/shuffle-app/shuffle-app-network-policy.yaml new file mode 100644 index 00000000..d4a24fe6 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/shuffle-app/shuffle-app-network-policy.yaml @@ -0,0 +1,61 @@ +{{- if .Values.app.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} +metadata: + name: {{ template "shuffle.app.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.app.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.app.podLabels .Values.commonLabels ) "context" . ) }} + podSelector: + matchLabels: {{- include "shuffle.app.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} + policyTypes: + - Ingress + - Egress + egress: + {{- if .Values.app.networkPolicy.allowExternalEgress }} + - {} + {{- else }} + # Allow DNS resolution with an in-cluster DNS server + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: kube-system + # Allow access to workers + - ports: + - port: 33333 + protocol: TCP + to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ .Release.Namespace }} + podSelector: + matchLabels: {{ include "shuffle.worker.matchLabels" . | nindent 14 }} + {{- if .Values.app.networkPolicy.extraEgress }} + {{- include "common.tplvalues.render" ( dict "value" .Values.app.networkPolicy.extraEgress "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} + ingress: + {{- if .Values.app.networkPolicy.allowExternal }} + - {} + {{- else }} + # Allow access from workers. Apps will typicaly use port 80/TCP, but this is not enforced. + - from: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ .Release.Namespace }} + podSelector: + matchLabels: {{ include "shuffle.worker.matchLabels" . | nindent 14 }} + {{- end }} + {{- if .Values.app.networkPolicy.extraIngress }} + {{- include "common.tplvalues.render" ( dict "value" .Values.app.networkPolicy.extraIngress "context" $ ) | nindent 4 }} + {{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/shuffle-app/shuffle-app-role-binding.yaml b/functions/kubernetes/charts/shuffle/templates/shuffle-app/shuffle-app-role-binding.yaml new file mode 100644 index 00000000..55a166e7 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/shuffle-app/shuffle-app-role-binding.yaml @@ -0,0 +1,18 @@ +{{ if .Values.app.rbac.create }} +kind: RoleBinding +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: {{ template "shuffle.app.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.app.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +subjects: + - kind: ServiceAccount + name: {{ include "shuffle.app.serviceAccount.name" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "shuffle.app.name" . }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/shuffle-app/shuffle-app-role.yaml b/functions/kubernetes/charts/shuffle/templates/shuffle-app/shuffle-app-role.yaml new file mode 100644 index 00000000..8be2a6f0 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/shuffle-app/shuffle-app-role.yaml @@ -0,0 +1,15 @@ +{{ if .Values.app.rbac.create }} +kind: Role +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: {{ template "shuffle.app.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.app.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +rules: + - apiGroups: [""] + resources: [""] + verbs: [""] +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/shuffle-app/shuffle-app-service-account.yaml b/functions/kubernetes/charts/shuffle/templates/shuffle-app/shuffle-app-service-account.yaml new file mode 100644 index 00000000..736e9957 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/shuffle-app/shuffle-app-service-account.yaml @@ -0,0 +1,14 @@ +{{- if .Values.app.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "shuffle.app.serviceAccount.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.app.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.app.serviceAccount.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" (dict "values" (list .Values.app.serviceAccount.annotations .Values.commonAnnotations) "context" .) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $ ) | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.app.serviceAccount.automountServiceAccountToken }} +{{- include "shuffle.app.serviceAccount.imagePullSecrets" . | nindent 0 }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/shuffle-worker/shuffle-worker-network-policy.yaml b/functions/kubernetes/charts/shuffle/templates/shuffle-worker/shuffle-worker-network-policy.yaml new file mode 100644 index 00000000..1b07d9a9 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/shuffle-worker/shuffle-worker-network-policy.yaml @@ -0,0 +1,69 @@ +{{- if .Values.worker.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: {{ include "common.capabilities.networkPolicy.apiVersion" . }} +metadata: + name: {{ template "shuffle.worker.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.worker.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +spec: + {{- $podLabels := include "common.tplvalues.merge" ( dict "values" ( list .Values.worker.podLabels .Values.commonLabels ) "context" . ) }} + podSelector: + matchLabels: {{- include "shuffle.worker.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} + policyTypes: + - Ingress + - Egress + egress: + {{- if .Values.worker.networkPolicy.allowExternalEgress }} + - {} + {{- else }} + # Allow DNS resolution with an in-cluster DNS server + - ports: + - port: 53 + protocol: UDP + - port: 53 + protocol: TCP + to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: kube-system + # Allow access to orborus + - ports: + - port: {{ .Values.orborus.containerPorts.http }} + protocol: TCP + to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ .Release.Namespace }} + podSelector: + matchLabels: {{ include "shuffle.orborus.matchLabels" . | nindent 14 }} + # Allow arbitrary connections to apps. Apps will typically use port 80/TCP, but this is not enforced. + - to: + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ .Release.Namespace }} + podSelector: + matchLabels: {{ include "shuffle.app.matchLabels" . | nindent 14 }} + {{- if .Values.worker.networkPolicy.extraEgress }} + {{- include "common.tplvalues.render" ( dict "value" .Values.worker.networkPolicy.extraEgress "context" $ ) | nindent 4 }} + {{- end }} + {{- end }} + ingress: + - ports: + - port: 33333 + protocol: TCP + {{- if not .Values.worker.networkPolicy.allowExternal }} + from: + # Allow traffic from orborus + - namespaceSelector: + matchLabels: + kubernetes.io/metadata.name: {{ .Release.Namespace }} + podSelector: + matchLabels: {{ include "shuffle.orborus.matchLabels" . | nindent 14 }} + {{- end }} + {{- if .Values.worker.networkPolicy.extraIngress }} + {{- include "common.tplvalues.render" ( dict "value" .Values.worker.networkPolicy.extraIngress "context" $ ) | nindent 4 }} + {{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/shuffle-worker/shuffle-worker-role-binding.yaml b/functions/kubernetes/charts/shuffle/templates/shuffle-worker/shuffle-worker-role-binding.yaml new file mode 100644 index 00000000..328b3dd5 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/shuffle-worker/shuffle-worker-role-binding.yaml @@ -0,0 +1,18 @@ +{{ if .Values.worker.rbac.create }} +kind: RoleBinding +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: {{ template "shuffle.worker.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.worker.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +subjects: + - kind: ServiceAccount + name: {{ include "shuffle.worker.serviceAccount.name" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "shuffle.worker.name" . }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/shuffle-worker/shuffle-worker-role.yaml b/functions/kubernetes/charts/shuffle/templates/shuffle-worker/shuffle-worker-role.yaml new file mode 100644 index 00000000..fdef5855 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/shuffle-worker/shuffle-worker-role.yaml @@ -0,0 +1,21 @@ +{{ if .Values.worker.rbac.create }} +kind: Role +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: {{ template "shuffle.worker.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.worker.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if .Values.commonAnnotations }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} + {{- end }} +rules: + - apiGroups: [""] + resources: ["pods"] + verbs: ["list", "delete"] + - apiGroups: [""] + resources: ["services"] + verbs: ["create"] + - apiGroups: ["apps"] + resources: ["deployments"] + verbs: ["list", "create"] +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/shuffle-worker/shuffle-worker-service-account.yaml b/functions/kubernetes/charts/shuffle/templates/shuffle-worker/shuffle-worker-service-account.yaml new file mode 100644 index 00000000..a9a90204 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/shuffle-worker/shuffle-worker-service-account.yaml @@ -0,0 +1,14 @@ +{{- if .Values.worker.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "shuffle.worker.serviceAccount.name" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "shuffle.worker.labels" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + {{- if or .Values.worker.serviceAccount.annotations .Values.commonAnnotations }} + {{- $annotations := include "common.tplvalues.merge" (dict "values" (list .Values.worker.serviceAccount.annotations .Values.commonAnnotations) "context" .) }} + annotations: {{- include "common.tplvalues.render" ( dict "value" $annotations "context" $ ) | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.worker.serviceAccount.automountServiceAccountToken }} +{{- include "shuffle.worker.serviceAccount.imagePullSecrets" . | nindent 0 }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/templates/vault-secrets.yaml b/functions/kubernetes/charts/shuffle/templates/vault-secrets.yaml new file mode 100644 index 00000000..0755f20a --- /dev/null +++ b/functions/kubernetes/charts/shuffle/templates/vault-secrets.yaml @@ -0,0 +1,19 @@ +{{ range $index, $element := .Values.vault.secrets }} +{{- $vaultRole := $element.vaultRole | default $.Values.vault.role }} +--- +apiVersion: ricoberger.de/v1alpha1 +kind: VaultSecret +metadata: + name: {{ include "common.names.fullname" $ }}-{{ $element.name }} +spec: + type: {{ $element.type }} + path: {{ $element.path }} + {{- if $vaultRole }} + vaultRole: {{ $vaultRole }} + {{- end }} + {{- range $k, $v := $element }} + {{- if (not (has $k (list "name" "type" "path" "vaultRole"))) }} + {{ $k }}: {{ $v }} + {{- end }} + {{- end }} +{{- end }} diff --git a/functions/kubernetes/charts/shuffle/values.schema.json b/functions/kubernetes/charts/shuffle/values.schema.json new file mode 100644 index 00000000..7a85b9fa --- /dev/null +++ b/functions/kubernetes/charts/shuffle/values.schema.json @@ -0,0 +1,2661 @@ +{ + "title": "Chart Values", + "type": "object", + "properties": { + "global": { + "type": "object", + "properties": { + "imageRegistry": { + "type": "string", + "description": "Global Docker image registry", + "default": "" + }, + "imagePullSecrets": { + "type": "array", + "description": "Global Docker registry secret names as an array", + "default": [], + "items": {} + }, + "defaultStorageClass": { + "type": "string", + "description": "Global default StorageClass for Persistent Volume(s)", + "default": "" + }, + "compatibility": { + "type": "object", + "properties": { + "openshift": { + "type": "object", + "properties": { + "adaptSecurityContext": { + "type": "string", + "description": "Adapt the securityContext sections of the deployment to make them compatible with Openshift restricted-v2 SCC: remove runAsUser, runAsGroup and fsGroup and let the platform use their allowed default IDs. Possible values: auto (apply if the detected running cluster is Openshift), force (perform the adaptation always), disabled (do not perform adaptation)", + "default": "auto" + } + } + }, + "omitEmptySeLinuxOptions": { + "type": "boolean", + "description": "If set to true, removes the seLinuxOptions from the securityContexts when it is set to an empty object", + "default": false + } + } + } + } + }, + "kubeVersion": { + "type": "string", + "description": "Override Kubernetes version", + "default": "" + }, + "nameOverride": { + "type": "string", + "description": "String to partially override common.names.name", + "default": "" + }, + "fullnameOverride": { + "type": "string", + "description": "String to fully override common.names.fullname", + "default": "" + }, + "namespaceOverride": { + "type": "string", + "description": "String to fully override common.names.namespace", + "default": "" + }, + "commonLabels": { + "type": "object", + "description": "Labels to add to all deployed objects", + "default": {} + }, + "commonAnnotations": { + "type": "object", + "description": "Annotations to add to all deployed objects", + "default": {} + }, + "clusterDomain": { + "type": "string", + "description": "Kubernetes cluster domain name", + "default": "cluster.local" + }, + "extraDeploy": { + "type": "array", + "description": "Array of extra objects to deploy with the release", + "default": [], + "items": {} + }, + "diagnosticMode": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable diagnostic mode (all probes will be disabled and the command will be overridden)", + "default": false + }, + "command": { + "type": "array", + "description": "Command to override all containers in the chart release", + "default": [ + "sleep" + ], + "items": { + "type": "string" + } + }, + "args": { + "type": "array", + "description": "Args to override all containers in the chart release", + "default": [ + "infinity" + ], + "items": { + "type": "string" + } + } + } + }, + "shuffle": { + "type": "object", + "properties": { + "baseUrl": { + "type": "string", + "description": "The external base URL under which Shuffle is reachable.", + "default": "" + }, + "org": { + "type": "string", + "description": "Default shuffle organization", + "default": "Shuffle" + }, + "appRegistry": { + "type": "string", + "description": "The registry from / to which shuffle apps are pulled / pushed", + "default": "" + }, + "timezone": { + "type": "string", + "description": "The timezone used by Shuffle", + "default": "Europe/Berlin" + } + } + }, + "backend": { + "type": "object", + "properties": { + "image": { + "type": "object", + "properties": { + "registry": { + "type": "string", + "description": "backend image registry", + "default": "ghcr.io" + }, + "repository": { + "type": "string", + "description": "backend image repository", + "default": "shuffle/shuffle-backend" + }, + "digest": { + "type": "string", + "description": "backend image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag image tag (immutable tags are recommended)", + "default": "" + }, + "pullPolicy": { + "type": "string", + "description": "backend image pull policy", + "default": "IfNotPresent" + }, + "pullSecrets": { + "type": "array", + "description": "backend image pull secrets", + "default": [], + "items": {} + } + } + }, + "replicaCount": { + "type": "number", + "description": "Number of backend replicas to deploy", + "default": 1 + }, + "containerPorts": { + "type": "object", + "properties": { + "http": { + "type": "number", + "description": "backend HTTP container port", + "default": 5001 + } + } + }, + "extraContainerPorts": { + "type": "array", + "description": "Optionally specify extra list of additional ports for backend containers", + "default": [], + "items": {} + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable livenessProbe on backend containers", + "default": false + }, + "initialDelaySeconds": { + "type": "number", + "description": "Initial delay seconds for livenessProbe", + "default": 0 + }, + "periodSeconds": { + "type": "number", + "description": "Period seconds for livenessProbe", + "default": 15 + }, + "timeoutSeconds": { + "type": "number", + "description": "Timeout seconds for livenessProbe", + "default": 1 + }, + "failureThreshold": { + "type": "number", + "description": "Failure threshold for livenessProbe", + "default": 4 + }, + "successThreshold": { + "type": "number", + "description": "Success threshold for livenessProbe", + "default": 1 + } + } + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable readinessProbe on backend containers", + "default": false + }, + "initialDelaySeconds": { + "type": "number", + "description": "Initial delay seconds for readinessProbe", + "default": 0 + }, + "periodSeconds": { + "type": "number", + "description": "Period seconds for readinessProbe", + "default": 5 + }, + "timeoutSeconds": { + "type": "number", + "description": "Timeout seconds for readinessProbe", + "default": 1 + }, + "failureThreshold": { + "type": "number", + "description": "Failure threshold for readinessProbe", + "default": 3 + }, + "successThreshold": { + "type": "number", + "description": "Success threshold for readinessProbe", + "default": 1 + } + } + }, + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable startupProbe on backend containers", + "default": false + }, + "initialDelaySeconds": { + "type": "number", + "description": "Initial delay seconds for startupProbe", + "default": 0 + }, + "periodSeconds": { + "type": "number", + "description": "Period seconds for startupProbe", + "default": 1 + }, + "timeoutSeconds": { + "type": "number", + "description": "Timeout seconds for startupProbe", + "default": 1 + }, + "failureThreshold": { + "type": "number", + "description": "Failure threshold for startupProbe", + "default": 60 + }, + "successThreshold": { + "type": "number", + "description": "Success threshold for startupProbe", + "default": 1 + } + } + }, + "customLivenessProbe": { + "type": "object", + "description": "Custom livenessProbe that overrides the default one", + "default": {} + }, + "customReadinessProbe": { + "type": "object", + "description": "Custom readinessProbe that overrides the default one", + "default": {} + }, + "customStartupProbe": { + "type": "object", + "description": "Custom startupProbe that overrides the default one", + "default": {} + }, + "resourcesPreset": { + "type": "string", + "description": "Set backend container resources according to one common preset (allowed values: none, nano, small, medium, large, xlarge, 2xlarge). This is ignored if backend.resources is set (backend.resources is recommended for production).", + "default": "small" + }, + "resources": { + "type": "object", + "description": "Set backend container requests and limits for different resources like CPU or memory (essential for production workloads)", + "default": {} + }, + "podSecurityContext": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable backend pods' Security Context", + "default": true + }, + "fsGroupChangePolicy": { + "type": "string", + "description": "Set filesystem group change policy for backend pods", + "default": "Always" + }, + "sysctls": { + "type": "array", + "description": "Set kernel settings using the sysctl interface for backend pods", + "default": [], + "items": {} + }, + "supplementalGroups": { + "type": "array", + "description": "Set filesystem extra groups for backend pods", + "default": [], + "items": {} + }, + "fsGroup": { + "type": "number", + "description": "Set fsGroup in backend pods' Security Context", + "default": 1001 + } + } + }, + "containerSecurityContext": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enabled backend container' Security Context", + "default": true + }, + "runAsUser": { + "type": "number", + "description": "Set runAsUser in backend container' Security Context", + "default": 1000 + }, + "runAsGroup": { + "type": "number", + "description": "Set runAsGroup in backend container' Security Context", + "default": 1000 + }, + "runAsNonRoot": { + "type": "boolean", + "description": "Set runAsNonRoot in backend container' Security Context", + "default": true + }, + "readOnlyRootFilesystem": { + "type": "boolean", + "description": "Set readOnlyRootFilesystem in backend container' Security Context", + "default": true + }, + "privileged": { + "type": "boolean", + "description": "Set privileged in backend container' Security Context", + "default": false + }, + "allowPrivilegeEscalation": { + "type": "boolean", + "description": "Set allowPrivilegeEscalation in backend container' Security Context", + "default": false + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "description": "List of capabilities to be dropped in backend container", + "default": [ + "ALL" + ], + "items": { + "type": "string" + } + } + } + }, + "seccompProfile": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Set seccomp profile in backend container", + "default": "RuntimeDefault" + } + } + } + } + }, + "command": { + "type": "array", + "description": "Override default backend container command (useful when using custom images)", + "default": [], + "items": {} + }, + "args": { + "type": "array", + "description": "Override default backend container args (useful when using custom images)", + "default": [], + "items": {} + }, + "automountServiceAccountToken": { + "type": "boolean", + "description": "Mount Service Account token in backend pods", + "default": true + }, + "hostAliases": { + "type": "array", + "description": "backend pods host aliases", + "default": [], + "items": {} + }, + "daemonsetAnnotations": { + "type": "object", + "description": "Annotations for backend daemonset", + "default": {} + }, + "deploymentAnnotations": { + "type": "object", + "description": "Annotations for backend deployment", + "default": {} + }, + "statefulsetAnnotations": { + "type": "object", + "description": "Annotations for backend statefulset", + "default": {} + }, + "podLabels": { + "type": "object", + "description": "Extra labels for backend pods", + "default": {} + }, + "podAnnotations": { + "type": "object", + "description": "Annotations for backend pods", + "default": {} + }, + "podAffinityPreset": { + "type": "string", + "description": "Pod affinity preset. Ignored if `backend.affinity` is set. Allowed values: `soft` or `hard`", + "default": "" + }, + "podAntiAffinityPreset": { + "type": "string", + "description": "Pod anti-affinity preset. Ignored if `backend.affinity` is set. Allowed values: `soft` or `hard`", + "default": "soft" + }, + "nodeAffinityPreset": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Node affinity preset type. Ignored if `backend.affinity` is set. Allowed values: `soft` or `hard`", + "default": "" + }, + "key": { + "type": "string", + "description": "Node label key to match. Ignored if `backend.affinity` is set", + "default": "" + }, + "values": { + "type": "array", + "description": "Node label values to match. Ignored if `backend.affinity` is set", + "default": [], + "items": {} + } + } + }, + "affinity": { + "type": "object", + "description": "Affinity for backend pods assignment", + "default": {} + }, + "nodeSelector": { + "type": "object", + "description": "Node labels for backend pods assignment", + "default": {} + }, + "tolerations": { + "type": "array", + "description": "Tolerations for backend pods assignment", + "default": [], + "items": {} + }, + "updateStrategy": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "backend statefulset strategy type", + "default": "RollingUpdate" + } + } + }, + "podManagementPolicy": { + "type": "string", + "description": "Pod management policy for backend statefulset", + "default": "OrderedReady" + }, + "priorityClassName": { + "type": "string", + "description": "backend pods' priorityClassName", + "default": "" + }, + "topologySpreadConstraints": { + "type": "array", + "description": "Topology Spread Constraints for backend pod assignment spread across your cluster among failure-domains", + "default": [], + "items": {} + }, + "schedulerName": { + "type": "string", + "description": "Name of the k8s scheduler (other than default) for backend pods", + "default": "" + }, + "terminationGracePeriodSeconds": { + "type": "string", + "description": "Seconds backend pods need to terminate gracefully", + "default": "" + }, + "lifecycleHooks": { + "type": "object", + "description": "for backend containers to automate configuration before or after startup", + "default": {} + }, + "extraEnvVars": { + "type": "array", + "description": "Array with extra environment variables to add to backend containers", + "default": [], + "items": {} + }, + "extraEnvVarsCM": { + "type": "string", + "description": "Name of existing ConfigMap containing extra env vars for backend containers", + "default": "" + }, + "extraEnvVarsSecret": { + "type": "string", + "description": "Name of existing Secret containing extra env vars for backend containers", + "default": "" + }, + "extraVolumes": { + "type": "array", + "description": "Optionally specify extra list of additional volumes for the backend pods", + "default": [], + "items": {} + }, + "extraVolumeMounts": { + "type": "array", + "description": "Optionally specify extra list of additional volumeMounts for the backend containers", + "default": [], + "items": {} + }, + "sidecars": { + "type": "array", + "description": "Add additional sidecar containers to the backend pods", + "default": [], + "items": {} + }, + "initContainers": { + "type": "array", + "description": "Add additional init containers to the backend pods", + "default": [], + "items": {} + }, + "pdb": { + "type": "object", + "properties": { + "create": { + "type": "boolean", + "description": "Enable/disable a Pod Disruption Budget creation", + "default": true + }, + "minAvailable": { + "type": "string", + "description": "Minimum number/percentage of pods that should remain scheduled", + "default": "" + }, + "maxUnavailable": { + "type": "string", + "description": "Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `backend.pdb.minAvailable` and `backend.pdb.maxUnavailable` are empty.", + "default": "" + } + } + }, + "autoscaling": { + "type": "object", + "properties": { + "vpa": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable VPA for backend pods", + "default": false + }, + "annotations": { + "type": "object", + "description": "Annotations for VPA resource", + "default": {} + }, + "controlledResources": { + "type": "array", + "description": "VPA List of resources that the vertical pod autoscaler can control. Defaults to cpu and memory", + "default": [], + "items": {} + }, + "maxAllowed": { + "type": "object", + "description": "VPA Max allowed resources for the pod", + "default": {} + }, + "minAllowed": { + "type": "object", + "description": "VPA Min allowed resources for the pod", + "default": {} + }, + "updatePolicy": { + "type": "object", + "properties": { + "updateMode": { + "type": "string", + "description": "Autoscaling update policy", + "default": "Auto" + } + } + } + } + }, + "hpa": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable HPA for backend pods", + "default": false + }, + "minReplicas": { + "type": "string", + "description": "Minimum number of replicas", + "default": "" + }, + "maxReplicas": { + "type": "string", + "description": "Maximum number of replicas", + "default": "" + }, + "targetCPU": { + "type": "string", + "description": "Target CPU utilization percentage", + "default": "" + }, + "targetMemory": { + "type": "string", + "description": "Target Memory utilization percentage", + "default": "" + } + } + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "create": { + "type": "boolean", + "description": "Specifies whether a ServiceAccount should be created", + "default": true + }, + "name": { + "type": "string", + "description": "The name of the ServiceAccount to use.", + "default": "" + }, + "annotations": { + "type": "object", + "description": "Additional Service Account annotations (evaluated as a template)", + "default": {} + }, + "automountServiceAccountToken": { + "type": "boolean", + "description": "Automount service account token for the backend service account", + "default": true + }, + "imagePullSecrets": { + "type": "array", + "description": "Add image pull secrets to the backend service account", + "default": [], + "items": {} + } + } + }, + "rbac": { + "type": "object", + "properties": { + "create": { + "type": "boolean", + "description": "Specifies whether RBAC resources should be created", + "default": true + } + } + }, + "networkPolicy": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Specifies whether a NetworkPolicy should be created", + "default": true + }, + "allowExternal": { + "type": "boolean", + "description": "Don't require server label for connections", + "default": true + }, + "allowExternalEgress": { + "type": "boolean", + "description": "Allow the pod to access any range of port and all destinations.", + "default": true + }, + "extraIngress": { + "type": "array", + "description": "Add extra ingress rules to the NetworkPolicy", + "default": [], + "items": {} + }, + "extraEgress": { + "type": "array", + "description": "Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true)", + "default": [], + "items": {} + } + } + }, + "cleanupSchedule": { + "type": "number", + "description": "The interval in seconds at which the cleanup job runs", + "default": 300 + }, + "openSearch": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "The URL at which OpenSearch is available", + "default": "http://{{ .Release.Name }}-opensearch:9200" + }, + "username": { + "type": "string", + "description": "The username that is used for authenticating with OpenSearch", + "default": "admin" + }, + "certificateFile": { + "type": "string", + "description": "The path to a custom OpenSearch certificate file", + "default": "" + }, + "skipSSLVerify": { + "type": "boolean", + "description": "Skip SSL verification", + "default": false + }, + "indexPrefix": { + "type": "string", + "description": "A prefix for OpenSearch indices", + "default": "" + } + } + }, + "apps": { + "type": "object", + "properties": { + "downloadLocation": { + "type": "string", + "description": "The location to a git repository from which default appps are downloaded on startup.", + "default": "https://github.com/shuffle/python-apps" + }, + "downloadBranch": { + "type": "string", + "description": "The branch from which apps should be downloaded on startup.", + "default": "master" + }, + "forceUpdate": { + "type": "boolean", + "description": "Force an update of apps on startup.", + "default": false + } + } + } + } + }, + "frontend": { + "type": "object", + "properties": { + "image": { + "type": "object", + "properties": { + "registry": { + "type": "string", + "description": "frontend image registry", + "default": "ghcr.io" + }, + "repository": { + "type": "string", + "description": "frontend image repository", + "default": "shuffle/shuffle-frontend" + }, + "digest": { + "type": "string", + "description": "frontend image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag image tag (immutable tags are recommended)", + "default": "" + }, + "pullPolicy": { + "type": "string", + "description": "frontend image pull policy", + "default": "IfNotPresent" + }, + "pullSecrets": { + "type": "array", + "description": "frontend image pull secrets", + "default": [], + "items": {} + } + } + }, + "replicaCount": { + "type": "number", + "description": "Number of frontend replicas to deploy", + "default": 1 + }, + "containerPorts": { + "type": "object", + "properties": { + "http": { + "type": "number", + "description": "frontend HTTP container port", + "default": 80 + }, + "https": { + "type": "number", + "description": "frontend HTTPS container port", + "default": 443 + } + } + }, + "extraContainerPorts": { + "type": "array", + "description": "Optionally specify extra list of additional ports for frontend containers", + "default": [], + "items": {} + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable livenessProbe on frontend containers", + "default": false + }, + "initialDelaySeconds": { + "type": "number", + "description": "Initial delay seconds for livenessProbe", + "default": 0 + }, + "periodSeconds": { + "type": "number", + "description": "Period seconds for livenessProbe", + "default": 15 + }, + "timeoutSeconds": { + "type": "number", + "description": "Timeout seconds for livenessProbe", + "default": 1 + }, + "failureThreshold": { + "type": "number", + "description": "Failure threshold for livenessProbe", + "default": 4 + }, + "successThreshold": { + "type": "number", + "description": "Success threshold for livenessProbe", + "default": 1 + } + } + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable readinessProbe on frontend containers", + "default": false + }, + "initialDelaySeconds": { + "type": "number", + "description": "Initial delay seconds for readinessProbe", + "default": 0 + }, + "periodSeconds": { + "type": "number", + "description": "Period seconds for readinessProbe", + "default": 5 + }, + "timeoutSeconds": { + "type": "number", + "description": "Timeout seconds for readinessProbe", + "default": 1 + }, + "failureThreshold": { + "type": "number", + "description": "Failure threshold for readinessProbe", + "default": 3 + }, + "successThreshold": { + "type": "number", + "description": "Success threshold for readinessProbe", + "default": 1 + } + } + }, + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable startupProbe on frontend containers", + "default": false + }, + "initialDelaySeconds": { + "type": "number", + "description": "Initial delay seconds for startupProbe", + "default": 0 + }, + "periodSeconds": { + "type": "number", + "description": "Period seconds for startupProbe", + "default": 1 + }, + "timeoutSeconds": { + "type": "number", + "description": "Timeout seconds for startupProbe", + "default": 1 + }, + "failureThreshold": { + "type": "number", + "description": "Failure threshold for startupProbe", + "default": 60 + }, + "successThreshold": { + "type": "number", + "description": "Success threshold for startupProbe", + "default": 1 + } + } + }, + "customLivenessProbe": { + "type": "object", + "description": "Custom livenessProbe that overrides the default one", + "default": {} + }, + "customReadinessProbe": { + "type": "object", + "description": "Custom readinessProbe that overrides the default one", + "default": {} + }, + "customStartupProbe": { + "type": "object", + "description": "Custom startupProbe that overrides the default one", + "default": {} + }, + "resourcesPreset": { + "type": "string", + "description": "Set frontend container resources according to one common preset (allowed values: none, nano, small, medium, large, xlarge, 2xlarge). This is ignored if frontend.resources is set (frontend.resources is recommended for production).", + "default": "nano" + }, + "resources": { + "type": "object", + "description": "Set frontend container requests and limits for different resources like CPU or memory (essential for production workloads)", + "default": {} + }, + "podSecurityContext": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable frontend pods' Security Context", + "default": false + }, + "fsGroupChangePolicy": { + "type": "string", + "description": "Set filesystem group change policy for frontend pods", + "default": "Always" + }, + "sysctls": { + "type": "array", + "description": "Set kernel settings using the sysctl interface for frontend pods", + "default": [], + "items": {} + }, + "supplementalGroups": { + "type": "array", + "description": "Set filesystem extra groups for frontend pods", + "default": [], + "items": {} + }, + "fsGroup": { + "type": "number", + "description": "Set fsGroup in frontend pods' Security Context", + "default": 1001 + } + } + }, + "containerSecurityContext": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enabled frontend container' Security Context", + "default": false + }, + "runAsUser": { + "type": "number", + "description": "Set runAsUser in frontend container' Security Context", + "default": 101 + }, + "runAsGroup": { + "type": "number", + "description": "Set runAsGroup in frontend container' Security Context", + "default": 101 + }, + "runAsNonRoot": { + "type": "boolean", + "description": "Set runAsNonRoot in frontend container' Security Context", + "default": true + }, + "readOnlyRootFilesystem": { + "type": "boolean", + "description": "Set readOnlyRootFilesystem in frontend container' Security Context", + "default": true + }, + "privileged": { + "type": "boolean", + "description": "Set privileged in frontend container' Security Context", + "default": false + }, + "allowPrivilegeEscalation": { + "type": "boolean", + "description": "Set allowPrivilegeEscalation in frontend container' Security Context", + "default": false + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "description": "List of capabilities to be dropped in frontend container", + "default": [ + "ALL" + ], + "items": { + "type": "string" + } + } + } + }, + "seccompProfile": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Set seccomp profile in frontend container", + "default": "RuntimeDefault" + } + } + } + } + }, + "command": { + "type": "array", + "description": "Override default frontend container command (useful when using custom images)", + "default": [], + "items": {} + }, + "args": { + "type": "array", + "description": "Override default frontend container args (useful when using custom images)", + "default": [], + "items": {} + }, + "automountServiceAccountToken": { + "type": "boolean", + "description": "Mount Service Account token in frontend pods", + "default": false + }, + "hostAliases": { + "type": "array", + "description": "frontend pods host aliases", + "default": [], + "items": {} + }, + "daemonsetAnnotations": { + "type": "object", + "description": "Annotations for frontend daemonset", + "default": {} + }, + "deploymentAnnotations": { + "type": "object", + "description": "Annotations for frontend deployment", + "default": {} + }, + "statefulsetAnnotations": { + "type": "object", + "description": "Annotations for frontend statefulset", + "default": {} + }, + "podLabels": { + "type": "object", + "description": "Extra labels for frontend pods", + "default": {} + }, + "podAnnotations": { + "type": "object", + "description": "Annotations for frontend pods", + "default": {} + }, + "podAffinityPreset": { + "type": "string", + "description": "Pod affinity preset. Ignored if `frontend.affinity` is set. Allowed values: `soft` or `hard`", + "default": "" + }, + "podAntiAffinityPreset": { + "type": "string", + "description": "Pod anti-affinity preset. Ignored if `frontend.affinity` is set. Allowed values: `soft` or `hard`", + "default": "soft" + }, + "nodeAffinityPreset": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Node affinity preset type. Ignored if `frontend.affinity` is set. Allowed values: `soft` or `hard`", + "default": "" + }, + "key": { + "type": "string", + "description": "Node label key to match. Ignored if `frontend.affinity` is set", + "default": "" + }, + "values": { + "type": "array", + "description": "Node label values to match. Ignored if `frontend.affinity` is set", + "default": [], + "items": {} + } + } + }, + "affinity": { + "type": "object", + "description": "Affinity for frontend pods assignment", + "default": {} + }, + "nodeSelector": { + "type": "object", + "description": "Node labels for frontend pods assignment", + "default": {} + }, + "tolerations": { + "type": "array", + "description": "Tolerations for frontend pods assignment", + "default": [], + "items": {} + }, + "updateStrategy": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "frontend statefulset strategy type", + "default": "RollingUpdate" + } + } + }, + "podManagementPolicy": { + "type": "string", + "description": "Pod management policy for frontend statefulset", + "default": "OrderedReady" + }, + "priorityClassName": { + "type": "string", + "description": "frontend pods' priorityClassName", + "default": "" + }, + "topologySpreadConstraints": { + "type": "array", + "description": "Topology Spread Constraints for frontend pod assignment spread across your cluster among failure-domains", + "default": [], + "items": {} + }, + "schedulerName": { + "type": "string", + "description": "Name of the k8s scheduler (other than default) for frontend pods", + "default": "" + }, + "terminationGracePeriodSeconds": { + "type": "string", + "description": "Seconds frontend pods need to terminate gracefully", + "default": "" + }, + "lifecycleHooks": { + "type": "object", + "description": "for frontend containers to automate configuration before or after startup", + "default": {} + }, + "extraEnvVars": { + "type": "array", + "description": "Array with extra environment variables to add to frontend containers", + "default": [], + "items": {} + }, + "extraEnvVarsCM": { + "type": "string", + "description": "Name of existing ConfigMap containing extra env vars for frontend containers", + "default": "" + }, + "extraEnvVarsSecret": { + "type": "string", + "description": "Name of existing Secret containing extra env vars for frontend containers", + "default": "" + }, + "extraVolumes": { + "type": "array", + "description": "Optionally specify extra list of additional volumes for the frontend pods", + "default": [], + "items": {} + }, + "extraVolumeMounts": { + "type": "array", + "description": "Optionally specify extra list of additional volumeMounts for the frontend containers", + "default": [], + "items": {} + }, + "sidecars": { + "type": "array", + "description": "Add additional sidecar containers to the frontend pods", + "default": [], + "items": {} + }, + "initContainers": { + "type": "array", + "description": "Add additional init containers to the frontend pods", + "default": [], + "items": {} + }, + "pdb": { + "type": "object", + "properties": { + "create": { + "type": "boolean", + "description": "Enable/disable a Pod Disruption Budget creation", + "default": true + }, + "minAvailable": { + "type": "string", + "description": "Minimum number/percentage of pods that should remain scheduled", + "default": "" + }, + "maxUnavailable": { + "type": "string", + "description": "Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `frontend.pdb.minAvailable` and `frontend.pdb.maxUnavailable` are empty.", + "default": "" + } + } + }, + "autoscaling": { + "type": "object", + "properties": { + "vpa": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable VPA for frontend pods", + "default": false + }, + "annotations": { + "type": "object", + "description": "Annotations for VPA resource", + "default": {} + }, + "controlledResources": { + "type": "array", + "description": "VPA List of resources that the vertical pod autoscaler can control. Defaults to cpu and memory", + "default": [], + "items": {} + }, + "maxAllowed": { + "type": "object", + "description": "VPA Max allowed resources for the pod", + "default": {} + }, + "minAllowed": { + "type": "object", + "description": "VPA Min allowed resources for the pod", + "default": {} + }, + "updatePolicy": { + "type": "object", + "properties": { + "updateMode": { + "type": "string", + "description": "Autoscaling update policy", + "default": "Auto" + } + } + } + } + }, + "hpa": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable HPA for frontend pods", + "default": false + }, + "minReplicas": { + "type": "string", + "description": "Minimum number of replicas", + "default": "" + }, + "maxReplicas": { + "type": "string", + "description": "Maximum number of replicas", + "default": "" + }, + "targetCPU": { + "type": "string", + "description": "Target CPU utilization percentage", + "default": "" + }, + "targetMemory": { + "type": "string", + "description": "Target Memory utilization percentage", + "default": "" + } + } + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "create": { + "type": "boolean", + "description": "Specifies whether a ServiceAccount should be created", + "default": true + }, + "name": { + "type": "string", + "description": "The name of the ServiceAccount to use.", + "default": "" + }, + "annotations": { + "type": "object", + "description": "Additional Service Account annotations (evaluated as a template)", + "default": {} + }, + "automountServiceAccountToken": { + "type": "boolean", + "description": "Automount service account token for the frontend service account", + "default": true + }, + "imagePullSecrets": { + "type": "array", + "description": "Add image pull secrets to the frontend service account", + "default": [], + "items": {} + } + } + }, + "networkPolicy": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Specifies whether a NetworkPolicy should be created", + "default": true + }, + "allowExternal": { + "type": "boolean", + "description": "Don't require server label for connections", + "default": true + }, + "allowExternalEgress": { + "type": "boolean", + "description": "Allow the pod to access any range of port and all destinations.", + "default": true + }, + "extraIngress": { + "type": "array", + "description": "Add extra ingress rules to the NetworkPolicy", + "default": [], + "items": {} + }, + "extraEgress": { + "type": "array", + "description": "Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true)", + "default": [], + "items": {} + } + } + } + } + }, + "orborus": { + "type": "object", + "properties": { + "image": { + "type": "object", + "properties": { + "registry": { + "type": "string", + "description": "orborus image registry", + "default": "ghcr.io" + }, + "repository": { + "type": "string", + "description": "orborus image repository", + "default": "shuffle/shuffle-orborus" + }, + "digest": { + "type": "string", + "description": "orborus image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag image tag (immutable tags are recommended)", + "default": "" + }, + "pullPolicy": { + "type": "string", + "description": "orborus image pull policy", + "default": "IfNotPresent" + }, + "pullSecrets": { + "type": "array", + "description": "orborus image pull secrets", + "default": [], + "items": {} + } + } + }, + "replicaCount": { + "type": "number", + "description": "Number of orborus replicas to deploy", + "default": 1 + }, + "containerPorts": { + "type": "object", + "properties": { + "http": { + "type": "number", + "description": "orborus HTTP container port", + "default": 8080 + } + } + }, + "extraContainerPorts": { + "type": "array", + "description": "Optionally specify extra list of additional ports for orborus containers", + "default": [], + "items": {} + }, + "livenessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable livenessProbe on orborus containers", + "default": false + }, + "initialDelaySeconds": { + "type": "number", + "description": "Initial delay seconds for livenessProbe", + "default": 0 + }, + "periodSeconds": { + "type": "number", + "description": "Period seconds for livenessProbe", + "default": 15 + }, + "timeoutSeconds": { + "type": "number", + "description": "Timeout seconds for livenessProbe", + "default": 1 + }, + "failureThreshold": { + "type": "number", + "description": "Failure threshold for livenessProbe", + "default": 4 + }, + "successThreshold": { + "type": "number", + "description": "Success threshold for livenessProbe", + "default": 1 + } + } + }, + "readinessProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable readinessProbe on orborus containers", + "default": false + }, + "initialDelaySeconds": { + "type": "number", + "description": "Initial delay seconds for readinessProbe", + "default": 0 + }, + "periodSeconds": { + "type": "number", + "description": "Period seconds for readinessProbe", + "default": 5 + }, + "timeoutSeconds": { + "type": "number", + "description": "Timeout seconds for readinessProbe", + "default": 1 + }, + "failureThreshold": { + "type": "number", + "description": "Failure threshold for readinessProbe", + "default": 3 + }, + "successThreshold": { + "type": "number", + "description": "Success threshold for readinessProbe", + "default": 1 + } + } + }, + "startupProbe": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable startupProbe on orborus containers", + "default": false + }, + "initialDelaySeconds": { + "type": "number", + "description": "Initial delay seconds for startupProbe", + "default": 0 + }, + "periodSeconds": { + "type": "number", + "description": "Period seconds for startupProbe", + "default": 1 + }, + "timeoutSeconds": { + "type": "number", + "description": "Timeout seconds for startupProbe", + "default": 1 + }, + "failureThreshold": { + "type": "number", + "description": "Failure threshold for startupProbe", + "default": 60 + }, + "successThreshold": { + "type": "number", + "description": "Success threshold for startupProbe", + "default": 1 + } + } + }, + "customLivenessProbe": { + "type": "object", + "description": "Custom livenessProbe that overrides the default one", + "default": {} + }, + "customReadinessProbe": { + "type": "object", + "description": "Custom readinessProbe that overrides the default one", + "default": {} + }, + "customStartupProbe": { + "type": "object", + "description": "Custom startupProbe that overrides the default one", + "default": {} + }, + "resourcesPreset": { + "type": "string", + "description": "Set orborus container resources according to one common preset (allowed values: none, nano, small, medium, large, xlarge, 2xlarge). This is ignored if orborus.resources is set (orborus.resources is recommended for production).", + "default": "nano" + }, + "resources": { + "type": "object", + "description": "Set orborus container requests and limits for different resources like CPU or memory (essential for production workloads)", + "default": {} + }, + "podSecurityContext": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable orborus pods' Security Context", + "default": true + }, + "fsGroupChangePolicy": { + "type": "string", + "description": "Set filesystem group change policy for orborus pods", + "default": "Always" + }, + "sysctls": { + "type": "array", + "description": "Set kernel settings using the sysctl interface for orborus pods", + "default": [], + "items": {} + }, + "supplementalGroups": { + "type": "array", + "description": "Set filesystem extra groups for orborus pods", + "default": [], + "items": {} + }, + "fsGroup": { + "type": "number", + "description": "Set fsGroup in orborus pods' Security Context", + "default": 1001 + } + } + }, + "containerSecurityContext": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enabled orborus container' Security Context", + "default": true + }, + "runAsUser": { + "type": "number", + "description": "Set runAsUser in orborus container' Security Context", + "default": 101 + }, + "runAsGroup": { + "type": "number", + "description": "Set runAsGroup in orborus container' Security Context", + "default": 101 + }, + "runAsNonRoot": { + "type": "boolean", + "description": "Set runAsNonRoot in orborus container' Security Context", + "default": true + }, + "readOnlyRootFilesystem": { + "type": "boolean", + "description": "Set readOnlyRootFilesystem in orborus container' Security Context", + "default": true + }, + "privileged": { + "type": "boolean", + "description": "Set privileged in orborus container' Security Context", + "default": false + }, + "allowPrivilegeEscalation": { + "type": "boolean", + "description": "Set allowPrivilegeEscalation in orborus container' Security Context", + "default": false + }, + "capabilities": { + "type": "object", + "properties": { + "drop": { + "type": "array", + "description": "List of capabilities to be dropped in orborus container", + "default": [ + "ALL" + ], + "items": { + "type": "string" + } + } + } + }, + "seccompProfile": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Set seccomp profile in orborus container", + "default": "RuntimeDefault" + } + } + } + } + }, + "command": { + "type": "array", + "description": "Override default orborus container command (useful when using custom images)", + "default": [], + "items": {} + }, + "args": { + "type": "array", + "description": "Override default orborus container args (useful when using custom images)", + "default": [], + "items": {} + }, + "automountServiceAccountToken": { + "type": "boolean", + "description": "Mount Service Account token in orborus pods", + "default": true + }, + "hostAliases": { + "type": "array", + "description": "orborus pods host aliases", + "default": [], + "items": {} + }, + "daemonsetAnnotations": { + "type": "object", + "description": "Annotations for orborus daemonset", + "default": {} + }, + "deploymentAnnotations": { + "type": "object", + "description": "Annotations for orborus deployment", + "default": {} + }, + "statefulsetAnnotations": { + "type": "object", + "description": "Annotations for orborus statefulset", + "default": {} + }, + "podLabels": { + "type": "object", + "description": "Extra labels for orborus pods", + "default": {} + }, + "podAnnotations": { + "type": "object", + "description": "Annotations for orborus pods", + "default": {} + }, + "podAffinityPreset": { + "type": "string", + "description": "Pod affinity preset. Ignored if `orborus.affinity` is set. Allowed values: `soft` or `hard`", + "default": "" + }, + "podAntiAffinityPreset": { + "type": "string", + "description": "Pod anti-affinity preset. Ignored if `orborus.affinity` is set. Allowed values: `soft` or `hard`", + "default": "soft" + }, + "nodeAffinityPreset": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Node affinity preset type. Ignored if `orborus.affinity` is set. Allowed values: `soft` or `hard`", + "default": "" + }, + "key": { + "type": "string", + "description": "Node label key to match. Ignored if `orborus.affinity` is set", + "default": "" + }, + "values": { + "type": "array", + "description": "Node label values to match. Ignored if `orborus.affinity` is set", + "default": [], + "items": {} + } + } + }, + "affinity": { + "type": "object", + "description": "Affinity for orborus pods assignment", + "default": {} + }, + "nodeSelector": { + "type": "object", + "description": "Node labels for orborus pods assignment", + "default": {} + }, + "tolerations": { + "type": "array", + "description": "Tolerations for orborus pods assignment", + "default": [], + "items": {} + }, + "updateStrategy": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "orborus statefulset strategy type", + "default": "RollingUpdate" + } + } + }, + "podManagementPolicy": { + "type": "string", + "description": "Pod management policy for orborus statefulset", + "default": "OrderedReady" + }, + "priorityClassName": { + "type": "string", + "description": "orborus pods' priorityClassName", + "default": "" + }, + "topologySpreadConstraints": { + "type": "array", + "description": "Topology Spread Constraints for orborus pod assignment spread across your cluster among failure-domains", + "default": [], + "items": {} + }, + "schedulerName": { + "type": "string", + "description": "Name of the k8s scheduler (other than default) for orborus pods", + "default": "" + }, + "terminationGracePeriodSeconds": { + "type": "string", + "description": "Seconds orborus pods need to terminate gracefully", + "default": "" + }, + "lifecycleHooks": { + "type": "object", + "description": "for orborus containers to automate configuration before or after startup", + "default": {} + }, + "extraEnvVars": { + "type": "array", + "description": "Array with extra environment variables to add to orborus containers", + "default": [], + "items": {} + }, + "extraEnvVarsCM": { + "type": "string", + "description": "Name of existing ConfigMap containing extra env vars for orborus containers", + "default": "" + }, + "extraEnvVarsSecret": { + "type": "string", + "description": "Name of existing Secret containing extra env vars for orborus containers", + "default": "" + }, + "extraVolumes": { + "type": "array", + "description": "Optionally specify extra list of additional volumes for the orborus pods", + "default": [], + "items": {} + }, + "extraVolumeMounts": { + "type": "array", + "description": "Optionally specify extra list of additional volumeMounts for the orborus containers", + "default": [], + "items": {} + }, + "sidecars": { + "type": "array", + "description": "Add additional sidecar containers to the orborus pods", + "default": [], + "items": {} + }, + "initContainers": { + "type": "array", + "description": "Add additional init containers to the orborus pods", + "default": [], + "items": {} + }, + "pdb": { + "type": "object", + "properties": { + "create": { + "type": "boolean", + "description": "Enable/disable a Pod Disruption Budget creation", + "default": true + }, + "minAvailable": { + "type": "string", + "description": "Minimum number/percentage of pods that should remain scheduled", + "default": "" + }, + "maxUnavailable": { + "type": "string", + "description": "Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `orborus.pdb.minAvailable` and `orborus.pdb.maxUnavailable` are empty.", + "default": "" + } + } + }, + "autoscaling": { + "type": "object", + "properties": { + "vpa": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable VPA for orborus pods", + "default": false + }, + "annotations": { + "type": "object", + "description": "Annotations for VPA resource", + "default": {} + }, + "controlledResources": { + "type": "array", + "description": "VPA List of resources that the vertical pod autoscaler can control. Defaults to cpu and memory", + "default": [], + "items": {} + }, + "maxAllowed": { + "type": "object", + "description": "VPA Max allowed resources for the pod", + "default": {} + }, + "minAllowed": { + "type": "object", + "description": "VPA Min allowed resources for the pod", + "default": {} + }, + "updatePolicy": { + "type": "object", + "properties": { + "updateMode": { + "type": "string", + "description": "Autoscaling update policy", + "default": "Auto" + } + } + } + } + }, + "hpa": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable HPA for orborus pods", + "default": false + }, + "minReplicas": { + "type": "string", + "description": "Minimum number of replicas", + "default": "" + }, + "maxReplicas": { + "type": "string", + "description": "Maximum number of replicas", + "default": "" + }, + "targetCPU": { + "type": "string", + "description": "Target CPU utilization percentage", + "default": "" + }, + "targetMemory": { + "type": "string", + "description": "Target Memory utilization percentage", + "default": "" + } + } + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "create": { + "type": "boolean", + "description": "Specifies whether a ServiceAccount should be created", + "default": true + }, + "name": { + "type": "string", + "description": "The name of the ServiceAccount to use.", + "default": "" + }, + "annotations": { + "type": "object", + "description": "Additional Service Account annotations (evaluated as a template)", + "default": {} + }, + "automountServiceAccountToken": { + "type": "boolean", + "description": "Automount service account token for the orborus service account", + "default": true + }, + "imagePullSecrets": { + "type": "array", + "description": "Add image pull secrets to the orborus service account", + "default": [], + "items": {} + } + } + }, + "rbac": { + "type": "object", + "properties": { + "create": { + "type": "boolean", + "description": "Specifies whether RBAC resources should be created", + "default": true + } + } + }, + "networkPolicy": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Specifies whether a NetworkPolicy should be created", + "default": true + }, + "allowExternal": { + "type": "boolean", + "description": "Don't require server label for connections", + "default": true + }, + "allowExternalEgress": { + "type": "boolean", + "description": "Allow the pod to access any range of port and all destinations.", + "default": true + }, + "extraIngress": { + "type": "array", + "description": "Add extra ingress rules to the NetworkPolicy", + "default": [], + "items": {} + }, + "extraEgress": { + "type": "array", + "description": "Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true)", + "default": [], + "items": {} + } + } + } + } + }, + "worker": { + "type": "object", + "properties": { + "image": { + "type": "object", + "properties": { + "registry": { + "type": "string", + "description": "worker image registry", + "default": "ghcr.io" + }, + "repository": { + "type": "string", + "description": "worker image repository", + "default": "shuffle/shuffle-worker" + }, + "digest": { + "type": "string", + "description": "worker image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag image tag (immutable tags are recommended)", + "default": "" + } + } + }, + "serviceAccount": { + "type": "object", + "properties": { + "create": { + "type": "boolean", + "description": "Specifies whether a ServiceAccount should be created", + "default": true + }, + "name": { + "type": "string", + "description": "The name of the ServiceAccount to use.", + "default": "" + }, + "annotations": { + "type": "object", + "description": "Additional Service Account annotations (evaluated as a template)", + "default": {} + }, + "automountServiceAccountToken": { + "type": "boolean", + "description": "Automount service account token for the worker service account", + "default": true + }, + "imagePullSecrets": { + "type": "array", + "description": "Add image pull secrets to the worker service account", + "default": [], + "items": {} + } + } + }, + "rbac": { + "type": "object", + "properties": { + "create": { + "type": "boolean", + "description": "Specifies whether RBAC resources should be created", + "default": true + } + } + }, + "networkPolicy": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Specifies whether a NetworkPolicy should be created", + "default": true + }, + "allowExternal": { + "type": "boolean", + "description": "Don't require server label for connections", + "default": true + }, + "allowExternalEgress": { + "type": "boolean", + "description": "Allow the pod to access any range of port and all destinations.", + "default": true + }, + "extraIngress": { + "type": "array", + "description": "Add extra ingress rules to the NetworkPolicy", + "default": [], + "items": {} + }, + "extraEgress": { + "type": "array", + "description": "Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true)", + "default": [], + "items": {} + } + } + } + } + }, + "app": { + "type": "object", + "properties": { + "serviceAccount": { + "type": "object", + "properties": { + "create": { + "type": "boolean", + "description": "Specifies whether a ServiceAccount should be created", + "default": true + }, + "name": { + "type": "string", + "description": "The name of the ServiceAccount to use.", + "default": "" + }, + "annotations": { + "type": "object", + "description": "Additional Service Account annotations (evaluated as a template)", + "default": {} + }, + "automountServiceAccountToken": { + "type": "boolean", + "description": "Automount service account token for the app service account", + "default": true + }, + "imagePullSecrets": { + "type": "array", + "description": "Add image pull secrets to the app service account", + "default": [], + "items": {} + } + } + }, + "rbac": { + "type": "object", + "properties": { + "create": { + "type": "boolean", + "description": "Specifies whether RBAC resources should be created", + "default": true + } + } + }, + "networkPolicy": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Specifies whether a NetworkPolicy should be created", + "default": true + }, + "allowExternal": { + "type": "boolean", + "description": "Don't require server label for connections", + "default": true + }, + "allowExternalEgress": { + "type": "boolean", + "description": "Allow the pod to access any range of port and all destinations.", + "default": true + }, + "extraIngress": { + "type": "array", + "description": "Add extra ingress rules to the NetworkPolicy", + "default": [], + "items": {} + }, + "extraEgress": { + "type": "array", + "description": "Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true)", + "default": [], + "items": {} + } + } + } + } + }, + "ingress": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable ingress record generation for frontend and backend", + "default": false + }, + "pathType": { + "type": "string", + "description": "Ingress path type for the frontend path", + "default": "Prefix" + }, + "backendPathType": { + "type": "string", + "description": "Ingress path type for the backend path", + "default": "Prefix" + }, + "apiVersion": { + "type": "string", + "description": "Force Ingress API version (automatically detected if not set)", + "default": "" + }, + "hostname": { + "type": "string", + "description": "Default host for the ingress record", + "default": "shuffle.local" + }, + "ingressClassName": { + "type": "string", + "description": "IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+)", + "default": "nginx" + }, + "path": { + "type": "string", + "description": "Ingress path for Shuffle frontend", + "default": "\"/\"" + }, + "backendPath": { + "type": "string", + "description": "Ingress path for Shuffle backend", + "default": "\"/api/\"" + }, + "annotations": { + "type": "object", + "description": "Additional annotations for the Ingress resource.", + "default": {} + }, + "tls": { + "type": "boolean", + "description": "Enable TLS configuration for the host defined at `ingress.hostname` parameter", + "default": false + }, + "selfSigned": { + "type": "boolean", + "description": "Create a TLS secret for this ingress record using self-signed certificates generated by Helm", + "default": false + }, + "extraHosts": { + "type": "array", + "description": "An array with additional hostname(s) to be covered with the ingress record", + "default": [], + "items": {} + }, + "extraPaths": { + "type": "array", + "description": "An array with additional arbitrary paths that may need to be added to the ingress under the main host", + "default": [], + "items": {} + }, + "extraTls": { + "type": "array", + "description": "TLS configuration for additional hostname(s) to be covered with this ingress record", + "default": [], + "items": {} + }, + "secrets": { + "type": "array", + "description": "Custom TLS certificates as secrets", + "default": [], + "items": {} + }, + "extraRules": { + "type": "array", + "description": "Additional rules to be covered with this ingress record", + "default": [], + "items": {} + } + } + }, + "istio": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable creation of an Istio Gateway and VirtualService for frontend and backend", + "default": false + }, + "apiVersion": { + "type": "string", + "description": "The istio apiVersion to use for Gateway and VirtualService resources", + "default": "networking.istio.io/v1" + }, + "hosts": { + "type": "array", + "description": "One or more hosts exposed by Istio", + "default": [], + "items": {} + }, + "gateway": { + "type": "object", + "properties": { + "annotations": { + "type": "object", + "description": "Additional annotations for the Gateway resource", + "default": {} + }, + "http": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable HTTP server port 80", + "default": true + }, + "httpsRedirect": { + "type": "boolean", + "description": "If set to true, a 301 redirect is send for all HTTP connections", + "default": false + } + } + }, + "https": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable HTTPS server on port 443", + "default": false + }, + "tlsCredentialName": { + "type": "string", + "description": "The name of the secret that holds the TLS certs including the CA certificates.", + "default": "" + }, + "tlsCipherSuites": { + "type": "array", + "description": "If specified, only support the specified cipher list.", + "default": [], + "items": {} + } + } + }, + "extraServers": { + "type": "array", + "description": "Additional servers for the Gateway resource", + "default": [], + "items": {} + } + } + }, + "virtualService": { + "type": "object", + "properties": { + "annotations": { + "type": "object", + "description": "Additional annotations for the VirtualService resource.", + "default": {} + }, + "backendHeaders": { + "type": "object", + "description": "Header manipulation rules for backend traffic", + "default": {} + }, + "frontendHeaders": { + "type": "object", + "description": "Header manipulation rules for frontend traffic", + "default": {} + } + } + } + } + }, + "persistence": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable persistence using Persistent Volume Claims", + "default": true + }, + "apps": { + "type": "object", + "properties": { + "existingClaim": { + "type": "string", + "description": "Name of an existing PVC to use", + "default": "" + }, + "storageClass": { + "type": "string", + "description": "PVC Storage Class for shuffle-apps volume", + "default": "" + }, + "subPath": { + "type": "string", + "description": "The sub path used in the volume", + "default": "" + }, + "accessModes": { + "type": "array", + "description": "The access mode of the volume", + "default": [ + "ReadWriteOnce" + ], + "items": { + "type": "string" + } + }, + "size": { + "type": "string", + "description": "The size of the volume", + "default": "5Gi" + }, + "annotations": { + "type": "object", + "description": "Annotations for the PVC", + "default": {} + }, + "selector": { + "type": "object", + "description": "Selector to match an existing Persistent Volume", + "default": {} + } + } + }, + "appBuilder": { + "type": "object", + "properties": { + "storageClass": { + "type": "string", + "description": "PVC Storage Class for backend-apps-claim volume", + "default": "" + }, + "accessModes": { + "type": "array", + "description": "The access mode of the volume", + "default": [ + "ReadWriteOnce" + ], + "items": { + "type": "string" + } + }, + "size": { + "type": "string", + "description": "The size of the volume", + "default": "5Gi" + }, + "annotations": { + "type": "object", + "description": "Annotations for the PVC", + "default": {} + }, + "selector": { + "type": "object", + "description": "Selector to match an existing Persistent Volume", + "default": {} + } + } + }, + "files": { + "type": "object", + "properties": { + "existingClaim": { + "type": "string", + "description": "Name of an existing PVC to use", + "default": "" + }, + "storageClass": { + "type": "string", + "description": "PVC Storage Class for shuffle-files volume", + "default": "" + }, + "subPath": { + "type": "string", + "description": "The sub path used in the volume", + "default": "" + }, + "accessModes": { + "type": "array", + "description": "The access mode of the volume", + "default": [ + "ReadWriteOnce" + ], + "items": { + "type": "string" + } + }, + "size": { + "type": "string", + "description": "The size of the volume", + "default": "5Gi" + }, + "annotations": { + "type": "object", + "description": "Annotations for the PVC", + "default": {} + }, + "selector": { + "type": "object", + "description": "Selector to match an existing Persistent Volume", + "default": {} + } + } + } + } + }, + "volumePermissions": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable init container that changes the owner/group of the PV mount point to `runAsUser:fsGroup`", + "default": false + }, + "image": { + "type": "object", + "properties": { + "registry": { + "type": "string", + "description": "OS Shell + Utility image registry", + "default": "docker.io" + }, + "repository": { + "type": "string", + "description": "OS Shell + Utility image repository", + "default": "bitnami/os-shell" + }, + "pullPolicy": { + "type": "string", + "description": "OS Shell + Utility image pull policy", + "default": "IfNotPresent" + }, + "pullSecrets": { + "type": "array", + "description": "OS Shell + Utility image pull secrets", + "default": [], + "items": {} + } + } + }, + "resourcesPreset": { + "type": "string", + "description": "Set init container resources according to one common preset (allowed values: none, nano, small, medium, large, xlarge, 2xlarge). This is ignored if volumePermissions.resources is set (volumePermissions.resources is recommended for production).", + "default": "nano" + }, + "resources": { + "type": "object", + "description": "Set init container requests and limits for different resources like CPU or memory (essential for production workloads)", + "default": {} + }, + "containerSecurityContext": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enabled init container' Security Context", + "default": true + }, + "runAsUser": { + "type": "number", + "description": "Set init container's Security Context runAsUser", + "default": 0 + } + } + } + } + }, + "opensearch": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Switch to enable or disable the opensearch helm chart", + "default": true + } + } + }, + "vault": { + "type": "object", + "properties": { + "role": { + "type": "string", + "description": "Specify the Vault role, which should be used to get the secret from Vault.", + "default": "" + }, + "secrets": { + "type": "array", + "description": "A list of VaultSecrets to create", + "default": [], + "items": {} + } + } + } + } +} \ No newline at end of file diff --git a/functions/kubernetes/charts/shuffle/values.yaml b/functions/kubernetes/charts/shuffle/values.yaml new file mode 100644 index 00000000..35492f94 --- /dev/null +++ b/functions/kubernetes/charts/shuffle/values.yaml @@ -0,0 +1,1834 @@ +--- +## @section Global parameters +## Global Docker image parameters +## Please, note that this will override the image parameters, including dependencies, configured to use the global value +## Current available global Docker image parameters: imageRegistry, imagePullSecrets and storageClass +## + +## @param global.imageRegistry Global Docker image registry +## @param global.imagePullSecrets Global Docker registry secret names as an array +## @param global.defaultStorageClass Global default StorageClass for Persistent Volume(s) +## +global: + imageRegistry: "" + ## e.g: + ## imagePullSecrets: + ## - myRegistryKeySecretName + ## + imagePullSecrets: [] + defaultStorageClass: "" + ## Compatibility adaptations for Kubernetes platforms + ## + compatibility: + ## Compatibility adaptations for Openshift + ## + openshift: + ## @param global.compatibility.openshift.adaptSecurityContext Adapt the securityContext sections of the deployment to make them compatible with Openshift restricted-v2 SCC: remove runAsUser, runAsGroup and fsGroup and let the platform use their allowed default IDs. Possible values: auto (apply if the detected running cluster is Openshift), force (perform the adaptation always), disabled (do not perform adaptation) + ## + adaptSecurityContext: auto + ## @param global.compatibility.omitEmptySeLinuxOptions If set to true, removes the seLinuxOptions from the securityContexts when it is set to an empty object + ## + omitEmptySeLinuxOptions: false + +## @section Common parameters +## + +## @param kubeVersion Override Kubernetes version +## +kubeVersion: "" +## @param nameOverride String to partially override common.names.name +## +nameOverride: "" +## @param fullnameOverride String to fully override common.names.fullname +## +fullnameOverride: "" +## @param namespaceOverride String to fully override common.names.namespace +## +namespaceOverride: "" +## @param commonLabels Labels to add to all deployed objects +## +commonLabels: {} +## @param commonAnnotations Annotations to add to all deployed objects +## +commonAnnotations: {} +## @param clusterDomain Kubernetes cluster domain name +## +clusterDomain: cluster.local +## @param extraDeploy Array of extra objects to deploy with the release +## +extraDeploy: [] +## Diagnostic mode +## @param diagnosticMode.enabled Enable diagnostic mode (all probes will be disabled and the command will be overridden) +## @param diagnosticMode.command Command to override all containers in the chart release +## @param diagnosticMode.args Args to override all containers in the chart release +## +diagnosticMode: + enabled: false + command: + - sleep + args: + - infinity + +## @section Shared Shuffle Parameters +## +shuffle: + ## @param shuffle.baseUrl The external base URL under which Shuffle is reachable. + ## + baseUrl: "" + + ## ref: https://shuffler.io/docs/organizations + ## This chart only supports single-tenant deployments at the moment + ## @param shuffle.org Default shuffle organization + ## + org: Shuffle + + ## @param shuffle.appRegistry The registry from / to which shuffle apps are pulled / pushed + ## + appRegistry: "" + + ## @param shuffle.timezone The timezone used by Shuffle + ## + timezone: Europe/Berlin + +## @section backend Parameters +## +backend: + ## backend image + ## @param backend.image.registry backend image registry + ## @param backend.image.repository backend image repository + ## @skip backend.image.tag backend image tag (immutable tags are recommended) + ## @param backend.image.digest backend image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag image tag (immutable tags are recommended) + ## @param backend.image.pullPolicy backend image pull policy + ## @param backend.image.pullSecrets backend image pull secrets + ## + image: + registry: ghcr.io + repository: shuffle/shuffle-backend + tag: nightly + digest: "" + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## @param backend.replicaCount Number of backend replicas to deploy + ## + replicaCount: 1 + ## @param backend.containerPorts.http backend HTTP container port + ## + containerPorts: + http: 5001 + ## @param backend.extraContainerPorts Optionally specify extra list of additional ports for backend containers + ## e.g: + ## extraContainerPorts: + ## - name: myservice + ## containerPort: 9090 + ## + extraContainerPorts: [] + ## Configure extra options for backend containers' liveness and readiness probes + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes + ## @param backend.livenessProbe.enabled Enable livenessProbe on backend containers + ## @param backend.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe + ## @param backend.livenessProbe.periodSeconds Period seconds for livenessProbe + ## @param backend.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe + ## @param backend.livenessProbe.failureThreshold Failure threshold for livenessProbe + ## @param backend.livenessProbe.successThreshold Success threshold for livenessProbe + ## + livenessProbe: + enabled: false + initialDelaySeconds: 0 + periodSeconds: 15 + timeoutSeconds: 1 + failureThreshold: 4 + successThreshold: 1 + ## @param backend.readinessProbe.enabled Enable readinessProbe on backend containers + ## @param backend.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe + ## @param backend.readinessProbe.periodSeconds Period seconds for readinessProbe + ## @param backend.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe + ## @param backend.readinessProbe.failureThreshold Failure threshold for readinessProbe + ## @param backend.readinessProbe.successThreshold Success threshold for readinessProbe + ## + readinessProbe: + enabled: false + initialDelaySeconds: 0 + periodSeconds: 5 + timeoutSeconds: 1 + failureThreshold: 3 + successThreshold: 1 + ## @param backend.startupProbe.enabled Enable startupProbe on backend containers + ## @param backend.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe + ## @param backend.startupProbe.periodSeconds Period seconds for startupProbe + ## @param backend.startupProbe.timeoutSeconds Timeout seconds for startupProbe + ## @param backend.startupProbe.failureThreshold Failure threshold for startupProbe + ## @param backend.startupProbe.successThreshold Success threshold for startupProbe + ## + startupProbe: + enabled: false + initialDelaySeconds: 0 + periodSeconds: 1 + timeoutSeconds: 1 + failureThreshold: 60 + successThreshold: 1 + ## @param backend.customLivenessProbe Custom livenessProbe that overrides the default one + ## + customLivenessProbe: {} + ## @param backend.customReadinessProbe Custom readinessProbe that overrides the default one + ## + customReadinessProbe: {} + ## @param backend.customStartupProbe Custom startupProbe that overrides the default one + ## + customStartupProbe: {} + ## backend resource requests and limits + ## ref: http://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + ## @param backend.resourcesPreset Set backend container resources according to one common preset (allowed values: none, nano, small, medium, large, xlarge, 2xlarge). This is ignored if backend.resources is set (backend.resources is recommended for production). + ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 + ## Shuffle gets OOM killed with 256M memory during startup. Up to 360MiB of memory usage were observed during testing. + ## The small preset grants 512M. + ## + resourcesPreset: "small" + ## @param backend.resources Set backend container requests and limits for different resources like CPU or memory (essential for production workloads) + ## Example: + ## resources: + ## requests: + ## cpu: 2 + ## memory: 512Mi + ## limits: + ## cpu: 3 + ## memory: 1024Mi + ## + resources: {} + ## Configure Pods Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + ## @param backend.podSecurityContext.enabled Enable backend pods' Security Context + ## @param backend.podSecurityContext.fsGroupChangePolicy Set filesystem group change policy for backend pods + ## @param backend.podSecurityContext.sysctls Set kernel settings using the sysctl interface for backend pods + ## @param backend.podSecurityContext.supplementalGroups Set filesystem extra groups for backend pods + ## @param backend.podSecurityContext.fsGroup Set fsGroup in backend pods' Security Context + ## + podSecurityContext: + enabled: true + fsGroupChangePolicy: Always + sysctls: [] + supplementalGroups: [] + fsGroup: 1001 + ## Configure Container Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + ## @param backend.containerSecurityContext.enabled Enabled backend container' Security Context + ## @param backend.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in backend container + ## @param backend.containerSecurityContext.runAsUser Set runAsUser in backend container' Security Context + ## @param backend.containerSecurityContext.runAsGroup Set runAsGroup in backend container' Security Context + ## @param backend.containerSecurityContext.runAsNonRoot Set runAsNonRoot in backend container' Security Context + ## @param backend.containerSecurityContext.readOnlyRootFilesystem Set readOnlyRootFilesystem in backend container' Security Context + ## @param backend.containerSecurityContext.privileged Set privileged in backend container' Security Context + ## @param backend.containerSecurityContext.allowPrivilegeEscalation Set allowPrivilegeEscalation in backend container' Security Context + ## @param backend.containerSecurityContext.capabilities.drop List of capabilities to be dropped in backend container + ## @param backend.containerSecurityContext.seccompProfile.type Set seccomp profile in backend container + ## + containerSecurityContext: + enabled: true + seLinuxOptions: {} + runAsUser: 1000 + runAsGroup: 1000 + runAsNonRoot: true + readOnlyRootFilesystem: true + privileged: false + allowPrivilegeEscalation: false + capabilities: + drop: ["ALL"] + seccompProfile: + type: "RuntimeDefault" + + ## @param backend.command Override default backend container command (useful when using custom images) + ## + command: [] + ## @param backend.args Override default backend container args (useful when using custom images) + ## + args: [] + ## @param backend.automountServiceAccountToken Mount Service Account token in backend pods + ## NOTE: backend requires the service account credentials to be mounted + ## + automountServiceAccountToken: true + ## @param backend.hostAliases backend pods host aliases + ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ + ## + hostAliases: [] + ## @param backend.daemonsetAnnotations Annotations for backend daemonset + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + daemonsetAnnotations: {} + ## @param backend.deploymentAnnotations Annotations for backend deployment + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + deploymentAnnotations: {} + ## @param backend.statefulsetAnnotations Annotations for backend statefulset + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + statefulsetAnnotations: {} + ## @param backend.podLabels Extra labels for backend pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + ## + podLabels: {} + ## @param backend.podAnnotations Annotations for backend pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + podAnnotations: {} + ## @param backend.podAffinityPreset Pod affinity preset. Ignored if `backend.affinity` is set. Allowed values: `soft` or `hard` + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## + podAffinityPreset: "" + ## @param backend.podAntiAffinityPreset Pod anti-affinity preset. Ignored if `backend.affinity` is set. Allowed values: `soft` or `hard` + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## + podAntiAffinityPreset: soft + ## Node backend.affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## + nodeAffinityPreset: + ## @param backend.nodeAffinityPreset.type Node affinity preset type. Ignored if `backend.affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param backend.nodeAffinityPreset.key Node label key to match. Ignored if `backend.affinity` is set + ## + key: "" + ## @param backend.nodeAffinityPreset.values Node label values to match. Ignored if `backend.affinity` is set + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + ## @param backend.affinity Affinity for backend pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## NOTE: `backend.podAffinityPreset`, `backend.podAntiAffinityPreset`, and `backend.nodeAffinityPreset` will be ignored when it's set + ## + affinity: {} + ## @param backend.nodeSelector Node labels for backend pods assignment + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ + ## + nodeSelector: {} + ## @param backend.tolerations Tolerations for backend pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + ## ONLY FOR DEPLOYMENTS: + ## @param backend.updateStrategy.type backend deployment strategy type + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy + ## ONLY FOR STATEFULSETS: + ## @param backend.updateStrategy.type backend statefulset strategy type + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies + ## + updateStrategy: + ## ONLY FOR DEPLOYMENTS: + ## Can be set to RollingUpdate or Recreate + ## ONLY FOR STATEFULSETS: + ## Can be set to RollingUpdate or OnDelete + ## + type: RollingUpdate + ## ONLY FOR STATEFULSETS: + ## @param backend.podManagementPolicy Pod management policy for backend statefulset + ## Ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies + ## + podManagementPolicy: OrderedReady + ## @param backend.priorityClassName backend pods' priorityClassName + ## + priorityClassName: "" + ## @param backend.topologySpreadConstraints Topology Spread Constraints for backend pod assignment spread across your cluster among failure-domains + ## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#spread-constraints-for-pods + ## + topologySpreadConstraints: [] + ## @param backend.schedulerName Name of the k8s scheduler (other than default) for backend pods + ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ + ## + schedulerName: "" + ## @param backend.terminationGracePeriodSeconds Seconds backend pods need to terminate gracefully + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods + ## + terminationGracePeriodSeconds: "" + ## @param backend.lifecycleHooks for backend containers to automate configuration before or after startup + ## + lifecycleHooks: {} + ## @param backend.extraEnvVars Array with extra environment variables to add to backend containers + ## e.g: + ## extraEnvVars: + ## - name: FOO + ## value: "bar" + ## + extraEnvVars: [] + ## @param backend.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for backend containers + ## + extraEnvVarsCM: "" + ## @param backend.extraEnvVarsSecret Name of existing Secret containing extra env vars for backend containers + ## + extraEnvVarsSecret: "" + ## @param backend.extraVolumes Optionally specify extra list of additional volumes for the backend pods + ## + extraVolumes: [] + ## @param backend.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the backend containers + ## + extraVolumeMounts: [] + ## @param backend.sidecars Add additional sidecar containers to the backend pods + ## e.g: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + ## @param backend.initContainers Add additional init containers to the backend pods + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ + ## e.g: + ## initContainers: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## command: ['sh', '-c', 'echo "hello world"'] + ## + initContainers: [] + ## Pod Disruption Budget configuration + ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb + ## @param backend.pdb.create Enable/disable a Pod Disruption Budget creation + ## @param backend.pdb.minAvailable Minimum number/percentage of pods that should remain scheduled + ## @param backend.pdb.maxUnavailable Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `backend.pdb.minAvailable` and `backend.pdb.maxUnavailable` are empty. + ## + pdb: + create: true + minAvailable: "" + maxUnavailable: "" + ## Autoscaling configuration + ## ref: https://kubernetes.io/docs/concepts/workloads/autoscaling/ + ## + autoscaling: + ## @param backend.autoscaling.vpa.enabled Enable VPA for backend pods + ## @param backend.autoscaling.vpa.annotations Annotations for VPA resource + ## @param backend.autoscaling.vpa.controlledResources VPA List of resources that the vertical pod autoscaler can control. Defaults to cpu and memory + ## @param backend.autoscaling.vpa.maxAllowed VPA Max allowed resources for the pod + ## @param backend.autoscaling.vpa.minAllowed VPA Min allowed resources for the pod + ## + vpa: + enabled: false + annotations: {} + controlledResources: [] + maxAllowed: {} + minAllowed: {} + ## @param backend.autoscaling.vpa.updatePolicy.updateMode Autoscaling update policy + ## Specifies whether recommended updates are applied when a Pod is started and whether recommended updates are applied during the life of a Pod + ## Possible values are "Off", "Initial", "Recreate", and "Auto". + ## + updatePolicy: + updateMode: Auto + ## @param backend.autoscaling.hpa.enabled Enable HPA for backend pods + ## @param backend.autoscaling.hpa.minReplicas Minimum number of replicas + ## @param backend.autoscaling.hpa.maxReplicas Maximum number of replicas + ## @param backend.autoscaling.hpa.targetCPU Target CPU utilization percentage + ## @param backend.autoscaling.hpa.targetMemory Target Memory utilization percentage + ## + hpa: + enabled: false + minReplicas: "" + maxReplicas: "" + targetCPU: "" + targetMemory: "" + + ## ServiceAccount configuration + ## + serviceAccount: + ## @param backend.serviceAccount.create Specifies whether a ServiceAccount should be created + ## + create: true + ## @param backend.serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the common.names.fullname template + ## + name: "" + ## @param backend.serviceAccount.annotations Additional Service Account annotations (evaluated as a template) + ## + annotations: {} + ## @param backend.serviceAccount.automountServiceAccountToken Automount service account token for the backend service account + ## + automountServiceAccountToken: true + ## @param backend.serviceAccount.imagePullSecrets Add image pull secrets to the backend service account + ## + imagePullSecrets: [] + + ## RBAC configuration + ## + rbac: + ## @param backend.rbac.create Specifies whether RBAC resources should be created + create: true + + ## Network Policies + ## Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ + ## + networkPolicy: + ## @param backend.networkPolicy.enabled Specifies whether a NetworkPolicy should be created + ## + enabled: true + ## @param backend.networkPolicy.allowExternal Don't require server label for connections + ## The Policy model to apply. When set to false, only pods with the correct + ## server label will have network access to the ports server is listening + ## on. When true, server will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + ## @param backend.networkPolicy.allowExternalEgress Allow the pod to access any range of port and all destinations. + ## + allowExternalEgress: true + ## @param backend.networkPolicy.extraIngress Add extra ingress rules to the NetworkPolicy + ## NOTE: You likely want to allow access from your ingress, e.g.: + ## extraIngress: + ## - ports: + ## - protocol: TCP + ## port: 5001 + ## from: + ## - namespaceSelector: + ## matchLabels: + ## kubernetes.io/metadata.name: istio-ingress + ## podSelector: + ## matchLabels: + ## istio: ingress + ## + extraIngress: [] + ## @param backend.networkPolicy.extraEgress Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true) + ## NOTE: You likely want to allow access to OpenSearch and cluster-proxies, e.g: + ## extraEgress: + ## - to: + ## - namespaceSelector: + ## matchLabels: + ## kubernetes.io/metadata.name: istio-system + ## podSelector: + ## matchLabels: + ## istio: pilot + ## - ports: + ## - protocol: TCP + ## port: 9200 + ## - protocol: TCP + ## port: 9300 + ## to: + ## - namespaceSelector: + ## matchLabels: + ## kubernetes.io/metadata.name: shuffle + ## podSelector: + ## matchLabels: + ## app.kubernetes.io/name: opensearch + ## + extraEgress: [] + + ## @param backend.cleanupSchedule The interval in seconds at which the cleanup job runs + ## + cleanupSchedule: 300 + + ## OpenSearch configuration + ## + openSearch: + ## @param backend.openSearch.url The URL at which OpenSearch is available + ## + url: "http://{{ .Release.Name }}-opensearch:9200" + ## @param backend.openSearch.username The username that is used for authenticating with OpenSearch + ## + username: admin + ## @param backend.openSearch.certificateFile The path to a custom OpenSearch certificate file + ## + certificateFile: "" + ## @param backend.openSearch.skipSSLVerify Skip SSL verification + ## + skipSSLVerify: false + ## @param backend.openSearch.indexPrefix A prefix for OpenSearch indices + ## + indexPrefix: "" + + ## App configuration + ## + apps: + ## @param backend.apps.downloadLocation The location to a git repository from which default appps are downloaded on startup. + ## + downloadLocation: https://github.com/shuffle/python-apps + ## @param backend.apps.downloadBranch The branch from which apps should be downloaded on startup. + ## + downloadBranch: master + ## @param backend.apps.forceUpdate Force an update of apps on startup. + ## + forceUpdate: false + +## @section frontend Parameters +## +frontend: + ## frontend image + ## @param frontend.image.registry frontend image registry + ## @param frontend.image.repository frontend image repository + ## @skip frontend.image.tag frontend image tag (immutable tags are recommended) + ## @param frontend.image.digest frontend image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag image tag (immutable tags are recommended) + ## @param frontend.image.pullPolicy frontend image pull policy + ## @param frontend.image.pullSecrets frontend image pull secrets + ## + image: + registry: ghcr.io + repository: shuffle/shuffle-frontend + tag: nightly + digest: "" + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## @param frontend.replicaCount Number of frontend replicas to deploy + ## + replicaCount: 1 + ## @param frontend.containerPorts.http frontend HTTP container port + ## @param frontend.containerPorts.https frontend HTTPS container port + ## + containerPorts: + http: 80 + https: 443 + ## @param frontend.extraContainerPorts Optionally specify extra list of additional ports for frontend containers + ## e.g: + ## extraContainerPorts: + ## - name: myservice + ## containerPort: 9090 + ## + extraContainerPorts: [] + ## Configure extra options for frontend containers' liveness and readiness probes + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes + ## @param frontend.livenessProbe.enabled Enable livenessProbe on frontend containers + ## @param frontend.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe + ## @param frontend.livenessProbe.periodSeconds Period seconds for livenessProbe + ## @param frontend.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe + ## @param frontend.livenessProbe.failureThreshold Failure threshold for livenessProbe + ## @param frontend.livenessProbe.successThreshold Success threshold for livenessProbe + ## + livenessProbe: + enabled: false + initialDelaySeconds: 0 + periodSeconds: 15 + timeoutSeconds: 1 + failureThreshold: 4 + successThreshold: 1 + ## @param frontend.readinessProbe.enabled Enable readinessProbe on frontend containers + ## @param frontend.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe + ## @param frontend.readinessProbe.periodSeconds Period seconds for readinessProbe + ## @param frontend.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe + ## @param frontend.readinessProbe.failureThreshold Failure threshold for readinessProbe + ## @param frontend.readinessProbe.successThreshold Success threshold for readinessProbe + ## + readinessProbe: + enabled: false + initialDelaySeconds: 0 + periodSeconds: 5 + timeoutSeconds: 1 + failureThreshold: 3 + successThreshold: 1 + ## @param frontend.startupProbe.enabled Enable startupProbe on frontend containers + ## @param frontend.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe + ## @param frontend.startupProbe.periodSeconds Period seconds for startupProbe + ## @param frontend.startupProbe.timeoutSeconds Timeout seconds for startupProbe + ## @param frontend.startupProbe.failureThreshold Failure threshold for startupProbe + ## @param frontend.startupProbe.successThreshold Success threshold for startupProbe + ## + startupProbe: + enabled: false + initialDelaySeconds: 0 + periodSeconds: 1 + timeoutSeconds: 1 + failureThreshold: 60 + successThreshold: 1 + ## @param frontend.customLivenessProbe Custom livenessProbe that overrides the default one + ## + customLivenessProbe: {} + ## @param frontend.customReadinessProbe Custom readinessProbe that overrides the default one + ## + customReadinessProbe: {} + ## @param frontend.customStartupProbe Custom startupProbe that overrides the default one + ## + customStartupProbe: {} + ## frontend resource requests and limits + ## ref: http://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + ## @param frontend.resourcesPreset Set frontend container resources according to one common preset (allowed values: none, nano, small, medium, large, xlarge, 2xlarge). This is ignored if frontend.resources is set (frontend.resources is recommended for production). + ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 + ## + resourcesPreset: "nano" + ## @param frontend.resources Set frontend container requests and limits for different resources like CPU or memory (essential for production workloads) + ## Example: + ## resources: + ## requests: + ## cpu: 2 + ## memory: 512Mi + ## limits: + ## cpu: 3 + ## memory: 1024Mi + ## + resources: {} + ## Configure Pods Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + ## @param frontend.podSecurityContext.enabled Enable frontend pods' Security Context + ## @param frontend.podSecurityContext.fsGroupChangePolicy Set filesystem group change policy for frontend pods + ## @param frontend.podSecurityContext.sysctls Set kernel settings using the sysctl interface for frontend pods + ## @param frontend.podSecurityContext.supplementalGroups Set filesystem extra groups for frontend pods + ## @param frontend.podSecurityContext.fsGroup Set fsGroup in frontend pods' Security Context + ## + podSecurityContext: + enabled: false + fsGroupChangePolicy: Always + sysctls: [] + supplementalGroups: [] + fsGroup: 1001 + ## Configure Container Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + ## @param frontend.containerSecurityContext.enabled Enabled frontend container' Security Context + ## @param frontend.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in frontend container + ## @param frontend.containerSecurityContext.runAsUser Set runAsUser in frontend container' Security Context + ## @param frontend.containerSecurityContext.runAsGroup Set runAsGroup in frontend container' Security Context + ## @param frontend.containerSecurityContext.runAsNonRoot Set runAsNonRoot in frontend container' Security Context + ## @param frontend.containerSecurityContext.readOnlyRootFilesystem Set readOnlyRootFilesystem in frontend container' Security Context + ## @param frontend.containerSecurityContext.privileged Set privileged in frontend container' Security Context + ## @param frontend.containerSecurityContext.allowPrivilegeEscalation Set allowPrivilegeEscalation in frontend container' Security Context + ## @param frontend.containerSecurityContext.capabilities.drop List of capabilities to be dropped in frontend container + ## @param frontend.containerSecurityContext.seccompProfile.type Set seccomp profile in frontend container + ## + containerSecurityContext: + enabled: false + seLinuxOptions: {} + runAsUser: 101 + runAsGroup: 101 + runAsNonRoot: true + readOnlyRootFilesystem: true + privileged: false + allowPrivilegeEscalation: false + capabilities: + drop: ["ALL"] + seccompProfile: + type: "RuntimeDefault" + + ## @param frontend.command Override default frontend container command (useful when using custom images) + ## + command: [] + ## @param frontend.args Override default frontend container args (useful when using custom images) + ## + args: [] + ## @param frontend.automountServiceAccountToken Mount Service Account token in frontend pods + ## + automountServiceAccountToken: false + ## @param frontend.hostAliases frontend pods host aliases + ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ + ## + hostAliases: [] + ## @param frontend.daemonsetAnnotations Annotations for frontend daemonset + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + daemonsetAnnotations: {} + ## @param frontend.deploymentAnnotations Annotations for frontend deployment + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + deploymentAnnotations: {} + ## @param frontend.statefulsetAnnotations Annotations for frontend statefulset + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + statefulsetAnnotations: {} + ## @param frontend.podLabels Extra labels for frontend pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + ## + podLabels: {} + ## @param frontend.podAnnotations Annotations for frontend pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + podAnnotations: {} + ## @param frontend.podAffinityPreset Pod affinity preset. Ignored if `frontend.affinity` is set. Allowed values: `soft` or `hard` + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## + podAffinityPreset: "" + ## @param frontend.podAntiAffinityPreset Pod anti-affinity preset. Ignored if `frontend.affinity` is set. Allowed values: `soft` or `hard` + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## + podAntiAffinityPreset: soft + ## Node frontend.affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## + nodeAffinityPreset: + ## @param frontend.nodeAffinityPreset.type Node affinity preset type. Ignored if `frontend.affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param frontend.nodeAffinityPreset.key Node label key to match. Ignored if `frontend.affinity` is set + ## + key: "" + ## @param frontend.nodeAffinityPreset.values Node label values to match. Ignored if `frontend.affinity` is set + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + ## @param frontend.affinity Affinity for frontend pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## NOTE: `frontend.podAffinityPreset`, `frontend.podAntiAffinityPreset`, and `frontend.nodeAffinityPreset` will be ignored when it's set + ## + affinity: {} + ## @param frontend.nodeSelector Node labels for frontend pods assignment + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ + ## + nodeSelector: {} + ## @param frontend.tolerations Tolerations for frontend pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + ## ONLY FOR DEPLOYMENTS: + ## @param frontend.updateStrategy.type frontend deployment strategy type + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy + ## ONLY FOR STATEFULSETS: + ## @param frontend.updateStrategy.type frontend statefulset strategy type + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies + ## + updateStrategy: + ## ONLY FOR DEPLOYMENTS: + ## Can be set to RollingUpdate or Recreate + ## ONLY FOR STATEFULSETS: + ## Can be set to RollingUpdate or OnDelete + ## + type: RollingUpdate + ## ONLY FOR STATEFULSETS: + ## @param frontend.podManagementPolicy Pod management policy for frontend statefulset + ## Ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies + ## + podManagementPolicy: OrderedReady + ## @param frontend.priorityClassName frontend pods' priorityClassName + ## + priorityClassName: "" + ## @param frontend.topologySpreadConstraints Topology Spread Constraints for frontend pod assignment spread across your cluster among failure-domains + ## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#spread-constraints-for-pods + ## + topologySpreadConstraints: [] + ## @param frontend.schedulerName Name of the k8s scheduler (other than default) for frontend pods + ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ + ## + schedulerName: "" + ## @param frontend.terminationGracePeriodSeconds Seconds frontend pods need to terminate gracefully + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods + ## + terminationGracePeriodSeconds: "" + ## @param frontend.lifecycleHooks for frontend containers to automate configuration before or after startup + ## + lifecycleHooks: {} + ## @param frontend.extraEnvVars Array with extra environment variables to add to frontend containers + ## e.g: + ## extraEnvVars: + ## - name: FOO + ## value: "bar" + ## + extraEnvVars: [] + ## @param frontend.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for frontend containers + ## + extraEnvVarsCM: "" + ## @param frontend.extraEnvVarsSecret Name of existing Secret containing extra env vars for frontend containers + ## + extraEnvVarsSecret: "" + ## @param frontend.extraVolumes Optionally specify extra list of additional volumes for the frontend pods + ## + extraVolumes: [] + ## @param frontend.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the frontend containers + ## + extraVolumeMounts: [] + ## @param frontend.sidecars Add additional sidecar containers to the frontend pods + ## e.g: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + ## @param frontend.initContainers Add additional init containers to the frontend pods + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ + ## e.g: + ## initContainers: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## command: ['sh', '-c', 'echo "hello world"'] + ## + initContainers: [] + ## Pod Disruption Budget configuration + ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb + ## @param frontend.pdb.create Enable/disable a Pod Disruption Budget creation + ## @param frontend.pdb.minAvailable Minimum number/percentage of pods that should remain scheduled + ## @param frontend.pdb.maxUnavailable Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `frontend.pdb.minAvailable` and `frontend.pdb.maxUnavailable` are empty. + ## + pdb: + create: true + minAvailable: "" + maxUnavailable: "" + ## Autoscaling configuration + ## ref: https://kubernetes.io/docs/concepts/workloads/autoscaling/ + ## + autoscaling: + ## @param frontend.autoscaling.vpa.enabled Enable VPA for frontend pods + ## @param frontend.autoscaling.vpa.annotations Annotations for VPA resource + ## @param frontend.autoscaling.vpa.controlledResources VPA List of resources that the vertical pod autoscaler can control. Defaults to cpu and memory + ## @param frontend.autoscaling.vpa.maxAllowed VPA Max allowed resources for the pod + ## @param frontend.autoscaling.vpa.minAllowed VPA Min allowed resources for the pod + ## + vpa: + enabled: false + annotations: {} + controlledResources: [] + maxAllowed: {} + minAllowed: {} + ## @param frontend.autoscaling.vpa.updatePolicy.updateMode Autoscaling update policy + ## Specifies whether recommended updates are applied when a Pod is started and whether recommended updates are applied during the life of a Pod + ## Possible values are "Off", "Initial", "Recreate", and "Auto". + ## + updatePolicy: + updateMode: Auto + ## @param frontend.autoscaling.hpa.enabled Enable HPA for frontend pods + ## @param frontend.autoscaling.hpa.minReplicas Minimum number of replicas + ## @param frontend.autoscaling.hpa.maxReplicas Maximum number of replicas + ## @param frontend.autoscaling.hpa.targetCPU Target CPU utilization percentage + ## @param frontend.autoscaling.hpa.targetMemory Target Memory utilization percentage + ## + hpa: + enabled: false + minReplicas: "" + maxReplicas: "" + targetCPU: "" + targetMemory: "" + + ## ServiceAccount configuration + ## + serviceAccount: + ## @param frontend.serviceAccount.create Specifies whether a ServiceAccount should be created + ## + create: true + ## @param frontend.serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the common.names.fullname template + ## + name: "" + ## @param frontend.serviceAccount.annotations Additional Service Account annotations (evaluated as a template) + ## + annotations: {} + ## @param frontend.serviceAccount.automountServiceAccountToken Automount service account token for the frontend service account + ## + automountServiceAccountToken: true + ## @param frontend.serviceAccount.imagePullSecrets Add image pull secrets to the frontend service account + ## + imagePullSecrets: [] + + ## Network Policies + ## Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ + ## + networkPolicy: + ## @param frontend.networkPolicy.enabled Specifies whether a NetworkPolicy should be created + ## + enabled: true + ## @param frontend.networkPolicy.allowExternal Don't require server label for connections + ## The Policy model to apply. When set to false, only pods with the correct + ## server label will have network access to the ports server is listening + ## on. When true, server will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + ## @param frontend.networkPolicy.allowExternalEgress Allow the pod to access any range of port and all destinations. + ## + allowExternalEgress: true + ## @param frontend.networkPolicy.extraIngress Add extra ingress rules to the NetworkPolicy + ## NOTE: You likely want to allow access from your ingress, e.g.: + ## extraIngress: + ## - ports: + ## - protocol: TCP + ## port: 5001 + ## from: + ## - namespaceSelector: + ## matchLabels: + ## kubernetes.io/metadata.name: istio-ingress + ## podSelector: + ## matchLabels: + ## istio: ingress + ## + extraIngress: [] + ## @param frontend.networkPolicy.extraEgress Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true) + ## + extraEgress: [] + +## @section orborus Parameters +## +orborus: + ## orborus image + ## @param orborus.image.registry orborus image registry + ## @param orborus.image.repository orborus image repository + ## @skip orborus.image.tag orborus image tag (immutable tags are recommended) + ## @param orborus.image.digest orborus image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag image tag (immutable tags are recommended) + ## @param orborus.image.pullPolicy orborus image pull policy + ## @param orborus.image.pullSecrets orborus image pull secrets + ## + image: + registry: ghcr.io + repository: shuffle/shuffle-orborus + tag: nightly + digest: "" + ## Specify a imagePullPolicy + ## Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent' + ## ref: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images + ## + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## @param orborus.replicaCount Number of orborus replicas to deploy + ## + replicaCount: 1 + ## @param orborus.containerPorts.http orborus HTTP container port + ## + containerPorts: + http: 8080 + ## @param orborus.extraContainerPorts Optionally specify extra list of additional ports for orborus containers + ## e.g: + ## extraContainerPorts: + ## - name: myservice + ## containerPort: 9090 + ## + extraContainerPorts: [] + ## Configure extra options for orborus containers' liveness and readiness probes + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes + ## @param orborus.livenessProbe.enabled Enable livenessProbe on orborus containers + ## @param orborus.livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe + ## @param orborus.livenessProbe.periodSeconds Period seconds for livenessProbe + ## @param orborus.livenessProbe.timeoutSeconds Timeout seconds for livenessProbe + ## @param orborus.livenessProbe.failureThreshold Failure threshold for livenessProbe + ## @param orborus.livenessProbe.successThreshold Success threshold for livenessProbe + ## + livenessProbe: + enabled: false + initialDelaySeconds: 0 + periodSeconds: 15 + timeoutSeconds: 1 + failureThreshold: 4 + successThreshold: 1 + ## @param orborus.readinessProbe.enabled Enable readinessProbe on orborus containers + ## @param orborus.readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe + ## @param orborus.readinessProbe.periodSeconds Period seconds for readinessProbe + ## @param orborus.readinessProbe.timeoutSeconds Timeout seconds for readinessProbe + ## @param orborus.readinessProbe.failureThreshold Failure threshold for readinessProbe + ## @param orborus.readinessProbe.successThreshold Success threshold for readinessProbe + ## + readinessProbe: + enabled: false + initialDelaySeconds: 0 + periodSeconds: 5 + timeoutSeconds: 1 + failureThreshold: 3 + successThreshold: 1 + ## @param orborus.startupProbe.enabled Enable startupProbe on orborus containers + ## @param orborus.startupProbe.initialDelaySeconds Initial delay seconds for startupProbe + ## @param orborus.startupProbe.periodSeconds Period seconds for startupProbe + ## @param orborus.startupProbe.timeoutSeconds Timeout seconds for startupProbe + ## @param orborus.startupProbe.failureThreshold Failure threshold for startupProbe + ## @param orborus.startupProbe.successThreshold Success threshold for startupProbe + ## + startupProbe: + enabled: false + initialDelaySeconds: 0 + periodSeconds: 1 + timeoutSeconds: 1 + failureThreshold: 60 + successThreshold: 1 + ## @param orborus.customLivenessProbe Custom livenessProbe that overrides the default one + ## + customLivenessProbe: {} + ## @param orborus.customReadinessProbe Custom readinessProbe that overrides the default one + ## + customReadinessProbe: {} + ## @param orborus.customStartupProbe Custom startupProbe that overrides the default one + ## + customStartupProbe: {} + ## orborus resource requests and limits + ## ref: http://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + ## @param orborus.resourcesPreset Set orborus container resources according to one common preset (allowed values: none, nano, small, medium, large, xlarge, 2xlarge). This is ignored if orborus.resources is set (orborus.resources is recommended for production). + ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 + ## + resourcesPreset: "nano" + ## @param orborus.resources Set orborus container requests and limits for different resources like CPU or memory (essential for production workloads) + ## Example: + ## resources: + ## requests: + ## cpu: 2 + ## memory: 512Mi + ## limits: + ## cpu: 3 + ## memory: 1024Mi + ## + resources: {} + ## Configure Pods Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + ## @param orborus.podSecurityContext.enabled Enable orborus pods' Security Context + ## @param orborus.podSecurityContext.fsGroupChangePolicy Set filesystem group change policy for orborus pods + ## @param orborus.podSecurityContext.sysctls Set kernel settings using the sysctl interface for orborus pods + ## @param orborus.podSecurityContext.supplementalGroups Set filesystem extra groups for orborus pods + ## @param orborus.podSecurityContext.fsGroup Set fsGroup in orborus pods' Security Context + ## + podSecurityContext: + enabled: true + fsGroupChangePolicy: Always + sysctls: [] + supplementalGroups: [] + fsGroup: 1001 + ## Configure Container Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + ## @param orborus.containerSecurityContext.enabled Enabled orborus container' Security Context + ## @param orborus.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in orborus container + ## @param orborus.containerSecurityContext.runAsUser Set runAsUser in orborus container' Security Context + ## @param orborus.containerSecurityContext.runAsGroup Set runAsGroup in orborus container' Security Context + ## @param orborus.containerSecurityContext.runAsNonRoot Set runAsNonRoot in orborus container' Security Context + ## @param orborus.containerSecurityContext.readOnlyRootFilesystem Set readOnlyRootFilesystem in orborus container' Security Context + ## @param orborus.containerSecurityContext.privileged Set privileged in orborus container' Security Context + ## @param orborus.containerSecurityContext.allowPrivilegeEscalation Set allowPrivilegeEscalation in orborus container' Security Context + ## @param orborus.containerSecurityContext.capabilities.drop List of capabilities to be dropped in orborus container + ## @param orborus.containerSecurityContext.seccompProfile.type Set seccomp profile in orborus container + ## + containerSecurityContext: + enabled: true + seLinuxOptions: {} + runAsUser: 101 + runAsGroup: 101 + runAsNonRoot: true + readOnlyRootFilesystem: true + privileged: false + allowPrivilegeEscalation: false + capabilities: + drop: ["ALL"] + seccompProfile: + type: "RuntimeDefault" + + ## @param orborus.command Override default orborus container command (useful when using custom images) + ## + command: [] + ## @param orborus.args Override default orborus container args (useful when using custom images) + ## + args: [] + ## @param orborus.automountServiceAccountToken Mount Service Account token in orborus pods + ## NOTE: orborus requires the service account credentials to be mounted + ## + automountServiceAccountToken: true + ## @param orborus.hostAliases orborus pods host aliases + ## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/ + ## + hostAliases: [] + ## @param orborus.daemonsetAnnotations Annotations for orborus daemonset + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + daemonsetAnnotations: {} + ## @param orborus.deploymentAnnotations Annotations for orborus deployment + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + deploymentAnnotations: {} + ## @param orborus.statefulsetAnnotations Annotations for orborus statefulset + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + statefulsetAnnotations: {} + ## @param orborus.podLabels Extra labels for orborus pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + ## + podLabels: {} + ## @param orborus.podAnnotations Annotations for orborus pods + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + ## + podAnnotations: {} + ## @param orborus.podAffinityPreset Pod affinity preset. Ignored if `orborus.affinity` is set. Allowed values: `soft` or `hard` + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## + podAffinityPreset: "" + ## @param orborus.podAntiAffinityPreset Pod anti-affinity preset. Ignored if `orborus.affinity` is set. Allowed values: `soft` or `hard` + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity + ## + podAntiAffinityPreset: soft + ## Node orborus.affinity preset + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity + ## + nodeAffinityPreset: + ## @param orborus.nodeAffinityPreset.type Node affinity preset type. Ignored if `orborus.affinity` is set. Allowed values: `soft` or `hard` + ## + type: "" + ## @param orborus.nodeAffinityPreset.key Node label key to match. Ignored if `orborus.affinity` is set + ## + key: "" + ## @param orborus.nodeAffinityPreset.values Node label values to match. Ignored if `orborus.affinity` is set + ## E.g. + ## values: + ## - e2e-az1 + ## - e2e-az2 + ## + values: [] + ## @param orborus.affinity Affinity for orborus pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + ## NOTE: `orborus.podAffinityPreset`, `orborus.podAntiAffinityPreset`, and `orborus.nodeAffinityPreset` will be ignored when it's set + ## + affinity: {} + ## @param orborus.nodeSelector Node labels for orborus pods assignment + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ + ## + nodeSelector: {} + ## @param orborus.tolerations Tolerations for orborus pods assignment + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + ## + tolerations: [] + ## ONLY FOR DEPLOYMENTS: + ## @param orborus.updateStrategy.type orborus deployment strategy type + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy + ## ONLY FOR STATEFULSETS: + ## @param orborus.updateStrategy.type orborus statefulset strategy type + ## ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies + ## + updateStrategy: + ## ONLY FOR DEPLOYMENTS: + ## Can be set to RollingUpdate or Recreate + ## ONLY FOR STATEFULSETS: + ## Can be set to RollingUpdate or OnDelete + ## + type: RollingUpdate + ## ONLY FOR STATEFULSETS: + ## @param orborus.podManagementPolicy Pod management policy for orborus statefulset + ## Ref: https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-management-policies + ## + podManagementPolicy: OrderedReady + ## @param orborus.priorityClassName orborus pods' priorityClassName + ## + priorityClassName: "" + ## @param orborus.topologySpreadConstraints Topology Spread Constraints for orborus pod assignment spread across your cluster among failure-domains + ## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#spread-constraints-for-pods + ## + topologySpreadConstraints: [] + ## @param orborus.schedulerName Name of the k8s scheduler (other than default) for orborus pods + ## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ + ## + schedulerName: "" + ## @param orborus.terminationGracePeriodSeconds Seconds orborus pods need to terminate gracefully + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods + ## + terminationGracePeriodSeconds: "" + ## @param orborus.lifecycleHooks for orborus containers to automate configuration before or after startup + ## + lifecycleHooks: {} + ## @param orborus.extraEnvVars Array with extra environment variables to add to orborus containers + ## e.g: + ## extraEnvVars: + ## - name: FOO + ## value: "bar" + ## + extraEnvVars: [] + ## @param orborus.extraEnvVarsCM Name of existing ConfigMap containing extra env vars for orborus containers + ## + extraEnvVarsCM: "" + ## @param orborus.extraEnvVarsSecret Name of existing Secret containing extra env vars for orborus containers + ## + extraEnvVarsSecret: "" + ## @param orborus.extraVolumes Optionally specify extra list of additional volumes for the orborus pods + ## + extraVolumes: [] + ## @param orborus.extraVolumeMounts Optionally specify extra list of additional volumeMounts for the orborus containers + ## + extraVolumeMounts: [] + ## @param orborus.sidecars Add additional sidecar containers to the orborus pods + ## e.g: + ## sidecars: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## ports: + ## - name: portname + ## containerPort: 1234 + ## + sidecars: [] + ## @param orborus.initContainers Add additional init containers to the orborus pods + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ + ## e.g: + ## initContainers: + ## - name: your-image-name + ## image: your-image + ## imagePullPolicy: Always + ## command: ['sh', '-c', 'echo "hello world"'] + ## + initContainers: [] + ## Pod Disruption Budget configuration + ## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb + ## @param orborus.pdb.create Enable/disable a Pod Disruption Budget creation + ## @param orborus.pdb.minAvailable Minimum number/percentage of pods that should remain scheduled + ## @param orborus.pdb.maxUnavailable Maximum number/percentage of pods that may be made unavailable. Defaults to `1` if both `orborus.pdb.minAvailable` and `orborus.pdb.maxUnavailable` are empty. + ## + pdb: + create: true + minAvailable: "" + maxUnavailable: "" + ## Autoscaling configuration + ## ref: https://kubernetes.io/docs/concepts/workloads/autoscaling/ + ## + autoscaling: + ## @param orborus.autoscaling.vpa.enabled Enable VPA for orborus pods + ## @param orborus.autoscaling.vpa.annotations Annotations for VPA resource + ## @param orborus.autoscaling.vpa.controlledResources VPA List of resources that the vertical pod autoscaler can control. Defaults to cpu and memory + ## @param orborus.autoscaling.vpa.maxAllowed VPA Max allowed resources for the pod + ## @param orborus.autoscaling.vpa.minAllowed VPA Min allowed resources for the pod + ## + vpa: + enabled: false + annotations: {} + controlledResources: [] + maxAllowed: {} + minAllowed: {} + ## @param orborus.autoscaling.vpa.updatePolicy.updateMode Autoscaling update policy + ## Specifies whether recommended updates are applied when a Pod is started and whether recommended updates are applied during the life of a Pod + ## Possible values are "Off", "Initial", "Recreate", and "Auto". + ## + updatePolicy: + updateMode: Auto + ## @param orborus.autoscaling.hpa.enabled Enable HPA for orborus pods + ## @param orborus.autoscaling.hpa.minReplicas Minimum number of replicas + ## @param orborus.autoscaling.hpa.maxReplicas Maximum number of replicas + ## @param orborus.autoscaling.hpa.targetCPU Target CPU utilization percentage + ## @param orborus.autoscaling.hpa.targetMemory Target Memory utilization percentage + ## + hpa: + enabled: false + minReplicas: "" + maxReplicas: "" + targetCPU: "" + targetMemory: "" + + ## ServiceAccount configuration + ## + serviceAccount: + ## @param orborus.serviceAccount.create Specifies whether a ServiceAccount should be created + ## + create: true + ## @param orborus.serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the common.names.fullname template + ## + name: "" + ## @param orborus.serviceAccount.annotations Additional Service Account annotations (evaluated as a template) + ## + annotations: {} + ## @param orborus.serviceAccount.automountServiceAccountToken Automount service account token for the orborus service account + ## + automountServiceAccountToken: true + ## @param orborus.serviceAccount.imagePullSecrets Add image pull secrets to the orborus service account + ## + imagePullSecrets: [] + + ## RBAC configuration + ## + rbac: + ## @param orborus.rbac.create Specifies whether RBAC resources should be created + create: true + + ## Network Policies + ## Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ + ## + networkPolicy: + ## @param orborus.networkPolicy.enabled Specifies whether a NetworkPolicy should be created + ## + enabled: true + ## @param orborus.networkPolicy.allowExternal Don't require server label for connections + ## The Policy model to apply. When set to false, only pods with the correct + ## server label will have network access to the ports server is listening + ## on. When true, server will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + ## @param orborus.networkPolicy.allowExternalEgress Allow the pod to access any range of port and all destinations. + ## + allowExternalEgress: true + ## @param orborus.networkPolicy.extraIngress Add extra ingress rules to the NetworkPolicy + ## + extraIngress: [] + ## @param orborus.networkPolicy.extraEgress Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true) + ## NOTE: You likely want to allow access to cluster-proxies, e.g: + ## extraEgress: + ## - to: + ## - namespaceSelector: + ## matchLabels: + ## kubernetes.io/metadata.name: istio-system + ## podSelector: + ## matchLabels: + ## istio: pilot + ## + extraEgress: [] + +## @section worker Parameters +## +worker: + ## worker image + ## @param worker.image.registry worker image registry + ## @param worker.image.repository worker image repository + ## @skip worker.image.tag worker image tag (immutable tags are recommended) + ## @param worker.image.digest worker image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag image tag (immutable tags are recommended) + ## + image: + registry: ghcr.io + repository: shuffle/shuffle-worker + tag: nightly + digest: "" + + ## ServiceAccount configuration + ## + serviceAccount: + ## @param worker.serviceAccount.create Specifies whether a ServiceAccount should be created + ## + create: true + ## @param worker.serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the common.names.fullname template + ## + name: "" + ## @param worker.serviceAccount.annotations Additional Service Account annotations (evaluated as a template) + ## + annotations: {} + ## @param worker.serviceAccount.automountServiceAccountToken Automount service account token for the worker service account + ## + automountServiceAccountToken: true + ## @param worker.serviceAccount.imagePullSecrets Add image pull secrets to the worker service account + ## + imagePullSecrets: [] + + ## RBAC configuration + ## + rbac: + ## @param worker.rbac.create Specifies whether RBAC resources should be created + create: true + + ## Network Policies + ## Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ + ## + networkPolicy: + ## @param worker.networkPolicy.enabled Specifies whether a NetworkPolicy should be created + ## + enabled: true + ## @param worker.networkPolicy.allowExternal Don't require server label for connections + ## The Policy model to apply. When set to false, only pods with the correct + ## server label will have network access to the ports server is listening + ## on. When true, server will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + ## @param worker.networkPolicy.allowExternalEgress Allow the pod to access any range of port and all destinations. + ## + allowExternalEgress: true + ## @param worker.networkPolicy.extraIngress Add extra ingress rules to the NetworkPolicy + ## + extraIngress: [] + ## @param worker.networkPolicy.extraEgress Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true) + ## NOTE: You likely want to allow access to cluster-proxies, e.g: + ## extraEgress: + ## - to: + ## - namespaceSelector: + ## matchLabels: + ## kubernetes.io/metadata.name: istio-system + ## podSelector: + ## matchLabels: + ## istio: pilot + ## + extraEgress: [] + +## @section app Parameters +## +app: + ## ServiceAccount configuration + ## + serviceAccount: + ## @param app.serviceAccount.create Specifies whether a ServiceAccount should be created + ## + create: true + ## @param app.serviceAccount.name The name of the ServiceAccount to use. + ## If not set and create is true, a name is generated using the common.names.fullname template + ## + name: "" + ## @param app.serviceAccount.annotations Additional Service Account annotations (evaluated as a template) + ## + annotations: {} + ## @param app.serviceAccount.automountServiceAccountToken Automount service account token for the app service account + ## NOTE: You likely want to allow access to cluster-proxies, e.g: + ## extraEgress: + ## - to: + ## - namespaceSelector: + ## matchLabels: + ## kubernetes.io/metadata.name: istio-system + ## podSelector: + ## matchLabels: + ## istio: pilot + ## + automountServiceAccountToken: true + ## @param app.serviceAccount.imagePullSecrets Add image pull secrets to the app service account + ## + imagePullSecrets: [] + + ## RBAC configuration + ## + rbac: + ## @param app.rbac.create Specifies whether RBAC resources should be created + create: true + + ## Network Policies + ## Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/ + ## + networkPolicy: + ## @param app.networkPolicy.enabled Specifies whether a NetworkPolicy should be created + ## + enabled: true + ## @param app.networkPolicy.allowExternal Don't require server label for connections + ## The Policy model to apply. When set to false, only pods with the correct + ## server label will have network access to the ports server is listening + ## on. When true, server will accept connections from any source + ## (with the correct destination port). + ## + allowExternal: true + ## @param app.networkPolicy.allowExternalEgress Allow the pod to access any range of port and all destinations. + ## + allowExternalEgress: true + ## @param app.networkPolicy.extraIngress Add extra ingress rules to the NetworkPolicy + ## + extraIngress: [] + ## @param app.networkPolicy.extraEgress Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true) + ## + extraEgress: [] + +## @section Traffic Exposure Parameters +## + +## ingress parameters +## ref: http://kubernetes.io/docs/concepts/services-networking/ingress/ +## +ingress: + ## @param ingress.enabled Enable ingress record generation for frontend and backend + ## + enabled: false + ## @param ingress.pathType Ingress path type for the frontend path + ## + pathType: Prefix + ## @param ingress.backendPathType Ingress path type for the backend path + ## + backendPathType: Prefix + ## @param ingress.apiVersion Force Ingress API version (automatically detected if not set) + ## + apiVersion: "" + ## @param ingress.hostname Default host for the ingress record + ## + hostname: shuffle.local + ## @param ingress.ingressClassName [default: nginx] IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+) + ## This is supported in Kubernetes 1.18+ and required if you have more than one IngressClass marked as the default for your cluster . + ## ref: https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/ + ## + ingressClassName: "" + ## @param ingress.path [default: "/"] Ingress path for Shuffle frontend + ## NOTE: The shuffle frontend currently does not support using base paths + ## + path: / + ## @param ingress.backendPath [default: "/api/"] Ingress path for Shuffle backend + ## NOTE: The shuffle backend is currently required to be reachable at shuffle-frontend.example.com/api/ + ## + backendPath: /api/ + ## @param ingress.annotations Additional annotations for the Ingress resource. + ## + annotations: {} + ## @param ingress.tls Enable TLS configuration for the host defined at `ingress.hostname` parameter + ## TLS certificates will be retrieved from a TLS secret with name: `{{- printf "%s-tls" .Values.ingress.hostname }}` + ## You can: + ## - Use the `ingress.secrets` parameter to create this TLS secret + ## - Rely on cert-manager to create it by setting the corresponding annotations + ## - Rely on Helm to create self-signed certificates by setting `ingress.selfSigned=true` + ## + tls: false + ## @param ingress.selfSigned Create a TLS secret for this ingress record using self-signed certificates generated by Helm + ## + selfSigned: false + ## @param ingress.extraHosts An array with additional hostname(s) to be covered with the ingress record + ## e.g: + ## extraHosts: + ## - name: example.local + ## path: / + ## + extraHosts: [] + ## @param ingress.extraPaths An array with additional arbitrary paths that may need to be added to the ingress under the main host + ## e.g: + ## extraPaths: + ## - path: /* + ## backend: + ## serviceName: ssl-redirect + ## servicePort: use-annotation + ## + extraPaths: [] + ## @param ingress.extraTls TLS configuration for additional hostname(s) to be covered with this ingress record + ## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#tls + ## e.g: + ## extraTls: + ## - hosts: + ## - example.local + ## secretName: example.local-tls + ## + extraTls: [] + ## @param ingress.secrets Custom TLS certificates as secrets + ## NOTE: 'key' and 'certificate' are expected in PEM format + ## NOTE: 'name' should line up with a 'secretName' set further up + ## If it is not set and you're using cert-manager, this is unneeded, as it will create a secret for you with valid certificates + ## If it is not set and you're NOT using cert-manager either, self-signed certificates will be created valid for 365 days + ## It is also possible to create and manage the certificates outside of this helm chart + ## Please see README.md for more information + ## e.g: + ## secrets: + ## - name: example.local-tls + ## key: |- + ## -----BEGIN RSA PRIVATE KEY----- + ## ... + ## -----END RSA PRIVATE KEY----- + ## certificate: |- + ## -----BEGIN CERTIFICATE----- + ## ... + ## -----END CERTIFICATE----- + ## + secrets: [] + ## @param ingress.extraRules Additional rules to be covered with this ingress record + ## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-rules + ## e.g: + ## extraRules: + ## - host: example.local + ## http: + ## path: / + ## backend: + ## service: + ## name: example-svc + ## port: + ## name: http + ## + extraRules: [] + +## @section Istio Parameters +## +istio: + ## @param istio.enabled Enable creation of an Istio Gateway and VirtualService for frontend and backend + ## + enabled: false + + ## @param istio.apiVersion The istio apiVersion to use for Gateway and VirtualService resources + ## + apiVersion: networking.istio.io/v1 + + ## @param istio.hosts One or more hosts exposed by Istio + ## + hosts: [] + + gateway: + ## @param istio.gateway.annotations Additional annotations for the Gateway resource + ## + annotations: {} + ## @param istio.gateway.selector [object, default: { istio: ingress }] The selector matches the ingress gateway pod labels + ## + selector: + istio: ingress + ## @param istio.gateway.http.enabled Enable HTTP server port 80 + ## @param istio.gateway.http.httpsRedirect If set to true, a 301 redirect is send for all HTTP connections + ## + http: + enabled: true + httpsRedirect: false + ## @param istio.gateway.https.enabled Enable HTTPS server on port 443 + ## @param istio.gateway.https.tlsCredentialName The name of the secret that holds the TLS certs including the CA certificates. + ## @param istio.gateway.https.tlsCipherSuites If specified, only support the specified cipher list. + ## NOTE: The secret must exist in the namespace of the istio gateway pod + ## + https: + enabled: false + tlsCredentialName: "" + tlsCipherSuites: [] + ## @param istio.gateway.extraServers Additional servers for the Gateway resource + ## ref: https://istio.io/latest/docs/reference/config/networking/gateway/#Server + ## + extraServers: [] + + virtualService: + ## @param istio.virtualService.annotations Additional annotations for the VirtualService resource. + ## + annotations: {} + ## @param istio.virtualService.backendHeaders Header manipulation rules for backend traffic + ## ref: https://istio.io/latest/docs/reference/config/networking/virtual-service/#Headers + ## + backendHeaders: {} + ## @param istio.virtualService.frontendHeaders Header manipulation rules for frontend traffic + ## ref: https://istio.io/latest/docs/reference/config/networking/virtual-service/#Headers + ## + frontendHeaders: {} + +## @section Persistence Parameters +## + +## Enable persistence using Persistent Volume Claims +## ref: https://kubernetes.io/docs/concepts/storage/persistent-volumes/ +## +persistence: + ## @param persistence.enabled Enable persistence using Persistent Volume Claims + ## + enabled: true + + ## @param persistence.apps.existingClaim Name of an existing PVC to use + ## @param persistence.apps.storageClass PVC Storage Class for shuffle-apps volume + ## Note: The default StorageClass will be used if not defined. Set it to `-` to disable dynamic provisioning + ## @param persistence.apps.subPath The sub path used in the volume + ## @param persistence.apps.accessModes The access mode of the volume + ## @param persistence.apps.size The size of the volume + ## @param persistence.apps.annotations Annotations for the PVC + ## @param persistence.apps.selector Selector to match an existing Persistent Volume + apps: + existingClaim: "" + storageClass: "" + subPath: "" + accessModes: + - ReadWriteOnce + size: 5Gi + annotations: {} + selector: {} + + ## @param persistence.appBuilder.storageClass PVC Storage Class for backend-apps-claim volume + ## Note: The default StorageClass will be used if not defined. Set it to `-` to disable dynamic provisioning + ## @param persistence.appBuilder.accessModes The access mode of the volume + ## @param persistence.appBuilder.size The size of the volume + ## @param persistence.appBuilder.annotations Annotations for the PVC + ## @param persistence.appBuilder.selector Selector to match an existing Persistent Volume + appBuilder: + storageClass: "" + accessModes: + - ReadWriteOnce + size: 5Gi + annotations: {} + selector: {} + + ## @param persistence.files.existingClaim Name of an existing PVC to use + ## @param persistence.files.storageClass PVC Storage Class for shuffle-files volume + ## Note: The default StorageClass will be used if not defined. Set it to `-` to disable dynamic provisioning + ## @param persistence.files.subPath The sub path used in the volume + ## @param persistence.files.accessModes The access mode of the volume + ## @param persistence.files.size The size of the volume + ## @param persistence.files.annotations Annotations for the PVC + ## @param persistence.files.selector Selector to match an existing Persistent Volume + files: + existingClaim: "" + storageClass: "" + subPath: "" + accessModes: + - ReadWriteOnce + size: 5Gi + annotations: {} + selector: {} + +## @section Init Container Parameters +## + +## 'volumePermissions' init container parameters +## Changes the owner and group of the persistent volume mount point to runAsUser:fsGroup values +## based on the *podSecurityContext/*containerSecurityContext parameters +## +volumePermissions: + ## @param volumePermissions.enabled Enable init container that changes the owner/group of the PV mount point to `runAsUser:fsGroup` + ## + enabled: false + ## OS Shell + Utility image + ## ref: https://hub.docker.com/r/bitnami/os-shell/tags/ + ## @param volumePermissions.image.registry OS Shell + Utility image registry + ## @param volumePermissions.image.repository OS Shell + Utility image repository + ## @skip volumePermissions.image.tag OS Shell + Utility image tag (immutable tags are recommended) + ## @param volumePermissions.image.pullPolicy OS Shell + Utility image pull policy + ## @param volumePermissions.image.pullSecrets OS Shell + Utility image pull secrets + ## + image: + registry: docker.io + repository: bitnami/os-shell + tag: 12-debian-12-r30 + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + ## + pullSecrets: [] + ## Init container's resource requests and limits + ## ref: http://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/ + ## @param volumePermissions.resourcesPreset Set init container resources according to one common preset (allowed values: none, nano, small, medium, large, xlarge, 2xlarge). This is ignored if volumePermissions.resources is set (volumePermissions.resources is recommended for production). + ## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15 + ## + resourcesPreset: "nano" + ## @param volumePermissions.resources Set init container requests and limits for different resources like CPU or memory (essential for production workloads) + ## Example: + ## resources: + ## requests: + ## cpu: 2 + ## memory: 512Mi + ## limits: + ## cpu: 3 + ## memory: 1024Mi + ## + resources: {} + ## Init container Container Security Context + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + ## @param volumePermissions.containerSecurityContext.enabled Enabled init container' Security Context + ## @param volumePermissions.containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in init container + ## @param volumePermissions.containerSecurityContext.runAsUser Set init container's Security Context runAsUser + ## NOTE: when runAsUser is set to special value "auto", init container will try to chown the + ## data folder to auto-determined user&group, using commands: `id -u`:`id -G | cut -d" " -f2` + ## "auto" is especially useful for OpenShift which has scc with dynamic user ids (and 0 is not allowed) + ## + containerSecurityContext: + enabled: true + seLinuxOptions: {} + runAsUser: 0 + +## @section OpenSearch Parameters +## + +## OpenSearch chart configuration +## ref: https://github.com/bitnami/charts/blob/main/bitnami/opensearch/values.yaml +## @param opensearch.enabled Switch to enable or disable the opensearch helm chart +## +opensearch: + enabled: true + +## @section Vault Parameters +## + +vault: + ## @param vault.role Specify the Vault role, which should be used to get the secret from Vault. + ## NOTE: This value is used as a default for all secrets and can be overwritten for individual secrets + ## with the vaultRole property. + ## + role: "" + + ## @param vault.secrets A list of VaultSecrets to create + ## NOTE: 'type', 'name' and 'path' must be set + ## type is the type of the Kubernetes secret + ## name is the suffix of the name of the resulting (Vault)Secret + ## path is the path of the corresponding secret in Vault + ## Additional VaultSecret parameters can optionally be set. + ## Ref: https://github.com/ricoberger/vault-secrets-operator/blob/0409d56beb36ab95c4582a0cc35c0a2b517961e7/api/v1alpha1/vaultsecret_types.go#L9-L59 + ## e.g: + ## secrets: + ## - type: Opaque + ## name: "example" + ## path: "example/secret" + ## + secrets: [] +## @section Other Parameters +## diff --git a/functions/onprem/orborus/Dockerfile b/functions/onprem/orborus/Dockerfile index 79245ae3..921514b0 100644 --- a/functions/onprem/orborus/Dockerfile +++ b/functions/onprem/orborus/Dockerfile @@ -1,11 +1,13 @@ -FROM golang:1.22 as builder +FROM golang:1.23 as builder WORKDIR /app COPY orborus.go /app/orborus.go COPY go.mod /app/go.mod -RUN go get +#RUN go get +RUN go mod download +RUN go mod tidy #RUN go build -v # Enabled CGO January 2025 (?) @@ -13,6 +15,7 @@ RUN go get RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o /app/orborus . FROM alpine:3.21.2 + RUN apk add --no-cache bash tzdata #COPY --from=builder /app/orborus orborus COPY --from=builder /app/ / diff --git a/functions/onprem/orborus/go.mod b/functions/onprem/orborus/go.mod index a883723c..0b35fe90 100644 --- a/functions/onprem/orborus/go.mod +++ b/functions/onprem/orborus/go.mod @@ -1,8 +1,8 @@ module orborus -go 1.22.7 +go 1.23.0 -toolchain go1.22.11 +toolchain go1.23.6 //replace github.com/shuffle/shuffle-shared => ../../../../shuffle-shared @@ -10,7 +10,7 @@ require ( github.com/docker/docker v27.5.0+incompatible github.com/docker/go-connections v0.5.0 github.com/satori/go.uuid v1.2.0 - github.com/shuffle/shuffle-shared v0.7.92 + github.com/shuffle/shuffle-shared v0.8.19 k8s.io/api v0.30.2 k8s.io/apimachinery v0.30.2 ) @@ -97,14 +97,14 @@ require ( go.opentelemetry.io/otel/trace v1.33.0 // indirect go.opentelemetry.io/proto/otlp v1.4.0 // indirect go4.org v0.0.0-20201209231011-d4a079459e60 // indirect - golang.org/x/crypto v0.32.0 // indirect + golang.org/x/crypto v0.36.0 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.34.0 // indirect - golang.org/x/oauth2 v0.24.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/term v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/net v0.37.0 // indirect + golang.org/x/oauth2 v0.23.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/term v0.30.0 // indirect + golang.org/x/text v0.23.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect diff --git a/functions/onprem/orborus/go.sum b/functions/onprem/orborus/go.sum index 4caf4280..39b13f42 100644 --- a/functions/onprem/orborus/go.sum +++ b/functions/onprem/orborus/go.sum @@ -38,8 +38,6 @@ github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF0 github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= -github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk= github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/adrg/strutil v0.2.3 h1:WZVn3ItPBovFmP4wMHHVXUr8luRaHrbyIuLlHt32GZQ= @@ -69,7 +67,6 @@ github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8b github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 h1:/P9/RL0xgWE+ehnCUUN5h3RpG3dmoMCOONO1CCvq23Y= github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013/go.mod h1:pccXHIvs3TV/TUqSNyEvF99sxjX2r4FFRIyw6TZY9+w= -github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -78,7 +75,6 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -90,8 +86,6 @@ github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWH github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= -github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo= github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -105,8 +99,8 @@ github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= -github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy v1.2.1 h1:njjgvO6cRG9rIqN2ebkqy6cQz2Njkx7Fsfv/zIZqgug= +github.com/elazarl/goproxy v1.2.1/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= @@ -125,18 +119,14 @@ github.com/frikky/schemaless v0.0.13 h1:ARiN9V7wr2VZXAr9JK5wvTbyPgpGrgeiL1VhR5Ml github.com/frikky/schemaless v0.0.13/go.mod h1:mooDxY+D6weHjhKvjy3+IE9S7P4g4cpNnidkdRv/cHQ= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= -github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= +github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= +github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= -github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8= github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= -github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= github.com/go-git/go-git/v5 v5.13.0 h1:vLn5wlGIh/X78El6r3Jr+30W16Blk0CTcxTYcYPWi5E= github.com/go-git/go-git/v5 v5.13.0/go.mod h1:Wjo7/JyVKtQgUNdXYXIepzWfJQkUEIGvkvVkiXRR/zw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -277,8 +267,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= -github.com/onsi/gomega v1.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE= -github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -309,21 +299,13 @@ github.com/sendgrid/rest v2.6.9+incompatible h1:1EyIcsNdn9KIisLW50MKwmSRSK+ekuei github.com/sendgrid/rest v2.6.9+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE= github.com/sendgrid/sendgrid-go v3.14.0+incompatible h1:KDSasSTktAqMJCYClHVE94Fcif2i7P7wzISv1sU6DUA= github.com/sendgrid/sendgrid-go v3.14.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= -github.com/shuffle/shuffle-shared v0.7.0 h1:T7nbC5An/K9ePx1pwvYqSnnNZuafwK3GVy6wPDuog18= -github.com/shuffle/shuffle-shared v0.7.0/go.mod h1:bBXhEsPKjxln0mFnSeri7gIJ3tL/636Sh5NyTyNrvIQ= -github.com/shuffle/shuffle-shared v0.7.82 h1:La11F5jp9bNtM3VuR9PawyWo90/vZ+1Txo4NIc4YdPg= -github.com/shuffle/shuffle-shared v0.7.82/go.mod h1:bBXhEsPKjxln0mFnSeri7gIJ3tL/636Sh5NyTyNrvIQ= -github.com/shuffle/shuffle-shared v0.7.83 h1:OyyDo0ii8rOYHN5wGbcM94JuDKLmbZ9jhMQ0+/KMb0A= -github.com/shuffle/shuffle-shared v0.7.83/go.mod h1:bBXhEsPKjxln0mFnSeri7gIJ3tL/636Sh5NyTyNrvIQ= +github.com/shuffle/shuffle-shared v0.8.19 h1:HXqU62sPhVzv9MeJnA5ZpPYwwbitVz1EtMMABbY3t74= +github.com/shuffle/shuffle-shared v0.8.19/go.mod h1:NruHSAscDsW595wpK2r7MeHPGspUEKRNvBpcN1iGbHI= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= -github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= @@ -384,12 +366,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -398,6 +376,8 @@ golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -417,7 +397,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -443,21 +422,16 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= +golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= -golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -466,9 +440,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -494,24 +467,15 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= -golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= -golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -522,9 +486,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= @@ -556,7 +519,6 @@ golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -642,7 +604,6 @@ gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/functions/onprem/orborus/orborus.go b/functions/onprem/orborus/orborus.go index 2ee3c441..432880cf 100755 --- a/functions/onprem/orborus/orborus.go +++ b/functions/onprem/orborus/orborus.go @@ -146,6 +146,7 @@ func init() { os.Setenv("SHUFFLE_PIPELINE_AUTH", pipelineApikey) } } + } // form id of current running container @@ -459,6 +460,7 @@ func deployServiceWorkers(image string) { } } + /* isMemcachedRunning, err := checkMemcached(ctx, dockercli) if err != nil { log.Printf("[ERROR] Failed checking memcached: %s", err) @@ -469,8 +471,10 @@ func deployServiceWorkers(image string) { } ip := "shuffle-cache" - - os.Setenv("SHUFFLE_MEMCACHED", fmt.Sprintf("%s:11211", ip)) + if len(os.Getenv("SHUFFLE_MEMCACHED")) == 0 { + os.Setenv("SHUFFLE_MEMCACHED", fmt.Sprintf("%s:11211", ip)) + } + */ defaultNetworkAttach := false if containerId != "" { @@ -611,7 +615,7 @@ func deployServiceWorkers(image string) { fmt.Sprintf("SHUFFLE_LOGS_DISABLED=%s", os.Getenv("SHUFFLE_LOGS_DISABLED")), fmt.Sprintf("DEBUG_MEMORY=%s", os.Getenv("DEBUG_MEMORY")), fmt.Sprintf("SHUFFLE_APP_SDK_TIMEOUT=%s", os.Getenv("SHUFFLE_APP_SDK_TIMEOUT")), - fmt.Sprintf("SHUFFLE_MAX_SWARM_NODES=%d", os.Getenv("SHUFFLE_MAX_SWARM_NODES")), + fmt.Sprintf("SHUFFLE_MAX_SWARM_NODES=%s", os.Getenv("SHUFFLE_MAX_SWARM_NODES")), fmt.Sprintf("SHUFFLE_BASE_IMAGE_NAME=%s", os.Getenv("SHUFFLE_BASE_IMAGE_NAME")), fmt.Sprintf("SHUFFLE_APP_REQUEST_TIMEOUT=%s", os.Getenv("SHUFFLE_APP_REQUEST_TIMEOUT")), }, @@ -655,6 +659,7 @@ func deployServiceWorkers(image string) { serviceSpec.TaskTemplate.ContainerSpec.Env = append(serviceSpec.TaskTemplate.ContainerSpec.Env, fmt.Sprintf("HTTP_PROXY=%s", os.Getenv("HTTP_PROXY"))) serviceSpec.TaskTemplate.ContainerSpec.Env = append(serviceSpec.TaskTemplate.ContainerSpec.Env, fmt.Sprintf("HTTPS_PROXY=%s", os.Getenv("HTTPS_PROXY"))) serviceSpec.TaskTemplate.ContainerSpec.Env = append(serviceSpec.TaskTemplate.ContainerSpec.Env, fmt.Sprintf("NO_PROXY=%s", os.Getenv("NO_PROXY"))) + serviceSpec.TaskTemplate.ContainerSpec.Env = append(serviceSpec.TaskTemplate.ContainerSpec.Env, fmt.Sprintf("no_proxy=%s", os.Getenv("no_proxy"))) } if len(workerServerUrl) > 0 { @@ -768,42 +773,40 @@ func handleBackendImageDownload(ctx context.Context, images string) error { // Remove the image handled := []string{} - log.Printf("[DEBUG] Should remove existing image (s): %s. Waiting 30 seconds to ensure backend has the latest images built and ready to distribute.", images) - removeOptions := image.RemoveOptions{} - - time.Sleep(time.Duration(30) * time.Second) + log.Printf("[DEBUG] Removing existing image (s): %s. Waiting 30 seconds before starting to ensure backend has the latest images built and ready to distribute.", images) + //time.Sleep(time.Duration(30) * time.Second) newImages := []string{} - for _, image := range strings.Split(images, ",") { - image = strings.TrimSpace(image) - if shuffle.ArrayContains(handled, image) { + for _, curimage := range strings.Split(images, ",") { + curimage = strings.TrimSpace(curimage) + if shuffle.ArrayContains(handled, curimage) { continue } - handled = append(handled, image) - if !strings.Contains(image, "/") { - image = fmt.Sprintf("frikky/shuffle:%s", image) + handled = append(handled, curimage) + if !strings.Contains(curimage, "/") { + curimage = fmt.Sprintf("frikky/shuffle:%s", curimage) } - newImages = append(newImages, image) + newImages = append(newImages, curimage) + + // Force remove the current image to avoid cached layers + _, err := dockercli.ImageRemove(ctx, curimage, image.RemoveOptions{ + Force: true, + PruneChildren: true, + }) - // There is no real point in actual removal. This may however be a good idea, as Worker will force download the new one anyway - resp, err := dockercli.ImageRemove(ctx, image, removeOptions) if err != nil { - log.Printf("[ERROR] Failed removing image: %s. Resp: %#v", err, resp) - - // Goroutining images that don't already exist, as they are most likely not the correct one - go shuffle.DownloadDockerImageBackend(&http.Client{Timeout: imagedownloadTimeout}, image) + log.Printf("[ERROR] Failed removing image for re-download: %s", err) } else { - log.Printf("[DEBUG] Removed image: %s", image) + log.Printf("[DEBUG] Removed image: %s", curimage) + } - err = shuffle.DownloadDockerImageBackend(&http.Client{Timeout: imagedownloadTimeout}, image) - if err != nil { - log.Printf("[ERROR] Failed downloading image: %s", err) - } else { - log.Printf("[DEBUG] Downloaded image: %s", image) - //break - } + err = shuffle.DownloadDockerImageBackend(&http.Client{Timeout: imagedownloadTimeout}, curimage) + if err != nil { + log.Printf("[ERROR] Failed downloading image: %s", err) + } else { + log.Printf("[DEBUG] Downloaded image: %s", curimage) } } @@ -822,20 +825,18 @@ func handleBackendImageDownload(ctx context.Context, images string) error { ) if err != nil { - log.Printf("[ERROR] Failed finding containers: %s", err) + log.Printf("[ERROR] Failed finding services: %s", err) } else { - log.Printf("[DEBUG] Found %d services", len(services)) - + found := false for _, service := range services { - - log.Printf("Imagename: %s", service.Spec.TaskTemplate.ContainerSpec.Image) + //log.Printf("Service image: %s", service.Spec.TaskTemplate.ContainerSpec.Image) for _, image := range newImages { if !strings.Contains(service.Spec.TaskTemplate.ContainerSpec.Image, image) { continue } - log.Printf("[DEBUG] Found service for image %#v: %#v", service.Spec.Annotations.Name) + log.Printf("[DEBUG] Found service for image: %#v", service.Spec.Annotations.Name) // Update the service to run with the new image //docker service update --image username/imagename:latest servicename --force @@ -855,9 +856,20 @@ func handleBackendImageDownload(ctx context.Context, images string) error { if !strings.Contains(fmt.Sprintf("%s", resp), "error") { break + } else { + found = true + log.Printf("[ERROR] Failed updating service %s with the new image %s: %s. Resp: %#v", service.Spec.Annotations.Name, image, err, resp) } } } + + if found { + break + } + } + + if !found { + log.Printf("[DEBUG] Failed to find service to update for service %s", newImages) } } @@ -978,8 +990,6 @@ func fixk8sRoles() { } } -func int32Ptr(i int32) *int32 { return &i } - func deployK8sWorker(image string, identifier string, env []string) error { env = append(env, fmt.Sprintf("IS_KUBERNETES=true")) env = append(env, fmt.Sprintf("KUBERNETES_NAMESPACE=%s", os.Getenv("KUBERNETES_NAMESPACE"))) @@ -1183,7 +1193,7 @@ func deployK8sWorker(image string, identifier string, env []string) error { Name: identifier, }, Spec: appsv1.DeploymentSpec{ - Replicas: int32Ptr(replicaNumberInt32), + Replicas: &replicaNumberInt32, Selector: &metav1.LabelSelector{ MatchLabels: containerLabels, }, @@ -1236,18 +1246,20 @@ func deployK8sWorker(image string, identifier string, env []string) error { } func deployWorker(image string, identifier string, env []string, executionRequest shuffle.ExecutionRequest) error { + + if len(os.Getenv("REGISTRY_URL")) > 0 && os.Getenv("REGISTRY_URL") != "" { env = append(env, fmt.Sprintf("REGISTRY_URL=%s", os.Getenv("REGISTRY_URL"))) } - // if isKubernetes == "true" { - // err := deployK8sWorker(image, identifier, env, executionRequest) - // if err != nil { - // log.Printf("[ERROR] Failed deploying Kubernetes worker: %s", err) - // } + if swarmConfig == "run" || swarmConfig == "swarm" || isKubernetes == "true" { + // FIXME: Should we handle replies properly? + // In certain cases, a workflow may e.g. be aborted already. If it's aborted, that returns + // a 401 from the worker, which returns an error here + go sendWorkerRequest(executionRequest, image, env) - // return err - // } + return nil + } // Binds is the actual "-v" volume. // Max 20% CPU every second @@ -1295,6 +1307,10 @@ func deployWorker(image string, identifier string, env []string, executionReques } } + + //var swarmConfig = os.Getenv("SHUFFLE_SWARM_CONFIG") + parsedUuid := uuid.NewV4() + config := &container.Config{ Image: image, Env: env, @@ -1302,22 +1318,12 @@ func deployWorker(image string, identifier string, env []string, executionReques if isKubernetes != "true" { hostConfig.NetworkMode = container.NetworkMode(fmt.Sprintf("container:%s", containerId)) + if strings.ToLower(cleanupEnv) != "false" { hostConfig.AutoRemove = true } } - //var swarmConfig = os.Getenv("SHUFFLE_SWARM_CONFIG") - parsedUuid := uuid.NewV4() - if swarmConfig == "run" || swarmConfig == "swarm" || isKubernetes == "true" { - // FIXME: Should we handle replies properly? - // In certain cases, a workflow may e.g. be aborted already. If it's aborted, that returns - // a 401 from the worker, which returns an error here - go sendWorkerRequest(executionRequest, image, env) - - return nil - } - //log.Printf("[INFO] Identifier: %s", identifier) cont, err := dockercli.ContainerCreate( context.Background(), @@ -1351,8 +1357,12 @@ func deployWorker(image string, identifier string, env []string, executionReques } } + // FIXME: Verbosity for testing + //log.Printf("WORKER STARTING WITH ENV: %#v", env) + + ctx := context.Background() containerStartOptions := container.StartOptions{} - err = dockercli.ContainerStart(context.Background(), cont.ID, containerStartOptions) + err = dockercli.ContainerStart(ctx, cont.ID, containerStartOptions) if err != nil { // Trying to recreate and start WITHOUT network if it's possible. No extended checks. Old execution system (<0.9.30) if strings.Contains(fmt.Sprintf("%s", err), "cannot join network") || strings.Contains(fmt.Sprintf("%s", err), "No such container") { @@ -1385,27 +1395,30 @@ func deployWorker(image string, identifier string, env []string, executionReques log.Printf("[INFO][%s] Worker Container created (2). Environment %s: docker logs %s", executionRequest.ExecutionId, environment, cont.ID) } - //stats, err := cli.ContainerInspect(context.Background(), containerName) - //if err != nil { - // log.Printf("Failed checking worker %s", containerName) - // return - //} + stats, err := dockercli.ContainerInspect(ctx, cont.ID) + if err != nil { + log.Printf("[WARNING] Failed checking worker '%s': %s", cont.ID, err) + return nil + } - //containerStatus := stats.ContainerJSONBase.State.Status - //if containerStatus != "running" { - // log.Printf("Status of %s is %s. Should be running. Will reset", containerName, containerStatus) - // err = stopWorker(containerName) - // if err != nil { - // log.Printf("Failed stopping worker %s", execution.ExecutionId) - // return - // } + containerStatus := stats.ContainerJSONBase.State.Status + if containerStatus != "running" { + log.Printf("[ERROR] Status of %s is %s. Should be running. Contact support@shuffler.io if this persists.", cont.ID, containerStatus) + } + /* + err = stopWorker(containerName) + if err != nil { + log.Printf("Failed stopping worker %s", execution.ExecutionId) + return nil + } - // err = deployWorke(cli, workerImage, containerName, env) - // if err != nil { - // log.Printf("Failed executing worker %s in state %s", execution.ExecutionId, containerStatus) - // return - // } - //} + err = deployWorker(dockercli, workerImage, containerName, env) + if err != nil { + log.Printf("Failed executing worker %s in state %s", execution.ExecutionId, containerStatus) + return nil + } + } + */ } else { log.Printf("[INFO][%s] New Worker created. Environment %s: docker logs %s", executionRequest.ExecutionId, environment, cont.ID) } @@ -1471,29 +1484,34 @@ func initializeImages() { } // check whether they are the same first - images := []string{ - fmt.Sprintf("frikky/shuffle:app_sdk"), - fmt.Sprintf("shuffle/shuffle:app_sdk"), - fmt.Sprintf("%s/%s/shuffle-app_sdk:%s", baseimageregistry, baseimagename, appSdkVersion), - newWorker, - } - pullOptions := image.PullOptions{} - for _, image := range images { - if isKubernetes == "true" { - log.Printf("[DEBUG] Skipping image pull of '%s' because Kubernetes does it in realtime instead", image) - } else { - log.Printf("[DEBUG] Pulling image %s", image) - reader, err := dockercli.ImagePull(ctx, image, pullOptions) - if err != nil { - log.Printf("[ERROR] Failed getting image %s: %s", image, err) - - continue - } - - io.Copy(os.Stdout, reader) - log.Printf("[DEBUG] Successfully downloaded and built %s", image) + if os.Getenv("SHUFFLE_AUTO_IMAGE_DOWNLOAD") != "true" { + images := []string{ + fmt.Sprintf("frikky/shuffle:app_sdk"), + fmt.Sprintf("shuffle/shuffle:app_sdk"), + fmt.Sprintf("%s/%s/shuffle-app_sdk:%s", baseimageregistry, baseimagename, appSdkVersion), + newWorker, } + + pullOptions := image.PullOptions{} + for _, image := range images { + if isKubernetes == "true" { + log.Printf("[DEBUG] Skipping image pull of '%s' because Kubernetes does it in realtime instead", image) + } else { + log.Printf("[DEBUG] Pulling image %s", image) + reader, err := dockercli.ImagePull(ctx, image, pullOptions) + if err != nil { + log.Printf("[ERROR] Failed getting image %s: %s", image, err) + + continue + } + + io.Copy(os.Stdout, reader) + log.Printf("[DEBUG] Successfully downloaded and built %s", image) + } + } + } else { + log.Printf("[DEBUG] Skipping image download as SHUFFLE_AUTO_IMAGE_DOWNLOAD is set to true") } } @@ -1914,6 +1932,10 @@ func main() { cleanupEnv = "true" } + if len(cleanupEnv) > 0 { + log.Printf("[DEBUG] Verbose mode. NOT cleaning up. Cleanup env: %s", cleanupEnv) + } + workerTimeout := 600 if workerTimeoutEnv != "" { tmpInt, err := strconv.Atoi(workerTimeoutEnv) @@ -2233,7 +2255,7 @@ func main() { toBeRemoved.Data = append(toBeRemoved.Data, incRequest) } else if incRequest.Type == "DOCKER_IMAGE_DOWNLOAD" { - log.Printf("[INFO] Should delete -> download new images: %#v", incRequest.ExecutionArgument) + log.Printf("[INFO] Re-downloading new image(s): %#v", incRequest.ExecutionArgument) if len(incRequest.ExecutionArgument) > 0 { // FIXME: Wait X seconds before running this as the image build may not be done yet. This is shitty, but may be ok to do in Orborus. Easy fix for the future: Just let it run through jobs 5-10 times before actually picking it up @@ -3311,6 +3333,11 @@ func extractZIP(zipFile, destDir string) error { } for _, f := range r.File { + // Fix path traversal + if strings.Contains(f.Name, "..") { + return fmt.Errorf("illegal file name: %s", f.Name) + } + err := extractFile(f, destDir) if err != nil { return err @@ -3450,7 +3477,7 @@ func sendPipelineHealthStatus() (shuffle.LakeConfig, error) { } else { tenzirDisabled = true - log.Printf("[ERROR] Disabling pipelines: %s. You will need to restart the Orborus to fix this.", err) + log.Printf("[WARNING] Disabling pipelines: %s. You will need to restart the Orborus to fix this.", err) } return pipelinePayload, err diff --git a/functions/onprem/worker/Dockerfile b/functions/onprem/worker/Dockerfile index 019e0fc7..a2fb13b3 100755 --- a/functions/onprem/worker/Dockerfile +++ b/functions/onprem/worker/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.22 as builder +FROM golang:1.23 as builder WORKDIR /app #RUN go get github.com/docker/docker/api/types github.com/docker/docker/api/types/container github.com/docker/docker/client @@ -9,7 +9,8 @@ COPY go.mod /app/go.mod #COPY go.sum /app/go.sum #RUN go #COPY go.sum /app/go.sum -RUN go get +RUN go mod download +RUN go mod tidy #RUN go mod init worker #RUN go get diff --git a/functions/onprem/worker/go.mod b/functions/onprem/worker/go.mod index ea1077ba..035ac090 100644 --- a/functions/onprem/worker/go.mod +++ b/functions/onprem/worker/go.mod @@ -1,14 +1,14 @@ module worker -go 1.22.7 +go 1.23.0 -toolchain go1.22.11 +toolchain go1.23.7 require ( github.com/docker/docker v27.5.0+incompatible github.com/gorilla/mux v1.8.1 github.com/satori/go.uuid v1.2.0 - github.com/shuffle/shuffle-shared v0.7.92 + github.com/shuffle/shuffle-shared v0.8.19 k8s.io/api v0.30.2 k8s.io/apimachinery v0.30.2 k8s.io/client-go v0.30.2 @@ -16,13 +16,13 @@ require ( require ( cloud.google.com/go v0.112.0 // indirect - cloud.google.com/go/compute v1.24.0 // indirect cloud.google.com/go/compute/metadata v0.5.0 // indirect cloud.google.com/go/datastore v1.15.0 // indirect cloud.google.com/go/iam v1.1.6 // indirect cloud.google.com/go/scheduler v1.10.6 // indirect cloud.google.com/go/storage v1.36.0 // indirect dario.cat/mergo v1.0.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ProtonMail/go-crypto v1.1.3 // indirect @@ -30,8 +30,8 @@ require ( github.com/algolia/algoliasearch-client-go/v3 v3.18.1 // indirect github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 // indirect github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cloudflare/circl v1.3.7 // indirect - github.com/containerd/log v0.1.0 // indirect github.com/cyphar/filepath-securejoin v0.2.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/distribution/reference v0.6.0 // indirect @@ -69,10 +69,8 @@ require ( github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect - github.com/moby/term v0.5.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/morikuni/aec v1.0.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect @@ -85,6 +83,7 @@ require ( github.com/sendgrid/rest v2.6.9+incompatible // indirect github.com/sendgrid/sendgrid-go v3.14.0+incompatible // indirect github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/skeema/knownhosts v1.3.0 // indirect github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e // indirect github.com/spf13/pflag v1.0.5 // indirect @@ -94,19 +93,19 @@ require ( go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect go.opentelemetry.io/otel v1.33.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 // indirect go.opentelemetry.io/otel/metric v1.33.0 // indirect - go.opentelemetry.io/otel/sdk v1.33.0 // indirect go.opentelemetry.io/otel/trace v1.33.0 // indirect + go.opentelemetry.io/proto/otlp v1.4.0 // indirect go4.org v0.0.0-20201209231011-d4a079459e60 // indirect - golang.org/x/crypto v0.32.0 // indirect + golang.org/x/crypto v0.36.0 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.34.0 // indirect + golang.org/x/net v0.37.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/term v0.28.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/sync v0.12.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/term v0.30.0 // indirect + golang.org/x/text v0.23.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/api v0.162.0 // indirect @@ -120,7 +119,6 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - gotest.tools/v3 v3.5.1 // indirect k8s.io/klog/v2 v2.120.1 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect diff --git a/functions/onprem/worker/go.sum b/functions/onprem/worker/go.sum index 91e7cc1f..028e4dd8 100644 --- a/functions/onprem/worker/go.sum +++ b/functions/onprem/worker/go.sum @@ -11,10 +11,6 @@ cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= -cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= -cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= -cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= @@ -33,8 +29,8 @@ cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYE dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= @@ -42,8 +38,6 @@ github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF0 github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= -github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk= github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/adrg/strutil v0.2.3 h1:WZVn3ItPBovFmP4wMHHVXUr8luRaHrbyIuLlHt32GZQ= @@ -72,7 +66,6 @@ github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874 h1:N7oVaKyGp8b github.com/bradfitz/gomemcache v0.0.0-20230905024940-24af94b03874/go.mod h1:r5xuitiExdLAJ09PR7vBVENGvp4ZuTBeWTGtxuX3K+c= github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013 h1:/P9/RL0xgWE+ehnCUUN5h3RpG3dmoMCOONO1CCvq23Y= github.com/bradfitz/slice v0.0.0-20180809154707-2b758aa73013/go.mod h1:pccXHIvs3TV/TUqSNyEvF99sxjX2r4FFRIyw6TZY9+w= -github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -80,17 +73,14 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa h1:jQCWAUqqlij9Pgj2i/PB79y4KOPYVyFYdROxgaCwdTQ= -github.com/cncf/xds/go v0.0.0-20231128003011-0fa0005c9caa/go.mod h1:x/1Gn8zydmfq8dk6e9PdstVsDgu9RuyIIJqAaF//0IM= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 h1:QVw89YDxXxEe+l8gU8ETbOasdwEV+avkR75ZzsVV9WI= +github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= -github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo= github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -98,16 +88,14 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v26.1.5+incompatible h1:NEAxTwEjxV6VbBMBoGG3zPqbiJosIApZjxlbrG9q3/g= -github.com/docker/docker v26.1.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v27.5.0+incompatible h1:um++2NcQtGRTz5eEgO6aJimo6/JxrTXC941hd05JO6U= github.com/docker/docker v27.5.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= -github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= +github.com/elazarl/goproxy v1.2.1 h1:njjgvO6cRG9rIqN2ebkqy6cQz2Njkx7Fsfv/zIZqgug= +github.com/elazarl/goproxy v1.2.1/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= @@ -116,8 +104,8 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A= -github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= +github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM= +github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frikky/kin-openapi v0.41.0 h1:oMmjo+ekGS971lb3KLeZZOqRDZOwWi3+g/OiSWP08+s= @@ -126,25 +114,19 @@ github.com/frikky/schemaless v0.0.13 h1:ARiN9V7wr2VZXAr9JK5wvTbyPgpGrgeiL1VhR5Ml github.com/frikky/schemaless v0.0.13/go.mod h1:mooDxY+D6weHjhKvjy3+IE9S7P4g4cpNnidkdRv/cHQ= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= -github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= +github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= +github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= -github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= -github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8= github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= -github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= -github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= github.com/go-git/go-git/v5 v5.13.0 h1:vLn5wlGIh/X78El6r3Jr+30W16Blk0CTcxTYcYPWi5E= github.com/go-git/go-git/v5 v5.13.0/go.mod h1:Wjo7/JyVKtQgUNdXYXIepzWfJQkUEIGvkvVkiXRR/zw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= -github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -231,8 +213,8 @@ github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56 github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0 h1:TmHmbvxPmaegwhDubVz0lICL0J5Ka2vwTzhoePEXsGE= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.24.0/go.mod h1:qztMSjm835F2bXf+5HKAPIS5qsmQDqZna/PgVt4rWtI= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -266,8 +248,7 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -280,8 +261,8 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= -github.com/onsi/gomega v1.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE= -github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk= +github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= +github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -300,8 +281,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk= github.com/sashabaranov/go-openai v1.19.2 h1:+dkuCADSnwXV02YVJkdphY8XD9AyHLUWwk6V7LB6EL8= github.com/sashabaranov/go-openai v1.19.2/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= @@ -311,25 +292,13 @@ github.com/sendgrid/rest v2.6.9+incompatible h1:1EyIcsNdn9KIisLW50MKwmSRSK+ekuei github.com/sendgrid/rest v2.6.9+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE= github.com/sendgrid/sendgrid-go v3.14.0+incompatible h1:KDSasSTktAqMJCYClHVE94Fcif2i7P7wzISv1sU6DUA= github.com/sendgrid/sendgrid-go v3.14.0+incompatible/go.mod h1:QRQt+LX/NmgVEvmdRw0VT/QgUn499+iza2FnDca9fg8= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= -github.com/shuffle/shuffle-shared v0.6.74 h1:os3BDSFZnl4U8ZgsTAY8IsTDADcMXhbc1rS9UMa0BIY= -github.com/shuffle/shuffle-shared v0.6.74/go.mod h1:RAJiSFjmuKmijKTbbEf9A6Ojb+3/te7g71lED7JjPus= -github.com/shuffle/shuffle-shared v0.6.90 h1:FzIYtEt44eWgEsW/9tj2ki7qq8FEm/HWXUok+THp72M= -github.com/shuffle/shuffle-shared v0.6.90/go.mod h1:RAJiSFjmuKmijKTbbEf9A6Ojb+3/te7g71lED7JjPus= -github.com/shuffle/shuffle-shared v0.7.0 h1:T7nbC5An/K9ePx1pwvYqSnnNZuafwK3GVy6wPDuog18= -github.com/shuffle/shuffle-shared v0.7.0/go.mod h1:bBXhEsPKjxln0mFnSeri7gIJ3tL/636Sh5NyTyNrvIQ= -github.com/shuffle/shuffle-shared v0.7.82 h1:La11F5jp9bNtM3VuR9PawyWo90/vZ+1Txo4NIc4YdPg= -github.com/shuffle/shuffle-shared v0.7.82/go.mod h1:bBXhEsPKjxln0mFnSeri7gIJ3tL/636Sh5NyTyNrvIQ= -github.com/shuffle/shuffle-shared v0.7.83 h1:OyyDo0ii8rOYHN5wGbcM94JuDKLmbZ9jhMQ0+/KMb0A= -github.com/shuffle/shuffle-shared v0.7.83/go.mod h1:bBXhEsPKjxln0mFnSeri7gIJ3tL/636Sh5NyTyNrvIQ= +github.com/shuffle/shuffle-shared v0.8.19 h1:HXqU62sPhVzv9MeJnA5ZpPYwwbitVz1EtMMABbY3t74= +github.com/shuffle/shuffle-shared v0.8.19/go.mod h1:NruHSAscDsW595wpK2r7MeHPGspUEKRNvBpcN1iGbHI= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= -github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= @@ -348,8 +317,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -365,32 +334,22 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 h1:UNQQKPfTDe1J81ViolILjTKPr9WetKW6uei2hFgJmFs= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0 h1:cEPbyTSEHlQR89XVlyo78gqluF8Y3oMeBkXGWzQsfXY= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.50.0/go.mod h1:DKdbWcT4GH1D0Y3Sqt/PFXt2naRKDWtU+eE6oLdFNA8= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= -go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k= -go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= go.opentelemetry.io/otel v1.33.0 h1:/FerN9bax5LoK51X/sI0SVYrjSE0/yUL7DpxW4K3FWw= go.opentelemetry.io/otel v1.33.0/go.mod h1:SUUkR6csvUQl+yjReHu5uM3EtVV7MBm5FHKRlNx4I8I= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0 h1:dT33yIHtmsqpixFsSQPwNeY5drM9wTcoL8h0FWF4oGM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0/go.mod h1:h95q0LBGh7hlAC08X2DhSeyIG02YQ0UyioTCVAqRPmc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0 h1:Mbi5PKN7u322woPa85d7ebZ+SOvEoPvoiBu+ryHWgfA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0/go.mod h1:e7ciERRhZaOZXVjx5MiL8TK5+Xv7G5Gv5PA2ZDEJdL8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0 h1:Vh5HayB/0HHfOQA7Ctx69E/Y/DcQSMPpKANYVMQ7fBA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.33.0/go.mod h1:cpgtDBaqD/6ok/UG0jT15/uKjAY8mRA53diogHBg3UI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0 h1:wpMfgF8E1rkrT1Z6meFh1NDtownE9Ii3n3X2GJYjsaU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.33.0/go.mod h1:wAy0T/dUbs468uOlkT31xjvqQgEVXv58BRFWEgn5v/0= -go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA= -go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= go.opentelemetry.io/otel/metric v1.33.0 h1:r+JOocAyeRVXD8lZpjdQjzMadVZp2M4WmQ+5WtEnklQ= go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M= -go.opentelemetry.io/otel/sdk v1.25.0 h1:PDryEJPC8YJZQSyLY5eqLeafHtG+X7FWnf3aXMtxbqo= -go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw= +go.opentelemetry.io/otel/sdk v1.33.0 h1:iax7M131HuAm9QkZotNHEfstof92xM+N8sr3uHXc2IM= go.opentelemetry.io/otel/sdk v1.33.0/go.mod h1:A1Q5oi7/9XaMlIWzPSxLRWOI8nG3FnzHJNbiENQuihM= -go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM= -go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= go.opentelemetry.io/otel/trace v1.33.0 h1:cCJuF7LRjUFso9LPnEAHJDB2pqzp+hbO8eu1qqW2d/s= go.opentelemetry.io/otel/trace v1.33.0/go.mod h1:uIcdVUZMpTAmz0tI1z04GoVSezK37CbGV4fr1f2nBck= -go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= -go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= +go.opentelemetry.io/proto/otlp v1.4.0 h1:TA9WRvW6zMwP+Ssb6fLoUIuirti1gGbP28GcKG1jgeg= +go.opentelemetry.io/proto/otlp v1.4.0/go.mod h1:PPBWZIP98o2ElSqI35IHfu7hIhSwvc5N38Jw8pXuGFY= go4.org v0.0.0-20201209231011-d4a079459e60 h1:iqAGo78tVOJXELHQFRjR6TMwItrvXH4hrGJ32I/NFF8= go4.org v0.0.0-20201209231011-d4a079459e60/go.mod h1:CIiUVy99QCPfoE13bO4EZaz5GZMZXMSBGhxRdsvzbkg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -400,12 +359,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= +golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -414,6 +369,8 @@ golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -433,9 +390,6 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -460,21 +414,14 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= +golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= -golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -485,11 +432,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= +golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -509,28 +453,20 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -541,11 +477,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -577,9 +510,6 @@ golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= -golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -621,12 +551,8 @@ google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= -google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de h1:jFNzHPIeuzhdRwVhbZdiym9q0ory/xY3sA+v2wPg8I0= -google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:5iCWqnniDlqZHrd3neWVTOwvh/v6s3232omMecelax8= google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q= google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda h1:LI5DOvAxUPMv/50agcLLoo+AdWc1irS9Rzz4vPuD1V4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY= google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -638,8 +564,6 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.63.0 h1:WjKe+dnvABXyPJMD7KDNLxtoGk5tgk+YFWN6cBWjZE8= -google.golang.org/grpc v1.63.0/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0= google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= @@ -653,8 +577,6 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -668,7 +590,6 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/functions/onprem/worker/worker.go b/functions/onprem/worker/worker.go index d212055f..a19ceb80 100644 --- a/functions/onprem/worker/worker.go +++ b/functions/onprem/worker/worker.go @@ -58,11 +58,10 @@ var swarmNetworkName = os.Getenv("SHUFFLE_SWARM_NETWORK_NAME") var dockerApiVersion = strings.ToLower(os.Getenv("DOCKER_API_VERSION")) var appServiceAccountName = os.Getenv("SHUFFLE_APP_SERVICE_ACCOUNT_NAME") -var baseimagename = "frikky/shuffle" var kubernetesNamespace = os.Getenv("KUBERNETES_NAMESPACE") var executionCount int64 -// var baseimagename = os.Getenv("SHUFFLE_BASE_IMAGE_NAME") +var baseimagename = os.Getenv("SHUFFLE_BASE_IMAGE_NAME") // var baseimagename = "registry.hub.docker.com/frikky/shuffle" var registryName = "registry.hub.docker.com" @@ -106,11 +105,9 @@ var window = shuffle.NewTimeWindow(10 * time.Second) // Images to be autodeployed in the latest version of Shuffle. var autoDeploy = map[string]string{ - "http:1.4.0": "frikky/shuffle:http_1.4.0", - "http:1.3.0": "frikky/shuffle:http_1.3.0", - "shuffle-tools:1.2.0": "frikky/shuffle:shuffle-tools_1.2.0", - "shuffle-subflow:1.0.0": "frikky/shuffle:shuffle-subflow_1.0.0", - "shuffle-subflow:1.1.0": "frikky/shuffle:shuffle-subflow_1.1.0", + "http:1.4.0": "frikky/shuffle:http_1.4.0", + "shuffle-tools:1.2.0": "frikky/shuffle:shuffle-tools_1.2.0", + "shuffle-subflow:1.1.0": "frikky/shuffle:shuffle-subflow_1.1.0", // "shuffle-tools-fork:1.0.0": "frikky/shuffle:shuffle-tools-fork_1.0.0", } @@ -393,8 +390,6 @@ func shutdown(workflowExecution shuffle.WorkflowExecution, nodeId string, reason } } -func int32Ptr(i int32) *int32 { return &i } - // ** STARTREMOVE ***/ func deployk8sApp(image string, identifier string, env []string) error { if len(os.Getenv("KUBERNETES_NAMESPACE")) > 0 { @@ -573,7 +568,7 @@ func deployk8sApp(image string, identifier string, env []string) error { Name: podName, }, Spec: appsv1.DeploymentSpec{ - Replicas: int32Ptr(replicaNumberInt32), + Replicas: &replicaNumberInt32, Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{ "app": podName, @@ -925,6 +920,8 @@ func deployApp(cli *dockerclient.Client, image string, identifier string, env [] Env: env, } + //log.Printf("[DEBUG] Deploying image with env: %#v", env) + // Checking as late as possible, just in case. newExecId := fmt.Sprintf("%s_%s", workflowExecution.ExecutionId, action.ID) _, err := shuffle.GetCache(ctx, newExecId) @@ -1463,6 +1460,7 @@ func handleExecutionResult(workflowExecution shuffle.WorkflowExecution) { env = append(env, fmt.Sprintf("HTTP_PROXY=%s", os.Getenv("HTTP_PROXY"))) env = append(env, fmt.Sprintf("HTTPS_PROXY=%s", os.Getenv("HTTPS_PROXY"))) env = append(env, fmt.Sprintf("NO_PROXY=%s", os.Getenv("NO_PROXY"))) + env = append(env, fmt.Sprintf("no_proxy=%s", os.Getenv("no_proxy"))) } overrideHttpProxy := os.Getenv("SHUFFLE_INTERNAL_HTTP_PROXY") @@ -3076,6 +3074,7 @@ func deploySwarmService(dockercli *dockerclient.Client, name, image string, depl serviceSpec.TaskTemplate.ContainerSpec.Env = append(serviceSpec.TaskTemplate.ContainerSpec.Env, fmt.Sprintf("HTTP_PROXY=%s", os.Getenv("HTTP_PROXY"))) serviceSpec.TaskTemplate.ContainerSpec.Env = append(serviceSpec.TaskTemplate.ContainerSpec.Env, fmt.Sprintf("HTTPS_PROXY=%s", os.Getenv("HTTPS_PROXY"))) serviceSpec.TaskTemplate.ContainerSpec.Env = append(serviceSpec.TaskTemplate.ContainerSpec.Env, fmt.Sprintf("NO_PROXY=%s", os.Getenv("NO_PROXY"))) + serviceSpec.TaskTemplate.ContainerSpec.Env = append(serviceSpec.TaskTemplate.ContainerSpec.Env, fmt.Sprintf("no_proxy=%s", os.Getenv("no_proxy"))) } overrideHttpProxy := os.Getenv("SHUFFLE_INTERNAL_HTTP_PROXY") @@ -3524,6 +3523,7 @@ func baseDeploy() { env = append(env, fmt.Sprintf("HTTP_PROXY=%s", os.Getenv("HTTP_PROXY"))) env = append(env, fmt.Sprintf("HTTPS_PROXY=%s", os.Getenv("HTTPS_PROXY"))) env = append(env, fmt.Sprintf("NO_PROXY=%s", os.Getenv("NO_PROXY"))) + env = append(env, fmt.Sprintf("no_proxy=%s", os.Getenv("no_proxy"))) } if len(os.Getenv("SHUFFLE_APP_SDK_TIMEOUT")) > 0 { @@ -3724,7 +3724,7 @@ func main() { } if baseimagename == "" { - log.Printf("[DEBUG] Setting baseimagename") + log.Printf("[DEBUG] Setting baseimagename to frikky/shuffle") baseimagename = "frikky/shuffle" // Dockerhub //baseimagename = "shuffle" // Github (ghcr.io) }