diff --git a/.github/workflows/ci-build.yaml b/.github/workflows/ci-build.yaml index 2f59d2a2ace5..215eec0ffcce 100644 --- a/.github/workflows/ci-build.yaml +++ b/.github/workflows/ci-build.yaml @@ -97,7 +97,7 @@ jobs: # proposals live only on GH as pure markdown - '!docs/proposals/**' # docs scripts & tools from `make docs` - - hack/check-mkdocs.sh + - hack/copy-readme.sh - hack/check-env-doc.sh - .markdownlint.yaml - .mlc_config.json diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0f31c76c4aad..16c3fa54521e 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -46,13 +46,6 @@ jobs: restore-keys: | ${{ runner.os }}-${{ matrix.platform }}-${{ matrix.target }}-buildx- - ## Codefresh - remove dockerhub - # - name: Docker Login - # uses: docker/login-action@v1 - # with: - # username: ${{ secrets.DOCKERIO_USERNAME }} - # password: ${{ secrets.DOCKERIO_PASSWORD }} - - name: Docker Login uses: docker/login-action@v2 with: @@ -74,15 +67,6 @@ jobs: tag_suffix=$(echo $PLATFORM | sed -r "s/\//-/g") image_name="${DOCKERIO_ORG}/${TARGET}:${tag}-${tag_suffix}" - ## Codefresh - remove dockerhub - # docker buildx build \ - # --cache-from "type=local,src=/tmp/.buildx-cache" \ - # --cache-to "type=local,dest=/tmp/.buildx-cache" \ - # --output "type=image,push=true" \ - # --platform="${PLATFORM}" \ - # --target $TARGET \ - # --tag $image_name . - docker buildx build \ --cache-from "type=local,src=/tmp/.buildx-cache" \ --cache-to "type=local,dest=/tmp/.buildx-cache" \ @@ -121,13 +105,6 @@ jobs: restore-keys: | ${{ runner.os }}-${{ matrix.platform }}-${{ matrix.target }}-buildx- - ## Codefresh - remove dockerhub - # - name: Docker Login - # uses: docker/login-action@v1 - # with: - # username: ${{ secrets.DOCKERIO_USERNAME }} - # password: ${{ secrets.DOCKERIO_PASSWORD }} - - name: Docker Login uses: docker/login-action@v2 with: @@ -149,15 +126,6 @@ jobs: tag_suffix=$(echo $PLATFORM | sed -r "s/\//-/g") image_name="${DOCKERIO_ORG}/${TARGET}:${tag}-${tag_suffix}" - ## Codefresh - remove dockerhub - # docker buildx build \ - # --cache-from "type=local,src=/tmp/.buildx-cache" \ - # --cache-to "type=local,dest=/tmp/.buildx-cache" \ - # --output "type=image,push=true" \ - # --platform="${PLATFORM}" \ - # --target $TARGET \ - # --tag $image_name . - docker buildx build \ --cache-from "type=local,src=/tmp/.buildx-cache" \ --cache-to "type=local,dest=/tmp/.buildx-cache" \ @@ -172,17 +140,11 @@ jobs: runs-on: windows-2022 steps: - uses: actions/checkout@v2 - ## Codefresh - remove dockerhub - # - name: Docker Login - # uses: Azure/docker-login@v1 - # with: - # username: ${{ secrets.DOCKERIO_USERNAME }} - # password: ${{ secrets.DOCKERIO_PASSWORD }} - name: Login to Quay - uses: Azure/docker-login@v1 + uses: docker/login-action@v2 with: - login-server: quay.io + registry: quay.io username: ${{ secrets.QUAYIO_USERNAME }} password: ${{ secrets.QUAYIO_PASSWORD }} @@ -215,17 +177,11 @@ jobs: needs: [ build-linux-amd64, build-linux-arm64, build-windows ] steps: - uses: actions/checkout@v2 - ## Codefresh - remove dockerhub - # - name: Docker Login - # uses: Azure/docker-login@v1 - # with: - # username: ${{ secrets.DOCKERIO_USERNAME }} - # password: ${{ secrets.DOCKERIO_PASSWORD }} - name: Login to Quay - uses: Azure/docker-login@v1 + uses: docker/login-action@v2 with: - login-server: quay.io + registry: quay.io username: ${{ secrets.QUAYIO_USERNAME }} password: ${{ secrets.QUAYIO_PASSWORD }} @@ -271,13 +227,6 @@ jobs: platform: [ linux/amd64 ] target: [ workflow-controller, argocli, argoexec ] steps: - ## Codefresh - remove dockerhub - # - name: Docker Login - # uses: Azure/docker-login@v1 - # with: - # username: ${{ secrets.DOCKERIO_USERNAME }} - # password: ${{ secrets.DOCKERIO_PASSWORD }} - - name: Login to Quay uses: Azure/docker-login@v1 with: @@ -297,8 +246,6 @@ jobs: fi image_name="${DOCKERIO_ORG}/${TARGET}:${tag}" - ## Codefresh - remove dockerhub - # docker pull $image_name docker pull quay.io/$image_name test-images-windows: @@ -307,13 +254,6 @@ jobs: runs-on: windows-2022 needs: [ push-images ] steps: - ## Codefresh - remove dockerhub - # - name: Docker Login - # uses: Azure/docker-login@v1 - # with: - # username: ${{ secrets.DOCKERIO_USERNAME }} - # password: ${{ secrets.DOCKERIO_PASSWORD }} - - name: Login to Quay uses: Azure/docker-login@v1 with: @@ -333,8 +273,6 @@ jobs: targets="argoexec" for target in $targets; do image_name="${docker_org}/${target}:${tag}" - ## Codefresh - remove dockerhub - # docker pull $image_name docker pull quay.io/$image_name done @@ -358,11 +296,13 @@ jobs: with: path: ui/node_modules key: ${{ runner.os }}-node-dep-v1-${{ hashFiles('**/yarn.lock') }} - - uses: actions/cache@v3 + - name: go build cache + uses: actions/cache@v3 with: path: /home/runner/.cache/go-build key: GOCACHE-v2-${{ hashFiles('**/go.mod') }} - - uses: actions/cache@v3 + - name: go mod cache + uses: actions/cache@v3 with: path: /home/runner/go/pkg/mod key: GOMODCACHE-v2-${{ hashFiles('**/go.mod') }} diff --git a/CHANGELOG.md b/CHANGELOG.md index ea069b8669d9..f8f10ff5bdb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,299 @@ # Changelog +## v3.5.5 (2024-02-29) + +* [6af917eb3](https://github.com/argoproj/argo-workflows/commit/6af917eb322bb84a2733723433a9eb87b7f1e85d) chore(deps): bump github.com/cloudflare/circl to 1.3.7 to fix GHSA-9763-4f94-gfch (#12556) +* [6ee52fc96](https://github.com/argoproj/argo-workflows/commit/6ee52fc96e700190de96a15993b933a26f0389c9) fix: make WF global parameters available in retries (#12698) +* [c2905bda5](https://github.com/argoproj/argo-workflows/commit/c2905bda5c9962fa64474a39a6e0c9b0a842e8c2) chore(deps): fixed medium CVE in github.com/docker/docker v24.0.0+incompatible (#12635) +* [dd8b4705b](https://github.com/argoproj/argo-workflows/commit/dd8b4705bdc3e3207e70eba70af7f72fb812cd3d) fix: documentation links (#12446) +* [72deab92a](https://github.com/argoproj/argo-workflows/commit/72deab92a5dec7b8df87109fb54398509ce24639) fix(docs): render Mermaid diagrams in docs (#12464) +* [9a4c787e7](https://github.com/argoproj/argo-workflows/commit/9a4c787e71e57edfe8a554a2f8f922cbe530430c) fix(docs): exclude `docs/requirements.txt` from docs build (#12466) +* [ae915fe9f](https://github.com/argoproj/argo-workflows/commit/ae915fe9ffae19fc721a790b7611a2428a23c845) fix(docs): handle `fields` examples with `md_in_html` (#12465) +* [a4674b9a1](https://github.com/argoproj/argo-workflows/commit/a4674b9a193451ad8379bd0c55604232c181abea) fix: merge env bug in workflow-controller-configmap and container. Fixes #12424 (#12426) +* [eb71bad60](https://github.com/argoproj/argo-workflows/commit/eb71bad60321fcdb5638471cf21ac67fb8a98a2a) fix: Add missing 'archived' prop for ArtifactPanel component. Fixes #12331 (#12397) +* [288eddcfe](https://github.com/argoproj/argo-workflows/commit/288eddcfeb34d53b14c72f698007c48e9afe7906) fix: wrong values are assigned to input parameters of workflowtemplat… (#12412) +* [c425aa0ee](https://github.com/argoproj/argo-workflows/commit/c425aa0ee572a39ead178add6357595cd4c20a07) fix(docs): remove `workflow-controller-configmap.yaml` self reference (#12654) +* [88332d4c3](https://github.com/argoproj/argo-workflows/commit/88332d4c37f34a71b5adbd4e9d720ff4645864dd) fix: upgrade expr-lang. Fixes #12037 (#12573) +* [a98027078](https://github.com/argoproj/argo-workflows/commit/a98027078fdd98113644b9d3e6833e79ecc57d2f) fix: make sure taskresult completed when mark node succeed when it has outputs (#12537) +* [901cfb636](https://github.com/argoproj/argo-workflows/commit/901cfb63632903b59b0f6858e813b85a104cb486) fix: controller option to not watch configmap (#12622) +* [a5bf99690](https://github.com/argoproj/argo-workflows/commit/a5bf99690c8b8189c439f2775685108e84a9cd02) fix: make etcd errors transient (#12567) +* [02a3e2e39](https://github.com/argoproj/argo-workflows/commit/02a3e2e399d90f59b4cb813aa41ad92aca045f03) fix(build): check for env vars in all dirs (#12652) +* [d4d28b5c7](https://github.com/argoproj/argo-workflows/commit/d4d28b5c7cfc7baf8c2180019bdaa3e9b04decc9) fix: SSO with Jumpcloud "email_verified" field #12257 (#12318) +* [16c4970e7](https://github.com/argoproj/argo-workflows/commit/16c4970e78c5f15ced290b7ae7d330e6c6252467) fix: Fixed mutex with withSequence in http template broken. Fixes #12018 (#12176) +* [23b1a4b24](https://github.com/argoproj/argo-workflows/commit/23b1a4b244e3e2ae1169854bf7f90ad60de2b62f) fix: prevent update race in workflow cache (Fixes #9574) (#12233) +* [8e33da1a1](https://github.com/argoproj/argo-workflows/commit/8e33da1a13ac6f8b09e45cac5ff39eab0927f498) fix: add resource quota evaluation timed out to transient (#12536) +* [8c75a72a5](https://github.com/argoproj/argo-workflows/commit/8c75a72a5b15ac39b5cddfed0886d3f76dcf9e3d) fix: cache configmap don't create with workflow has retrystrategy. Fixes: #12490 #10426 (#12491) +* [33521350e](https://github.com/argoproj/argo-workflows/commit/33521350ebd287ca16c7c76df94bb9a492a4dff9) fix: update minio chart repo (#12552) +* [0319b79d5](https://github.com/argoproj/argo-workflows/commit/0319b79d5e13217e86784f92be67524fed3b8af4) fix: Global Artifact Passing. Fixes #12554 (#12559) +* [56a591185](https://github.com/argoproj/argo-workflows/commit/56a59118541d79be7c4b3ba3feb2a67b4f9c900e) fix(ui): clone the `ListWatch` callback array in `WorkflowsList` (#12562) +* [2a21d1445](https://github.com/argoproj/argo-workflows/commit/2a21d1445df644894f96d0af62d4d7688b93489b) fix: Mark resource && data template report-outputs-completed true (#12544) +* [fcfbfbd0b](https://github.com/argoproj/argo-workflows/commit/fcfbfbd0b5a1251e6cd0cb728131604c613dedc3) fix(resources): improve ressource accounting. Fixes #12468 (#12492) +* [0bffab1dd](https://github.com/argoproj/argo-workflows/commit/0bffab1dd3971ae1c9adbc4a7c2ceb6969098678) fix: Allow valueFrom in dag arguments parameters. Fixes #11900 (#11902) +* [636f79a8b](https://github.com/argoproj/argo-workflows/commit/636f79a8bddea8d021737104bc6d2e4be516e7f4) fix: artifact subdir error when using volumeMount (#12638) +* [93f0b6ebd](https://github.com/argoproj/argo-workflows/commit/93f0b6ebd6757c2f4957cbe151061c7848e68d57) fix: pass through burst and qps for auth.kubeclient (#12575) +* [9b69363ba](https://github.com/argoproj/argo-workflows/commit/9b69363ba62fa76ac994c1d8542904b4fd331d53) fix: retry node with expression status Running -> Pending (#12637) +* [c95c6abc5](https://github.com/argoproj/argo-workflows/commit/c95c6abc510a42dbae2bb8e929589cfb99c811f4) fix(controller): add missing namespace index from workflow informer (#12666) +* [c62e6ad34](https://github.com/argoproj/argo-workflows/commit/c62e6ad34ec5659a391eeb0cf755a3792a21347d) fix(controller): re-allow changing executor `args` (#12609) +* [715791b17](https://github.com/argoproj/argo-workflows/commit/715791b17bc92e3880f14fffea020ecb5af44d85) fix(ui): `ListWatch` should not _both_ set and depend on `nextOffset` (#12672) +* [8207a0890](https://github.com/argoproj/argo-workflows/commit/8207a08900b9e7433d5ae939c44a08c065db5f7b) fix(typo): fix some typo (#12673) +* [ea753f097](https://github.com/argoproj/argo-workflows/commit/ea753f097db03eb057bb54e78d9a8f45b1d924d8) fix: Patch taskset with subresources to delete completed node status.… (#12620) +* [3d4a2cbd6](https://github.com/argoproj/argo-workflows/commit/3d4a2cbd6d7d4a0829d7f6ef8e46788c6e244489) fix: Add limit to number of Workflows in CronWorkflow history (#12681) +* [32918ba55](https://github.com/argoproj/argo-workflows/commit/32918ba5532c8044d3a12c5baf3fb6f696b71bb6) fix: find correct retry node when using `templateRef`. Fixes: #12633 (#12683) + +### Contributors + +* Alan Clucas +* AloysAqemia +* Anton Gilgur +* Dennis Lawler +* Eduardo Rodrigues +* Garett MacGowan +* Isitha Subasinghe +* Jason Meridth +* João Pedro +* Paolo Quadri +* Raffael +* Ruin09 +* Ryan Currah +* Son Bui +* Tal Yitzhak +* Tianchu Zhao +* Yulin Li +* jiangjiang +* jswxstw +* panicboat +* shuangkun tian + +## v3.5.4 (2024-01-13) + +* [960af331a](https://github.com/argoproj/argo-workflows/commit/960af331a8c0a3f2e263c8b90f1daf4303816ba8) fix: autolink dep in yarn.lock is incorrect +* [ec7d1f698](https://github.com/argoproj/argo-workflows/commit/ec7d1f698360242dd28f6be5b227c415da63d473) fix: Resolve vulnerabilities in axios (#12470) +* [f5fee5661](https://github.com/argoproj/argo-workflows/commit/f5fee5661b29441e5dae78e44d8b6fc05ffd6565) fix: Switch to upstream go-git. Fixes CVE-2023-49569 (#12515) + +### Contributors + +* Yuan Tang + +## v3.5.3 (2024-01-10) + +* [46efafea3](https://github.com/argoproj/argo-workflows/commit/46efafea3fbd1ed26ceb92948caf7f9fde1cfa41) chore(deps): bump tj-actions/changed-files from 39 to 40 (#12090) +* [5dcb08928](https://github.com/argoproj/argo-workflows/commit/5dcb08928d491839c37186f1f665d35be2d7b752) chore(deps): bump google.golang.org/api from 0.149.0 to 0.151.0 (#12262) +* [5e8d30181](https://github.com/argoproj/argo-workflows/commit/5e8d3018175acef2f8774554e8d7fbabac1e0fbd) chore(deps): bump github.com/antonmedv/expr from 1.15.3 to 1.15.5 (#12263) +* [5ac12e8e2](https://github.com/argoproj/argo-workflows/commit/5ac12e8e29ed08594b926d131b19432f542caf0c) chore(deps): bump github.com/upper/db/v4 from 4.6.0 to 4.7.0 (#12260) +* [f92b39c69](https://github.com/argoproj/argo-workflows/commit/f92b39c69da4676b1e3a878fd6b64a19feeb43c8) chore(deps): bump cloud.google.com/go/storage from 1.34.1 to 1.35.1 (#12266) +* [b4cd9a43c](https://github.com/argoproj/argo-workflows/commit/b4cd9a43cdb44c330342faa1d6aa3d1d72531078) chore(deps-dev): bump @types/prop-types from 15.7.10 to 15.7.11 in /ui (#12261) +* [2019c8d43](https://github.com/argoproj/argo-workflows/commit/2019c8d434e741dc362cc6e26427727cd356809d) chore(deps): bump react-datepicker from 4.21.0 to 4.23.0 in /ui (#12259) +* [b606eda2f](https://github.com/argoproj/argo-workflows/commit/b606eda2f4f787d3519181b6d94ad7f9bd609d6b) chore(deps): bump sigs.k8s.io/yaml from 1.3.0 to 1.4.0 (#12092) +* [d172b3b9b](https://github.com/argoproj/argo-workflows/commit/d172b3b9b1ec500edd5f86ca4a910cb31daf97cd) chore(deps): bump github.com/aliyun/credentials-go from 1.3.1 to 1.3.2 (#12227) +* [2f1102b8d](https://github.com/argoproj/argo-workflows/commit/2f1102b8db2ff160d3db2f21fb824454f6d2f688) chore(deps-dev): bump @types/react-datepicker from 4.19.1 to 4.19.3 in /ui (#12222) +* [0547738a4](https://github.com/argoproj/argo-workflows/commit/0547738a41420f10792ebc7163d0186311ab9841) chore(deps): bump cronstrue from 2.41.0 to 2.44.0 in /ui (#12224) +* [c9762c961](https://github.com/argoproj/argo-workflows/commit/c9762c961222895b58cc6a3c7f5439987363d927) chore(deps-dev): bump @types/react-helmet from 6.1.7 to 6.1.9 in /ui (#12223) +* [f896f2022](https://github.com/argoproj/argo-workflows/commit/f896f20221c1a1f69e34021938a64e46428b8197) chore(deps-dev): bump ts-loader from 9.5.0 to 9.5.1 in /ui (#12221) +* [9cf231a15](https://github.com/argoproj/argo-workflows/commit/9cf231a15b488e59fb3aef8d7db7b49e832ed191) chore(deps-dev): bump @types/react-autocomplete from 1.8.8 to 1.8.9 in /ui (#12220) +* [87b346308](https://github.com/argoproj/argo-workflows/commit/87b346308745f42f2c6eb485f97f6d0c830ac036) chore(deps-dev): bump @types/superagent from 4.1.21 to 4.1.22 in /ui (#12219) +* [e4572282f](https://github.com/argoproj/argo-workflows/commit/e4572282f2b8de52a40f9b39685d82ccfeace9fb) chore(deps-dev): bump @types/js-yaml from 4.0.8 to 4.0.9 in /ui (#12218) +* [fcf2f6f5b](https://github.com/argoproj/argo-workflows/commit/fcf2f6f5bf22c41ddf48bb8b1108922c26bb214a) chore(deps): bump golang.org/x/sync from 0.4.0 to 0.5.0 (#12185) +* [6ec24a1bd](https://github.com/argoproj/argo-workflows/commit/6ec24a1bdbee4afa2f38d4bb83752bb9a21a7dc2) chore(deps): bump golang.org/x/time from 0.3.0 to 0.4.0 (#12186) +* [2d6f5ea5f](https://github.com/argoproj/argo-workflows/commit/2d6f5ea5f9e562842e93d8123a95d8f1a12d79c2) chore(deps-dev): bump @types/uuid from 9.0.6 to 9.0.7 in /ui (#12181) +* [fbe747882](https://github.com/argoproj/argo-workflows/commit/fbe7478823111cb4af7d5ad14f42e141b1512ce9) chore(deps-dev): bump @types/dagre from 0.7.51 to 0.7.52 in /ui (#12180) +* [2619e28a4](https://github.com/argoproj/argo-workflows/commit/2619e28a43e603afe2819d0712d3ea3770c741db) chore(deps-dev): bump @types/superagent from 4.1.20 to 4.1.21 in /ui (#12179) +* [1e92929ac](https://github.com/argoproj/argo-workflows/commit/1e92929ac5a7123e7b064bc1f648f5e53d564df6) chore(deps-dev): bump @types/prop-types from 15.7.8 to 15.7.10 in /ui (#12178) +* [93db4365c](https://github.com/argoproj/argo-workflows/commit/93db4365c8a90d225e8accf971e0d82f9a78119b) chore(deps-dev): bump @types/dagre from 0.7.50 to 0.7.51 in /ui (#12141) +* [29325d143](https://github.com/argoproj/argo-workflows/commit/29325d143b695a61d67c09b3178c02ab362dd29e) chore(deps): bump monaco-editor from 0.43.0 to 0.44.0 in /ui (#12142) +* [e17e8e051](https://github.com/argoproj/argo-workflows/commit/e17e8e0511dfa284e301ec77669e7b91d94373ef) chore(deps-dev): bump sass from 1.69.4 to 1.69.5 in /ui (#12143) +* [360e37785](https://github.com/argoproj/argo-workflows/commit/360e37785a62fe7b4626c89c71a7dca9078d0b44) chore(deps): bump cloud.google.com/go/storage from 1.33.0 to 1.34.1 (#12138) +* [5e9325dc6](https://github.com/argoproj/argo-workflows/commit/5e9325dc65a4f42486a8adf3352e5e64158239cb) chore(deps): bump react-datepicker and @types/react-datepicker in /ui (#12096) +* [6dec40240](https://github.com/argoproj/argo-workflows/commit/6dec4024094cc47abb783e9e8303a7c7bacbe943) chore(deps-dev): bump @types/uuid from 9.0.4 to 9.0.6 in /ui (#12095) +* [f5b244ed0](https://github.com/argoproj/argo-workflows/commit/f5b244ed07f2dd128d6e62cc6da8a8429f1e577f) chore(deps-dev): bump @types/react-autocomplete from 1.8.7 to 1.8.8 in /ui (#12094) +* [9b7ed2ed5](https://github.com/argoproj/argo-workflows/commit/9b7ed2ed5ae25e4a2d97429814415113edde51c0) chore(deps-dev): bump @types/js-yaml from 4.0.6 to 4.0.8 in /ui (#12093) +* [9b3951c38](https://github.com/argoproj/argo-workflows/commit/9b3951c3870d04ddd4a3c5af81cac9188ab0e512) chore(deps): upgrade `swagger-ui-react` to latest 4.x.x (#12058) +* [3cf8ae22f](https://github.com/argoproj/argo-workflows/commit/3cf8ae22ff1858eab2044e7df73adfef4ed595cb) chore(deps): bump google.golang.org/api from 0.147.0 to 0.148.0 (#12051) +* [5fe2c9cb6](https://github.com/argoproj/argo-workflows/commit/5fe2c9cb63b1c28bd339b803ebdb43ac54cfca9a) chore(deps-dev): bump @types/superagent from 4.1.18 to 4.1.20 in /ui (#12056) +* [9034d4ffd](https://github.com/argoproj/argo-workflows/commit/9034d4ffd8e8c1bc125501c703e8e995ae3c765c) chore(deps-dev): bump webpack from 5.88.2 to 5.89.0 in /ui (#12054) +* [eeec54f33](https://github.com/argoproj/argo-workflows/commit/eeec54f33d42e39e5b9290f1163309acd3a3288e) chore(deps-dev): bump ts-loader from 9.4.4 to 9.5.0 in /ui (#12053) +* [f455d0a4a](https://github.com/argoproj/argo-workflows/commit/f455d0a4a29c4583f0840ac578b39205de5c22e1) chore(deps-dev): bump sass from 1.69.0 to 1.69.4 in /ui (#12052) +* [2b561638c](https://github.com/argoproj/argo-workflows/commit/2b561638c8e137fbbb15dcc046c4b1f74d19b16b) chore(deps): bump github.com/coreos/go-oidc/v3 from 3.5.0 to 3.7.0 (#12050) +* [e1cbeedd5](https://github.com/argoproj/argo-workflows/commit/e1cbeedd52e7ac2afa99e58abc188d8553f1e710) chore(deps): automatically `audit fix` UI deps (#12036) +* [ec8e73348](https://github.com/argoproj/argo-workflows/commit/ec8e73348ceb63d39be388e8839499ae41d36a18) chore(deps-dev): bump @types/react-helmet from 6.1.6 to 6.1.7 in /ui (#11910) +* [70dc1b4ac](https://github.com/argoproj/argo-workflows/commit/70dc1b4ac46d5f0958893b6ecc8cf19c238fda04) chore(deps): bump google.golang.org/api from 0.143.0 to 0.147.0 (#12001) +* [89f79cf5b](https://github.com/argoproj/argo-workflows/commit/89f79cf5bbe6bcdc4aeaaca0d6775781aeabdf8a) chore(deps-dev): bump @types/prop-types from 15.7.7 to 15.7.8 in /ui (#11998) +* [0b48ece51](https://github.com/argoproj/argo-workflows/commit/0b48ece51a46cd1cf30eafc6a9a9e94845671799) fix: Resolve lint issues in UI code +* [6330c0a02](https://github.com/argoproj/argo-workflows/commit/6330c0a02aa46d74daba9e950386449d0390c0db) chore(deps): bump golang.org/x/crypto from 0.14.0 to 0.15.0 (#12265) +* [f25017e8b](https://github.com/argoproj/argo-workflows/commit/f25017e8bb95960af558d9d05afb3848ad433c25) chore(deps): bump actions/setup-node from 3 to 4 (#12091) +* [9ae27831e](https://github.com/argoproj/argo-workflows/commit/9ae27831e7914726cf774ce28da97371ee468269) chore(deps): bump github.com/gorilla/handlers from 1.5.1 to 1.5.2 (#12294) +* [986c16108](https://github.com/argoproj/argo-workflows/commit/986c16108eaa7ebedb1704b21c954e400472892c) chore(deps): bump actions/setup-java from 3 to 4 (#12291) +* [13b69e719](https://github.com/argoproj/argo-workflows/commit/13b69e719998c0f64d69807eb85b90e1690175a5) chore(deps): update nixpkgs to nixos-23.11 (#12335) +* [86a39445a](https://github.com/argoproj/argo-workflows/commit/86a39445acb66dbb88721643cd3571851a3d9092) chore(deps): bump actions/setup-python from 4 to 5 (#12342) +* [3631e9cdf](https://github.com/argoproj/argo-workflows/commit/3631e9cdfa5095fbf6723da0adbd564ebcbaafc5) chore(deps): bump github.com/minio/minio-go/v7 from 7.0.64 to 7.0.65 (#12344) +* [d325af186](https://github.com/argoproj/argo-workflows/commit/d325af1867fff47d0fa62cda7e6a3b904956cc04) chore(deps): bump github.com/itchyny/gojq from 0.12.13 to 0.12.14 (#12346) +* [4fbe64c6d](https://github.com/argoproj/argo-workflows/commit/4fbe64c6d858db250bca74ecbaa0ceda113b2fd6) chore(deps): bump monaco-editor from 0.44.0 to 0.45.0 in /ui (#12373) +* [1bdfff03b](https://github.com/argoproj/argo-workflows/commit/1bdfff03bb6586b787b57e9b2cda1b910a71db9b) chore(deps): bump upload and download artifact to v4 (#12384) +* [cc881166e](https://github.com/argoproj/argo-workflows/commit/cc881166e60137891eaa39905b958d3344659e1c) fix: resolve output artifact of steps from expression when it refers … (#12320) +* [5568a2536](https://github.com/argoproj/argo-workflows/commit/5568a2536dae57406005af08837df8a83cee5d5d) fix: fix missing artifacts for stopped workflows. Fixes #12401 (#12402) +* [852f8a35a](https://github.com/argoproj/argo-workflows/commit/852f8a35a22eec40f039e14173b42fd8e75f115d) fix: remove deprecated function rand.Seed (#12271) +* [35b8b4094](https://github.com/argoproj/argo-workflows/commit/35b8b40942cbc4c7277024a7477ab153eaea1525) fix: Add identifiable user agent in API client. Fixes #11996 (#12276) +* [3ecfe56f5](https://github.com/argoproj/argo-workflows/commit/3ecfe56f50180935f7e621c6e37f1596298a6996) fix: completed workflow tracking (#12198) +* [c4251fa5b](https://github.com/argoproj/argo-workflows/commit/c4251fa5b54be3ce77c7551fc8f78c024f895347) fix: missing Object Value when Unmarshaling Plugin struct. Fixes #12202 (#12285) +* [c1c4936ec](https://github.com/argoproj/argo-workflows/commit/c1c4936ecd7d1fbd722d28e4a59e8b5eff784566) fix: properly resolve exit handler inputs (fixes #12283) (#12288) +* [b998c50d9](https://github.com/argoproj/argo-workflows/commit/b998c50d94ca377e0760264c1c66bd1435fd8bc8) fix: Fix variables not substitue bug when creation failed for the first time. Fixes (#11487) +* [29e613e84](https://github.com/argoproj/argo-workflows/commit/29e613e84997f2b742f0c86a826d733226183e20) fix: allow withItems when hooks are involved (#12281) +* [c6702d595](https://github.com/argoproj/argo-workflows/commit/c6702d595a6f052a46e20f8e7ae07ec27dee7559) fix: Changes to workflow semaphore does work #12194 (#12284) +* [8bcf64669](https://github.com/argoproj/argo-workflows/commit/8bcf6466999330546abbafb8e114f8a6c7ee7f06) fix: return failed instead of success when no container status (#12197) +* [1b17b7ad1](https://github.com/argoproj/argo-workflows/commit/1b17b7ad184af4e11ecc1af48290bede2fb90324) fix: ensure wftmplLifecycleHook wait for each dag task (#12192) +* [35ba1c1eb](https://github.com/argoproj/argo-workflows/commit/35ba1c1eb9781716b6b7db2426893e8e37e210be) fix: create dir when input path is not exist in oss (#12323) +* [00719cfeb](https://github.com/argoproj/argo-workflows/commit/00719cfebc30d54fbeb339c0692cf468d9804db4) fix: liveness check (healthz) type asserts to wrong type (#12353) +* [bfb15dae3](https://github.com/argoproj/argo-workflows/commit/bfb15dae310ecf869ce8e43718977391a02a40c9) fix: delete pending pod when workflow terminated (#12196) +* [b89b16115](https://github.com/argoproj/argo-workflows/commit/b89b16115009da847704032b1ef25eec43dfd68b) fix: move log with potential sensitive data to debug loglevel. Fixes: #12366 (#12368) +* [4cce92063](https://github.com/argoproj/argo-workflows/commit/4cce9206356935234c3cc3f10a41c7ccf9f66356) fix: custom columns not supporting annotations (#12421) +* [aaf919269](https://github.com/argoproj/argo-workflows/commit/aaf919269db09b92733658c4c679bd18c3a5cea1) fix: ensure workflow wait for onExit hook for DAG template (#11880) (#12436) +* [e5d86ed8e](https://github.com/argoproj/argo-workflows/commit/e5d86ed8e045c64f9337575a32ff9d2d367927c6) fix: Apply workflow level PodSpecPatch in agent pod. Fixes #12387 (#12440) +* [299bc169a](https://github.com/argoproj/argo-workflows/commit/299bc169a9af56342a56899cbcfcfe03252ffb8b) fix: CI Artifact Download Timeout. Fixes #12452 (#12454) +* [e8cc7152b](https://github.com/argoproj/argo-workflows/commit/e8cc7152ba15fe2f308ebae586debee0cd8c5cec) fix: http template host header rewrite(#12385) (#12386) +* [5c0ecde28](https://github.com/argoproj/argo-workflows/commit/5c0ecde2875220b07918bd658a84731f89ab8cc5) fix(docs): release-3.5 readthedocs backport (#12475) + +### Contributors + +* Alan Clucas +* Anton Gilgur +* Bryce-Huang +* Denys Melnyk +* Garett MacGowan +* Jason Meridth +* Julie Vogelman +* Son Bui +* Yang Lu +* Yuan (Terry) Tang +* Yuan Tang +* dependabot[bot] +* gussan +* ivancili +* jswxstw +* neosu +* renovate[bot] +* shuangkun tian +* 刘达 + +## v3.5.2 (2023-11-27) + +* [237addc9d](https://github.com/argoproj/argo-workflows/commit/237addc9dab0f31435e8eb7f98bf254c2d19c480) fix: Update yarn.lock file +* [afd5399cb](https://github.com/argoproj/argo-workflows/commit/afd5399cbd129b267a2d31d278402aa1c06d07c5) fix(ui): Cost Opt should only apply to live Workflows (#12170) +* [c296cf233](https://github.com/argoproj/argo-workflows/commit/c296cf233235e46bd581a0333e0c4e675a5f3e80) fix: ArtifactGC Fails for Stopped Workflows. Fixes #11879 (#11947) +* [82560421a](https://github.com/argoproj/argo-workflows/commit/82560421aaa4845d3e33dc5f98e69a2dc2495b1d) fix: retry S3 on RequestError. Fixes #9914 (#12191) +* [a69ca2342](https://github.com/argoproj/argo-workflows/commit/a69ca234237145ae3ec15dffe7f510e7dfc70b2b) fix: Resource version incorrectly overridden for wfInformer list requests. Fixes #11948 (#12133) +* [1faa1e62e](https://github.com/argoproj/argo-workflows/commit/1faa1e62eb67512cab96a0b435eef640c10947fe) fix(server): allow passing loglevels as env vars to Server (#12145) +* [9c378d162](https://github.com/argoproj/argo-workflows/commit/9c378d162f9d244b775d25ede751c7841d64127d) fix: Fix for missing steps in the UI (#12203) +* [59f5409c9](https://github.com/argoproj/argo-workflows/commit/59f5409c95da83d9045fa936b0ec2dbb09e7724b) fix: leak stream (#12193) +* [4b162df16](https://github.com/argoproj/argo-workflows/commit/4b162df16260053d1493e66bcae64689053f03e2) refactor(ui): code-split gigantic Monaco Editor dep (#12150) +* [8615f5364](https://github.com/argoproj/argo-workflows/commit/8615f5364c0f4c3fc7ca35d86d9739e3bd9210b1) refactor(ui): replace `moment-timezone` with native `Intl` (#12097) +* [d83f7b3b8](https://github.com/argoproj/argo-workflows/commit/d83f7b3b829ee44de329399294dad23e0de50166) build(ui): code-split `ApiDocs` and `Reports` components (#12061) +* [93b54c5d0](https://github.com/argoproj/argo-workflows/commit/93b54c5d054fe422b758c902999ddc0a6d97066f) chore(deps): bump github.com/creack/pty from 1.1.18 to 1.1.20 (#12139) +* [4558bfc69](https://github.com/argoproj/argo-workflows/commit/4558bfc69deeb94484dd6e5d6c6a2ab4ca5948d5) chore(deps): bump github.com/aliyun/aliyun-oss-go-sdk from 2.2.9+incompatible to 3.0.1+incompatible (#12140) +* [913c71881](https://github.com/argoproj/argo-workflows/commit/913c718812e91d540f0075457bbc895e9edda598) chore(deps): bump github.com/go-jose/go-jose/v3 from 3.0.0 to 3.0.1 (#12184) +* [92923f960](https://github.com/argoproj/argo-workflows/commit/92923f9605318e10b1b2d241365b0c98adc735d9) chore(deps): bump golang.org/x/term from 0.13.0 to 0.14.0 (#12225) +* [67dff4f22](https://github.com/argoproj/argo-workflows/commit/67dff4f22178028b81253f1b239cda2b06ebe9e1) chore(deps): bump github.com/gorilla/websocket from 1.5.0 to 1.5.1 (#12226) +* [a16ba1df8](https://github.com/argoproj/argo-workflows/commit/a16ba1df88303b40e48e480c91854269d4a45d76) chore(deps): bump github.com/TwiN/go-color from 1.4.0 to 1.4.1 (#11567) +* [30b6a91a5](https://github.com/argoproj/argo-workflows/commit/30b6a91a5a04aef3370f36d1ccc39a76834c79a5) chore(deps): bump github.com/minio/minio-go/v7 from 7.0.63 to 7.0.64 (#12267) + +### Contributors + +* Alan Clucas +* Anton Gilgur +* Garett MacGowan +* Helge Willum Thingvad +* Weidong Cai +* Yuan (Terry) Tang +* Yuan Tang +* dependabot[bot] + +## v3.5.1 (2023-11-03) + +* [877c55230](https://github.com/argoproj/argo-workflows/commit/877c5523066e17687856fe3484c9b2d398e986f5) chore(deps): bump golang.org/x/oauth2 from 0.12.0 to 0.13.0 (#12000) +* [2b44c4ad6](https://github.com/argoproj/argo-workflows/commit/2b44c4ad65e5699adf3a2549bf7cb6ae0a0e09ff) chore(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.3.1 to 1.4.0 (#12003) +* [1a7d9c940](https://github.com/argoproj/argo-workflows/commit/1a7d9c94043b9b1a4a99a317fcdb4e185a8413a3) chore(deps): bump react-datepicker and @types/react-datepicker in /ui (#12004) +* [16dbb6e49](https://github.com/argoproj/argo-workflows/commit/16dbb6e4907f5d675485e651f01acb4d21d679be) chore(deps): use official versions of `bufpipe` and `expr` (#12033) +* [39b8583bd](https://github.com/argoproj/argo-workflows/commit/39b8583bd47c064639c81ada9c6b04b7e3e6ba21) chore(deps): bump github.com/evanphx/json-patch from 5.6.0+incompatible to 5.7.0+incompatible (#11868) +* [9e04496c3](https://github.com/argoproj/argo-workflows/commit/9e04496c3a4f24c1883a2e1fe57a82e2089c8d4f) fix: Upgrade axios to v1.6.0. Fixes #12085 (#12111) +* [0e04980c6](https://github.com/argoproj/argo-workflows/commit/0e04980c670fa7730af1972db21f07ff1ca8ccd4) fix(ui): don't show pagination warning on first page if all are displayed (#11979) +* [98aba1599](https://github.com/argoproj/argo-workflows/commit/98aba159942c8bdf033cfbfc41da6630a5be8358) fix: retry only proper node (#11589) (#11839) +* [d51a87ace](https://github.com/argoproj/argo-workflows/commit/d51a87acef4d0cad0c50adec72eedf2e1c21b3b8) fix: Fix the Maximum Recursion Depth prompt link in the CLI. (#12015) +* [4997ddd7d](https://github.com/argoproj/argo-workflows/commit/4997ddd7d52d95702a07dfa595b38aa7131dca90) fix: remove WorkflowSpec VolumeClaimTemplates patch key (#11662) +* [49fe42088](https://github.com/argoproj/argo-workflows/commit/49fe4208858099aee1295eb6ff8ba7868fbd822f) fix: Fixed workflow onexit condition skipped when retry. Fixes #11884 (#12019) +* [84d15792a](https://github.com/argoproj/argo-workflows/commit/84d15792a631626dcb1cabebcf56215d0c72b844) fix: suppress error about unable to obtain node (#12020) +* [430faf09d](https://github.com/argoproj/argo-workflows/commit/430faf09d3b134746e84bb6705e1a818ecf48405) fix(ui): remove accidentally rendered semi-colon (#12060) +* [2a34dc1a7](https://github.com/argoproj/argo-workflows/commit/2a34dc1a7de2a7e4b8bed61163c7b39241a1f493) fix: Revert #11761 to avoid argo-server performance issue (#12068) +* [7645b98ac](https://github.com/argoproj/argo-workflows/commit/7645b98ac4d259225e55fa6b9ac194efbd78d1f9) fix: conflicting type of "workflow" logging attribute (#12083) +* [90a92215f](https://github.com/argoproj/argo-workflows/commit/90a92215fc43b0cebcd046cd783c3eb237800126) fix: oss list bucket return all records (#12084) +* [8f55b8da7](https://github.com/argoproj/argo-workflows/commit/8f55b8da721e0694aac22dc9a4d12af07b11dcc1) fix: regression in memoization without outputs (#12130) + +### Contributors + +* Alan Clucas +* Anton Gilgur +* Ruin09 +* Takumi Sue +* Vasily Chekalkin +* Yang Lu +* Yuan (Terry) Tang +* dependabot[bot] +* gussan +* happyso +* shuangkun tian + +## v3.5.0 (2023-10-13) + +* [bf735a2e8](https://github.com/argoproj/argo-workflows/commit/bf735a2e861d6b1c686dd4a076afc3468aa89c4a) fix(windows): prevent infinite run. Fixes #11810 (#11993) +* [375a860b5](https://github.com/argoproj/argo-workflows/commit/375a860b51e22378ca529da77fe3ed1ecb8e6de6) fix: Fix gRPC and HTTP2 high vulnerabilities (#11986) +* [f01dbb1df](https://github.com/argoproj/argo-workflows/commit/f01dbb1df1584c6e5daa288fd6fe7e8416697bd8) fix: Permit enums w/o values. Fixes #11471. (#11736) +* [96d964375](https://github.com/argoproj/argo-workflows/commit/96d964375f19bf376d51aa1907f5a1b4bcea9964) fix(ui): remove "last month" default date filter mention from New Version Modal (#11982) +* [6b0f04794](https://github.com/argoproj/argo-workflows/commit/6b0f0479495182dfb9e6a26689f5a2f3877a5414) fix(ui): faulty `setInterval` -> `setTimeout` in clipboard (#11945) +* [7576abcee](https://github.com/argoproj/argo-workflows/commit/7576abcee2cd7253c2022fc6c4744e325668993b) fix: show pagination warning on all pages (fixes #11968) (#11973) +* [a45afc0c8](https://github.com/argoproj/argo-workflows/commit/a45afc0c87b0ffa52a110c753b97d48f06cdf166) fix: Replace antonmedv/expr with expr-lang/expr (#11971) +* [8fa8f7970](https://github.com/argoproj/argo-workflows/commit/8fa8f7970bfd3ccc5cff1246ea08a7771a03b8ad) chore(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azcore from 1.7.1 to 1.8.0 (#11958) +* [f9aa01fe3](https://github.com/argoproj/argo-workflows/commit/f9aa01fe3b920cd992508158c624448a004c6170) chore(deps-dev): bump sass from 1.67.0 to 1.69.0 in /ui (#11960) +* [05c6db12a](https://github.com/argoproj/argo-workflows/commit/05c6db12adfd581331f5ae5b0234b72c407e7760) fix(ui): `ClipboardText` tooltip properly positioned (#11946) +* [743d29750](https://github.com/argoproj/argo-workflows/commit/743d29750784810e26ea46f6e87e91f021c583c0) fix(ui): ensure `WorkflowsRow` message is not too long (#11908) +* [26481a214](https://github.com/argoproj/argo-workflows/commit/26481a2146107ad0937ef7698c27f3686f93c81e) refactor(ui): convert `WorkflowsList` + `WorkflowsFilter` to functional components (#11891) +* [89667b609](https://github.com/argoproj/argo-workflows/commit/89667b6092c74807b59f8840d6327f9307c8598e) chore(deps-dev): bump @types/prop-types from 15.7.5 to 15.7.7 in /ui (#11911) +* [bdc536252](https://github.com/argoproj/argo-workflows/commit/bdc536252b1048b9c110b05af31934b9972499bd) chore(deps): bump google.golang.org/api from 0.138.0 to 0.143.0 (#11915) +* [7a5ba7972](https://github.com/argoproj/argo-workflows/commit/7a5ba797246a29b00a43f42476a47e706f31a1e8) chore(deps-dev): bump @types/react-autocomplete from 1.8.6 to 1.8.7 in /ui (#11913) +* [9469a1bf0](https://github.com/argoproj/argo-workflows/commit/9469a1bf049de784d8416c1f37600413d6762972) fix(ui): use `popup.confirm` instead of browser `confirm` (#11907) +* [a363e6a58](https://github.com/argoproj/argo-workflows/commit/a363e6a5875d0b9b9b2ad9c3fc2a0586f2b70f2c) refactor(ui): optimize Link functionality (#11743) +* [14df2e400](https://github.com/argoproj/argo-workflows/commit/14df2e400d529ffa5b43bf55cb70a3cd135ae8e3) refactor(ui): convert ParametersInput to functional components (#11894) +* [68ad03938](https://github.com/argoproj/argo-workflows/commit/68ad03938be929befba48f70d7c8fdae6839f433) refactor(ui): InputFilter and WorkflowTimeline components from class to functional (#11899) +* [e91c2737f](https://github.com/argoproj/argo-workflows/commit/e91c2737f3dff1fee41ce97991e294a57c53fc93) fix: Correctly retry an archived wf even when it exists in the cluster. Fixes #11903 (#11906) +* [c86a5cdb1](https://github.com/argoproj/argo-workflows/commit/c86a5cdb1ec1155e6ed17e67b46d5df59a566b08) fix: Automate nix updates with renovate (#11887) +* [2e4f28142](https://github.com/argoproj/argo-workflows/commit/2e4f281427e5eb8542ff847cb23d7f37808cbb03) refactor(ui): use async/await in several components (#11882) +* [b5f69a882](https://github.com/argoproj/argo-workflows/commit/b5f69a8826609eabc6e11fb477eea3472ba4f91f) fix: Fixed running multiple workflows with mutex and memo concurrently is broken (#11883) +* [148d97a85](https://github.com/argoproj/argo-workflows/commit/148d97a85880a5e6adbf773e92d3f9ae1c4196a2) chore(deps-dev): bump @types/js-yaml from 4.0.5 to 4.0.6 in /ui (#11832) +* [b2c6b55fa](https://github.com/argoproj/argo-workflows/commit/b2c6b55fac3de4a8a8d9d12d75332008ab750932) chore(deps): bump golang.org/x/crypto from 0.12.0 to 0.13.0 (#11873) +* [3bad9c557](https://github.com/argoproj/argo-workflows/commit/3bad9c557698684bb775a387bcd1bd41f7cac22c) chore(deps-dev): bump @types/dagre from 0.7.49 to 0.7.50 in /ui (#11874) +* [baa65c5c3](https://github.com/argoproj/argo-workflows/commit/baa65c5c34545d5c9144bfd9dbd2d4a355791baf) chore(deps): bump cloud.google.com/go/storage from 1.32.0 to 1.33.0 (#11870) +* [361af5aaf](https://github.com/argoproj/argo-workflows/commit/361af5aaf54c0858ff886346e91b572afcfb7caa) chore(deps): bump github.com/antonmedv/expr from 1.14.0 to 1.15.3 (#11871) +* [24c1c1083](https://github.com/argoproj/argo-workflows/commit/24c1c10838a59f72716fbbe5f476dae390e5288a) chore(deps): bump github.com/aliyun/aliyun-oss-go-sdk from 2.2.8+incompatible to 2.2.9+incompatible (#11866) +* [a83df9721](https://github.com/argoproj/argo-workflows/commit/a83df9721e57f8c15d26a20187e39b6e23645c78) chore(deps): bump golang.org/x/term from 0.11.0 to 0.12.0 (#11869) +* [eae277cbe](https://github.com/argoproj/argo-workflows/commit/eae277cbe8c4ea27a61d316b709176db420baa4b) chore(deps): bump github.com/tidwall/gjson from 1.15.0 to 1.17.0 (#11867) +* [5def5289a](https://github.com/argoproj/argo-workflows/commit/5def5289a6c010265bb9e8a6bfcd6f1bba80624b) feat: show history about completed runs in each cron workflow (#11811) +* [6fbfedf81](https://github.com/argoproj/argo-workflows/commit/6fbfedf8103d78f85010feec0eb9db03136b86d4) refactor(ui): migrate `UserInfo` to functional component (#11793) +* [0fde6800c](https://github.com/argoproj/argo-workflows/commit/0fde6800cbc5d6e2ee6aeb9840079c75fed1d3c3) fix: when key not present assume NodeRunning. Fixes 11843 (#11847) +* [c6fdb0311](https://github.com/argoproj/argo-workflows/commit/c6fdb0311eecf99ed23e21a6062f093441115500) refactor(ui): migrate `Reports` to functional component and split files (#11794) +* [27132d956](https://github.com/argoproj/argo-workflows/commit/27132d9563d1ba80afd3f294eca596f0f942c5d8) refactor(ui): convert a few components to use hooks (#11800) +* [fbe9375d5](https://github.com/argoproj/argo-workflows/commit/fbe9375d5307bb7f3f30770dc36fc48ef34c290e) fix: shouldn't fail to run cronworkflow because previous got shutdown on its own (race condition) (#11845) + +### Contributors + +* Anton Gilgur +* Isitha Subasinghe +* Julie Vogelman +* Justice +* Matt Farmer +* Michael Weibel +* Ruin09 +* Sebast1aan +* Tim Collins +* Yuan (Terry) Tang +* Yusuke Shinoda +* dependabot[bot] + ## v3.5.0-rc2 (2023-09-20) * [fa116b63e](https://github.com/argoproj/argo-workflows/commit/fa116b63e8aa9ddb6bd985d479b7e65c9b18785f) fix: use same date filter in the UI and CLI (#11840) @@ -399,6 +693,118 @@ * yeicandoit * younggil +## v3.4.16 (2024-01-14) + +* [910a9aabc](https://github.com/argoproj/argo-workflows/commit/910a9aabce5de6568b54350c181a431f8263605a) fix: Fix lint build +* [65befdeec](https://github.com/argoproj/argo-workflows/commit/65befdeecd871f965fc5b5213f269b6eb1fbce09) fix: Switch to upstream go-git. Fixes CVE-2023-49569 (#12515) + +### Contributors + +* Yuan Tang + +## v3.4.15 (2024-01-13) + +* [b3aaaa45d](https://github.com/argoproj/argo-workflows/commit/b3aaaa45daff66444e42b8d78dd149e8dc132a6b) chore(build): Replaced master to main in changelogs +* [fbf933563](https://github.com/argoproj/argo-workflows/commit/fbf9335635225eaa54420f3a520ef5c0043e5c34) fix: Resolve vulnerabilities in axios (#12470) +* [feb992505](https://github.com/argoproj/argo-workflows/commit/feb992505ecbd57ddd16b8d27b88e26045bf3588) fix: liveness check (healthz) type asserts to wrong type (#12353) +* [edb0a98c3](https://github.com/argoproj/argo-workflows/commit/edb0a98c31d7a459233131ae11e783ee45301ce6) fix(docs): release-3.4 readthedocs backport (#12474) + +### Contributors + +* Jason Meridth +* Julie Vogelman +* Saravanan Balasubramanian +* Yuan Tang + +## v3.4.14 (2023-11-27) + +* [a34723324](https://github.com/argoproj/argo-workflows/commit/a3472332401f0cff56fd39293eebe3aeca7220ad) fix: Upgrade go-jose to v3.0.1 +* [3201f61fb](https://github.com/argoproj/argo-workflows/commit/3201f61fba1a11147a55e57e57972c3df5758cc7) feat: Use WorkflowTemplate/ClusterWorkflowTemplate Informers when validating CronWorkflows (#11470) +* [d9a0797e7](https://github.com/argoproj/argo-workflows/commit/d9a0797e7778b4a109518fe9c4d9f9367c3beac8) fix: Resource version incorrectly overridden for wfInformer list requests. Fixes #11948 (#12133) +* [b3033ea11](https://github.com/argoproj/argo-workflows/commit/b3033ea1133b350e4cc702e1023dd8dc907526d6) Revert "fix: Add missing new version modal for v3.5 (#11692)" +* [f829cb52e](https://github.com/argoproj/argo-workflows/commit/f829cb52e2398f256829e4b4f49af671ee36c2a1) fix(ui): missing `uiUrl` in `ArchivedWorkflowsList` (#12172) +* [0c50de391](https://github.com/argoproj/argo-workflows/commit/0c50de3912e6fa4e725f67e1255280ad4a5475ac) fix: Revert "fix: regression in memoization without outputs (#12130)" (#12201) + +### Contributors + +* Anton Gilgur +* Julie Vogelman +* Yuan (Terry) Tang +* Yuan Tang + +## v3.4.13 (2023-11-03) + +* [bdc1b2590](https://github.com/argoproj/argo-workflows/commit/bdc1b25900f44c194ab36d202821cec01ba96a73) fix: regression in memoization without outputs (#12130) +* [1cf98efef](https://github.com/argoproj/argo-workflows/commit/1cf98efef6e9afbbb99f6c481440d0199904b8b8) chore(deps): bump golang.org/x/oauth2 from 0.12.0 to 0.13.0 (#12000) +* [2a044bf8f](https://github.com/argoproj/argo-workflows/commit/2a044bf8f8af2614cce0d25d019ef669b855a230) fix: Upgrade axios to v1.6.0. Fixes #12085 (#12111) +* [37b5750dc](https://github.com/argoproj/argo-workflows/commit/37b5750dcb23916ddd6f18284b5b70fcfae872da) fix: Workflow controller crash on nil pointer (#11770) +* [2c6c4d618](https://github.com/argoproj/argo-workflows/commit/2c6c4d61822493a627b13874987e20ec43d8ee26) fix: conflicting type of "workflow" logging attribute (#12083) +* [ade6fb4d7](https://github.com/argoproj/argo-workflows/commit/ade6fb4d72c98f73486d19a147df5c4919f43c99) fix: oss list bucket return all records (#12084) + +### Contributors + +* Alan Clucas +* Cheng Wang +* Vasily Chekalkin +* Yuan (Terry) Tang +* dependabot[bot] +* shuangkun tian + +## v3.4.12 (2023-10-19) + +* [11e61a8fe](https://github.com/argoproj/argo-workflows/commit/11e61a8fe81dd3d110a6bce2f5887f5f9cd3cf3c) fix(ui): remove "last month" default date filter mention from New Version Modal (#11982) +* [f87aba36a](https://github.com/argoproj/argo-workflows/commit/f87aba36a6a858fc5c0b1e43f9ea78e4372c0ccd) feat: filter sso groups based on regex (#11774) +* [b23647a10](https://github.com/argoproj/argo-workflows/commit/b23647a10eb8eea495c28e71d2822ea289a4370b) fix: Fix gRPC and HTTP2 high vulnerabilities (#11986) +* [18ad37587](https://github.com/argoproj/argo-workflows/commit/18ad37587690c471a1ab9d7245265a24fbe7c9d3) chore(deps): bump dependabot/fetch-metadata from 1.4.0 to 1.5.1 (#11141) +* [aa8e6937e](https://github.com/argoproj/argo-workflows/commit/aa8e6937e3e0c66ee10c11a29828f65358ac3622) chore(deps): bump react-datepicker from 4.11.0 to 4.12.0 in /ui (#11147) +* [7979bb0db](https://github.com/argoproj/argo-workflows/commit/7979bb0db73669a34b90d617589a2d1cf690d7c2) chore(deps): bump github.com/go-sql-driver/mysql from 1.7.0 to 1.7.1 (#11007) +* [df23b7e5e](https://github.com/argoproj/argo-workflows/commit/df23b7e5ef16487703e25c8c04bee860fa30d07c) chore(deps): bump cronstrue from 2.27.0 to 2.28.0 in /ui (#11329) +* [a11f8f9be](https://github.com/argoproj/argo-workflows/commit/a11f8f9be9593270337c7870ba4a94c52ef451d1) chore(deps): bump github.com/antonmedv/expr from 1.12.5 to 1.12.6 (#11365) +* [4eb3c116d](https://github.com/argoproj/argo-workflows/commit/4eb3c116d22aa45446e506581fa2313f4cf8f081) chore(deps): bump superagent from 8.0.9 to 8.1.2 in /ui (#11590) +* [d25897ece](https://github.com/argoproj/argo-workflows/commit/d25897eced31dd2327c4ee89cf7aef46f39ee928) chore(deps): upgrade `monaco-editor` to 0.30 (#11593) +* [cac4f0cbd](https://github.com/argoproj/argo-workflows/commit/cac4f0cbd6ea6972a3a5f8bb163a97d5838db9c3) chore(deps): bump docker/build-push-action from 4 to 5 (#11830) +* [bd057ed18](https://github.com/argoproj/argo-workflows/commit/bd057ed1889a45df3ec5cd916e692efb81d81293) chore(deps): bump docker/login-action from 2 to 3 (#11827) +* [370949dc5](https://github.com/argoproj/argo-workflows/commit/370949dc560fc2c28cdcd709a34b2c00b0f034dc) fix: fail test on pr #11368 (#11576) +* [46297cad7](https://github.com/argoproj/argo-workflows/commit/46297cad798cb48627baf23d548a2c7e595ed316) fix: Add missing new version modal for v3.5 (#11692) +* [5b30e3034](https://github.com/argoproj/argo-workflows/commit/5b30e3034cf29652376c6053ac5c4bbe40b8b95c) fix: Health check from lister not apiserver (#11375) +* [f553d7f06](https://github.com/argoproj/argo-workflows/commit/f553d7f06a8ccbde4a722f32288eda5bb07650de) fix(ui): don't use `Buffer` for FNV hash (#11766) +* [9ebb70a26](https://github.com/argoproj/argo-workflows/commit/9ebb70a26ea5f7726e51739bfa10d82aa0703f9b) fix: Correct limit in WorkflowTaskResultInformer List API calls. Fixes #11607 (#11722) +* [b8b70980c](https://github.com/argoproj/argo-workflows/commit/b8b70980c9218260c0e4aa2be4f4a243fd25b902) fix(ui): handle `undefined` dates in Workflows List filter (#11792) +* [d258bcabf](https://github.com/argoproj/argo-workflows/commit/d258bcabf3de43ca505c1d8b5236cfec78c51949) fix: close response body when request event-stream failed (#11818) +* [f6bd94af4](https://github.com/argoproj/argo-workflows/commit/f6bd94af4c4cb5e1d217dc72e81cec6940da5daa) fix(ui): merge WF List FTU Panel with New Version Modal (#11742) +* [71ad0a23c](https://github.com/argoproj/argo-workflows/commit/71ad0a23c35fa47315977a446763560bbc6dbeea) fix: Fixed workflow template skip whitespaced parameters. Fixes #11767 (#11781) +* [a08d73a8f](https://github.com/argoproj/argo-workflows/commit/a08d73a8f2e4b8c350822ab113905a2a3e58416f) fix: add prometheus label validation for realtime gauge metric (#11825) +* [3080ab837](https://github.com/argoproj/argo-workflows/commit/3080ab83773f855ef0bf62d11eb26022c6a85233) fix: shouldn't fail to run cronworkflow because previous got shutdown on its own (race condition) (#11845) +* [20f1c6b3b](https://github.com/argoproj/argo-workflows/commit/20f1c6b3b1dfb50540572c07b1a50e1ce0870d7a) fix: when key not present assume NodeRunning. Fixes 11843 (#11847) +* [4b6cdaeec](https://github.com/argoproj/argo-workflows/commit/4b6cdaeec934086796283ddfb09597bfd4d08774) fix: Fixed running multiple workflows with mutex and memo concurrently is broken (#11883) +* [396be7252](https://github.com/argoproj/argo-workflows/commit/396be72529bb4a05d05f9ab9f471421971d81c88) fix: Automate nix updates with renovate (#11887) +* [96e44c01d](https://github.com/argoproj/argo-workflows/commit/96e44c01d67cf4006486bc2ab2a6f2f6e6247600) fix(ui): `ClipboardText` tooltip properly positioned (#11946) +* [1447472ff](https://github.com/argoproj/argo-workflows/commit/1447472ff1ddfb0853154ff6132cf421cf54831e) fix(ui): faulty `setInterval` -> `setTimeout` in clipboard (#11945) +* [c543932b9](https://github.com/argoproj/argo-workflows/commit/c543932b9870b40cd9b2ad61c285afe90c8ffc29) fix: Permit enums w/o values. Fixes #11471. (#11736) +* [142f5bd65](https://github.com/argoproj/argo-workflows/commit/142f5bd653251e9504fd9f71fbd7626d196d8a2b) fix(windows): prevent infinite run. Fixes #11810 (#11993) +* [4d09777d3](https://github.com/argoproj/argo-workflows/commit/4d09777d3d7b524e043b5e48fb3761e527eb2ea8) fix: remove WorkflowSpec VolumeClaimTemplates patch key (#11662) +* [fe880539a](https://github.com/argoproj/argo-workflows/commit/fe880539ab4d0e3fecdf35b9d9a7c11f3adca117) fix: Fixed workflow onexit condition skipped when retry. Fixes #11884 (#12019) +* [61f00ba56](https://github.com/argoproj/argo-workflows/commit/61f00ba568e7ecbe2c164fb5d114493029c2e47f) fix: suppress error about unable to obtain node (#12020) + +### Contributors + +* Alec Rabold +* Anton Gilgur +* Basanth Jenu H B +* Isitha Subasinghe +* Julie Vogelman +* Matt Farmer +* Michael Weibel +* Ruin09 +* Son Bui +* Takumi Sue +* Thearas +* Tim Collins +* Weidong Cai +* Yuan (Terry) Tang +* dependabot[bot] +* happyso + ## v3.4.11 (2023-09-06) * [ee939bbd2](https://github.com/argoproj/argo-workflows/commit/ee939bbd2d8950a2fa1badd7cfad3b88c039da26) fix: Support OOMKilled with container-set. Fixes #10063. FOR 3.4.11 only (#11757) diff --git a/Makefile b/Makefile index ebc018797a8d..a3d3cb7e19ba 100644 --- a/Makefile +++ b/Makefile @@ -721,12 +721,12 @@ docs: /usr/local/bin/mkdocs \ docs-lint \ # TODO: This is temporarily disabled to unblock merging PRs. # docs-linkcheck + # copy README.md to docs/README.md + ./hack/copy-readme.sh # check environment-variables.md contains all variables mentioned in the code ./hack/check-env-doc.sh - # check all docs are listed in mkdocs.yml - ./hack/check-mkdocs.sh # build the docs - mkdocs build + mkdocs build --strict # tell the user the fastest way to edit docs @echo "ℹ️ If you want to preview your docs, open site/index.html. If you want to edit them with hot-reload, run 'make docs-serve' to start mkdocs on port 8000" diff --git a/api/jsonschema/schema.json b/api/jsonschema/schema.json index 59e9ab33bbfd..ff8a6e4b04a2 100644 --- a/api/jsonschema/schema.json +++ b/api/jsonschema/schema.json @@ -7389,7 +7389,7 @@ "description": "PodDNSConfig defines the DNS parameters of a pod in addition to those generated from DNSPolicy." }, "dnsPolicy": { - "description": "Set DNS policy for the pod. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.", + "description": "Set DNS policy for workflow pods. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.", "type": "string" }, "entrypoint": { diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 36c1e1efebcd..773cc59c8228 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -11396,7 +11396,7 @@ "$ref": "#/definitions/io.k8s.api.core.v1.PodDNSConfig" }, "dnsPolicy": { - "description": "Set DNS policy for the pod. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.", + "description": "Set DNS policy for workflow pods. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.", "type": "string" }, "entrypoint": { diff --git a/docs/README.md b/docs/README.md index 1087874fcaab..b0b54c1d7c7d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,8 @@ -# Argo Workflows - + [![slack](https://img.shields.io/badge/slack-argoproj-brightgreen.svg?logo=slack)](https://argoproj.github.io/community/join-slack) [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3830/badge)](https://bestpractices.coreinfrastructure.org/projects/3830) +[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/argoproj/argo-workflows/badge)](https://api.securityscorecards.dev/projects/github.com/argoproj/argo-workflows) +[![Artifact HUB](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/argo-workflows)](https://artifacthub.io/packages/helm/argo/argo-workflows) [![Twitter Follow](https://img.shields.io/twitter/follow/argoproj?style=social)](https://twitter.com/argoproj) ## What is Argo Workflows? @@ -33,13 +34,13 @@ Argo is a [Cloud Native Computing Foundation (CNCF)](https://cncf.io/) graduated environments. * Cloud agnostic and can run on any Kubernetes cluster. -[Read what people said in our latest survey](https://blog.argoproj.io/argo-workflows-2021-survey-results-d6fa890030ee) +[Read what people said in our latest survey](https://blog.argoproj.io/argo-workflows-events-2023-user-survey-results-82c53bc30543) ## Try Argo Workflows [Access the demo environment](https://workflows.apps.argoproj.io/workflows/argo) (login using Github) -![Screenshot](https://github.com/argoproj/argo-workflows/raw/main/docs/assets/screenshot.png) +![Screenshot](assets/screenshot.png) ## Who uses Argo Workflows? @@ -58,6 +59,7 @@ Just some of the projects that use or rely on Argo Workflows (complete list [her * [Netflix Metaflow](https://metaflow.org) * [Onepanel](https://www.onepanel.ai/) * [Orchest](https://github.com/orchest/orchest/) +* [Piper](https://github.com/rookout/piper) * [Ploomber](https://github.com/ploomber/ploomber) * [Seldon](https://github.com/SeldonIO/seldon-core) * [SQLFlow](https://github.com/sql-machine-learning/sqlflow) @@ -68,13 +70,12 @@ Check out our [Java, Golang and Python clients](client-libraries.md). ## Quickstart -* [Get started here](quick-start.md) -* [Walk-through examples](walk-through/index.md) +* [Get started here](https://argo-workflows.readthedocs.io/en/release-3.5/quick-start/) +* [Walk-through examples](https://argo-workflows.readthedocs.io/en/release-3.5/walk-through/) ## Documentation -[View the docs](README.md) - +You're here! ## Features @@ -137,6 +138,7 @@ the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-o * [Argo Ansible role: Provisioning Argo Workflows on OpenShift](https://medium.com/@marekermk/provisioning-argo-on-openshift-with-ansible-and-kustomize-340a1fda8b50) * [Argo Workflows vs Apache Airflow](http://bit.ly/30YNIvT) * [CI/CD with Argo on Kubernetes](https://medium.com/@bouwe.ceunen/ci-cd-with-argo-on-kubernetes-28c1a99616a9) +* [Define Your CI/CD Pipeline with Argo Workflows](https://haque-zubair.medium.com/define-your-ci-cd-pipeline-with-argo-workflows-25aefb02fa63) * [Running Argo Workflows Across Multiple Kubernetes Clusters](https://admiralty.io/blog/running-argo-workflows-across-multiple-kubernetes-clusters/) * [Open Source Model Management Roundup: Polyaxon, Argo, and Seldon](https://www.anaconda.com/blog/developer-blog/open-source-model-management-roundup-polyaxon-argo-and-seldon/) * [Producing 200 OpenStreetMap extracts in 35 minutes using a scalable data workflow](https://www.interline.io/blog/scaling-openstreetmap-data-workflows/) @@ -151,4 +153,4 @@ the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-o ## Security -See [SECURITY.md](https://github.com/argoproj/argo-workflows/blob/main/SECURITY.md). +See [Security](security.md). diff --git a/docs/argo-server-sso.md b/docs/argo-server-sso.md index 46394dd08064..ec33829d55e1 100644 --- a/docs/argo-server-sso.md +++ b/docs/argo-server-sso.md @@ -83,7 +83,7 @@ metadata: # Must evaluate to a boolean. # If you want an account to be the default to use, this rule can be "true". # Details of the expression language are available in - # https://github.com/expr-lang/expr/blob/master/docs/language-definition.md. + # https://expr-lang.org/docs/language-definition. workflows.argoproj.io/rbac-rule: "'admin' in groups" # The precedence is used to determine which service account to use whe # Precedence is an integer. It may be negative. If omitted, it defaults to "0". @@ -110,7 +110,7 @@ The precedence must be the lowest of all your service accounts. As of Kubernetes v1.24, secrets for a service account token are no longer automatically created. Therefore, service account secrets for SSO RBAC must be created manually. -See [Manually create secrets](manually-create-secrets.md) for detailed instructions. +See [Service Account Secrets](service-account-secrets.md) for detailed instructions. ## SSO RBAC Namespace Delegation diff --git a/docs/data-sourcing-and-transformation.md b/docs/data-sourcing-and-transformation.md index 0c5f78505835..4b5d19f687fb 100644 --- a/docs/data-sourcing-and-transformation.md +++ b/docs/data-sourcing-and-transformation.md @@ -53,6 +53,6 @@ A `data` template must always contain a `source`. Current available sources: A `data` template may contain any number of transformations (or zero). The transformations will be applied serially in order. Current available transformations: -* `expression`: an [`expr`](https://github.com/expr-lang/expr) expression. See language definition [here](https://github.com/expr-lang/expr/blob/master/docs/Language-Definition.md). When defining `expr` expressions Argo will pass the available data to the environment as a variable called `data` (see example above). +* `expression`: an [expression](variables.md#expression). The data is accessible in the `data` variable (see example above). We understand that the `expression` transformation is limited. We intend to greatly expand the functionality of this template with our community's feedback. Please see the link at the top of this document to submit ideas or use cases for this feature. diff --git a/docs/events.md b/docs/events.md index d7d6eb72d5cd..70e92e21d6f0 100644 --- a/docs/events.md +++ b/docs/events.md @@ -150,14 +150,12 @@ requirements](https://kubernetes.io/docs/concepts/overview/working-with-objects/ ## Event Expression Syntax and the Event Expression Environment -**Event expressions** are expressions that are evaluated over the **event expression environment**. +**Event expressions** are [expressions](variables.md#expression) that are evaluated over the **event expression environment**. ### Expression Syntax Because the endpoint accepts any JSON data, it is the user's responsibility to write a suitable expression to correctly filter the events they are interested in. Therefore, DO NOT assume the existence of any fields, and guard against them using a nil check. -[Learn more about expression syntax](https://github.com/expr-lang/expr). - ### Expression Environment The event environment contains: diff --git a/docs/fields.md b/docs/fields.md index b3b9f5223e21..79cecc220ef1 100644 --- a/docs/fields.md +++ b/docs/fields.md @@ -793,7 +793,7 @@ WorkflowSpec is the specification of a Workflow. |`artifactRepositoryRef`|[`ArtifactRepositoryRef`](#artifactrepositoryref)|ArtifactRepositoryRef specifies the configMap name and key containing the artifact repository config.| |`automountServiceAccountToken`|`boolean`|AutomountServiceAccountToken indicates whether a service account token should be automatically mounted in pods. ServiceAccountName of ExecutorConfig must be specified if this value is false.| |`dnsConfig`|[`PodDNSConfig`](#poddnsconfig)|PodDNSConfig defines the DNS parameters of a pod in addition to those generated from DNSPolicy.| -|`dnsPolicy`|`string`|Set DNS policy for the pod. Defaults to "ClusterFirst". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.| +|`dnsPolicy`|`string`|Set DNS policy for workflow pods. Defaults to "ClusterFirst". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.| |`entrypoint`|`string`|Entrypoint is a template reference to the starting point of the io.argoproj.workflow.v1alpha1.| |`executor`|[`ExecutorConfig`](#executorconfig)|Executor holds configurations of executor containers of the io.argoproj.workflow.v1alpha1.| |`hooks`|[`LifecycleHook`](#lifecyclehook)|Hooks holds the lifecycle hook which is invoked at lifecycle of step, irrespective of the success, failure, or error status of the primary step| diff --git a/docs/installation.md b/docs/installation.md index cce7a42c17c0..17e52de3bbb4 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -14,9 +14,12 @@ To install Argo Workflows, navigate to the [releases page](https://github.com/ar You can use Kustomize to patch your preferred [configurations](managed-namespace.md) on top of the base manifest. -⚠️ If you are using GitOps, never use Kustomize remote base: this is dangerous. Instead, copy the manifests into your Git repo. +!!! Note "Use a full hash" + If you are using a [remote base](https://github.com/kubernetes-sigs/kustomize/blob/ab519fdc13ded9875e42d70ac8a5b1b9023a2dbb/examples/remoteBuild.md) with Kustomize, you should specify a full commit hash, for example `?ref=960af331a8c0a3f2e263c8b90f1daf4303816ba8`. -⚠️ `latest` is tip, not stable. Never run it in production. +!!! Warning "`latest` vs stable" + `latest` is the tip of the `main` branch and may not be stable. + In production, you should use a specific release version. #### Argo Workflows Helm Chart diff --git a/docs/releasing.md b/docs/releasing.md index 072934599c12..215518a5d9fb 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -7,12 +7,21 @@ Then get a list of commits you may want to cherry-pick: ```bash -./hack/what-to-cherry-pick.sh release-3.3 "fix" -./hack/what-to-cherry-pick.sh release-3.3 "chore(deps)" -./hack/what-to-cherry-pick.sh release-3.3 "build" -./hack/what-to-cherry-pick.sh release-3.3 "ci" +./hack/cherry-pick.sh release-3.3 "fix" +./hack/cherry-pick.sh release-3.3 "chore(deps)" +./hack/cherry-pick.sh release-3.3 "build" +./hack/cherry-pick.sh release-3.3 "ci" ``` +To automatically cherry-pick, run the following: + +```bash +./hack/cherry-pick.sh release-3.3 "fix" false +``` + +Then look for "failed to cherry-pick" in the log to find commits that fail to be cherry-picked and decide if a +manual patch is necessary. + Ignore: * Fixes for features only on `main`. diff --git a/docs/requirements.txt b/docs/requirements.txt index 4eab2e00983f..d58f648b8db0 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1,2 @@ -mkdocs-material==8.2.6 +mkdocs-material==9.* +mkdocs-redirects==1.* diff --git a/docs/retries.md b/docs/retries.md index 00106a521d49..7f3ccec878c6 100644 --- a/docs/retries.md +++ b/docs/retries.md @@ -85,9 +85,8 @@ spec: > v3.2 and after -You can also use `expression` to control retries. The `expression` field -accepts an [expr](https://github.com/expr-lang/expr) expression and has -access to the following variables: +You can also use `expression` to control retries. +This is an [expression](variables.md#expression) with access to the following variables: - `lastRetry.exitCode`: The exit code of the last retry, or "-1" if not available - `lastRetry.status`: The phase of the last retry: Error, Failed diff --git a/docs/manually-create-secrets.md b/docs/service-account-secrets.md similarity index 100% rename from docs/manually-create-secrets.md rename to docs/service-account-secrets.md diff --git a/docs/variables.md b/docs/variables.md index 501dc9fd5559..4da721c412cd 100644 --- a/docs/variables.md +++ b/docs/variables.md @@ -56,7 +56,7 @@ The tag is substituted with the result of evaluating the tag as an expression. Note that any hyphenated parameter names or step names will cause a parsing error. You can reference them by indexing into the parameter or step map, e.g. `inputs.parameters['my-param']` or `steps['my-step'].outputs.result`. -[Learn about the expression syntax](https://github.com/expr-lang/expr/blob/master/docs/language-definition.md). +[Learn more about the expression syntax](https://expr-lang.org/docs/language-definition). #### Examples diff --git a/docs/use-cases/webhdfs.md b/docs/webhdfs.md similarity index 93% rename from docs/use-cases/webhdfs.md rename to docs/webhdfs.md index fe5f5061efc7..089f5fdb82b0 100644 --- a/docs/use-cases/webhdfs.md +++ b/docs/webhdfs.md @@ -4,7 +4,7 @@ ## Input Artifacts -You can use [HTTP artifacts](../walk-through/hardwired-artifacts.md) to connect to webHDFS, where the URL will be the webHDFS endpoint including the file path and any query parameters. +You can use [HTTP artifacts](walk-through/hardwired-artifacts.md) to connect to webHDFS, where the URL will be the webHDFS endpoint including the file path and any query parameters. Suppose your webHDFS endpoint is available under `https://mywebhdfsprovider.com/webhdfs/v1/` and you have a file `my-art.txt` located in a `data` folder, which you want to use as an input artifact. To construct the URL, you append the file path to the base webHDFS endpoint and set the [OPEN operation](https://hadoop.apache.org/docs/r3.3.3/hadoop-project-dist/hadoop-hdfs/WebHDFS.html#Open_and_Read_a_File) via query parameter. The result is: `https://mywebhdfsprovider.com/webhdfs/v1/data/my-art.txt?op=OPEN`. See the below Workflow which will download the specified webHDFS artifact into the specified `path`: diff --git a/go.mod b/go.mod index 7ab35d0a6cb9..ffe8b951b11a 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module github.com/argoproj/argo-workflows/v3 go 1.21 require ( - cloud.google.com/go/storage v1.35.1 - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 - github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 + cloud.google.com/go/storage v1.36.0 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 + github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible github.com/Masterminds/sprig/v3 v3.2.3 github.com/TwiN/go-color v1.4.1 @@ -22,11 +22,11 @@ require ( github.com/expr-lang/expr v1.16.0 github.com/gavv/httpexpect/v2 v2.10.0 github.com/go-git/go-git/v5 v5.11.0 - github.com/go-jose/go-jose/v3 v3.0.1 + github.com/go-jose/go-jose/v3 v3.0.3 github.com/go-openapi/jsonreference v0.20.2 github.com/go-sql-driver/mysql v1.7.1 github.com/gogo/protobuf v1.3.2 - github.com/golang/protobuf v1.5.3 + github.com/golang/protobuf v1.5.4 github.com/google/go-containerregistry v0.16.1 github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20220720195016-31786c6cbb82 github.com/gorilla/handlers v1.5.2 @@ -55,7 +55,7 @@ require ( github.com/upper/db/v4 v4.7.0 github.com/valyala/fasttemplate v1.2.2 github.com/xeipuuv/gojsonschema v1.2.0 - golang.org/x/crypto v0.17.0 + golang.org/x/crypto v0.22.0 golang.org/x/exp v0.0.0-20230905200255-921286631fa9 golang.org/x/oauth2 v0.13.0 golang.org/x/sync v0.5.0 @@ -83,16 +83,16 @@ require ( github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/evilmonkeyinc/jsonpath v0.8.1 // indirect - github.com/golang-jwt/jwt/v5 v5.0.0 // indirect + github.com/golang-jwt/jwt/v5 v5.2.0 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.14.1 // indirect + github.com/jackc/pgconn v1.14.3 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.2 // indirect + github.com/jackc/pgproto3/v2 v2.3.3 // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgtype v1.14.0 // indirect - github.com/jackc/pgx/v4 v4.18.1 // indirect + github.com/jackc/pgx/v4 v4.18.2 // indirect github.com/jcmturner/aescts/v2 v2.0.0 // indirect github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect github.com/jcmturner/goidentity/v6 v6.0.1 // indirect @@ -118,8 +118,8 @@ require ( cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/iam v1.1.3 // indirect github.com/Azure/azure-sdk-for-go v66.0.0+incompatible // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 - github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 + github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.27 // indirect @@ -129,7 +129,7 @@ require ( github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect - github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 // indirect + github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 // indirect github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.2.0 // indirect @@ -158,13 +158,13 @@ require ( github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect github.com/chrismellard/docker-credential-acr-env v0.0.0-20220327082430-c57b701bfc08 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect - github.com/creack/pty v1.1.20 + github.com/creack/pty v1.1.21 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd // indirect github.com/dimchansky/utfbom v1.1.1 // indirect github.com/docker/cli v24.0.7+incompatible // indirect github.com/docker/distribution v2.8.2+incompatible // indirect - github.com/docker/docker v24.0.0+incompatible // indirect + github.com/docker/docker v24.0.9+incompatible // indirect github.com/docker/docker-credential-helpers v0.7.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/emicklei/go-restful/v3 v3.10.0 // indirect @@ -191,7 +191,7 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/google/uuid v1.4.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect @@ -237,7 +237,7 @@ require ( github.com/opencontainers/image-spec v1.1.0-rc3 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect - github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/procfs v0.10.1 // indirect github.com/rs/xid v1.5.0 // indirect @@ -263,13 +263,13 @@ require ( github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect go.opencensus.io v0.24.0 // indirect go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.15.0 + golang.org/x/net v0.22.0 // indirect + golang.org/x/sys v0.19.0 // indirect + golang.org/x/term v0.19.0 golang.org/x/text v0.14.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect @@ -285,3 +285,6 @@ require ( sigs.k8s.io/kustomize/kyaml v0.13.6 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect ) + +// Avoid CVE-2023-45288 +replace golang.org/x/net => golang.org/x/net v0.23.0 diff --git a/go.sum b/go.sum index 77d0a75daadd..4b93d5f78011 100644 --- a/go.sum +++ b/go.sum @@ -47,24 +47,26 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -cloud.google.com/go/storage v1.35.1 h1:B59ahL//eDfx2IIKFBeT5Atm9wnNmj3+8xG/W4WB//w= -cloud.google.com/go/storage v1.35.1/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= +cloud.google.com/go/storage v1.36.0 h1:P0mOkAcaJxhCTvAkMhxMfrTKiNcub4YmmPBtlhAyTr8= +cloud.google.com/go/storage v1.36.0/go.mod h1:M6M/3V/D3KpzMTJyPOR/HU6n2Si5QdaXYEsng2xgOs8= 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/azure-sdk-for-go v66.0.0+incompatible h1:bmmC38SlE8/E81nNADlgmVGurPWMHDX2YNXVQMrBpEE= github.com/Azure/azure-sdk-for-go v66.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0 h1:9kDVnTz3vbfweTqAUmk/a/pH5pWFCHtvRpHYC0G/dcA= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.8.0/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 h1:E+OJmp2tPvt1W+amx48v1eqbjDYsgN+RzP4q16yV5eM= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo= github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0/go.mod h1:HcM1YX14R7CJcghJGOYCgdezslRSVzqwLf/q+4Y2r/0= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2TzfVZ1pCb5vxm4BtZPUdYWe/Xo8= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 h1:sXr+ck84g/ZlZUOZiNELInmMgOsuGwdjjVkEIde0OtY= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 h1:u/LLAOFgsMv7HmNL4Qufg58y+qElGOt5qv0z1mURkRY= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0/go.mod h1:2e8rMJtl2+2j+HXbTBwnyGpm5Nou7KhvSfxOq8JpTag= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0 h1:AifHbc4mg0x9zW52WOpKbsHaDKuRhlI7TVl47thgQ70= +github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0/go.mod h1:T5RfihdXtBDxt1Ch2wobif3TvzTdumDy29kahv6AV9A= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2 h1:YUUxeiOWgdAQE3pXt2H7QXzZs0q8UBjgRbl56qo8GYM= +github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.2/go.mod h1:dmXQgZuiSubAecswZE+Sm8jkvEa7kQgTPVRvwL/nd0E= 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-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= @@ -97,8 +99,8 @@ github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1 h1:WpB/QDNLpMw72xHJc34BNNykqSOeEJDAWkhf0u12/Jk= -github.com/AzureAD/microsoft-authentication-library-for-go v1.1.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= @@ -248,8 +250,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t 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/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.20 h1:VIPb/a2s17qNeQgDnkfZC35RScx+blkKF8GV68n80J4= -github.com/creack/pty v1.1.20/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= +github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/danieljoos/wincred v1.1.0/go.mod h1:XYlo+eRTsVA9aHGp7NGjFkPla4m+DCL7hqDjlFjiygg= @@ -272,8 +274,8 @@ github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvM github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.0+incompatible h1:z4bf8HvONXX9Tde5lGBMQ7yCJgNahmJumdrStZAbeY4= -github.com/docker/docker v24.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0= +github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.6.4/go.mod h1:ofX3UI0Gz1TteYBjtgs07O36Pyasyp66D2uKT7H8W1c= github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= @@ -355,8 +357,8 @@ github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lK 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-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-jose/go-jose/v3 v3.0.1 h1:pWmKFVtt+Jl0vBZTIpz/eAKwsm6LkIxDVVbFHKkchhA= -github.com/go-jose/go-jose/v3 v3.0.1/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= +github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= +github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -401,8 +403,8 @@ github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzw github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= -github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= @@ -442,8 +444,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e h1:KhcknUwkWHKZPbFy2P7jH5LKJ3La+0ZeknkkmrSgqb0= github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk= @@ -508,8 +510,8 @@ github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= @@ -597,8 +599,9 @@ github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfG github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= -github.com/jackc/pgconn v1.14.1 h1:smbxIaZA08n6YuxEX1sDyjV/qkbtUtkH20qLkR9MUR4= github.com/jackc/pgconn v1.14.1/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= +github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= +github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -614,8 +617,9 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0= github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= @@ -629,8 +633,9 @@ github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08 github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0= github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= +github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU= +github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= @@ -835,8 +840,8 @@ github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR 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/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= -github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/diff v0.0.0-20200914180035-5b29258ca4f7/go.mod h1:zO8QMzTeZd5cpnIkz/Gn6iK0jDfGicM1nynOkkPIl28= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1083,7 +1088,6 @@ golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaE 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-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1103,11 +1107,11 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4 golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +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/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 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= @@ -1153,73 +1157,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180921000356-2f5d2388922f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -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-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -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-20201031054903-ff519b6c9102/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-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -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.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= 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= @@ -1300,7 +1239,6 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/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-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1310,9 +1248,7 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/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= @@ -1320,14 +1256,12 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/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-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/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-20220704084225-05e143d24a9e/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= @@ -1339,25 +1273,23 @@ 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.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +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/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 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.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +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/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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= @@ -1372,8 +1304,6 @@ 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.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= @@ -1585,8 +1515,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba 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.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/hack/check-mkdocs.sh b/hack/check-mkdocs.sh deleted file mode 100755 index 4261fa0fb2e1..000000000000 --- a/hack/check-mkdocs.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env sh -set -eu - -echo "Checking all docs are listed in mkdocs.yml..."ß - -# https://www.mkdocs.org/user-guide/configuration/#validation since 1.5.0 -mkdocs build --strict - -echo "✅ Success - all docs appear to be listed in mkdocs.yml" diff --git a/hack/cherry-pick.sh b/hack/cherry-pick.sh index e52e0c5c8d48..16ffddc81a0f 100755 --- a/hack/cherry-pick.sh +++ b/hack/cherry-pick.sh @@ -1,46 +1,56 @@ #!/usr/bin/env bash set -eu -# See docs/releasing.md for instructions. +# See ../docs/releasing.md for instructions. -br="$1" # branch name, e.g. release-3.3 +branch="$1" # branch name, e.g. release-3.3 commitPrefix="$2" # prefix to use to filter commits, e.g. fix, chore(deps), build, ci -# whether this is dry-run. If set to `true`, this script will only print out the list -# of commits. Otherwise, this script will automatically cherry-pick the commits to the branch. -dryRun="$3" +# If dryRun is unset or `true`, only print the list of commits to be cherry-picked. +# Otherwise, cherry-pick the commits to the specified branch. +dryRun="${3:-"true"}" + +# unfortunately, cherry-picking to another branch is not possible, so error out if not on the branch (c.f. https://stackoverflow.com/q/13878904/3431180) +curr_branch=$(git rev-parse --abbrev-ref HEAD) +if [[ "$curr_branch" != "$branch" ]]; then + echo "Current branch is '$curr_branch', but trying to cherry-pick to branch '$branch'. You must have branch '$branch' checked out in order to cherry-pick" + exit 1 +fi commitGrepPattern="^${commitPrefix}(*.*)*:.*(#" # find the branch point -base=$(git merge-base "$br" main) +base=$(git merge-base "$branch" main) # extract the PRs from stdin -prNo() { - set -eu +getPRNum() { cat | sed "s|.*(\(#[0-9]*\))|\1|" } # list the PRs on each branch -prs() { - set -eu - git log --format="%s" --grep "${commitGrepPattern}" "$1...$2" | prNo | sort > "/tmp/$2" +getPRs() { + git log --format="%s" --grep "${commitGrepPattern}" "$1...$2" | getPRNum | sort > "/tmp/$2" } -prs "$base" "$br" -prs "$base" main +getPRs "$base" "$branch" +getPRs "$base" main # find PRs added to main -diff "/tmp/$br" /tmp/main | grep "^> " | cut -c 3- > /tmp/prs +diff "/tmp/$branch" /tmp/main | grep "^> " | cut -c 3- > /tmp/prs # print all the commits that need cherry-picking -git log --oneline --grep "${commitGrepPattern}" "$base...main" | while read -r m; do +git log --oneline --grep "${commitGrepPattern}" "$base...main" | tac | while read -r m; do + if ! grep -q "$(echo "$m" | getPRNum)" /tmp/prs ; then + continue + fi + if [[ "$dryRun" == "true" ]]; then - grep -q "$(echo "$m" | prNo)" /tmp/prs && echo "$m" - else - commit=$(grep -q "$(echo "$m" | prNo)" /tmp/prs && echo "${m:0:9}") - echo "cherry-picking: $commit" - if ! git cp "$commit"; then - echo "failed to cherry-pick $commit" - git cp --abort - fi + echo "$m" + continue + fi + + commit=${m:0:9} + echo "cherry-picking: $commit" + if ! git cherry-pick "$commit" -x -Xpatience ; then + echo "failed to cherry-pick $commit" + git cherry-pick --abort fi done diff --git a/hack/copy-readme.sh b/hack/copy-readme.sh new file mode 100755 index 000000000000..96450609a2fd --- /dev/null +++ b/hack/copy-readme.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -euo pipefail + +target="docs/README.md" +cp README.md $target + +replaceTarget() { + # cross-platform for Linux and Mac, based off https://unix.stackexchange.com/a/381201/152866 + sed -i.bak -e "$1" "$target" && rm $target.bak +} + +# replace absolute links with relative links +replaceTarget 's/(https:\/\/argo-workflows\.readthedocs\.io\/en\/latest\/\(.*\)\/)/(\1\.md)/' +replaceTarget 's/walk-through\.md/walk-through\/index\.md/' # index routes need special handling +# adjust existing relative links +replaceTarget 's/(docs\//(/' # remove `docs/` prefix +replaceTarget 's/(USERS\.md/(https:\/\/github\.com\/argoproj\/argo-workflows\/blob\/main\/USERS\.md/' # replace non-docs link with an absolute link +replaceTarget 's/SECURITY\.md\](SECURITY/Security\](security/' # case-sensitive -- the file is docs/security.md vs. SECURITY.md. also remove the .md from a docs link + +# change text for docs self-link +replaceTarget 's/.*View the docs.*/You'\''re here!/' diff --git a/hack/swagger/secondaryswaggergen.go b/hack/swagger/secondaryswaggergen.go index 8e302feb0188..579e0dc59866 100644 --- a/hack/swagger/secondaryswaggergen.go +++ b/hack/swagger/secondaryswaggergen.go @@ -38,6 +38,7 @@ func secondarySwaggerGen() { if err != nil { panic(err) } + defer f.Close() e := json.NewEncoder(f) e.SetIndent("", " ") err = e.Encode(swagger) diff --git a/hack/what-to-cherry-pick.sh b/hack/what-to-cherry-pick.sh deleted file mode 100755 index daf87a95a672..000000000000 --- a/hack/what-to-cherry-pick.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env sh -set -eu -# this script prints out a list a commits that are on master that you should probably cherry-pick to the release branch - -br=$1;# branch -commitPrefix=$2;# examples: fix, chore(deps), build, ci -commitGrepPattern="^${commitPrefix}(*.*)*:.*(#" - -# find the branch point -base=$(git merge-base $br master) - -# extract the PRs from stdin -prNo() { - set -eu - cat | sed 's|.*(\(#[0-9]*\))|\1|' -} - -# list the PRs on each branch -prs() { - set -eu - git log --format=%s --grep ${commitGrepPattern} $1...$2 | prNo | sort > /tmp/$2 -} - -prs $base $br -prs $base master - -# find PRs added to master -diff /tmp/$br /tmp/master | grep '^> ' | cut -c 3- > /tmp/prs - -# print all the commits that need cherry-picking -git log --oneline --grep ${commitGrepPattern} $base...master | while read -r m; do - grep -q "$(echo $m | prNo)" /tmp/prs && echo $m -done \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 265122681508..d1146c28b8df 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -40,6 +40,12 @@ markdown_extensions: format: !!python/name:pymdownx.superfences.fence_code_format - toc: permalink: true +plugins: + - redirects: + redirect_maps: + use-cases/webhdfs.md: webhdfs.md + manually-create-secrets.md: service-account-secrets.md + - search # re-include the default: https://www.mkdocs.org/user-guide/configuration/#plugins, validation: omitted_files: warn absolute_links: warn @@ -131,6 +137,7 @@ nav: - workflow-of-workflows.md - workflow-notifications.md - work-avoidance.md + - webhdfs.md - UI Features: - artifact-visualization.md - widgets.md @@ -163,7 +170,6 @@ nav: - use-cases/infrastructure-automation.md - use-cases/machine-learning.md - use-cases/stream-processing.md - - use-cases/webhdfs.md - use-cases/other.md # other should always be last - FAQ: faq.md - kubectl.md @@ -241,7 +247,7 @@ nav: - workflow-executors.md - workflow-restrictions.md - sidecar-injection.md - - manually-create-secrets.md + - service-account-secrets.md - Argo Server: - argo-server.md - argo-server-auth-mode.md diff --git a/persist/sqldb/workflow_archive.go b/persist/sqldb/workflow_archive.go index 56020f64dec0..fce2ff97b432 100644 --- a/persist/sqldb/workflow_archive.go +++ b/persist/sqldb/workflow_archive.go @@ -8,7 +8,9 @@ import ( log "github.com/sirupsen/logrus" "github.com/upper/db/v4" "google.golang.org/grpc/codes" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/types" wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" sutils "github.com/argoproj/argo-workflows/v3/server/utils" @@ -30,6 +32,9 @@ type archivedWorkflowMetadata struct { Phase wfv1.WorkflowPhase `db:"phase"` StartedAt time.Time `db:"startedat"` FinishedAt time.Time `db:"finishedat"` + Labels string `db:"labels,omitempty"` + Annotations string `db:"annotations,omitempty"` + Progress string `db:"progress,omitempty"` } type archivedWorkflowRecord struct { @@ -142,7 +147,7 @@ func (r *workflowArchive) ArchiveWorkflow(wf *wfv1.Workflow) error { } func (r *workflowArchive) ListWorkflows(namespace string, name string, namePrefix string, minStartedAt, maxStartedAt time.Time, labelRequirements labels.Requirements, limit int, offset int) (wfv1.Workflows, error) { - var archivedWfs []archivedWorkflowRecord + var archivedWfs []archivedWorkflowMetadata // If we were passed 0 as the limit, then we should load all available archived workflows // to match the behavior of the `List` operations in the Kubernetes API @@ -151,8 +156,13 @@ func (r *workflowArchive) ListWorkflows(namespace string, name string, namePrefi offset = -1 } + selectQuery, err := selectArchivedWorkflowQuery(r.dbType) + if err != nil { + return nil, err + } + selector := r.session.SQL(). - Select("workflow"). + Select(selectQuery). From(archiveTableName). Where(r.clusterManagedNamespaceAndInstanceID()). And(namespaceEqual(namespace)). @@ -161,7 +171,7 @@ func (r *workflowArchive) ListWorkflows(namespace string, name string, namePrefi And(startedAtFromClause(minStartedAt)). And(startedAtToClause(maxStartedAt)) - selector, err := labelsClause(selector, r.dbType, labelRequirements) + selector, err = labelsClause(selector, r.dbType, labelRequirements) if err != nil { return nil, err } @@ -174,16 +184,35 @@ func (r *workflowArchive) ListWorkflows(namespace string, name string, namePrefi return nil, err } - wfs := make(wfv1.Workflows, 0) - for _, archivedWf := range archivedWfs { - wf := wfv1.Workflow{} - err = json.Unmarshal([]byte(archivedWf.Workflow), &wf) - if err != nil { - log.WithFields(log.Fields{"workflowUID": archivedWf.UID, "workflowName": archivedWf.Name}).Errorln("unable to unmarshal workflow from database") - } else { - // For backward compatibility, we should label workflow retrieved from DB as Persisted. - wf.ObjectMeta.Labels[common.LabelKeyWorkflowArchivingStatus] = "Persisted" - wfs = append(wfs, wf) + wfs := make(wfv1.Workflows, len(archivedWfs)) + for i, md := range archivedWfs { + labels := make(map[string]string) + if err := json.Unmarshal([]byte(md.Labels), &labels); err != nil { + return nil, err + } + // For backward compatibility, we should label workflow retrieved from DB as Persisted. + labels[common.LabelKeyWorkflowArchivingStatus] = "Persisted" + + annotations := make(map[string]string) + if err := json.Unmarshal([]byte(md.Annotations), &annotations); err != nil { + return nil, err + } + + wfs[i] = wfv1.Workflow{ + ObjectMeta: v1.ObjectMeta{ + Name: md.Name, + Namespace: md.Namespace, + UID: types.UID(md.UID), + CreationTimestamp: v1.Time{Time: md.StartedAt}, + Labels: labels, + Annotations: annotations, + }, + Status: wfv1.WorkflowStatus{ + Phase: md.Phase, + StartedAt: v1.Time{Time: md.StartedAt}, + FinishedAt: v1.Time{Time: md.FinishedAt}, + Progress: wfv1.Progress(md.Progress), + }, } } return wfs, nil @@ -347,3 +376,13 @@ func (r *workflowArchive) DeleteExpiredWorkflows(ttl time.Duration) error { log.WithFields(log.Fields{"rowsAffected": rowsAffected}).Info("Deleted archived workflows") return nil } + +func selectArchivedWorkflowQuery(t dbType) (*db.RawExpr, error) { + switch t { + case MySQL: + return db.Raw("name, namespace, uid, phase, startedat, finishedat, coalesce(workflow->>'$.metadata.labels', '{}') as labels,coalesce(workflow->>'$.metadata.annotations', '{}') as annotations, coalesce(workflow->>'$.status.progress', '') as progress"), nil + case Postgres: + return db.Raw("name, namespace, uid, phase, startedat, finishedat, coalesce((workflow::json)->'metadata'->>'labels', '{}') as labels, coalesce((workflow::json)->'metadata'->>'annotations', '{}') as annotations, coalesce((workflow::json)->'status'->>'progress', '') as progress"), nil + } + return nil, fmt.Errorf("unsupported db type %s", t) +} diff --git a/pkg/apis/workflow/v1alpha1/generated.proto b/pkg/apis/workflow/v1alpha1/generated.proto index f301e6297d49..1abdbf4732aa 100644 --- a/pkg/apis/workflow/v1alpha1/generated.proto +++ b/pkg/apis/workflow/v1alpha1/generated.proto @@ -1972,7 +1972,7 @@ message WorkflowSpec { // Host networking requested for this workflow pod. Default to false. optional bool hostNetwork = 14; - // Set DNS policy for the pod. + // Set DNS policy for workflow pods. // Defaults to "ClusterFirst". // Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. // DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. diff --git a/pkg/apis/workflow/v1alpha1/openapi_generated.go b/pkg/apis/workflow/v1alpha1/openapi_generated.go index 1873d1ce9440..c947e1420988 100644 --- a/pkg/apis/workflow/v1alpha1/openapi_generated.go +++ b/pkg/apis/workflow/v1alpha1/openapi_generated.go @@ -7557,7 +7557,7 @@ func schema_pkg_apis_workflow_v1alpha1_WorkflowSpec(ref common.ReferenceCallback }, "dnsPolicy": { SchemaProps: spec.SchemaProps{ - Description: "Set DNS policy for the pod. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.", + Description: "Set DNS policy for workflow pods. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.", Type: []string{"string"}, Format: "", }, diff --git a/pkg/apis/workflow/v1alpha1/workflow_types.go b/pkg/apis/workflow/v1alpha1/workflow_types.go index 5747cdbe674f..46d7d2ae38c8 100644 --- a/pkg/apis/workflow/v1alpha1/workflow_types.go +++ b/pkg/apis/workflow/v1alpha1/workflow_types.go @@ -326,7 +326,7 @@ type WorkflowSpec struct { // Host networking requested for this workflow pod. Default to false. HostNetwork *bool `json:"hostNetwork,omitempty" protobuf:"bytes,14,opt,name=hostNetwork"` - // Set DNS policy for the pod. + // Set DNS policy for workflow pods. // Defaults to "ClusterFirst". // Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. // DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. @@ -3427,6 +3427,34 @@ func (wf *Workflow) SetStoredTemplate(scope ResourceScope, resourceName string, return false, nil } +// SetStoredInlineTemplate stores a inline template in stored templates of the workflow. +func (wf *Workflow) SetStoredInlineTemplate(scope ResourceScope, resourceName string, tmpl *Template) error { + // Store inline templates in steps. + for _, steps := range tmpl.Steps { + for _, step := range steps.Steps { + if step.GetTemplate() != nil { + _, err := wf.SetStoredTemplate(scope, resourceName, &step, step.GetTemplate()) + if err != nil { + return err + } + } + } + } + // Store inline templates in DAG tasks. + if tmpl.DAG != nil { + for _, task := range tmpl.DAG.Tasks { + if task.GetTemplate() != nil { + _, err := wf.SetStoredTemplate(scope, resourceName, &task, task.GetTemplate()) + if err != nil { + return err + } + } + } + } + + return nil +} + // resolveTemplateReference resolves the stored template name of a given template holder on the template scope and determines // if it should be stored func resolveTemplateReference(callerScope ResourceScope, resourceName string, caller TemplateReferenceHolder) (string, bool) { diff --git a/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1WorkflowSpec.md b/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1WorkflowSpec.md index 24e847068076..e889ac8f8756 100644 --- a/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1WorkflowSpec.md +++ b/sdks/java/client/docs/IoArgoprojWorkflowV1alpha1WorkflowSpec.md @@ -16,7 +16,7 @@ Name | Type | Description | Notes **artifactRepositoryRef** | [**IoArgoprojWorkflowV1alpha1ArtifactRepositoryRef**](IoArgoprojWorkflowV1alpha1ArtifactRepositoryRef.md) | | [optional] **automountServiceAccountToken** | **Boolean** | AutomountServiceAccountToken indicates whether a service account token should be automatically mounted in pods. ServiceAccountName of ExecutorConfig must be specified if this value is false. | [optional] **dnsConfig** | [**io.kubernetes.client.openapi.models.V1PodDNSConfig**](io.kubernetes.client.openapi.models.V1PodDNSConfig.md) | | [optional] -**dnsPolicy** | **String** | Set DNS policy for the pod. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'. | [optional] +**dnsPolicy** | **String** | Set DNS policy for workflow pods. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'. | [optional] **entrypoint** | **String** | Entrypoint is a template reference to the starting point of the io.argoproj.workflow.v1alpha1. | [optional] **executor** | [**IoArgoprojWorkflowV1alpha1ExecutorConfig**](IoArgoprojWorkflowV1alpha1ExecutorConfig.md) | | [optional] **hooks** | [**Map<String, IoArgoprojWorkflowV1alpha1LifecycleHook>**](IoArgoprojWorkflowV1alpha1LifecycleHook.md) | Hooks holds the lifecycle hook which is invoked at lifecycle of step, irrespective of the success, failure, or error status of the primary step | [optional] diff --git a/sdks/python/client/argo_workflows/model/io_argoproj_workflow_v1alpha1_workflow_spec.py b/sdks/python/client/argo_workflows/model/io_argoproj_workflow_v1alpha1_workflow_spec.py index bdd8b4ea2e81..7abb58743a4b 100644 --- a/sdks/python/client/argo_workflows/model/io_argoproj_workflow_v1alpha1_workflow_spec.py +++ b/sdks/python/client/argo_workflows/model/io_argoproj_workflow_v1alpha1_workflow_spec.py @@ -276,7 +276,7 @@ def _from_openapi_data(cls, *args, **kwargs): # noqa: E501 artifact_repository_ref (IoArgoprojWorkflowV1alpha1ArtifactRepositoryRef): [optional] # noqa: E501 automount_service_account_token (bool): AutomountServiceAccountToken indicates whether a service account token should be automatically mounted in pods. ServiceAccountName of ExecutorConfig must be specified if this value is false.. [optional] # noqa: E501 dns_config (PodDNSConfig): [optional] # noqa: E501 - dns_policy (str): Set DNS policy for the pod. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.. [optional] # noqa: E501 + dns_policy (str): Set DNS policy for workflow pods. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.. [optional] # noqa: E501 entrypoint (str): Entrypoint is a template reference to the starting point of the io.argoproj.workflow.v1alpha1.. [optional] # noqa: E501 executor (IoArgoprojWorkflowV1alpha1ExecutorConfig): [optional] # noqa: E501 hooks ({str: (IoArgoprojWorkflowV1alpha1LifecycleHook,)}): Hooks holds the lifecycle hook which is invoked at lifecycle of step, irrespective of the success, failure, or error status of the primary step. [optional] # noqa: E501 @@ -399,7 +399,7 @@ def __init__(self, *args, **kwargs): # noqa: E501 artifact_repository_ref (IoArgoprojWorkflowV1alpha1ArtifactRepositoryRef): [optional] # noqa: E501 automount_service_account_token (bool): AutomountServiceAccountToken indicates whether a service account token should be automatically mounted in pods. ServiceAccountName of ExecutorConfig must be specified if this value is false.. [optional] # noqa: E501 dns_config (PodDNSConfig): [optional] # noqa: E501 - dns_policy (str): Set DNS policy for the pod. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.. [optional] # noqa: E501 + dns_policy (str): Set DNS policy for workflow pods. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'.. [optional] # noqa: E501 entrypoint (str): Entrypoint is a template reference to the starting point of the io.argoproj.workflow.v1alpha1.. [optional] # noqa: E501 executor (IoArgoprojWorkflowV1alpha1ExecutorConfig): [optional] # noqa: E501 hooks ({str: (IoArgoprojWorkflowV1alpha1LifecycleHook,)}): Hooks holds the lifecycle hook which is invoked at lifecycle of step, irrespective of the success, failure, or error status of the primary step. [optional] # noqa: E501 diff --git a/sdks/python/client/docs/IoArgoprojWorkflowV1alpha1WorkflowSpec.md b/sdks/python/client/docs/IoArgoprojWorkflowV1alpha1WorkflowSpec.md index d0ac0b10fbb6..3f9ded2612a9 100644 --- a/sdks/python/client/docs/IoArgoprojWorkflowV1alpha1WorkflowSpec.md +++ b/sdks/python/client/docs/IoArgoprojWorkflowV1alpha1WorkflowSpec.md @@ -13,7 +13,7 @@ Name | Type | Description | Notes **artifact_repository_ref** | [**IoArgoprojWorkflowV1alpha1ArtifactRepositoryRef**](IoArgoprojWorkflowV1alpha1ArtifactRepositoryRef.md) | | [optional] **automount_service_account_token** | **bool** | AutomountServiceAccountToken indicates whether a service account token should be automatically mounted in pods. ServiceAccountName of ExecutorConfig must be specified if this value is false. | [optional] **dns_config** | [**PodDNSConfig**](PodDNSConfig.md) | | [optional] -**dns_policy** | **str** | Set DNS policy for the pod. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'. | [optional] +**dns_policy** | **str** | Set DNS policy for workflow pods. Defaults to \"ClusterFirst\". Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst', 'Default' or 'None'. DNS parameters given in DNSConfig will be merged with the policy selected with DNSPolicy. To have DNS options set along with hostNetwork, you have to specify DNS policy explicitly to 'ClusterFirstWithHostNet'. | [optional] **entrypoint** | **str** | Entrypoint is a template reference to the starting point of the io.argoproj.workflow.v1alpha1. | [optional] **executor** | [**IoArgoprojWorkflowV1alpha1ExecutorConfig**](IoArgoprojWorkflowV1alpha1ExecutorConfig.md) | | [optional] **hooks** | [**{str: (IoArgoprojWorkflowV1alpha1LifecycleHook,)}**](IoArgoprojWorkflowV1alpha1LifecycleHook.md) | Hooks holds the lifecycle hook which is invoked at lifecycle of step, irrespective of the success, failure, or error status of the primary step | [optional] diff --git a/test/e2e/argo_server_test.go b/test/e2e/argo_server_test.go index 015a93e7e025..d9112d8b038c 100644 --- a/test/e2e/argo_server_test.go +++ b/test/e2e/argo_server_test.go @@ -1540,6 +1540,38 @@ spec: } +// A test can simply reproduce the problem mentioned in the link https://github.com/argoproj/argo-workflows/pull/12574 +// First, add the code to func "taskResultReconciliation".You can adjust this time to be larger for better reproduction. +// +// if !woc.checkTaskResultsInProgress() { +// time.Sleep(time.Second * 2) +// } +// +// Second, run the test. +// Finally, you will get a workflow in Running status but its labelCompleted is true. +func (s *ArgoServerSuite) TestRetryStoppedButIncompleteWorkflow() { + var workflowName string + s.Given(). + Workflow(`@testdata/retry-on-stopped.yaml`). + When(). + SubmitWorkflow(). + WaitForWorkflow(fixtures.ToBeFailed). + Then(). + ExpectWorkflow(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + workflowName = metadata.Name + }) + + time.Sleep(1 * time.Second) + s.Run("Retry", func() { + s.e().PUT("/api/v1/workflows/argo/{workflowName}/retry", workflowName). + Expect(). + Status(200). + JSON(). + Path("$.metadata.name"). + NotNull() + }) +} + func (s *ArgoServerSuite) TestWorkflowTemplateService() { s.Run("Lint", func() { s.e().POST("/api/v1/workflow-templates/argo/lint"). diff --git a/test/e2e/cli_test.go b/test/e2e/cli_test.go index 9377a8d1da38..051e609b3ef4 100644 --- a/test/e2e/cli_test.go +++ b/test/e2e/cli_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/yaml" @@ -913,6 +914,41 @@ func (s *CLISuite) TestWorkflowRetryWithRecreatedPVC() { }) } +func (s *CLISuite) TestRetryWorkflowWithContinueOn() { + var workflowName string + s.Given(). + Workflow(`@testdata/retry-workflow-with-continueon.yaml`). + When(). + SubmitWorkflow(). + WaitForWorkflow(fixtures.ToBeFailed). + Then(). + ExpectWorkflow(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + workflowName = metadata.Name + assert.Equal(t, 6, len(status.Nodes)) + }). + RunCli([]string{"retry", workflowName}, func(t *testing.T, output string, err error) { + if assert.NoError(t, err, output) { + assert.Contains(t, output, "Name:") + assert.Contains(t, output, "Namespace:") + } + }) + + s.Given(). + When(). + WaitForWorkflow(fixtures.ToBeCompleted). + Then(). + ExpectWorkflow(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + workflowName = metadata.Name + assert.Equal(t, wfv1.WorkflowFailed, status.Phase) + assert.Equal(t, 6, len(status.Nodes)) + }). + ExpectWorkflowNode(func(status wfv1.NodeStatus) bool { + return strings.Contains(status.Name, "retry-workflow-with-continueon.success") + }, func(t *testing.T, status *wfv1.NodeStatus, pod *corev1.Pod) { + assert.Equal(t, 2, len(status.Children)) + }) +} + func (s *CLISuite) TestWorkflowStop() { s.Given(). Workflow("@smoke/basic.yaml"). diff --git a/test/e2e/fixtures/when.go b/test/e2e/fixtures/when.go index eb3d5dc7c48b..46cd1241bebe 100644 --- a/test/e2e/fixtures/when.go +++ b/test/e2e/fixtures/when.go @@ -347,6 +347,7 @@ func (w *When) WaitForWorkflowList(listOptions metav1.ListOptions, condition fun return w } } + time.Sleep(time.Second) } } diff --git a/test/e2e/hooks_test.go b/test/e2e/hooks_test.go index 3eafa1f59206..5090fc980fd9 100644 --- a/test/e2e/hooks_test.go +++ b/test/e2e/hooks_test.go @@ -488,7 +488,7 @@ spec: container: image: argoproj/argosay:v2 command: ["/bin/sh", "-c"] - args: ["/bin/sleep 1; /argosay"] + args: ["/bin/sleep 5; /argosay"] - name: argosay-sleep-2seconds container: image: argoproj/argosay:v2 @@ -647,6 +647,133 @@ spec: }) } +func (s *HooksSuite) TestTemplateLevelHooksWithRetry() { + var children []string + (s.Given(). + Workflow(` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + name: retries-with-hooks-and-artifact + labels: + workflows.argoproj.io/test: "true" + annotations: + workflows.argoproj.io/description: | + when retries and hooks are both included, the workflow cannot resolve the artifact + workflows.argoproj.io/version: '>= 3.5.0' +spec: + entrypoint: main + templates: + - name: main + steps: + - - name: build + template: output-artifact + hooks: + started: + expression: steps["build"].status == "Running" + template: started + success: + expression: steps["build"].status == "Succeeded" + template: success + failed: + expression: steps["build"].status == "Failed" || steps["build"].status == "Error" + template: failed + - - name: print + template: print-artifact + arguments: + artifacts: + - name: message + from: "{{steps.build.outputs.artifacts.result}}" + + - name: output-artifact + script: + image: python:alpine3.6 + command: [ python ] + source: | + import time + import random + import sys + time.sleep(1) # lifecycle hook for running won't trigger unless it runs for more than "a few seconds" + with open("result.txt", "w") as f: + f.write("Welcome") + if {{retries}} == 2: + sys.exit(0) + sys.exit(1) + retryStrategy: + limit: 2 + outputs: + artifacts: + - name: result + path: /result.txt + + - name: started + container: + image: python:alpine3.6 + command: [sh, -c] + args: ["echo STARTED!"] + + - name: success + container: + image: python:alpine3.6 + command: [sh, -c] + args: ["echo SUCCEEDED!"] + + - name: failed + container: + image: python:alpine3.6 + command: [sh, -c] + args: ["echo FAILED or ERROR!"] + + - name: print-artifact + inputs: + artifacts: + - name: message + path: /tmp/message + container: + image: python:alpine3.6 + command: [sh, -c] + args: ["cat /tmp/message"] +`).When(). + SubmitWorkflow(). + WaitForWorkflow(fixtures.ToBeCompleted). + Then(). + ExpectWorkflow(func(t *testing.T, metadata *v1.ObjectMeta, status *v1alpha1.WorkflowStatus) { + assert.True(t, status.Fulfilled()) + assert.Equal(t, v1alpha1.WorkflowSucceeded, status.Phase) + for _, node := range status.Nodes { + if node.Type == v1alpha1.NodeTypeRetry { + assert.Equal(t, v1alpha1.NodeSucceeded, node.Phase) + children = node.Children + } + } + }). + ExpectWorkflowNode(func(status v1alpha1.NodeStatus) bool { + return status.Name == "retries-with-hooks-and-artifact[0].build(0)" + }, func(t *testing.T, status *v1alpha1.NodeStatus, pod *apiv1.Pod) { + assert.Contains(t, children, status.ID) + assert.Equal(t, false, status.NodeFlag.Hooked) + }). + ExpectWorkflowNode(func(status v1alpha1.NodeStatus) bool { + return status.Name == "retries-with-hooks-and-artifact[0].build.hooks.started" + }, func(t *testing.T, status *v1alpha1.NodeStatus, pod *apiv1.Pod) { + assert.Contains(t, children, status.ID) + assert.Equal(t, true, status.NodeFlag.Hooked) + assert.Equal(t, v1alpha1.NodeSucceeded, status.Phase) + })). + ExpectWorkflowNode(func(status v1alpha1.NodeStatus) bool { + return status.Name == "retries-with-hooks-and-artifact[0].build.hooks.success" + }, func(t *testing.T, status *v1alpha1.NodeStatus, pod *apiv1.Pod) { + assert.Contains(t, children, status.ID) + assert.Equal(t, true, status.NodeFlag.Hooked) + assert.Equal(t, v1alpha1.NodeSucceeded, status.Phase) + }). + ExpectWorkflowNode(func(status v1alpha1.NodeStatus) bool { + return status.Name == "retries-with-hooks-and-artifact[1].print" + }, func(t *testing.T, status *v1alpha1.NodeStatus, pod *apiv1.Pod) { + assert.Equal(t, v1alpha1.NodeSucceeded, status.Phase) + }) +} + func TestHooksSuite(t *testing.T) { suite.Run(t, new(HooksSuite)) } diff --git a/test/e2e/testdata/retry-on-stopped.yaml b/test/e2e/testdata/retry-on-stopped.yaml new file mode 100644 index 000000000000..88960dedb828 --- /dev/null +++ b/test/e2e/testdata/retry-on-stopped.yaml @@ -0,0 +1,65 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: wf-retry-stopped- +spec: + workflowMetadata: + labels: + workflows.argoproj.io/test: "true" + workflows.argoproj.io/workflow: "wf-retry-stopped" + entrypoint: wf-retry-stopped-main + serviceAccountName: argo + executor: + serviceAccountName: default + templates: + - name: wf-retry-stopped-main + steps: + - - name: create + template: create + - name: sleep + template: sleep + - name: stop + template: stop + + - name: sleep + container: + image: alpine:latest + command: [ sleep, "10" ] + + - name: stop + container: + image: quay.io/argoproj/argocli:latest + args: + - stop + - -l + - workflows.argoproj.io/workflow=wf-retry-stopped + - --namespace=argo + - --loglevel=debug + + - name: create + container: + image: argoproj/argosay:v2 + command: + - sh + - -c + args: + - | + echo "hello world" > /tmp/message + sleep 999 + outputs: + artifacts: + - name: my-artifact + path: /tmp/message + s3: + key: my-artifact + bucket: my-bucket + endpoint: minio:9000 + insecure: true + accessKeySecret: + name: my-minio-cred + key: accesskey + secretKeySecret: + name: my-minio-cred + key: secretkey + archive: + none: {} diff --git a/test/e2e/testdata/retry-workflow-with-continueon.yaml b/test/e2e/testdata/retry-workflow-with-continueon.yaml new file mode 100644 index 000000000000..9d2ce1414860 --- /dev/null +++ b/test/e2e/testdata/retry-workflow-with-continueon.yaml @@ -0,0 +1,55 @@ +apiVersion: argoproj.io/v1alpha1 +kind: WorkflowTemplate +metadata: + name: retry-workflow-with-continueon +spec: + entrypoint: dag + templates: + - name: dag + dag: + failFast: false + tasks: + - name: success + template: node-to-exit + arguments: + parameters: + - name: exitCode + value: 0 + - name: failure + template: node-to-exit + dependencies: [success] + arguments: + parameters: + - name: exitCode + value: 1 + - name: task-after-failure + template: node-to-exit + dependencies: [failure] + arguments: + parameters: + - name: exitCode + value: 0 + - name: continue + template: node-to-exit + continueOn: + failed: true + dependencies: [success] + arguments: + parameters: + - name: exitCode + value: 2 + - name: task-after-continue + template: node-to-exit + dependencies: [continue] + arguments: + parameters: + - name: exitCode + value: 0 + + - name: node-to-exit + inputs: + parameters: + - name: exitCode + container: + image: alpine:3.7 + command: [ sh, "-c", "exit {{inputs.parameters.exitCode}}" ] \ No newline at end of file diff --git a/test/e2e/workflow_test.go b/test/e2e/workflow_test.go index 623b44f750a6..e10ca1558b81 100644 --- a/test/e2e/workflow_test.go +++ b/test/e2e/workflow_test.go @@ -4,15 +4,19 @@ package e2e import ( + "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" + apiv1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" wfv1 "github.com/argoproj/argo-workflows/v3/pkg/apis/workflow/v1alpha1" "github.com/argoproj/argo-workflows/v3/test/e2e/fixtures" + "github.com/argoproj/argo-workflows/v3/workflow/common" ) type WorkflowSuite struct { @@ -85,6 +89,105 @@ spec: }) } +func (s *WorkflowSuite) TestWorkflowFailedWhenAllPodSetFailedFromPending() { + (s.Given().Workflow(` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: active-deadline-fanout-template-level- + namespace: argo +spec: + entrypoint: entrypoint + templates: + - name: entrypoint + steps: + - - name: fanout + template: echo + arguments: + parameters: + - name: item + value: "{{item}}" + withItems: + - 1 + - 2 + - 3 + - 4 + - name: echo + inputs: + parameters: + - name: item + container: + image: centos:latest + imagePullPolicy: Always + command: + - sh + - '-c' + args: + - echo + - 'workflow number {{inputs.parameters.item}}' + - sleep + - '20' + activeDeadlineSeconds: 2 # defined on template level, not workflow level ! +`). + When(). + SubmitWorkflow(). + WaitForWorkflow(fixtures.ToBeFailed, time.Minute*11). + Then(). + ExpectWorkflow(func(t *testing.T, metadata *metav1.ObjectMeta, status *wfv1.WorkflowStatus) { + assert.Equal(t, wfv1.WorkflowFailed, status.Phase) + for _, node := range status.Nodes { + if node.Type == wfv1.NodeTypePod { + assert.Equal(t, wfv1.NodeFailed, node.Phase) + assert.Contains(t, node.Message, "Pod was active on the node longer than the specified deadline") + } + } + }). + ExpectWorkflowNode(func(status v1alpha1.NodeStatus) bool { + return strings.Contains(status.Name, "fanout(0:1)") + }, func(t *testing.T, status *v1alpha1.NodeStatus, pod *apiv1.Pod) { + for _, c := range pod.Status.ContainerStatuses { + if c.Name == common.WaitContainerName && c.State.Terminated == nil { + assert.NotNil(t, c.State.Waiting) + assert.Contains(t, c.State.Waiting.Reason, "PodInitializing") + assert.Nil(t, c.State.Running) + } + } + }). + ExpectWorkflowNode(func(status v1alpha1.NodeStatus) bool { + return strings.Contains(status.Name, "fanout(1:2)") + }, func(t *testing.T, status *v1alpha1.NodeStatus, pod *apiv1.Pod) { + for _, c := range pod.Status.ContainerStatuses { + if c.Name == common.WaitContainerName && c.State.Terminated == nil { + assert.NotNil(t, c.State.Waiting) + assert.Contains(t, c.State.Waiting.Reason, "PodInitializing") + assert.Nil(t, c.State.Running) + } + } + })). + ExpectWorkflowNode(func(status v1alpha1.NodeStatus) bool { + return strings.Contains(status.Name, "fanout(2:3)") + }, func(t *testing.T, status *v1alpha1.NodeStatus, pod *apiv1.Pod) { + for _, c := range pod.Status.ContainerStatuses { + if c.Name == common.WaitContainerName && c.State.Terminated == nil { + assert.NotNil(t, c.State.Waiting) + assert.Contains(t, c.State.Waiting.Reason, "PodInitializing") + assert.Nil(t, c.State.Running) + } + } + }). + ExpectWorkflowNode(func(status v1alpha1.NodeStatus) bool { + return strings.Contains(status.Name, "fanout(3:4)") + }, func(t *testing.T, status *v1alpha1.NodeStatus, pod *apiv1.Pod) { + for _, c := range pod.Status.ContainerStatuses { + if c.Name == common.WaitContainerName && c.State.Terminated == nil { + assert.NotNil(t, c.State.Waiting) + assert.Contains(t, c.State.Waiting.Reason, "PodInitializing") + assert.Nil(t, c.State.Running) + } + } + }) +} + func TestWorkflowSuite(t *testing.T) { suite.Run(t, new(WorkflowSuite)) } diff --git a/ui/src/app/shared/services/event-source-service.ts b/ui/src/app/shared/services/event-source-service.ts index 559586237011..1c81b26fad2c 100644 --- a/ui/src/app/shared/services/event-source-service.ts +++ b/ui/src/app/shared/services/event-source-service.ts @@ -33,8 +33,8 @@ export const EventSourceService = { return requests.loadEventSource(`api/v1/stream/event-sources/${namespace}`).pipe(map(line => line && (JSON.parse(line).result as EventSourceWatchEvent))); }, - eventSourcesLogs(namespace: string, name = '', eventSourceType = '', eventName = '', grep = '', tailLines = -1) { - const params = ['podLogOptions.follow=true']; + eventSourcesLogs(namespace: string, name = '', eventSourceType = '', eventName = '', grep = '', tailLines = -1, container = 'main') { + const params = ['podLogOptions.follow=true', `podLogOptions.container=${container}`]; if (name) { params.push('name=' + name); } diff --git a/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx b/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx index 06b0fd4bbed6..47446937b004 100644 --- a/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx +++ b/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx @@ -297,7 +297,8 @@ export function WorkflowLogsViewer({workflow, nodeId, initialPodName, container, )} {execSpec(workflow).podGC && ( <> - Your pod GC settings will delete pods and their logs immediately on completion. + Your pod GC settings will delete pods and their logs{' '} + {execSpec(workflow).podGC.deleteDelayDuration ? `after ${execSpec(workflow).podGC.deleteDelayDuration}` : 'immediately'} on completion. )}{' '} Logs may not appear for pods that are deleted.{' '} diff --git a/ui/src/models/workflows.ts b/ui/src/models/workflows.ts index b46440f631fb..8acf9178bb99 100644 --- a/ui/src/models/workflows.ts +++ b/ui/src/models/workflows.ts @@ -825,6 +825,7 @@ export interface WorkflowSpec { */ podGC?: { strategy?: string; + deleteDelayDuration?: string; }; /** * SecurityContext holds pod-level security attributes and common container settings. diff --git a/ui/yarn.lock b/ui/yarn.lock index 808dac761123..be5c81b309ac 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -4122,9 +4122,9 @@ find-yarn-workspace-root@^2.0.0: micromatch "^4.0.2" follow-redirects@^1.0.0, follow-redirects@^1.15.4: - version "1.15.4" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf" - integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw== + version "1.15.6" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== for-in@^1.0.2: version "1.0.2" @@ -8457,9 +8457,9 @@ typescript@^4.6.4, typescript@^4.9.5: integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== undici@^5.24.0: - version "5.26.4" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.26.4.tgz#dc861c35fb53ae025a173a790d984aa9b2e279a1" - integrity sha512-OG+QOf0fTLtazL9P9X7yqWxQ+Z0395Wk6DSkyTxtaq3wQEjIroVe7Y4asCX/vcCxYpNGMnwz8F0qbRYUoaQVMw== + version "5.28.4" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.4.tgz#6b280408edb6a1a604a9b20340f45b422e373068" + integrity sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g== dependencies: "@fastify/busboy" "^2.0.0" diff --git a/workflow/artifacts/oss/oss.go b/workflow/artifacts/oss/oss.go index a49b705f438a..d414a4c02a73 100644 --- a/workflow/artifacts/oss/oss.go +++ b/workflow/artifacts/oss/oss.go @@ -3,6 +3,7 @@ package oss import ( "fmt" "io" + "math" "os" "path/filepath" "strings" @@ -41,6 +42,7 @@ var ( // OSS error code reference: https://error-center.alibabacloud.com/status/product/Oss ossTransientErrorCodes = []string{"RequestTimeout", "QuotaExceeded.Refresh", "Default", "ServiceUnavailable", "Throttling", "RequestTimeTooSkewed", "SocketException", "SocketTimeout", "ServiceBusy", "DomainNetWorkVisitedException", "ConnectionTimeout", "CachedTimeTooLarge"} bucketLogFilePrefix = "bucket-log-" + maxObjectSize = int64(5 * 1024 * 1024 * 1024) ) type ossCredentials struct { @@ -337,9 +339,66 @@ func isTransientOSSErr(err error) bool { return false } +// OSS simple upload code reference: https://www.alibabacloud.com/help/en/oss/user-guide/simple-upload?spm=a2c63.p38356.0.0.2c072398fh5k3W#section-ym8-svm-rmu +func simpleUpload(bucket *oss.Bucket, objectName, path string) error { + log.Info("OSS Simple Uploading") + return bucket.PutObjectFromFile(objectName, path) +} + +// OSS multipart upload code reference: https://www.alibabacloud.com/help/en/oss/user-guide/multipart-upload?spm=a2c63.p38356.0.0.4ebe423fzsaPiN#section-trz-mpy-tes +func multipartUpload(bucket *oss.Bucket, objectName, path string, objectSize int64) error { + log.Info("OSS Multipart Uploading") + // Calculate the number of chunks + chunkNum := int(math.Ceil(float64(objectSize)/float64(maxObjectSize))) + 1 + chunks, err := oss.SplitFileByPartNum(path, chunkNum) + if err != nil { + return err + } + fd, err := os.Open(filepath.Clean(path)) + if err != nil { + return err + } + defer fd.Close() + // Initialize a multipart upload event. + imur, err := bucket.InitiateMultipartUpload(objectName) + if err != nil { + return err + } + // Upload the chunks. + var parts []oss.UploadPart + for _, chunk := range chunks { + _, err := fd.Seek(chunk.Offset, io.SeekStart) + if err != nil { + return err + } + // Call the UploadPart method to upload each chunck. + part, err := bucket.UploadPart(imur, fd, chunk.Size, chunk.Number) + if err != nil { + log.Warnf("Upload part error: %v", err) + return err + } + log.Infof("Upload part number: %v, ETag: %v", part.PartNumber, part.ETag) + parts = append(parts, part) + } + _, err = bucket.CompleteMultipartUpload(imur, parts) + if err != nil { + log.Warnf("Complete multipart upload error: %v", err) + return err + } + return nil +} + func putFile(bucket *oss.Bucket, objectName, path string) error { log.Debugf("putFile from %s to %s", path, objectName) - return bucket.PutObjectFromFile(objectName, path) + fStat, err := os.Stat(path) + if err != nil { + return err + } + // Determine upload method based on file size. + if fStat.Size() <= maxObjectSize { + return simpleUpload(bucket, objectName, path) + } + return multipartUpload(bucket, objectName, path, fStat.Size()) } func putDirectory(bucket *oss.Bucket, objectName, dir string) error { diff --git a/workflow/controller/agent.go b/workflow/controller/agent.go index 35552f151c38..f9d0f0122c7a 100644 --- a/workflow/controller/agent.go +++ b/workflow/controller/agent.go @@ -198,11 +198,11 @@ func (woc *wfOperationCtx) createAgentPod(ctx context.Context) (*apiv1.Pod, erro // the `init` container populates the shared empty-dir volume with tokens agentInitCtr := agentCtrTemplate.DeepCopy() agentInitCtr.Name = common.InitContainerName - agentInitCtr.Args = []string{"agent", "init"} + agentInitCtr.Args = []string{"agent", "init", "--loglevel", getExecutorLogLevel()} // the `main` container runs the actual work agentMainCtr := agentCtrTemplate.DeepCopy() agentMainCtr.Name = common.MainContainerName - agentMainCtr.Args = []string{"agent", "main"} + agentMainCtr.Args = []string{"agent", "main", "--loglevel", getExecutorLogLevel()} pod := &apiv1.Pod{ ObjectMeta: metav1.ObjectMeta{ @@ -243,6 +243,7 @@ func (woc *wfOperationCtx) createAgentPod(ctx context.Context) (*apiv1.Pod, erro tmpl := &wfv1.Template{} addSchedulingConstraints(pod, woc.execWf.Spec.DeepCopy(), tmpl) woc.addMetadata(pod, tmpl) + woc.addDNSConfig(pod) if woc.execWf.Spec.HasPodSpecPatch() { patchedPodSpec, err := util.ApplyPodSpecPatch(pod.Spec, woc.execWf.Spec.PodSpecPatch) diff --git a/workflow/controller/artifact_gc.go b/workflow/controller/artifact_gc.go index ca2f48c3a03b..a6fcbca52e79 100644 --- a/workflow/controller/artifact_gc.go +++ b/workflow/controller/artifact_gc.go @@ -613,7 +613,7 @@ func (woc *wfOperationCtx) processCompletedArtifactGCPod(ctx context.Context, po strategy := wfv1.ArtifactGCStrategy(strategyStr) if pod.Status.Phase == corev1.PodFailed { - errMsg := fmt.Sprintf("Artifact Garbage Collection failed for strategy %s, pod %s exited with non-zero exit code: check pod logs for more information", pod.Name, strategy) + errMsg := fmt.Sprintf("Artifact Garbage Collection failed for strategy %s, pod %s exited with non-zero exit code: check pod logs for more information", strategy, pod.Name) woc.addArtGCCondition(errMsg) woc.addArtGCEvent(errMsg) } diff --git a/workflow/controller/controller.go b/workflow/controller/controller.go index 92928277a84f..60aa9f4b1748 100644 --- a/workflow/controller/controller.go +++ b/workflow/controller/controller.go @@ -783,7 +783,7 @@ func (wfc *WorkflowController) processNextItem(ctx context.Context) bool { woc := newWorkflowOperationCtx(wf, wfc) - if !wfc.throttler.Admit(key.(string)) { + if !(woc.GetShutdownStrategy().Enabled() && woc.GetShutdownStrategy() == wfv1.ShutdownStrategyTerminate) && !wfc.throttler.Admit(key.(string)) { log.WithField("key", key).Info("Workflow processing has been postponed due to max parallelism limit") if woc.wf.Status.Phase == wfv1.WorkflowUnknown { woc.markWorkflowPhase(ctx, wfv1.WorkflowPending, "Workflow processing has been postponed because too many workflows are already running") diff --git a/workflow/controller/controller_test.go b/workflow/controller/controller_test.go index 6bee65ee23fc..96bb7d703496 100644 --- a/workflow/controller/controller_test.go +++ b/workflow/controller/controller_test.go @@ -664,6 +664,17 @@ spec: - name: main container: image: my-image +`), + wfv1.MustUnmarshalWorkflow(` +metadata: + name: my-wf-2 +spec: + shutdown: Terminate + entrypoint: main + templates: + - name: main + container: + image: my-image `), f, ) @@ -671,6 +682,7 @@ spec: ctx := context.Background() assert.True(t, controller.processNextItem(ctx)) assert.True(t, controller.processNextItem(ctx)) + assert.True(t, controller.processNextItem(ctx)) expectWorkflow(ctx, controller, "my-wf-0", func(wf *wfv1.Workflow) { if assert.NotNil(t, wf) { @@ -683,6 +695,11 @@ spec: assert.Equal(t, "Workflow processing has been postponed because too many workflows are already running", wf.Status.Message) } }) + expectWorkflow(ctx, controller, "my-wf-2", func(wf *wfv1.Workflow) { + if assert.NotNil(t, wf) { + assert.Equal(t, wfv1.WorkflowSucceeded, wf.Status.Phase) + } + }) }) } } @@ -1137,6 +1154,25 @@ spec: assert.Len(t, pods.Items, 0) } +func TestPendingPodWhenTerminate(t *testing.T) { + wf := wfv1.MustUnmarshalWorkflow(helloWorldWf) + wf.Spec.Shutdown = wfv1.ShutdownStrategyTerminate + wf.Status.Phase = wfv1.WorkflowPending + + cancel, controller := newController(wf) + defer cancel() + + ctx := context.Background() + assert.True(t, controller.processNextItem(ctx)) + + woc := newWorkflowOperationCtx(wf, controller) + woc.operate(ctx) + assert.Equal(t, wfv1.WorkflowSucceeded, woc.wf.Status.Phase) + for _, node := range woc.wf.Status.Nodes { + assert.Equal(t, wfv1.NodeSkipped, node.Phase) + } +} + func TestWorkflowReferItselfFromExpression(t *testing.T) { wf := wfv1.MustUnmarshalWorkflow(fromExrpessingWf) cancel, controller := newController(wf) diff --git a/workflow/controller/inline_test.go b/workflow/controller/inline_test.go index 982bd5577181..7df05d334ca5 100644 --- a/workflow/controller/inline_test.go +++ b/workflow/controller/inline_test.go @@ -2,6 +2,7 @@ package controller import ( "context" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -74,3 +75,220 @@ spec: assert.Equal(t, "message", node.Inputs.Parameters[0].Name) assert.Equal(t, "foo", node.Inputs.Parameters[0].Value.String()) } + +var workflowCallTemplateWithInline = ` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + name: test-call-inline-iterated + namespace: argo +spec: + entrypoint: main + templates: + - name: main + dag: + tasks: + - name: process + templateRef: + name: test-inline-iterated + template: main` + +var workflowTemplateWithInlineSteps = ` +apiVersion: argoproj.io/v1alpha1 +kind: WorkflowTemplate +metadata: + name: test-inline-iterated + namespace: argo +spec: + entrypoint: main + templates: + - name: main + steps: + - - name: iterated + template: steps-inline + arguments: + parameters: + - name: arg + value: "{{ item }}" + withItems: + - foo + - bar + + - name: steps-inline + inputs: + parameters: + - name: arg + steps: + - - name: inline-a + arguments: + parameters: + - name: arg + value: "{{ inputs.parameters.arg }}" + inline: + inputs: + parameters: + - name: arg + container: + image: docker/whalesay + command: [echo] + args: + - "{{ inputs.parameters.arg }} a" + outputs: + parameters: + - name: arg-out + value: "{{ inputs.parameters.arg }}" + - name: inline-b + arguments: + parameters: + - name: arg + value: "{{ inputs.parameters.arg }}" + inline: + inputs: + parameters: + - name: arg + container: + image: docker/whalesay + command: [echo] + args: + - "{{ inputs.parameters.arg }} b" + outputs: + parameters: + - name: arg-out + value: "{{ inputs.parameters.arg }}" +` + +func TestCallTemplateWithInlineSteps(t *testing.T) { + wftmpl := wfv1.MustUnmarshalWorkflowTemplate(workflowTemplateWithInlineSteps) + wf := wfv1.MustUnmarshalWorkflow(workflowCallTemplateWithInline) + cancel, controller := newController(wf, wftmpl) + defer cancel() + + ctx := context.Background() + woc := newWorkflowOperationCtx(wf, controller) + woc.operate(ctx) + pods, err := listPods(woc) + assert.Nil(t, err) + assert.Equal(t, 4, len(pods.Items)) + count := 0 + for _, pod := range pods.Items { + nodeName := pod.Annotations["workflows.argoproj.io/node-name"] + if strings.Contains(nodeName, "foo") { + count++ + assert.Contains(t, pod.Spec.Containers[1].Args[0], "foo") + } + if strings.Contains(nodeName, "bar") { + assert.Contains(t, pod.Spec.Containers[1].Args[0], "bar") + } + } + assert.Equal(t, 2, count) + for name, storedTemplate := range woc.wf.Status.StoredTemplates { + if strings.Contains(name, "inline-a") { + assert.Equal(t, storedTemplate.Container.Args[0], "{{ inputs.parameters.arg }} a") + } + if strings.Contains(name, "inline-b") { + assert.Equal(t, storedTemplate.Container.Args[0], "{{ inputs.parameters.arg }} b") + } + } +} + +var workflowTemplateWithInlineDAG = ` +apiVersion: argoproj.io/v1alpha1 +kind: WorkflowTemplate +metadata: + name: test-inline-iterated + namespace: argo +spec: + entrypoint: main + templates: + - name: main + steps: + - - name: iterated + template: dag-inline + arguments: + parameters: + - name: arg + value: "{{ item }}" + withItems: + - foo + - bar + + - name: dag-inline + inputs: + parameters: + - name: arg + dag: + tasks: + - name: inline-a + arguments: + parameters: + - name: arg + value: '{{ inputs.parameters.arg }}' + inline: + container: + args: + - '{{ inputs.parameters.arg }} a' + command: + - echo + image: docker/whalesay + inputs: + parameters: + - name: arg + outputs: + parameters: + - name: arg-out + value: '{{ inputs.parameters.arg }}' + + - name: inline-b + arguments: + parameters: + - name: arg + value: '{{ inputs.parameters.arg }}' + inline: + container: + args: + - '{{ inputs.parameters.arg }} b' + command: + - echo + image: docker/whalesay + inputs: + parameters: + - name: arg + outputs: + parameters: + - name: arg-out + value: '{{ inputs.parameters.arg }}' +` + +func TestCallTemplateWithInlineDAG(t *testing.T) { + wftmpl := wfv1.MustUnmarshalWorkflowTemplate(workflowTemplateWithInlineDAG) + wf := wfv1.MustUnmarshalWorkflow(workflowCallTemplateWithInline) + cancel, controller := newController(wf, wftmpl) + defer cancel() + + ctx := context.Background() + woc := newWorkflowOperationCtx(wf, controller) + woc.operate(ctx) + pods, err := listPods(woc) + assert.Nil(t, err) + assert.Equal(t, 4, len(pods.Items)) + count := 0 + for _, pod := range pods.Items { + nodeName := pod.Annotations["workflows.argoproj.io/node-name"] + if strings.Contains(nodeName, "foo") { + count++ + assert.Contains(t, pod.Spec.Containers[1].Args[0], "foo") + } + if strings.Contains(nodeName, "bar") { + assert.Contains(t, pod.Spec.Containers[1].Args[0], "bar") + } + } + assert.Equal(t, 2, count) + for name, storedTemplate := range woc.wf.Status.StoredTemplates { + if strings.Contains(name, "inline-a") { + assert.Equal(t, storedTemplate.Container.Args[0], "{{ inputs.parameters.arg }} a") + } + if strings.Contains(name, "inline-b") { + assert.Equal(t, storedTemplate.Container.Args[0], "{{ inputs.parameters.arg }} b") + } + } +} diff --git a/workflow/controller/operator.go b/workflow/controller/operator.go index 8b0a6e16b810..4042f98e608f 100644 --- a/workflow/controller/operator.go +++ b/workflow/controller/operator.go @@ -190,9 +190,6 @@ func (woc *wfOperationCtx) operate(ctx context.Context) { defer argoruntime.RecoverFromPanic(woc.log) defer func() { - if woc.wf.Status.Fulfilled() { - woc.killDaemonedChildren("") - } woc.persistUpdates(ctx) }() defer func() { @@ -240,7 +237,7 @@ func (woc *wfOperationCtx) operate(ctx context.Context) { woc.taskResultReconciliation() // Do artifact GC if task result reconciliation is complete. - if woc.checkReconciliationComplete() { + if woc.wf.Status.Fulfilled() { if err := woc.garbageCollectArtifacts(ctx); err != nil { woc.log.WithError(err).Error("failed to GC artifacts") return @@ -511,6 +508,10 @@ func (woc *wfOperationCtx) operate(ctx context.Context) { woc.markWorkflowError(ctx, err) } + if !woc.wf.Status.Fulfilled() { + return + } + if woc.execWf.Spec.Metrics != nil { woc.globalParams[common.GlobalVarWorkflowStatus] = string(workflowStatus) localScope, realTimeScope := woc.prepareMetricScope(node) @@ -744,6 +745,12 @@ func (woc *wfOperationCtx) persistUpdates(ctx context.Context) { } } + // Remove completed taskset status before update workflow. + err = woc.removeCompletedTaskSetStatus(ctx) + if err != nil { + woc.log.WithError(err).Warn("error updating taskset") + } + wf, err := wfClient.Update(ctx, woc.wf, metav1.UpdateOptions{}) if err != nil { woc.log.Warnf("Error updating workflow: %v %s", err, apierr.ReasonForError(err)) @@ -791,18 +798,16 @@ func (woc *wfOperationCtx) persistUpdates(ctx context.Context) { time.Sleep(1 * time.Second) } - err = woc.removeCompletedTaskSetStatus(ctx) - - if err != nil { - woc.log.WithError(err).Warn("error updating taskset") - } - - // Make sure the TaskResults are incorporated into WorkflowStatus before we delete them. - if woc.checkReconciliationComplete() { + // Make sure the workflow completed. + if woc.wf.Status.Fulfilled() { if err := woc.deleteTaskResults(ctx); err != nil { woc.log.WithError(err).Warn("failed to delete task-results") } } + // If Finalizer exists, requeue to make sure Finalizer can be removed. + if woc.wf.Status.Fulfilled() && len(wf.GetFinalizers()) > 0 { + woc.requeueAfter(5 * time.Second) + } // It is important that we *never* label pods as completed until we successfully updated the workflow // Failing to do so means we can have inconsistent state. @@ -810,9 +815,9 @@ func (woc *wfOperationCtx) persistUpdates(ctx context.Context) { woc.queuePodsForCleanup() } -func (woc *wfOperationCtx) checkReconciliationComplete() bool { +func (woc *wfOperationCtx) checkTaskResultsInProgress() bool { woc.log.Debugf("Task results completion status: %v", woc.wf.Status.TaskResultsCompletionStatus) - return woc.wf.Status.Phase.Completed() && !woc.wf.Status.TaskResultsInProgress() + return woc.wf.Status.TaskResultsInProgress() } func (woc *wfOperationCtx) deleteTaskResults(ctx context.Context) error { @@ -1218,7 +1223,18 @@ func (woc *wfOperationCtx) podReconciliation(ctx context.Context) (error, bool) node.Daemoned = nil woc.updated = true } - woc.markNodePhase(node.Name, wfv1.NodeError, "pod deleted") + woc.markNodeError(node.Name, errors.New("", "pod deleted")) + // Set pod's child(container) error if pod deleted + for _, childNodeID := range node.Children { + childNode, err := woc.wf.Status.Nodes.Get(childNodeID) + if err != nil { + woc.log.Errorf("was unable to obtain node for %s", childNodeID) + continue + } + if childNode.Type == wfv1.NodeTypeContainer { + woc.markNodeError(childNode.Name, errors.New("", "container deleted")) + } + } } } return nil, !taskResultIncomplete @@ -1387,7 +1403,7 @@ func (woc *wfOperationCtx) assessNodeStatus(pod *apiv1.Pod, old *wfv1.NodeStatus if x, ok := pod.Annotations[common.AnnotationKeyReportOutputsCompleted]; ok { woc.log.Warn("workflow uses legacy/insecure pod patch, see https://argo-workflows.readthedocs.io/en/release-3.5/workflow-rbac/") - resultName := pod.GetName() + resultName := woc.nodeID(pod) if x == "true" { woc.wf.Status.MarkTaskResultComplete(resultName) } else { @@ -1429,21 +1445,18 @@ func (woc *wfOperationCtx) assessNodeStatus(pod *apiv1.Pod, old *wfv1.NodeStatus new.Outputs.ExitCode = pointer.StringPtr(fmt.Sprint(*exitCode)) } - // If the init container failed, we should mark the node as failed. - var initContainerFailed bool for _, c := range pod.Status.InitContainerStatuses { if c.State.Terminated != nil && int(c.State.Terminated.ExitCode) != 0 { new.Phase = wfv1.NodeFailed - initContainerFailed = true woc.log.WithField("new.phase", new.Phase).Info("marking node as failed since init container has non-zero exit code") break } } - // We cannot fail the node until the wait container is finished (unless any init container has failed) because it may be busy saving outputs, and these + // We cannot fail the node if the wait container is still running because it may be busy saving outputs, and these // would not get captured successfully. for _, c := range pod.Status.ContainerStatuses { - if (c.Name == common.WaitContainerName && c.State.Terminated == nil && new.Phase.Completed()) && !initContainerFailed { + if c.Name == common.WaitContainerName && c.State.Running != nil && new.Phase.Completed() { woc.log.WithField("new.phase", new.Phase).Info("leaving phase un-changed: wait container is not yet terminated ") new.Phase = old.Phase } @@ -1700,7 +1713,7 @@ func (woc *wfOperationCtx) deletePVCs(ctx context.Context) error { switch gcStrategy { case wfv1.VolumeClaimGCOnSuccess: - if woc.wf.Status.Phase == wfv1.WorkflowError || woc.wf.Status.Phase == wfv1.WorkflowFailed { + if woc.wf.Status.Phase != wfv1.WorkflowSucceeded { // Skip deleting PVCs to reuse them for retried failed/error workflows. // PVCs are automatically deleted when corresponded owner workflows get deleted. return nil @@ -1759,7 +1772,17 @@ func (woc *wfOperationCtx) deletePVCs(ctx context.Context) error { // Check if we have a retry node which wasn't memoized and return that if we do func (woc *wfOperationCtx) possiblyGetRetryChildNode(node *wfv1.NodeStatus) *wfv1.NodeStatus { if node.Type == wfv1.NodeTypeRetry && !(node.MemoizationStatus != nil && node.MemoizationStatus.Hit) { - return getChildNodeIndex(node, woc.wf.Status.Nodes, -1) + // If a retry node has hooks, the hook nodes will also become its children, + // so we need to filter out the hook nodes when finding the last child node of the retry node. + for i := len(node.Children) - 1; i >= 0; i-- { + childNode := getChildNodeIndex(node, woc.wf.Status.Nodes, i) + if childNode == nil { + continue + } + if childNode.NodeFlag == nil || !childNode.NodeFlag.Hooked { + return childNode + } + } } return nil } @@ -2285,6 +2308,14 @@ func (woc *wfOperationCtx) checkTemplateTimeout(tmpl *wfv1.Template, node *wfv1. // markWorkflowPhase is a convenience method to set the phase of the workflow with optional message // optionally marks the workflow completed, which sets the finishedAt timestamp and completed label func (woc *wfOperationCtx) markWorkflowPhase(ctx context.Context, phase wfv1.WorkflowPhase, message string) { + // Check whether or not the workflow needs to continue processing when it is completed + if phase.Completed() && (woc.checkTaskResultsInProgress() || woc.hasDaemonNodes()) { + woc.log.WithFields(log.Fields{"fromPhase": woc.wf.Status.Phase, "toPhase": phase}). + Debug("taskresults of workflow are incomplete or still have daemon nodes, so can't mark workflow completed") + woc.killDaemonedChildren("") + return + } + if woc.wf.Status.Phase != phase { if woc.wf.Status.Fulfilled() { woc.log.WithFields(log.Fields{"fromPhase": woc.wf.Status.Phase, "toPhase": phase}). @@ -2335,33 +2366,30 @@ func (woc *wfOperationCtx) markWorkflowPhase(ctx context.Context, phase wfv1.Wor switch phase { case wfv1.WorkflowSucceeded, wfv1.WorkflowFailed, wfv1.WorkflowError: - // Make sure all task results have been reconciled and wait for all daemon nodes to get terminated before marking the workflow completed. - if woc.checkReconciliationComplete() && !woc.hasDaemonNodes() { - woc.log.Info("Marking workflow completed") - woc.wf.Status.FinishedAt = metav1.Time{Time: time.Now().UTC()} - woc.globalParams[common.GlobalVarWorkflowDuration] = fmt.Sprintf("%f", woc.wf.Status.FinishedAt.Sub(woc.wf.Status.StartedAt.Time).Seconds()) - if woc.wf.ObjectMeta.Labels == nil { - woc.wf.ObjectMeta.Labels = make(map[string]string) - } - woc.wf.ObjectMeta.Labels[common.LabelKeyCompleted] = "true" - woc.wf.Status.Conditions.UpsertCondition(wfv1.Condition{Status: metav1.ConditionTrue, Type: wfv1.ConditionTypeCompleted}) - err := woc.deletePDBResource(ctx) - if err != nil { - woc.wf.Status.Phase = wfv1.WorkflowError - woc.wf.ObjectMeta.Labels[common.LabelKeyPhase] = string(wfv1.NodeError) - woc.updated = true - woc.wf.Status.Message = err.Error() - } - if woc.controller.wfArchive.IsEnabled() { - if woc.controller.isArchivable(woc.wf) { - woc.log.Info("Marking workflow as pending archiving") - woc.wf.Labels[common.LabelKeyWorkflowArchivingStatus] = "Pending" - } else { - woc.log.Info("Doesn't match with archive label selector. Skipping Archive") - } - } + woc.log.Info("Marking workflow completed") + woc.wf.Status.FinishedAt = metav1.Time{Time: time.Now().UTC()} + woc.globalParams[common.GlobalVarWorkflowDuration] = fmt.Sprintf("%f", woc.wf.Status.FinishedAt.Sub(woc.wf.Status.StartedAt.Time).Seconds()) + if woc.wf.ObjectMeta.Labels == nil { + woc.wf.ObjectMeta.Labels = make(map[string]string) + } + woc.wf.ObjectMeta.Labels[common.LabelKeyCompleted] = "true" + woc.wf.Status.Conditions.UpsertCondition(wfv1.Condition{Status: metav1.ConditionTrue, Type: wfv1.ConditionTypeCompleted}) + err := woc.deletePDBResource(ctx) + if err != nil { + woc.wf.Status.Phase = wfv1.WorkflowError + woc.wf.ObjectMeta.Labels[common.LabelKeyPhase] = string(wfv1.NodeError) woc.updated = true + woc.wf.Status.Message = err.Error() } + if woc.controller.wfArchive.IsEnabled() { + if woc.controller.isArchivable(woc.wf) { + woc.log.Info("Marking workflow as pending archiving") + woc.wf.Labels[common.LabelKeyWorkflowArchivingStatus] = "Pending" + } else { + woc.log.Info("Doesn't match with archive label selector. Skipping Archive") + } + } + woc.updated = true woc.controller.queuePodForCleanup(woc.wf.Namespace, woc.getAgentPodName(), deletePod) } } @@ -2796,8 +2824,7 @@ func (woc *wfOperationCtx) executeContainer(ctx context.Context, nodeName string func (woc *wfOperationCtx) getOutboundNodes(nodeID string) []string { node, err := woc.wf.Status.Nodes.Get(nodeID) if err != nil { - woc.log.Fatalf("was unable to obtain node for %s", nodeID) - panic(fmt.Sprintf("Expected node for %s", nodeID)) + woc.log.Panicf("was unable to obtain node for %s", nodeID) } switch node.Type { case wfv1.NodeTypeSkipped, wfv1.NodeTypeSuspend, wfv1.NodeTypeHTTP, wfv1.NodeTypePlugin: @@ -2835,6 +2862,10 @@ func (woc *wfOperationCtx) getOutboundNodes(nodeID string) []string { if numChildren > 0 { return []string{node.Children[numChildren-1]} } + case wfv1.NodeTypeSteps, wfv1.NodeTypeDAG: + if node.MemoizationStatus != nil && node.MemoizationStatus.Hit { + return []string{node.ID} + } } outbound := make([]string, 0) for _, outboundNodeID := range node.OutboundNodes { @@ -3235,8 +3266,7 @@ func (woc *wfOperationCtx) addChildNode(parent string, child string) { childID := woc.wf.NodeID(child) node, err := woc.wf.Status.Nodes.Get(parentID) if err != nil { - woc.log.Fatalf("was unable to obtain node for %s", parentID) - panic(fmt.Sprintf("parent node %s not initialized", parent)) + woc.log.Panicf("was unable to obtain node for %s", parentID) } for _, nodeID := range node.Children { if childID == nodeID { diff --git a/workflow/controller/operator_test.go b/workflow/controller/operator_test.go index 31267e6ea67c..76bcaca1ff5c 100644 --- a/workflow/controller/operator_test.go +++ b/workflow/controller/operator_test.go @@ -1587,6 +1587,32 @@ func TestAssessNodeStatus(t *testing.T) { }, node: &wfv1.NodeStatus{TemplateName: templateName}, want: wfv1.NodeFailed, + }, { + name: "pod failed - wait container waiting but pod was set failed", + pod: &apiv1.Pod{ + Status: apiv1.PodStatus{ + InitContainerStatuses: []apiv1.ContainerStatus{ + { + Name: common.InitContainerName, + State: apiv1.ContainerState{Terminated: &apiv1.ContainerStateTerminated{ExitCode: 0}}, + }, + }, + ContainerStatuses: []apiv1.ContainerStatus{ + { + Name: common.WaitContainerName, + State: apiv1.ContainerState{Terminated: nil, Waiting: &apiv1.ContainerStateWaiting{Reason: "PodInitializing"}}, + }, + { + Name: common.MainContainerName, + State: apiv1.ContainerState{Terminated: nil}, + }, + }, + Message: "failed since wait contain waiting", + Phase: apiv1.PodFailed, + }, + }, + node: &wfv1.NodeStatus{TemplateName: templateName}, + want: wfv1.NodeFailed, }, { name: "pod running", pod: &apiv1.Pod{ @@ -5383,6 +5409,177 @@ func TestConfigMapCacheLoadOperateNoOutputs(t *testing.T) { } } +var workflowWithMemoizedInSteps = ` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: memoized-bug- + namespace: default +spec: + entrypoint: main + templates: + - name: main + steps: + - - name: hello-steps + template: memoized + - - name: whatever + template: hello + + - name: memoized + outputs: + parameters: + - name: msg + valueFrom: + parameter: "{{steps.hello-step.outputs.result}}" + steps: + - - name: hello-step + template: hello + memoize: + key: "memoized-bug-steps-0" + cache: + configMap: + name: my-config + + - name: hello + container: + image: alpine:latest + command: [sh, -c] + args: ["echo Hello"] +` + +var workflowWithMemoizedInDAG = ` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + generateName: memoized-bug- + namespace: default +spec: + entrypoint: main + templates: + - name: main + steps: + - - name: hello-dag + template: memoized + - - name: whatever + template: hello + + - name: memoized + outputs: + parameters: + - name: msg + valueFrom: + parameter: "{{dag.hello-dag.outputs.result}}" + dag: + tasks: + - name: hello-dag + template: hello + memoize: + key: "memoized-bug-dag-0" + cache: + configMap: + name: my-config + + - name: hello + container: + image: alpine:latest + command: [sh, -c] + args: ["echo Hello"] +` + +func TestGetOutboundNodesFromCacheHitSteps(t *testing.T) { + myConfigMapCacheEntry := apiv1.ConfigMap{ + Data: map[string]string{ + "memoized-bug-steps-0": `{"nodeID":"memoized-bug-wqbj4-3475368823","outputs":null,"creationTimestamp":"2020-09-21T18:12:56Z","lastHitTimestamp":"2024-03-11T05:59:58Z"}`, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "ConfigMap", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-config", + ResourceVersion: "80004", + Labels: map[string]string{ + common.LabelKeyConfigMapType: common.LabelValueTypeConfigMapCache, + }, + }, + } + + wf := wfv1.MustUnmarshalWorkflow(workflowWithMemoizedInSteps) + cancel, controller := newController() + defer cancel() + + ctx := context.Background() + _, err := controller.wfclientset.ArgoprojV1alpha1().Workflows(wf.ObjectMeta.Namespace).Create(ctx, wf, metav1.CreateOptions{}) + assert.NoError(t, err) + _, err = controller.kubeclientset.CoreV1().ConfigMaps("default").Create(ctx, &myConfigMapCacheEntry, metav1.CreateOptions{}) + assert.NoError(t, err) + + woc := newWorkflowOperationCtx(wf, controller) + woc.operate(ctx) + makePodsPhase(ctx, woc, apiv1.PodSucceeded) + woc.operate(ctx) + + assert.Equal(t, wfv1.WorkflowSucceeded, woc.wf.Status.Phase) + + hitCache := 0 + for _, node := range woc.wf.Status.Nodes { + if node.DisplayName == "hello-steps" { + hitCache++ + assert.NotNil(t, node.MemoizationStatus) + assert.True(t, node.MemoizationStatus.Hit) + assert.Equal(t, 1, len(node.Children)) + } + } + assert.Equal(t, 1, hitCache) +} + +func TestGetOutboundNodesFromCacheHitDAG(t *testing.T) { + myConfigMapCacheEntry := apiv1.ConfigMap{ + Data: map[string]string{ + "memoized-bug-dag-0": `{"nodeID":"memoized-bug-wqbj4-3475368823","outputs":null,"creationTimestamp":"2020-09-21T18:12:56Z","lastHitTimestamp":"2024-03-11T05:59:58Z"}`, + }, + TypeMeta: metav1.TypeMeta{ + Kind: "ConfigMap", + APIVersion: "v1", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "my-config", + ResourceVersion: "80004", + Labels: map[string]string{ + common.LabelKeyConfigMapType: common.LabelValueTypeConfigMapCache, + }, + }, + } + + wf := wfv1.MustUnmarshalWorkflow(workflowWithMemoizedInDAG) + cancel, controller := newController() + defer cancel() + + ctx := context.Background() + _, err := controller.wfclientset.ArgoprojV1alpha1().Workflows(wf.ObjectMeta.Namespace).Create(ctx, wf, metav1.CreateOptions{}) + assert.NoError(t, err) + _, err = controller.kubeclientset.CoreV1().ConfigMaps("default").Create(ctx, &myConfigMapCacheEntry, metav1.CreateOptions{}) + assert.NoError(t, err) + + woc := newWorkflowOperationCtx(wf, controller) + woc.operate(ctx) + makePodsPhase(ctx, woc, apiv1.PodSucceeded) + woc.operate(ctx) + + assert.Equal(t, wfv1.WorkflowSucceeded, woc.wf.Status.Phase) + + hitCache := 0 + for _, node := range woc.wf.Status.Nodes { + if node.DisplayName == "hello-dag" { + hitCache++ + assert.NotNil(t, node.MemoizationStatus) + assert.True(t, node.MemoizationStatus.Hit) + assert.Equal(t, 1, len(node.Children)) + } + } + assert.Equal(t, 1, hitCache) +} + var workflowCachedMaxAge = ` apiVersion: argoproj.io/v1alpha1 kind: Workflow @@ -10335,3 +10532,339 @@ func TestWorkflowNeedReconcile(t *testing.T) { assert.Equal(t, "steps-need-reconcile", pods.Items[1].Spec.Containers[1].Env[0].Value) } } + +func TestWorkflowRunningButLabelCompleted(t *testing.T) { + wf := wfv1.MustUnmarshalWorkflow(` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + annotations: + workflows.argoproj.io/pod-name-format: v2 + creationTimestamp: "2024-02-04T08:43:42Z" + generateName: wf-retry-stopped- + generation: 11 + labels: + workflows.argoproj.io/completed: "true" + workflows.argoproj.io/phase: Running + workflows.argoproj.io/test: "true" + workflows.argoproj.io/workflow: wf-retry-stopped + workflows.argoproj.io/workflow-archiving-status: Archived + name: wf-retry-stopped-pn6mm + namespace: argo + resourceVersion: "307888" + uid: 6c14e28b-1c31-4bd5-a10b-f4799971448f +spec: + activeDeadlineSeconds: 300 + arguments: {} + entrypoint: wf-retry-stopped-main + executor: + serviceAccountName: default + podSpecPatch: | + terminationGracePeriodSeconds: 3 + serviceAccountName: argo + templates: + - inputs: {} + metadata: {} + name: wf-retry-stopped-main + outputs: {} + steps: + - - arguments: {} + name: create + template: create + - arguments: {} + name: sleep + template: sleep + - arguments: {} + name: stop + template: stop + - container: + command: + - sleep + - "10" + image: alpine:latest + name: "" + resources: {} + inputs: {} + metadata: {} + name: sleep + outputs: {} + - container: + args: + - stop + - -l + - workflows.argoproj.io/workflow=wf-retry-stopped + - --namespace=argo + - --loglevel=debug + image: argoproj/argocli:latest + name: "" + resources: {} + inputs: {} + metadata: {} + name: stop + outputs: {} + - container: + args: + - | + echo "hello world" > /tmp/message + sleep 999 + command: + - sh + - -c + image: argoproj/argosay:v2 + name: "" + resources: {} + inputs: {} + metadata: {} + name: create + outputs: + artifacts: + - archive: + none: {} + name: my-artifact + path: /tmp/message + s3: + accessKeySecret: + key: accesskey + name: my-minio-cred + bucket: my-bucket + endpoint: minio:9000 + insecure: true + key: my-artifact + secretKeySecret: + key: secretkey + name: my-minio-cred + workflowMetadata: + labels: + workflows.argoproj.io/test: "true" + workflows.argoproj.io/workflow: wf-retry-stopped +status: + artifactGCStatus: + notSpecified: true + artifactRepositoryRef: + artifactRepository: + archiveLogs: true + s3: + accessKeySecret: + key: accesskey + name: my-minio-cred + bucket: my-bucket + endpoint: minio:9000 + insecure: true + secretKeySecret: + key: secretkey + name: my-minio-cred + configMap: artifact-repositories + key: default-v1 + namespace: argo + conditions: + - status: "False" + type: PodRunning + - status: "True" + type: Completed + finishedAt: "2024-02-04T08:44:20Z" + message: Stopped with strategy 'Stop' + nodes: + wf-retry-stopped-pn6mm: + children: + - wf-retry-stopped-pn6mm-4109534602 + displayName: wf-retry-stopped-pn6mm + finishedAt: null + id: wf-retry-stopped-pn6mm + name: wf-retry-stopped-pn6mm + phase: Running + progress: 0/3 + startedAt: "2024-02-04T08:44:03Z" + templateName: wf-retry-stopped-main + templateScope: local/wf-retry-stopped-pn6mm + type: Steps + wf-retry-stopped-pn6mm-1672493720: + finishedAt: null + id: "" + name: "" + outputs: + artifacts: + - archive: + none: {} + name: my-artifact + path: /tmp/message + s3: + accessKeySecret: + key: accesskey + name: my-minio-cred + bucket: my-bucket + endpoint: minio:9000 + insecure: true + key: my-artifact + secretKeySecret: + key: secretkey + name: my-minio-cred + - name: main-logs + s3: + key: wf-retry-stopped-pn6mm/wf-retry-stopped-pn6mm-create-1672493720/main.log + startedAt: null + type: "" + wf-retry-stopped-pn6mm-4109534602: + boundaryID: wf-retry-stopped-pn6mm + displayName: '[0]' + finishedAt: null + id: wf-retry-stopped-pn6mm-4109534602 + name: wf-retry-stopped-pn6mm[0] + nodeFlag: {} + phase: Running + progress: 0/3 + startedAt: "2024-02-04T08:44:03Z" + templateScope: local/wf-retry-stopped-pn6mm + type: StepGroup + wf-retry-stopped-pn6mm-4140492335: + finishedAt: null + id: "" + name: "" + outputs: + artifacts: + - name: main-logs + s3: + key: wf-retry-stopped-pn6mm/wf-retry-stopped-pn6mm-sleep-4140492335/main.log + startedAt: null + type: "" + phase: Running + progress: 0/3 + startedAt: "2024-02-04T08:44:03Z" + taskResultsCompletionStatus: + wf-retry-stopped-pn6mm-1672493720: true + wf-retry-stopped-pn6mm-2766965604: true + wf-retry-stopped-pn6mm-4140492335: true +`) + + cancel, controller := newController(wf) + defer cancel() + + ctx := context.Background() + reconceilNeeded := reconciliationNeeded(wf) + assert.False(t, reconceilNeeded) + + delete(wf.Labels, common.LabelKeyCompleted) + woc := newWorkflowOperationCtx(wf, controller) + assert.True(t, len(woc.wf.Status.Nodes) > 0) + nodeId := "wf-retry-stopped-pn6mm-1672493720" + + woc.wf.Status.MarkTaskResultIncomplete(nodeId) + woc.operate(ctx) + assert.Equal(t, wfv1.WorkflowRunning, woc.wf.Status.Phase) + + woc.wf.Status.MarkTaskResultComplete(nodeId) + woc.operate(ctx) + assert.Equal(t, wfv1.WorkflowFailed, woc.wf.Status.Phase) + + delete(wf.Labels, common.LabelKeyCompleted) + woc = newWorkflowOperationCtx(wf, controller) + n := woc.markNodePhase(wf.Name, wfv1.NodeError) + assert.Equal(t, n.Phase, wfv1.NodeError) + woc.wf.Status.MarkTaskResultIncomplete(nodeId) + woc.operate(ctx) + assert.Equal(t, wfv1.WorkflowRunning, woc.wf.Status.Phase) + + woc.wf.Status.MarkTaskResultComplete(nodeId) + woc.operate(ctx) + assert.Equal(t, wfv1.WorkflowError, woc.wf.Status.Phase) + + delete(wf.Labels, common.LabelKeyCompleted) + woc = newWorkflowOperationCtx(wf, controller) + n = woc.markNodePhase(wf.Name, wfv1.NodeSucceeded) + assert.Equal(t, n.Phase, wfv1.NodeSucceeded) + woc.wf.Status.MarkTaskResultIncomplete(nodeId) + woc.operate(ctx) + assert.Equal(t, wfv1.WorkflowRunning, woc.wf.Status.Phase) + + woc.wf.Status.MarkTaskResultComplete(nodeId) + woc.operate(ctx) + assert.Equal(t, wfv1.WorkflowSucceeded, woc.wf.Status.Phase) +} + +var wfHasContainerSet = ` +apiVersion: argoproj.io/v1alpha1 +kind: Workflow +metadata: + name: lovely-rhino +spec: + templates: + - name: init + dag: + tasks: + - name: A + template: run + arguments: {} + - name: run + containerSet: + containers: + - name: main + image: alpine:latest + command: + - /bin/sh + args: + - '-c' + - sleep 9000 + resources: {} + - name: main2 + image: alpine:latest + command: + - /bin/sh + args: + - '-c' + - sleep 9000 + resources: {} + entrypoint: init + arguments: {} + ttlStrategy: + secondsAfterCompletion: 300 + podGC: + strategy: OnPodCompletion` + +// TestContainerSetDeleteContainerWhenPodDeleted test whether a workflow has ContainerSet error when pod deleted. +func TestContainerSetDeleteContainerWhenPodDeleted(t *testing.T) { + cancel, controller := newController() + defer cancel() + ctx := context.Background() + wfcset := controller.wfclientset.ArgoprojV1alpha1().Workflows("") + wf := wfv1.MustUnmarshalWorkflow(wfHasContainerSet) + wf, err := wfcset.Create(ctx, wf, metav1.CreateOptions{}) + assert.Nil(t, err) + wf, err = wfcset.Get(ctx, wf.ObjectMeta.Name, metav1.GetOptions{}) + assert.Nil(t, err) + woc := newWorkflowOperationCtx(wf, controller) + woc.operate(ctx) + pods, err := listPods(woc) + assert.Nil(t, err) + assert.Equal(t, 1, len(pods.Items)) + + // mark pod Running + makePodsPhase(ctx, woc, apiv1.PodRunning) + woc = newWorkflowOperationCtx(woc.wf, controller) + woc.operate(ctx) + for _, node := range woc.wf.Status.Nodes { + if node.Type == wfv1.NodeTypePod { + assert.Equal(t, wfv1.NodeRunning, node.Phase) + } + } + + // TODO: Refactor to use local-scoped env vars in test to avoid long wait. See https://github.com/argoproj/argo-workflows/pull/12756#discussion_r1530245007 + // delete pod + time.Sleep(10 * time.Second) + deletePods(ctx, woc) + pods, err = listPods(woc) + assert.Nil(t, err) + assert.Equal(t, 0, len(pods.Items)) + + // reconcile + woc = newWorkflowOperationCtx(woc.wf, controller) + woc.operate(ctx) + assert.Equal(t, wfv1.WorkflowError, woc.wf.Status.Phase) + for _, node := range woc.wf.Status.Nodes { + assert.Equal(t, wfv1.NodeError, node.Phase) + if node.Type == wfv1.NodeTypePod { + assert.Equal(t, "pod deleted", node.Message) + } + if node.Type == wfv1.NodeTypeContainer { + assert.Equal(t, "container deleted", node.Message) + } + } +} diff --git a/workflow/controller/steps.go b/workflow/controller/steps.go index 65bc3fd468db..e742bdd3b2a5 100644 --- a/workflow/controller/steps.go +++ b/workflow/controller/steps.go @@ -344,8 +344,7 @@ func (woc *wfOperationCtx) executeStepGroup(ctx context.Context, stepGroup []wfv for _, childNodeID := range node.Children { childNode, err := woc.wf.Status.Nodes.Get(childNodeID) if err != nil { - woc.log.Fatalf("was unable to obtain node for %s", childNodeID) - panic(fmt.Sprintf("unable to get childNode for %s", childNodeID)) + woc.log.Panicf("Coudn't obtain child for %s, panicking", childNodeID) } step := nodeSteps[childNode.Name] if childNode.FailedOrError() && !step.ContinuesOn(childNode.Phase) { diff --git a/workflow/controller/workflowpod.go b/workflow/controller/workflowpod.go index fd0af602e55a..f94d5974d4d7 100644 --- a/workflow/controller/workflowpod.go +++ b/workflow/controller/workflowpod.go @@ -194,13 +194,7 @@ func (woc *wfOperationCtx) createWorkflowPod(ctx context.Context, nodeName strin pod.Spec.HostNetwork = *woc.execWf.Spec.HostNetwork } - if woc.execWf.Spec.DNSPolicy != nil { - pod.Spec.DNSPolicy = *woc.execWf.Spec.DNSPolicy - } - - if woc.execWf.Spec.DNSConfig != nil { - pod.Spec.DNSConfig = woc.execWf.Spec.DNSConfig - } + woc.addDNSConfig(pod) if woc.controller.Config.InstanceID != "" { pod.ObjectMeta.Labels[common.LabelKeyControllerInstanceID] = woc.controller.Config.InstanceID @@ -679,6 +673,17 @@ func (woc *wfOperationCtx) addMetadata(pod *apiv1.Pod, tmpl *wfv1.Template) { } } +// addDNSConfig applies DNSConfig to the pod +func (woc *wfOperationCtx) addDNSConfig(pod *apiv1.Pod) { + if woc.execWf.Spec.DNSPolicy != nil { + pod.Spec.DNSPolicy = *woc.execWf.Spec.DNSPolicy + } + + if woc.execWf.Spec.DNSConfig != nil { + pod.Spec.DNSConfig = woc.execWf.Spec.DNSConfig + } +} + // addSchedulingConstraints applies any node selectors or affinity rules to the pod, either set in the workflow or the template func addSchedulingConstraints(pod *apiv1.Pod, wfSpec *wfv1.WorkflowSpec, tmpl *wfv1.Template) { // Set nodeSelector (if specified) diff --git a/workflow/executor/executor.go b/workflow/executor/executor.go index df6f77ce20b5..5ab5fb7dc370 100644 --- a/workflow/executor/executor.go +++ b/workflow/executor/executor.go @@ -798,8 +798,8 @@ func (we *WorkflowExecutor) FinalizeOutput(ctx context.Context) { err := we.patchTaskResultLabels(ctx, map[string]string{ common.LabelKeyReportOutputsCompleted: "true", }) - if apierr.IsForbidden(err) { - log.WithError(err).Warn("failed to patch task set, falling back to legacy/insecure pod patch, see https://argo-workflows.readthedocs.io/en/release-3.5/workflow-rbac/") + if apierr.IsForbidden(err) || apierr.IsNotFound(err) { + log.WithError(err).Warn("failed to patch task result, falling back to legacy/insecure pod patch, see https://argo-workflows.readthedocs.io/en/release-3.5/workflow-rbac/") // Only added as a backup in case LabelKeyReportOutputsCompleted could not be set err = we.AddAnnotation(ctx, common.AnnotationKeyReportOutputsCompleted, "true") } @@ -820,7 +820,7 @@ func (we *WorkflowExecutor) InitializeOutput(ctx context.Context) { }, errorsutil.IsTransientErr, func() error { err := we.upsertTaskResult(ctx, wfv1.NodeResult{}) if apierr.IsForbidden(err) { - log.WithError(err).Warn("failed to patch task set, falling back to legacy/insecure pod patch, see https://argo-workflows.readthedocs.io/en/release-3.5/workflow-rbac/") + log.WithError(err).Warn("failed to patch task result, falling back to legacy/insecure pod patch, see https://argo-workflows.readthedocs.io/en/release-3.5/workflow-rbac/") // Only added as a backup in case LabelKeyReportOutputsCompleted could not be set err = we.AddAnnotation(ctx, common.AnnotationKeyReportOutputsCompleted, "false") } @@ -848,7 +848,7 @@ func (we *WorkflowExecutor) reportResult(ctx context.Context, result wfv1.NodeRe }, errorsutil.IsTransientErr, func() error { err := we.upsertTaskResult(ctx, result) if apierr.IsForbidden(err) { - log.WithError(err).Warn("failed to patch task set, falling back to legacy/insecure pod patch, see https://argo-workflows.readthedocs.io/en/release-3.5/workflow-rbac/") + log.WithError(err).Warn("failed to patch task result, falling back to legacy/insecure pod patch, see https://argo-workflows.readthedocs.io/en/release-3.5/workflow-rbac/") if result.Outputs.HasOutputs() { value, err := json.Marshal(result.Outputs) if err != nil { diff --git a/workflow/gccontroller/gc_controller.go b/workflow/gccontroller/gc_controller.go index 77a6b21b1815..be700721efd7 100644 --- a/workflow/gccontroller/gc_controller.go +++ b/workflow/gccontroller/gc_controller.go @@ -205,9 +205,22 @@ func (c *Controller) deleteWorkflow(ctx context.Context, key string) error { // It should be impossible for a workflow to have been queue without a valid key. namespace, name, _ := cache.SplitMetaNamespaceKey(key) + // Double check that this workflow is still completed. If it were retried, it may be running again (c.f. https://github.com/argoproj/argo-workflows/issues/12636) + obj, exists, err := c.wfInformer.GetStore().GetByKey(key) + if err != nil { + return nil + } + if exists { + un, ok := obj.(*unstructured.Unstructured) + if ok && !common.IsDone(un) { + log.Infof("Workflow '%s' is not completed due to a retry operation, ignore deletion", key) + return nil + } + } + // Any workflow that was queued must need deleting, therefore we do not check the expiry again. log.Infof("Deleting garbage collected workflow '%s'", key) - err := c.wfclientset.ArgoprojV1alpha1().Workflows(namespace).Delete(ctx, name, metav1.DeleteOptions{PropagationPolicy: commonutil.GetDeletePropagation()}) + err = c.wfclientset.ArgoprojV1alpha1().Workflows(namespace).Delete(ctx, name, metav1.DeleteOptions{PropagationPolicy: commonutil.GetDeletePropagation()}) if err != nil { if apierr.IsNotFound(err) { log.Infof("Workflow already deleted '%s'", key) diff --git a/workflow/templateresolution/context.go b/workflow/templateresolution/context.go index c57987bd798a..131864685887 100644 --- a/workflow/templateresolution/context.go +++ b/workflow/templateresolution/context.go @@ -211,6 +211,10 @@ func (ctx *Context) resolveTemplateImpl(tmplHolder wfv1.TemplateReferenceHolder) ctx.log.Debug("Stored the template") templateStored = true } + err = ctx.workflow.SetStoredInlineTemplate(scope, resourceName, newTmpl) + if err != nil { + ctx.log.Errorf("Failed to store the inline template: %v", err) + } } tmpl = newTmpl } diff --git a/workflow/util/util.go b/workflow/util/util.go index fc3e0f2690a8..7e7fda53f9f6 100644 --- a/workflow/util/util.go +++ b/workflow/util/util.go @@ -699,7 +699,7 @@ func FormulateResubmitWorkflow(ctx context.Context, wf *wfv1.Workflow, memoized onExitNodeName := wf.ObjectMeta.Name + ".onExit" err := packer.DecompressWorkflow(wf) if err != nil { - log.Fatal(err) + log.Panic(err) } for _, node := range wf.Status.Nodes { newNode := node.DeepCopy() @@ -764,14 +764,27 @@ func getDescendantNodeIDs(wf *wfv1.Workflow, node wfv1.NodeStatus) []string { for _, child := range node.Children { childStatus, err := wf.Status.Nodes.Get(child) if err != nil { - log.Fatalf("Couldn't get child, panicking") - panic("Was not able to obtain child") + log.Panicf("Coudn't obtain child for %s, panicking", child) } descendantNodeIDs = append(descendantNodeIDs, getDescendantNodeIDs(wf, *childStatus)...) } return descendantNodeIDs } +func isDescendantNodeSucceeded(wf *wfv1.Workflow, node wfv1.NodeStatus, nodeIDsToReset map[string]bool) bool { + for _, child := range node.Children { + childStatus, err := wf.Status.Nodes.Get(child) + if err != nil { + log.Panicf("Coudn't obtain child for %s, panicking", child) + } + _, present := nodeIDsToReset[child] + if (!present && childStatus.Phase == wfv1.NodeSucceeded) || isDescendantNodeSucceeded(wf, *childStatus, nodeIDsToReset) { + return true + } + } + return false +} + func deletePodNodeDuringRetryWorkflow(wf *wfv1.Workflow, node wfv1.NodeStatus, deletedPods map[string]bool, podsToDelete []string) (map[string]bool, []string) { templateName := GetTemplateFromNode(node) version := GetWorkflowPodNameVersion(wf) @@ -801,8 +814,7 @@ func resetConnectedParentGroupNodes(oldWF *wfv1.Workflow, newWF *wfv1.Workflow, for { currentNode, err := oldWF.Status.Nodes.Get(currentNodeID) if err != nil { - log.Fatalf("dying due to inability to obtain node for %s", currentNodeID) - panic("was not able to get node, panicking") + log.Panicf("dying due to inability to obtain node for %s, panicking", currentNodeID) } if !containsNode(resetParentGroupNodes, currentNodeID) { newWF.Status.Nodes.Set(currentNodeID, resetNode(*currentNode.DeepCopy())) @@ -812,8 +824,7 @@ func resetConnectedParentGroupNodes(oldWF *wfv1.Workflow, newWF *wfv1.Workflow, if currentNode.BoundaryID != "" && currentNode.BoundaryID != oldWF.ObjectMeta.Name { parentNode, err := oldWF.Status.Nodes.Get(currentNode.BoundaryID) if err != nil { - log.Fatalf("panicking unable to obtain node for %s", currentNode.BoundaryID) - panic("was not able to get node") + log.Panicf("unable to obtain node for %s, panicking", currentNode.BoundaryID) } if isGroupNode(*parentNode) { currentNodeID = parentNode.ID @@ -902,7 +913,7 @@ func FormulateRetryWorkflow(ctx context.Context, wf *wfv1.Workflow, restartSucce for _, child := range descendantNodeIDs { childNode, err := wf.Status.Nodes.Get(child) if err != nil { - log.Fatalf("was unable to obtain node for %s due to %s", child, err) + log.Warnf("was unable to obtain node for %s due to %s", child, err) return nil, nil, fmt.Errorf("Was unable to obtain node for %s due to %s", child, err) } if _, present := nodeIDsToReset[child]; present { @@ -932,7 +943,7 @@ func FormulateRetryWorkflow(ctx context.Context, wf *wfv1.Workflow, restartSucce deletedNodes[descendantNodeID] = true descendantNode, err := wf.Status.Nodes.Get(descendantNodeID) if err != nil { - log.Fatalf("Was unable to obtain node for %s due to %s", descendantNodeID, err) + log.Warnf("Was unable to obtain node for %s due to %s", descendantNodeID, err) return nil, nil, fmt.Errorf("Was unable to obtain node for %s due to %s", descendantNodeID, err) } if descendantNode.Type == wfv1.NodeTypePod { @@ -960,6 +971,11 @@ func FormulateRetryWorkflow(ctx context.Context, wf *wfv1.Workflow, restartSucce log.Debugf("Reset %s node %s since it's a group node", node.Name, string(node.Phase)) continue } else { + if isDescendantNodeSucceeded(wf, node, nodeIDsToReset) { + log.Debugf("Node %s remains as is since it has succeed child nodes.", node.Name) + newWF.Status.Nodes.Set(node.ID, node) + continue + } log.Debugf("Deleted %s node %s since it's not a group node", node.Name, string(node.Phase)) deletedPods, podsToDelete = deletePodNodeDuringRetryWorkflow(wf, node, deletedPods, podsToDelete) log.Debugf("Deleted pod node: %s", node.Name) diff --git a/workflow/util/util_test.go b/workflow/util/util_test.go index d392b84eef20..8e57bc3b9875 100644 --- a/workflow/util/util_test.go +++ b/workflow/util/util_test.go @@ -1367,6 +1367,64 @@ func TestFormulateRetryWorkflow(t *testing.T) { } } }) + + t.Run("Retry continue on failed workflow", func(t *testing.T) { + wf := &wfv1.Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: "continue-on-failed-workflow", + Labels: map[string]string{}, + }, + Status: wfv1.WorkflowStatus{ + Phase: wfv1.WorkflowFailed, + Nodes: map[string]wfv1.NodeStatus{ + "continue-on-failed-workflow": {ID: "continue-on-failed-workflow", Phase: wfv1.NodeFailed, Type: wfv1.NodeTypeDAG, Children: []string{"1"}, OutboundNodes: []string{"3", "5"}}, + "1": {ID: "1", Phase: wfv1.NodeSucceeded, Type: wfv1.NodeTypePod, BoundaryID: "continue-on-failed-workflow", Children: []string{"2", "4"}, Name: "node1"}, + "2": {ID: "2", Phase: wfv1.NodeFailed, Type: wfv1.NodeTypePod, BoundaryID: "continue-on-failed-workflow", Children: []string{"3"}, Name: "node2"}, + "3": {ID: "3", Phase: wfv1.NodeSucceeded, Type: wfv1.NodeTypePod, BoundaryID: "continue-on-failed-workflow", Name: "node3"}, + "4": {ID: "4", Phase: wfv1.NodeFailed, Type: wfv1.NodeTypePod, BoundaryID: "continue-on-failed-workflow", Children: []string{"5"}, Name: "node4"}, + "5": {ID: "5", Phase: wfv1.NodeOmitted, Type: wfv1.NodeTypeSkipped, BoundaryID: "continue-on-failed-workflow", Name: "node5"}}, + }, + } + _, err := wfClient.Create(ctx, wf, metav1.CreateOptions{}) + assert.NoError(t, err) + wf, podsToDelete, err := FormulateRetryWorkflow(ctx, wf, false, "", nil) + if assert.NoError(t, err) { + if assert.Len(t, wf.Status.Nodes, 4) { + assert.Equal(t, wfv1.NodeFailed, wf.Status.Nodes["2"].Phase) + assert.Equal(t, wfv1.NodeSucceeded, wf.Status.Nodes["3"].Phase) + assert.Equal(t, 2, len(podsToDelete)) + } + } + }) + + t.Run("Retry continue on failed workflow with restartSuccessful and nodeFieldSelector", func(t *testing.T) { + wf := &wfv1.Workflow{ + ObjectMeta: metav1.ObjectMeta{ + Name: "continue-on-failed-workflow-2", + Labels: map[string]string{}, + }, + Status: wfv1.WorkflowStatus{ + Phase: wfv1.WorkflowFailed, + Nodes: map[string]wfv1.NodeStatus{ + "continue-on-failed-workflow-2": {ID: "continue-on-failed-workflow-2", Phase: wfv1.NodeFailed, Type: wfv1.NodeTypeDAG, Children: []string{"1"}, OutboundNodes: []string{"3", "5"}}, + "1": {ID: "1", Phase: wfv1.NodeSucceeded, Type: wfv1.NodeTypePod, BoundaryID: "continue-on-failed-workflow-2", Children: []string{"2", "4"}, Name: "node1"}, + "2": {ID: "2", Phase: wfv1.NodeFailed, Type: wfv1.NodeTypePod, BoundaryID: "continue-on-failed-workflow-2", Children: []string{"3"}, Name: "node2"}, + "3": {ID: "3", Phase: wfv1.NodeSucceeded, Type: wfv1.NodeTypePod, BoundaryID: "continue-on-failed-workflow-2", Name: "node3"}, + "4": {ID: "4", Phase: wfv1.NodeFailed, Type: wfv1.NodeTypePod, BoundaryID: "continue-on-failed-workflow-2", Children: []string{"5"}, Name: "node4"}, + "5": {ID: "5", Phase: wfv1.NodeOmitted, Type: wfv1.NodeTypeSkipped, BoundaryID: "continue-on-failed-workflow-2", Name: "node5"}}, + }, + } + _, err := wfClient.Create(ctx, wf, metav1.CreateOptions{}) + assert.NoError(t, err) + wf, podsToDelete, err := FormulateRetryWorkflow(ctx, wf, true, "id=3", nil) + if assert.NoError(t, err) { + if assert.Len(t, wf.Status.Nodes, 2) { + assert.Equal(t, wfv1.NodeSucceeded, wf.Status.Nodes["1"].Phase) + assert.Equal(t, wfv1.NodeRunning, wf.Status.Nodes["continue-on-failed-workflow-2"].Phase) + assert.Equal(t, 4, len(podsToDelete)) + } + } + }) } func TestFromUnstructuredObj(t *testing.T) {