From 5eaa7b8495a6e6fc5b2255da94294a7310b917ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nick=20M=C3=BCller?= Date: Thu, 15 Dec 2022 19:15:08 +0100 Subject: [PATCH] Implemented CacheService Added endpoint for evicting execution cache Added endpoint for evicting task execution cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Nick Müller --- go.mod | 13 +- go.sum | 456 +- pkg/manager/impl/cache_manager.go | 463 ++ pkg/manager/impl/cache_manager_test.go | 8529 ++++++++++++++++++++ pkg/manager/impl/execution_manager_test.go | 10 +- pkg/manager/impl/shared/constants.go | 2 + pkg/manager/interfaces/cache.go | 12 + pkg/manager/mocks/cache.go | 42 + pkg/rpc/cacheservice/base.go | 86 + pkg/rpc/cacheservice/cache.go | 59 + pkg/rpc/cacheservice/metrics.go | 36 + pkg/server/service.go | 8 + 12 files changed, 9569 insertions(+), 147 deletions(-) create mode 100644 pkg/manager/impl/cache_manager.go create mode 100644 pkg/manager/impl/cache_manager_test.go create mode 100644 pkg/manager/interfaces/cache.go create mode 100644 pkg/manager/mocks/cache.go create mode 100644 pkg/rpc/cacheservice/base.go create mode 100644 pkg/rpc/cacheservice/cache.go create mode 100644 pkg/rpc/cacheservice/metrics.go diff --git a/go.mod b/go.mod index eb30f352b..9b3a961aa 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,13 @@ module github.com/flyteorg/flyteadmin go 1.18 +replace ( + github.com/flyteorg/flyteidl => github.com/blackshark-ai/flyteidl v0.24.22-0.20221215141908-3e44057796c6 + github.com/flyteorg/flyteplugins => github.com/blackshark-ai/flyteplugins v1.0.2-0.20221215151032-3ce2c1315081 + github.com/flyteorg/flytepropeller => github.com/blackshark-ai/flytepropeller v0.16.48-0.20221215161838-a505ae7f1062 + github.com/flyteorg/flytestdlib => github.com/blackshark-ai/flytestdlib v1.0.1-0.20221215152838-ded77ffa67cf +) + require ( cloud.google.com/go/iam v0.3.0 cloud.google.com/go/storage v1.22.0 @@ -198,9 +205,9 @@ require ( github.com/imdario/mergo v0.3.13 // indirect github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 // indirect github.com/prometheus/common v0.32.1 // indirect - go.uber.org/atomic v1.7.0 // indirect - go.uber.org/multierr v1.6.0 // indirect - go.uber.org/zap v1.19.1 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.8.0 // indirect + go.uber.org/zap v1.21.0 // indirect k8s.io/klog/v2 v2.60.1 // indirect k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect diff --git a/go.sum b/go.sum index 5d9e68acf..454a6f290 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,7 @@ cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxK cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= @@ -17,7 +18,6 @@ cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKV cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.66.0/go.mod h1:dgqGAjKCDxyhGTtC9dAREQGUJpkceNm1yt590Qno0Ko= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= @@ -51,6 +51,7 @@ cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLq cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= cloud.google.com/go/iam v0.1.0/go.mod h1:vcUNEa0pEm0qRVpmWepWaFMIAI8/hjB9mO8rNCJtF6c= cloud.google.com/go/iam v0.3.0 h1:exkAomrVUuzx9kWFI1wm3KI0uoDeUFPB4kKGzx6x+Gc= cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= @@ -68,68 +69,71 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= 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.12.0/go.mod h1:fFLk2dp2oAhDz8QFKwqrjdJvxSp/W2g7nillojlL5Ho= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= cloud.google.com/go/storage v1.22.0 h1:NUV0NNp9nkBuW66BFRLuMgldN60C57ET3dhbwLIYio8= cloud.google.com/go/storage v1.22.0/go.mod h1:GbaLEoMqbVm6sx3Z0R++gSiBlgMv6yUi2q1DeGFKQgE= contrib.go.opencensus.io/exporter/stackdriver v0.13.1/go.mod h1:z2tyTZtPmQ2HvWH4cOmVDgtY+1lomfKdbLnkJvZdc8c= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/azure-sdk-for-go v62.3.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v63.4.0+incompatible h1:fle3M5Q7vr8auaiPffKyUQmLbvYeqpw30bKU6PrWJFo= github.com/Azure/azure-sdk-for-go v63.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v0.21.1/go.mod h1:fBF9PQNqB8scdgpZ3ufzaLntG0AG7C1WjPMsiFOmfHM= +github.com/Azure/azure-sdk-for-go/sdk/azcore v0.23.0/go.mod h1:w5pDIZuawUmY3Bj4tVx3Xb8KS96ToB0j315w9rqpAg0= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.23.1 h1:3CVsSo4mp8NDWO11tHzN/mdo2zP0CtaSK5IcwBjfqRA= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.23.1/go.mod h1:w5pDIZuawUmY3Bj4tVx3Xb8KS96ToB0j315w9rqpAg0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.14.0 h1:NVS/4LOQfkBpk+B1VopIzv1ptmYeEskA8w/3K/w7vjo= -github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.14.0/go.mod h1:RG0cZndeZM17StwohYclmcXSr4oOJ8b1I5hB8llIc6Y= +github.com/Azure/azure-sdk-for-go/sdk/internal v0.9.1/go.mod h1:KLF4gFr6DcKFZwSuH8w8yEK6DpFl3LP5rhdvAb7Yz5I= github.com/Azure/azure-sdk-for-go/sdk/internal v0.9.2 h1:Px2KVERcYEg2Lv25AqC2hVr0xUWaq94wuEObLIkYzmA= github.com/Azure/azure-sdk-for-go/sdk/internal v0.9.2/go.mod h1:CdSJQNNzZhCkwDaV27XV1w48ZBPtxe7mlrZAsPNxD5g= -github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.0 h1:0nJeKDmB7a1a8RDMjTltahlPsaNlWjq/LpkZleSwINk= github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.4.0/go.mod h1:mbwxKc/fW+IkF0GG591MuXw0KuEQBDkeRoZ9vmVJPxg= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= +github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= 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= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= -github.com/Azure/go-autorest/autorest v0.11.17/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= +github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630= github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA= github.com/Azure/go-autorest/autorest v0.11.27 h1:F3R3q42aWytozkV8ihzcgMO4OA4cuqr3bNlsEuF6//A= github.com/Azure/go-autorest/autorest v0.11.27/go.mod h1:7l8ybrIdUmGqZMTD0sRtAr8NvbHjfofbf8RSP2q7w7U= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= -github.com/Azure/go-autorest/autorest/adal v0.9.10/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q= github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M= github.com/Azure/go-autorest/autorest/adal v0.9.18 h1:kLnPsRjzZZUF3K5REu/Kc+qMQrvuza2bwSnNdhmzLfQ= github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= +github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= +github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk= github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+ZtXWSmf4Tg= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= 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 v0.4.0 h1:WVsrXCnHlDDX8ls+tootqRE87/hL9S/g4ewig9RsD/c= +github.com/AzureAD/microsoft-authentication-library-for-go v0.4.0/go.mod h1:Vt9sXTKwMyGcOxSmLDMnGPgqsUg7m8pe215qMLrDXw4= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/datadog-go v3.4.1+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/datadog-go v4.0.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/opencensus-go-exporter-datadog v0.0.0-20191210083620-6965a1cfed68/go.mod h1:gMGUEe16aZh0QN941HgDjwrdjU4iTthPoz2/AtDRADE= -github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/DiSiqueira/GoTree v1.0.1-0.20180907134536-53a8e837f295/go.mod h1:e0aH495YLkrsIe9fhedd6aSR6fgU/qhKvtroi6y7G/M= +github.com/GoogleCloudPlatform/spark-on-k8s-operator v0.0.0-20200723154620-6f35a1152625/go.mod h1:6PnrZv6zUDkrNMw0mIoGRmGBR7i9LulhKPmxFq4rUiM= +github.com/Jeffail/gabs/v2 v2.5.1/go.mod h1:xCn81vdHKxFUuWWAaD5jCTQDNPBMh5pPs9IJ+NcziBI= github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= @@ -144,8 +148,11 @@ github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8 github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= +github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/Selvatico/go-mocket v1.0.7 h1:sXuFMnMfVL9b/Os8rGXPgbOFbr4HJm8aHsulD/uMTUk= @@ -156,8 +163,9 @@ github.com/Shopify/sarama v1.26.4 h1:+17TxUq/PJEAfZAll0T7XJjSgQWCpaQSoki/x5yN8o8 github.com/Shopify/sarama v1.26.4/go.mod h1:NbSGBSSndYaIhRcBtY9V0U7AyH+x71bG668AuWys/yU= github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= -github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= +github.com/adammck/venv v0.0.0-20160819025605-8a9c907a37d3/go.mod h1:3zXR2a/VSQndtpShh783rUTaEA2mpqN2VqZclBARBc0= +github.com/adammck/venv v0.0.0-20200610172036-e77789703e7c/go.mod h1:3zXR2a/VSQndtpShh783rUTaEA2mpqN2VqZclBARBc0= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -165,33 +173,39 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= -github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= -github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU= -github.com/aws/aws-sdk-go v1.23.4/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/amazon-sagemaker-operator-for-k8s v1.0.1-0.20210303003444-0fb33b1fd49d/go.mod h1:mZUP7GJmjiWtf8v3FD1X/QdK08BqyeH/1Ejt0qhNzCs= github.com/aws/aws-sdk-go v1.23.19/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.31.3/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= -github.com/aws/aws-sdk-go v1.37.1/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= +github.com/aws/aws-sdk-go v1.37.3/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/aws/aws-sdk-go v1.44.2 h1:5VBk5r06bgxgRKVaUtm1/4NT/rtrnH2E4cnAYv5zgQc= github.com/aws/aws-sdk-go v1.44.2/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= -github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= +github.com/aws/aws-sdk-go-v2 v1.0.0/go.mod h1:smfAbmpW+tcRVuNUjo3MOArSZmW72t62rkCzc2i0TWM= +github.com/aws/aws-sdk-go-v2 v1.2.0/go.mod h1:zEQs02YRBw1DjK0PoJv3ygDYOFTre1ejlJWl8FwAuQo= +github.com/aws/aws-sdk-go-v2/config v1.0.0/go.mod h1:WysE/OpUgE37tjtmtJd8GXgT8s1euilE5XtUkRNUQ1w= +github.com/aws/aws-sdk-go-v2/credentials v1.0.0/go.mod h1:/SvsiqBf509hG4Bddigr3NB12MIpfHhZapyBurJe8aY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.0.0/go.mod h1:wpMHDCXvOXZxGCRSidyepa8uJHY4vaBGfY2/+oKU/Bc= +github.com/aws/aws-sdk-go-v2/service/athena v1.0.0/go.mod h1:qY8QFbemf2ceqweXcS6hQqiiIe1z42WqTvHsK2Lb0rE= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.0.0/go.mod h1:3jExOmpbjgPnz2FJaMOfbSk1heTkZ66aD3yNtVhnjvI= +github.com/aws/aws-sdk-go-v2/service/sts v1.0.0/go.mod h1:5f+cELGATgill5Pu3/vK3Ebuigstc+qYEHW5MvGWZO4= github.com/aws/aws-xray-sdk-go v0.9.4/go.mod h1:XtMKdBQfpVut+tJEwI7+dJFRxxRdxHDyVNp2tHXRq04= +github.com/aws/smithy-go v1.0.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= +github.com/aws/smithy-go v1.1.0/go.mod h1:EzMw8dbp/YJL4A5/sbhGddag+NPT7q084agLbB9LgIw= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= @@ -203,12 +217,22 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= +github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/blackshark-ai/flyteidl v0.24.22-0.20221215141908-3e44057796c6 h1:ekMpKRTsX2FjEIP2WCWrdOAfvg9nwoObBkJCCnksQaM= +github.com/blackshark-ai/flyteidl v0.24.22-0.20221215141908-3e44057796c6/go.mod h1:sgOlQA2lnugarwSN8M+9gWoCZmzYNFI8gpShZrm+wmo= +github.com/blackshark-ai/flyteplugins v1.0.2-0.20221215151032-3ce2c1315081 h1:Qxsd2LWl44bfLn75MHrPv32P1PhPZ9fajg39eHZ/a7g= +github.com/blackshark-ai/flyteplugins v1.0.2-0.20221215151032-3ce2c1315081/go.mod h1:ZbZVBxEWh8Icj1AgfNKg0uPzHHGd9twa4eWcY2Yt6xE= +github.com/blackshark-ai/flytepropeller v0.16.48-0.20221215161838-a505ae7f1062 h1:YsvNz+6O3EJ4+SmuNvaVDly28i/srudS4TVk9GxqUms= +github.com/blackshark-ai/flytepropeller v0.16.48-0.20221215161838-a505ae7f1062/go.mod h1:8TkbXE8oinqU+FBgUWUeewr6X40GpGpVxodiKxGuXGY= +github.com/blackshark-ai/flytestdlib v1.0.1-0.20221215152838-ded77ffa67cf h1:tKQlA5yx6BVA9W2zJl60b60nTOgZKTP8Uk9xIQfhDMA= +github.com/blackshark-ai/flytestdlib v1.0.1-0.20221215152838-ded77ffa67cf/go.mod h1:RpZN5PTZ4081mOvsmciE5E/Q817//fT3i/dhq2aXmCY= +github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmatcuk/doublestar/v2 v2.0.3/go.mod h1:QMmcs3H2AUQICWhfzLXz+IYln8lRQmTZRptLie8RgRw= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737 h1:rRISKWyXfVxvoa702s91Zl5oREZTrR3yv+tXrrX7G/g= github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60= -github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= @@ -226,7 +250,8 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cihub/seelog v0.0.0-20170130134532-f561c5e57575/go.mod h1:9d6lWj8KzO/fd/NrVaLscBKmPigpZpn5YawRPw+e3Yo= -github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= +github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= +github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.8.0 h1:hRguaVL9rVsO8PMOpKSZ5gYZ2kjGRCvuKw4yMlfsBtg= github.com/cloudevents/sdk-go/binding/format/protobuf/v2 v2.8.0/go.mod h1:Ba4CS2d+naAK8tGd6nm5ftGIWuHim+1lryAaIxhuh1k= @@ -273,9 +298,9 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= @@ -300,9 +325,9 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/dnaeon/go-vcr v1.1.0 h1:ReYa/UBrRyQdant9B4fNHGoCNKw6qh6P0fsdGmZpR7c= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= -github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= -github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -318,7 +343,6 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8 github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0 h1:YOEu7KNc61ntiQlcEeUIoDTJ2o8mQznoNvUhiigpIqc= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= @@ -339,12 +363,15 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go. github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ernesto-jimenez/gogen v0.0.0-20180125220232-d7d4131e6607/go.mod h1:Cg4fM0vhYWOZdgM7RIOSTRNIc8/VT7CXClC3Ni86lu4= +github.com/evanphx/json-patch v0.0.0-20200808040245-162e5629780b/go.mod h1:NAJj0yf/KaRKURN6nyi7A9IZydMivZEm9oQLWNjfKDc= +github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= @@ -352,16 +379,6 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/flyteorg/flyteidl v1.2.5 h1:oPs0PX9opR9JtWjP5ZH2YMChkbGGL45PIy+90FlaxYc= -github.com/flyteorg/flyteidl v1.2.5/go.mod h1:OJAq333OpInPnMhvVz93AlEjmlQ+t0FAD4aakIYE4OU= -github.com/flyteorg/flyteplugins v1.0.20 h1:8ZGN2c0iaZa3d/UmN2VYozLBRhthAIO48aD5g8Wly7s= -github.com/flyteorg/flyteplugins v1.0.20/go.mod h1:ZbZVBxEWh8Icj1AgfNKg0uPzHHGd9twa4eWcY2Yt6xE= -github.com/flyteorg/flytepropeller v1.1.51 h1:ITPH2Fqx+/1hKBFnfb6Rawws3VbEJ3tQ/1tQXSIXvcQ= -github.com/flyteorg/flytepropeller v1.1.51/go.mod h1:zstMUz30mIskZB4uMkObzOj3CjsGfXIV/+nVxlOmI7I= -github.com/flyteorg/flytestdlib v1.0.0/go.mod h1:QSVN5wIM1lM9d60eAEbX7NwweQXW96t5x4jbyftn89c= -github.com/flyteorg/flytestdlib v1.0.14 h1:P6hy9yVrIEUxp4JaxV7/KwTSTYjHGizQu1fKXYkq9Y8= -github.com/flyteorg/flytestdlib v1.0.14/go.mod h1:nIBmBHtjTJvhZEn3e/EwVC/iMkR2tUX8hEiXjRBpH/s= -github.com/flyteorg/stow v0.3.3/go.mod h1:HBld7ud0i4khMHwJjkO8v+NSP7ddKa/ruhf4I8fliaA= github.com/flyteorg/stow v0.3.6 h1:jt50ciM14qhKBaIrB+ppXXY+SXB59FNREFgTJqCyqIk= github.com/flyteorg/stow v0.3.6/go.mod h1:5dfBitPM004dwaZdoVylVjxFT4GWAgI0ghAndhNUzCo= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= @@ -370,8 +387,6 @@ github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoD github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= -github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= -github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/frankban/quicktest v1.4.1/go.mod h1:36zfPVQyHxymz4cH7wlDmVwDrJuljRB60qkgn7rorfQ= github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= github.com/frankban/quicktest v1.10.0 h1:Gfh+GAJZOAoKZsIZeZbdn2JF10kN1XHNvjsvQK8gVkE= @@ -385,6 +400,8 @@ github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49P github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= +github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/go-bindata/go-bindata v3.1.1+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= 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= @@ -393,37 +410,76 @@ github.com/go-gormigrate/gormigrate/v2 v2.0.0 h1:e2A3Uznk4viUC4UuemuVgsNnvYZyOA8 github.com/go-gormigrate/gormigrate/v2 v2.0.0/go.mod h1:YuVJ+D/dNt4HWrThTBnjgZuRbt7AuwINeg4q52ZE3Jw= 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/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.2.1/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= +github.com/go-logr/zapr v0.2.0/go.mod h1:qhKdvif7YF5GI9NWEpyxTSSBdGmzkNguibrdCNVPunU= github.com/go-logr/zapr v1.2.0 h1:n4JnPI1T3Qq1SFEi/F8rwLrZERp2bso19PJZDB9dayk= github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro= +github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= +github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= +github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk= +github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU= +github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0= +github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94= +github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= +github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= +github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= +github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= +github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= +github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= +github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs= +github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk= +github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA= +github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64= +github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4= +github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= +github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= +github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU= +github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY= +github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU= +github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= +github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= +github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= +github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= +github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= +github.com/go-redis/redis v6.15.7+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M= github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/gobuffalo/attrs v0.1.0/go.mod h1:fmNpaWyHM0tRm8gCZWKx8yY9fvaNLo2PyzBNSrBZ5Hw= @@ -672,6 +728,7 @@ github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXP github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c= +github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ= @@ -701,6 +758,7 @@ github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71 github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= +github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -727,6 +785,7 @@ github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/cel-go v0.9.0/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= github.com/google/cel-go v0.10.1/go.mod h1:U7ayypeSkw23szu4GaQTPJGx66c20mx8JklMSxrmI1w= github.com/google/cel-spec v0.6.0/go.mod h1:Nwjgxy5CbjlPrtCWjeDjUyKMl8w41YBYGjsyDdqk0xA= github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54= @@ -765,12 +824,12 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -789,10 +848,16 @@ github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0 github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= github.com/googleapis/gax-go/v2 v2.3.0 h1:nRJtk3y8Fm770D42QV6T90ZnvFZyk7agSo3Q+Z9p3WI= github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2HZ2JwRxfA2tA= github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gopherjs/gopherjs v0.0.0-20181004151105-1babbf986f6f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= @@ -831,22 +896,31 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFb github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69 h1:7xsUJsB2NrdcttQPa7JLEaGzvdbk7KvfrjgHZXOQRo0= github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69/go.mod h1:YLEMZOtU+AZ7dhN9T/IpGhXVGly2bvkJQ+zxj3WeVQo= github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= +github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= +github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -856,18 +930,22 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo= github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= @@ -937,6 +1015,7 @@ github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.2.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jarcoal/httpmock v1.2.0/go.mod h1:oCoTsnAz4+UoOUIf5lJOWV2QQIW5UoeUI6aM2YnWAZk= github.com/jcmturner/gofork v0.0.0-20190328161633-dc7c13fece03/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= @@ -970,6 +1049,7 @@ github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -1005,9 +1085,8 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxv github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= @@ -1015,7 +1094,10 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kubeflow/common v0.4.3/go.mod h1:Qb/5aON7/OWVkN8OnjRqqT0i8X/XzMekRIZ8lkLosj4= +github.com/kubeflow/training-operator v1.5.0-rc.0/go.mod h1:xgcu/ZI/RwKbTvYgzU7ZWFpxbsefSey5We3KmKroALY= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lestrrat-go/backoff/v2 v2.0.7 h1:i2SeK33aOFJlUNJZzf2IpXRBvqBBnaGXfY5Xaop/GsE= github.com/lestrrat-go/backoff/v2 v2.0.7/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= github.com/lestrrat-go/codegen v1.0.0/go.mod h1:JhJw6OQAuPEfVKUCLItpaVLumDGWQznd1VaXrBk9TdM= @@ -1038,18 +1120,20 @@ github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= -github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= github.com/luna-duclos/instrumentedsql v0.0.0-20181127104832-b7d587d28109/go.mod h1:PWUIzhtavmOR965zfawVsHXbEuU1G29BPZ/CB3C7jXk= github.com/luna-duclos/instrumentedsql v1.1.2/go.mod h1:4LGbEqDnopzNAiyxPPDXhLspyunZxgPTMJBKtC6U0BQ= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= +github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= @@ -1078,7 +1162,6 @@ github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcncea github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= @@ -1088,6 +1171,7 @@ github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= @@ -1105,10 +1189,14 @@ github.com/mattn/goveralls v0.0.6/go.mod h1:h8b4ow6FxSPMQHF6o2ve3qsclnffZjYTNEKm github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/maxatome/go-testdeep v1.11.0/go.mod h1:011SgQ6efzZYAen6fDn4BqQ+lUR72ysdyKe7Dyogw70= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= +github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= @@ -1123,6 +1211,8 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= +github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -1135,6 +1225,7 @@ github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3P github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q= +github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -1142,23 +1233,15 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8m github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg= -github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU= -github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k= -github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w= -github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= -github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= -github.com/ncw/swift v1.0.49/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/ncw/swift v1.0.53 h1:luHjjTNtekIEvHg5KdAFIBaH7bWfNkefwFnpDffSIks= github.com/ncw/swift v1.0.53/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oleiade/reflections v1.0.0 h1:0ir4pc6v8/PJ0yw5AEtMddfXpWBXg9cnG7SgSoJuCgY= github.com/oleiade/reflections v1.0.0/go.mod h1:RbATFBbKYkVdqmSFtx13Bb/tVhR0lgOBXunWTZKeL4w= @@ -1173,7 +1256,12 @@ github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+ github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -1182,22 +1270,24 @@ github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/onsi/gomega v1.6.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= -github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.1-0.20190913142402-a7454ce5950e/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4= +github.com/orcaman/concurrent-map v1.0.0/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI= github.com/ory/analytics-go/v4 v4.0.0/go.mod h1:FMx9cLRD9xN+XevPvZ5FDMfignpmcqPP6FUKnJ9/MmE= github.com/ory/dockertest v3.3.5+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs= github.com/ory/dockertest/v3 v3.5.4/go.mod h1:J8ZUbNB2FOhm1cFZW9xBpDsODqsSWcyYgtJYVPcnF70= @@ -1224,25 +1314,23 @@ github.com/ory/x v0.0.93/go.mod h1:lfcTaGXpTZs7IEQAW00r9EtTCOxD//SiP5uWtNiz31g= github.com/ory/x v0.0.110/go.mod h1:DJfkE3GdakhshNhw4zlKoRaL/ozg/lcTahA9OCih2BE= github.com/ory/x v0.0.162 h1:xE/UBmmMlInTvlgGXUyo+VeZAcWU5gyWb/xh6jmBWsI= github.com/ory/x v0.0.162/go.mod h1:sj3z/MeCrAyNFFTfN6yK1nTmHXGSFnw+QwIIQ/Rowec= -github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= -github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.0-beta.8 h1:dy81yyLYJDwMTifq24Oi/IslOslRrDSb3jwDggjz3Z0= github.com/pelletier/go-toml/v2 v2.0.0-beta.8/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= -github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.2.6+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.4.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4 v2.5.2+incompatible h1:WCjObylUIOlKy/+7Abdn34TLIkXiA4UWUMhxq9m9ZXI= @@ -1255,57 +1343,52 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA= -github.com/pkg/sftp v1.10.0/go.mod h1:NxmoDg/QLVWluQDUYG7XBZTLUpKeFa8e3aMf1BfjyHk= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= +github.com/pkg/sftp v1.13.4/go.mod h1:LzqnAvaD5TWeNBsZpfKxSYn1MbjWwOsCIAFFJbpIsK8= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= +github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 h1:0XM1XL/OFFJjXsYXlG30spTkV/E9+gmd5GD1w2HE8xM= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/pquerna/ffjson v0.0.0-20190813045741-dac163c6c0a9/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= +github.com/pquerna/ffjson v0.0.0-20190930134022-aa0246cd15f7/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v0.9.4/go.mod h1:oCXIBxdI62A4cR6aTRJCgetEjecSIYzOEaeAn4iYEpM= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= +github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.9.0/go.mod h1:FqZLKOZnGdFAhOK4nqGHa7D66IdsO+O441Eve7ptJDU= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= +github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.15.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.3.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/ray-project/kuberay/ray-operator v0.0.0-20220728052838-eaa75fa6707c/go.mod h1:uLBlYqsCS2nsKiVlxJxI5EVgq8CrqNeHDP5uq3hde+c= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 h1:MkV+77GLUNo5oJ0jf870itWm3D0Sjh7+Za9gazKc5LQ= @@ -1329,7 +1412,7 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sagikazarmark/crypt v0.5.0/go.mod h1:l+nzl7KWh51rpzp2h7t4MZWyiEWdhNpOAnclKvg+mdA= github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4= github.com/santhosh-tekuri/jsonschema/v2 v2.1.0/go.mod h1:yzJzKUGV4RbWqWIBBP4wSOBqavX5saE02yirLS0OTyg= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -1377,7 +1460,6 @@ github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a/go.mod h1:X github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= -github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= @@ -1386,7 +1468,6 @@ github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B github.com/spf13/afero v1.2.0/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.3.2/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= -github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= @@ -1400,8 +1481,8 @@ github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= +github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= @@ -1419,14 +1500,12 @@ github.com/spf13/viper v1.3.1/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= github.com/spf13/viper v1.11.0 h1:7OX/1FS6n7jHD1zGrZTM7WtY13ZELRyosK4k93oPr44= github.com/spf13/viper v1.11.0/go.mod h1:djo0X/bA5+tYVoCn+C7cAYJGcVn/qYLFTG8gdUsX7Zk= github.com/sqs/goreturns v0.0.0-20181028201513-538ac6014518/go.mod h1:CKI4AZ4XmGV240rTHfO0hfE83S6/a3/Q1siZJ/vXf7A= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= -github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -1452,6 +1531,7 @@ github.com/tinylib/msgp v1.1.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDW github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/uber-go/atomic v1.3.2/go.mod h1:/Ct5t2lcmbJ4OSe/waGBoaVvVqtO0bmtfVNex1PFV8g= github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= github.com/uber/jaeger-client-go v2.22.1+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= @@ -1464,11 +1544,10 @@ github.com/unionai/cron/v3 v3.0.2-0.20210825070134-bfc34418fe84/go.mod h1:eQICP3 github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/vektra/mockery v1.1.2/go.mod h1:VcfZjKaFOPO+MpN4ZvwPjs4c48lkq1o3Ym8yHZJu0jU= +github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -1480,7 +1559,9 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= go.elastic.co/apm v1.8.0/go.mod h1:tCw6CkOJgkWnzEthFN9HUP1uL3Gjc/Ur6m7gRPLaoH0= @@ -1489,20 +1570,26 @@ go.elastic.co/apm/module/apmot v1.8.0/go.mod h1:Q5Xzabte8G/fkvDjr1jlDuOSUt9hkVWN go.elastic.co/fastjson v1.0.0/go.mod h1:PmeUOMMtLHQr9ZS9J9owrAVg0FkaZDRZJEFTTGHtchs= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200819165624-17cef6e3e9d5/go.mod h1:skWido08r9w6Lq/w70DO5XYIKMu4QFu1+4VsqLQuJy8= go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs= +go.etcd.io/etcd/api/v3 v3.5.2/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= +go.etcd.io/etcd/client/pkg/v3 v3.5.2/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ= +go.etcd.io/etcd/client/v2 v2.305.2/go.mod h1:2D7ZejHVMIfog1221iLSYlQRzrtECw3kz4I4VAQm3qI= go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0= go.etcd.io/etcd/client/v3 v3.5.1/go.mod h1:OnjH4M8OnAotwaB2l9bVgZzRFKru7/ZMoS46OtKyd3Q= go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE= go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc= go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= +go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= +go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= @@ -1510,7 +1597,6 @@ go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opencensus.io v0.22.6/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc= @@ -1532,24 +1618,31 @@ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.5.1/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= +go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= +go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= +go.uber.org/zap v1.8.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= +go.uber.org/zap v1.15.0/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= -go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI= go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= +go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= +go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180830192347-182538f80094/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -1567,7 +1660,9 @@ golang.org/x/crypto v0.0.0-20181127143415-eb0de9b17e85/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190102171810-8d7daa0c54b3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190103213133-ff983b9c42bc/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= @@ -1575,28 +1670,36 @@ golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/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-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/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-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191122220453-ac88ee75c92c/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200204104054-c9f3fb736b72/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200320181102-891825fb96df/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20201217014255-9d1352758620/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1643,6 +1746,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/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-20180816102801-aaf60122140d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1661,9 +1766,9 @@ golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181207154023-610586996380/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-20190125091013-d26f9f9a57f3/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-20190320064053-1272bf9dcd53/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= @@ -1677,6 +1782,7 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191003171128-d98b1b443823/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= @@ -1693,7 +1799,6 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/ 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-20200904194848-62affa334b73/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 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= @@ -1705,6 +1810,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v 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-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/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= @@ -1716,6 +1823,8 @@ golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1727,14 +1836,15 @@ golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210126194326-f9ce19ea3013/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= @@ -1753,6 +1863,7 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1772,14 +1883,15 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181106135930-3a76605856fd/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181206074257-70b957f3b65e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190102155601-82a175fd1598/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190116161447-11f53e031339/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1793,14 +1905,17 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191022100944-742c48ecaeb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1824,19 +1939,20 @@ 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-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200828194041-157a740278f4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/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-20201214210602-f9fddec55a1e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-20210303074136-134d130e1a04/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= @@ -1852,11 +1968,14 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/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-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1864,14 +1983,21 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/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-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/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-20220608164250-635b8c9b7f68/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY= golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +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= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1886,19 +2012,17 @@ golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181003024731-2f84ea8ef872/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181006002542-f60d9635b16a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181008205924-a2b3f7f249e9/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181013182035-5e66757b835f/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181017214349-06f26fdaaa28/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181024171208-a2dc47679d30/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1920,6 +2044,7 @@ golang.org/x/tools v0.0.0-20190104182027-498d95493402/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190111214448-fc1d57b08d7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190118193359-16909d206f00/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -1933,6 +2058,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190613204242-ed0dc450797f/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624190245-7f2218787638/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -1940,7 +2066,9 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190711191110-9a621aea19f8/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1969,26 +2097,25 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200323144430-8dcfad9e016e/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200721223218-6123e77877b2/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200828161849-5deb26317202/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20200915173823-2db8f0ff891c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -1999,8 +2126,10 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM= golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= +golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4= golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2012,14 +2141,15 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= +gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= gonum.org/v1/gonum v0.6.2/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/netlib v0.0.0-20191229114700-bbb4dff026f8/go.mod h1:2IgXn/sJaRbePPBA1wRj8OE+QLvVaH0q8SK6TSTKlnk= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= gonum.org/v1/plot v0.0.0-20200111075622-4abb28f724d5/go.mod h1:+HbaZVpsa73UwN7kXGCECULRHovLRJjH+t5cFPgxErs= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -2038,14 +2168,12 @@ google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.31.0/go.mod h1:CL+9IBCa2WWU6gRuBWaKqGWLFFwbEUXkfeMkHLQWYWo= -google.golang.org/api v0.32.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.38.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8= google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= @@ -2054,6 +2182,7 @@ google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6 google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= @@ -2078,7 +2207,6 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190626174449-989357319d63/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190708153700-3bdd9d9f5532/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= @@ -2108,10 +2236,7 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200831141814-d751682dd103/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200914193844-75d14daec038/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200921151605-7abf4a1a14d5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201102152239-715cce707fb0/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -2119,7 +2244,6 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210126160654-44e461bb6506/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210302174412-5ede27ff9881/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -2144,6 +2268,8 @@ google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEc google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= @@ -2164,7 +2290,6 @@ google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220426171045-31bebdecfb46 h1:G1IeWbjrqEq9ChWxEuRPJu6laA67+XgTFHVSAvepr38= google.golang.org/genproto v0.0.0-20220426171045-31bebdecfb46/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= @@ -2183,7 +2308,6 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= @@ -2225,13 +2349,11 @@ gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod 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= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/mold.v2 v2.2.0/go.mod h1:XMyyRsGtakkDPbxXbrA5VODo6bUXyvoDjLd5l3T0XoA= @@ -2257,7 +2379,7 @@ gopkg.in/jcmturner/gokrb5.v7 v7.5.0 h1:a9tsXlIDD9SKxotJMK3niV7rPZAJeX2aD/0yg3qlI gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= gopkg.in/jcmturner/rpc.v1 v1.1.0 h1:QHIUxTX1ISuAv9dD2wJ9HWQVuWDX/Zc0PfeC2tjc4rU= gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= -gopkg.in/kothar/go-backblaze.v0 v0.0.0-20190520213052-702d4e7eb465/go.mod h1:zJ2QpyDCYo1KvLXlmdnFlQAyF/Qfth0fB8239Qg7BIE= +gopkg.in/kothar/go-backblaze.v0 v0.0.0-20210124194846-35409b867216/go.mod h1:zJ2QpyDCYo1KvLXlmdnFlQAyF/Qfth0fB8239Qg7BIE= gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= @@ -2268,7 +2390,6 @@ gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/validator.v2 v2.0.0-20180514200540-135c24b11c19/go.mod h1:o4V0GXN9/CAmCsvJ0oXYZvrZOe7syiDZSN1GWGZTGzc= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -2280,6 +2401,7 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -2304,7 +2426,6 @@ gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -2313,37 +2434,83 @@ honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= -k8s.io/api v0.0.0-20210217171935-8e2decd92398/go.mod h1:60tmSUpHxGPFerNHbo/ayI2lKxvtrhbxFyXuEIWJd78= -k8s.io/api v0.20.2/go.mod h1:d7n6Ehyzx+S+cE3VhTGfVNNqtGc/oL9DCdYYahlurV8= +k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78= +k8s.io/api v0.18.6/go.mod h1:eeyxr+cwCjMdLAmr2W3RyDI0VvTawSg/3RFFBEnmZGI= +k8s.io/api v0.18.8/go.mod h1:d/CXqwWv+Z2XEG1LgceeDmHQwpUJhROPx16SlxJgERY= +k8s.io/api v0.19.6/go.mod h1:Plxx44Nh4zVblkJrIgxVPgPre1mvng6tXf1Sj3bs0fU= +k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg= +k8s.io/api v0.24.0/go.mod h1:5Jl90IUrJHUJYEMANRURMiVvJ0g7Ax7r3R1bqO8zx8I= k8s.io/api v0.24.1 h1:BjCMRDcyEYz03joa3K1+rbshwh1Ay6oB53+iUx2H8UY= k8s.io/api v0.24.1/go.mod h1:JhoOvNiLXKTPQ60zh2g0ewpA+bnEYf5q44Flhquh4vQ= +k8s.io/apiextensions-apiserver v0.18.2/go.mod h1:q3faSnRGmYimiocj6cHQ1I3WpLqmDgJFlKL37fC4ZvY= +k8s.io/apiextensions-apiserver v0.18.6/go.mod h1:lv89S7fUysXjLZO7ke783xOwVTm6lKizADfvUM/SS/M= +k8s.io/apiextensions-apiserver v0.23.0/go.mod h1:xIFAEEDlAZgpVBl/1VSjGDmLoXAWRG40+GsWhKhAxY4= +k8s.io/apiextensions-apiserver v0.24.0/go.mod h1:iuVe4aEpe6827lvO6yWQVxiPSpPoSKVjkq+MIdg84cM= k8s.io/apiextensions-apiserver v0.24.1 h1:5yBh9+ueTq/kfnHQZa0MAo6uNcPrtxPMpNQgorBaKS0= k8s.io/apiextensions-apiserver v0.24.1/go.mod h1:A6MHfaLDGfjOc/We2nM7uewD5Oa/FnEbZ6cD7g2ca4Q= -k8s.io/apimachinery v0.0.0-20210217011835-527a61b4dffe/go.mod h1:Z7ps/g0rjlTeMstYrMOUttJfT2Gg34DEaG/f2PYLCWY= +k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA= +k8s.io/apimachinery v0.18.6/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko= +k8s.io/apimachinery v0.18.8/go.mod h1:6sQd+iHEqmOtALqOFjSWp2KZ9F0wlU/nWm0ZgsYWMig= +k8s.io/apimachinery v0.19.6/go.mod h1:6sRbGRAVY5DOCuZwB5XkqguBqpqLU6q/kOaOdk29z6Q= k8s.io/apimachinery v0.20.2/go.mod h1:WlLqWAHZGg07AeltaI0MV5uk1Omp8xaN0JGLY6gkRpU= +k8s.io/apimachinery v0.23.0/go.mod h1:fFCTTBKvKcwTPFzjlcxp91uPFZr+JA0FubU4fLzzFYc= +k8s.io/apimachinery v0.24.0/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= k8s.io/apimachinery v0.24.1 h1:ShD4aDxTQKN5zNf8K1RQ2u98ELLdIW7jEnlO9uAMX/I= k8s.io/apimachinery v0.24.1/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= +k8s.io/apiserver v0.18.2/go.mod h1:Xbh066NqrZO8cbsoenCwyDJ1OSi8Ag8I2lezeHxzwzw= +k8s.io/apiserver v0.18.6/go.mod h1:Zt2XvTHuaZjBz6EFYzpp+X4hTmgWGy8AthNVnTdm3Wg= +k8s.io/apiserver v0.19.6/go.mod h1:05XquZxCDzQ27ebk7uV2LrFIK4lm5Yt47XkkUvLAoAM= +k8s.io/apiserver v0.23.0/go.mod h1:Cec35u/9zAepDPPFyT+UMrgqOCjgJ5qtfVJDxjZYmt4= +k8s.io/apiserver v0.24.0/go.mod h1:WFx2yiOMawnogNToVvUYT9nn1jaIkMKj41ZYCVycsBA= k8s.io/apiserver v0.24.1/go.mod h1:dQWNMx15S8NqJMp0gpYfssyvhYnkilc1LpExd/dkLh0= -k8s.io/client-go v0.0.0-20210217172142-7279fc64d847/go.mod h1:q0EaghmVye2uui19vxSZ2NG6ssgUWgjudO6vrwXneSI= +k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU= +k8s.io/client-go v0.18.6/go.mod h1:/fwtGLjYMS1MaM5oi+eXhKwG+1UHidUEXRh6cNsdO0Q= +k8s.io/client-go v0.18.8/go.mod h1:HqFqMllQ5NnQJNwjro9k5zMyfhZlOwpuTLVrxjkYSxU= +k8s.io/client-go v0.19.6/go.mod h1:gEiS+efRlXYUEQ9Oz4lmNXlxAl5JZ8y2zbTDGhvXXnk= +k8s.io/client-go v0.23.0/go.mod h1:hrDnpnK1mSr65lHHcUuIZIXDgEbzc7/683c6hyG4jTA= +k8s.io/client-go v0.24.0/go.mod h1:VFPQET+cAFpYxh6Bq6f4xyMY80G6jKKktU6G0m00VDw= k8s.io/client-go v0.24.1 h1:w1hNdI9PFrzu3OlovVeTnf4oHDt+FJLd9Ndluvnb42E= k8s.io/client-go v0.24.1/go.mod h1:f1kIDqcEYmwXS/vTbbhopMUbhKp2JhOeVTfxgaCIlF8= +k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= +k8s.io/code-generator v0.18.6/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= +k8s.io/code-generator v0.19.6/go.mod h1:lwEq3YnLYb/7uVXLorOJfxg+cUu2oihFhHZ0n9NIla0= +k8s.io/code-generator v0.23.0/go.mod h1:vQvOhDXhuzqiVfM/YHp+dmg10WDZCchJVObc9MvowsE= +k8s.io/code-generator v0.24.0/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w= k8s.io/code-generator v0.24.1/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w= +k8s.io/component-base v0.18.2/go.mod h1:kqLlMuhJNHQ9lz8Z7V5bxUUtjFZnrypArGl58gmDfUM= +k8s.io/component-base v0.18.6/go.mod h1:knSVsibPR5K6EW2XOjEHik6sdU5nCvKMrzMt2D4In14= +k8s.io/component-base v0.19.6/go.mod h1:8Btsf8J00/fVDa/YFmXjei7gVkcFrlKZXjSeP4SZNJg= +k8s.io/component-base v0.23.0/go.mod h1:DHH5uiFvLC1edCpvcTDV++NKULdYYU6pR9Tt3HIKMKI= +k8s.io/component-base v0.24.0/go.mod h1:Dgazgon0i7KYUsS8krG8muGiMVtUZxG037l1MKyXgrA= k8s.io/component-base v0.24.1 h1:APv6W/YmfOWZfo+XJ1mZwep/f7g7Tpwvdbo9CQLDuts= k8s.io/component-base v0.24.1/go.mod h1:DW5vQGYVCog8WYpNob3PMmmsY8A3L9QZNg4j/dV3s38= +k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20200428234225-8167cfdcfc14/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo v0.0.0-20211129171323-c02415ce4185/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.4.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.5.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= +k8s.io/kube-openapi v0.0.0-20200410145947-61e04a5be9a6/go.mod h1:GRQhZsXIAJ1xR0C9bd8UpWHZ5plfAS9fzPjJuQ6JL3E= +k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o= k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= +k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 h1:Gii5eqf+GmIEwGNKQYQClCayuJCe2/4fZUvF7VG99sU= k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= -k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20200324210504-a9aa75ae1b89/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 h1:HNSDgDCrr/6Ly3WEGKZftiE7IY19Vz2GdbOCyI4qqhc= k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= @@ -2355,18 +2522,29 @@ rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8 rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7/go.mod h1:PHgbrJT7lCHcxMU+mDHEm+nx46H4zuuHZkDP6icnhu0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.9/go.mod h1:dzAXnQbTRyDlZPJX2SUPEqvnB+j7AJjtlox7PEwigU0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.25/go.mod h1:Mlj9PNLmG9bZ6BHFwFKDo5afkpWyUISkb9Me0GnK66I= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30/go.mod h1:fEO7lRTdivWO2qYVCVG7dEADOMo/MLDCVr8So2g88Uw= +sigs.k8s.io/controller-runtime v0.6.2/go.mod h1:vhcq/rlnENJ09SIRp3EveTaZ0yqH526hjf9iJdbUJ/E= +sigs.k8s.io/controller-runtime v0.11.1/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA= sigs.k8s.io/controller-runtime v0.12.1 h1:4BJY01xe9zKQti8oRjj/NeHKRXthf1YkYJAgLONFFoI= sigs.k8s.io/controller-runtime v0.12.1/go.mod h1:BKhxlA4l7FPK4AQcsuL4X6vZeWnKDXez/vp1Y8dxTU0= +sigs.k8s.io/controller-tools v0.3.0/go.mod h1:enhtKGfxZD1GFEoMgP8Fdbu+uKQ/cq1/WGJhdVChfvI= +sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124 h1:2sgAQQcY0dEW2SsQwTXhQV4vO6+rSslYx8K3XmM5hqQ= sigs.k8s.io/json v0.0.0-20220525155127-227cbc7cc124/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0-20200116222232-67a7b8c61874/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= +sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= -sigs.k8s.io/structured-merge-diff/v4 v4.0.3/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= +sigs.k8s.io/structured-merge-diff/v4 v4.2.0/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo= sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= -sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= +volcano.sh/apis v1.2.0-k8s1.19.6/go.mod h1:UaeJ/s5Hyd+ZhFLc+Kw9YlgM8gRZ/5OzXqHa0yKOoXY= diff --git a/pkg/manager/impl/cache_manager.go b/pkg/manager/impl/cache_manager.go new file mode 100644 index 000000000..8e4039db4 --- /dev/null +++ b/pkg/manager/impl/cache_manager.go @@ -0,0 +1,463 @@ +package impl + +import ( + "context" + "strings" + "time" + + "github.com/golang/protobuf/proto" + "github.com/prometheus/client_golang/prometheus" + + "github.com/flyteorg/flyteadmin/pkg/manager/impl/shared" + "github.com/flyteorg/flyteadmin/pkg/manager/impl/util" + "github.com/flyteorg/flyteadmin/pkg/manager/impl/validation" + "github.com/flyteorg/flyteadmin/pkg/manager/interfaces" + repoInterfaces "github.com/flyteorg/flyteadmin/pkg/repositories/interfaces" + "github.com/flyteorg/flyteadmin/pkg/repositories/models" + "github.com/flyteorg/flyteadmin/pkg/repositories/transformers" + runtimeInterfaces "github.com/flyteorg/flyteadmin/pkg/runtime/interfaces" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/core" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/service" + "github.com/flyteorg/flyteplugins/go/tasks/pluginmachinery/catalog" + "github.com/flyteorg/flytepropeller/pkg/apis/flyteworkflow/v1alpha1" + "github.com/flyteorg/flytestdlib/catalog/datacatalog" + "github.com/flyteorg/flytestdlib/logger" + "github.com/flyteorg/flytestdlib/promutils" +) + +var ( + _ interfaces.CacheInterface = &CacheManager{} +) + +var sortByCreatedAtAsc = &admin.Sort{Key: shared.CreatedAt, Direction: admin.Sort_ASCENDING} + +const ( + nodeExecutionLimit = 10000 + taskExecutionLimit = 10000 + reservationHeartbeat = 10 * time.Second +) + +type cacheMetrics struct { + Scope promutils.Scope + CacheEvictionTime promutils.StopWatch + CacheEvictionSuccess prometheus.Counter + CacheEvictionFailures prometheus.Counter +} + +type CacheManager struct { + db repoInterfaces.Repository + config runtimeInterfaces.Configuration + catalogClient catalog.Client + metrics cacheMetrics +} + +func (m *CacheManager) EvictExecutionCache(ctx context.Context, req service.EvictExecutionCacheRequest) (*service.EvictCacheResponse, error) { + if err := validation.ValidateWorkflowExecutionIdentifier(req.GetWorkflowExecutionId()); err != nil { + logger.Debugf(ctx, "EvictExecutionCache request [%+v] failed validation with err: %v", req, err) + return nil, err + } + + ctx = getExecutionContext(ctx, req.WorkflowExecutionId) + + executionModel, err := util.GetExecutionModel(ctx, m.db, *req.WorkflowExecutionId) + if err != nil { + logger.Debugf(ctx, "Failed to get workflow execution model for workflow execution ID %+v: %v", req.WorkflowExecutionId, err) + return nil, err + } + + logger.Debugf(ctx, "Starting to evict cache for execution %d of workflow %+v", executionModel.ID, req.WorkflowExecutionId) + + nodeExecutions, err := m.listAllNodeExecutionsForWorkflow(ctx, req.WorkflowExecutionId, "") + if err != nil { + logger.Debugf(ctx, "Failed to list all node executions for execution %d of workflow %+v: %v", executionModel.ID, req.WorkflowExecutionId, err) + return nil, err + } + + var evictionErrors []*core.CacheEvictionError + for _, nodeExecution := range nodeExecutions { + evictionErrors = m.evictNodeExecutionCache(ctx, nodeExecution, evictionErrors) + } + + logger.Debugf(ctx, "Finished evicting cache for execution %d of workflow %+v", executionModel.ID, req.WorkflowExecutionId) + return &service.EvictCacheResponse{ + Errors: &core.CacheEvictionErrorList{Errors: evictionErrors}, + }, nil +} + +func (m *CacheManager) EvictTaskExecutionCache(ctx context.Context, req service.EvictTaskExecutionCacheRequest) (*service.EvictCacheResponse, error) { + if err := validation.ValidateTaskExecutionIdentifier(req.GetTaskExecutionId()); err != nil { + logger.Debugf(ctx, "EvictTaskExecutionCache request [%+v] failed validation with err: %v", req, err) + return nil, err + } + + ctx = getTaskExecutionContext(ctx, req.TaskExecutionId) + + // Sanity check to ensure referenced task execution exists although only encapsulated node execution is strictly required + _, err := util.GetTaskExecutionModel(ctx, m.db, req.TaskExecutionId) + if err != nil { + logger.Debugf(ctx, "Failed to get task execution model for task execution ID %+v: %v", req.TaskExecutionId, err) + return nil, err + } + + logger.Debugf(ctx, "Starting to evict cache for execution %+v of task %+v", req.TaskExecutionId, req.TaskExecutionId.TaskId) + + nodeExecutionModel, err := util.GetNodeExecutionModel(ctx, m.db, req.TaskExecutionId.NodeExecutionId) + if err != nil { + logger.Debugf(ctx, "Failed to get node execution model for node execution ID %+v: %v", req.TaskExecutionId.NodeExecutionId, err) + return nil, err + } + + evictionErrors := m.evictNodeExecutionCache(ctx, *nodeExecutionModel, nil) + + logger.Debugf(ctx, "Finished evicting cache for execution %+v of task %+v", req.TaskExecutionId, req.TaskExecutionId.TaskId) + return &service.EvictCacheResponse{ + Errors: &core.CacheEvictionErrorList{Errors: evictionErrors}, + }, nil +} + +func (m *CacheManager) evictNodeExecutionCache(ctx context.Context, nodeExecutionModel models.NodeExecution, + evictionErrors []*core.CacheEvictionError) []*core.CacheEvictionError { + if strings.HasSuffix(nodeExecutionModel.NodeID, v1alpha1.StartNodeID) || strings.HasSuffix(nodeExecutionModel.NodeID, v1alpha1.EndNodeID) { + return evictionErrors + } + + nodeExecution, err := transformers.FromNodeExecutionModel(nodeExecutionModel) + if err != nil { + logger.Warnf(ctx, "Failed to transform node execution model %+v: %v", + nodeExecutionModel.NodeExecutionKey, err) + m.metrics.CacheEvictionFailures.Inc() + evictionErrors = append(evictionErrors, &core.CacheEvictionError{ + NodeExecutionId: &core.NodeExecutionIdentifier{ + NodeId: nodeExecutionModel.NodeID, + ExecutionId: &core.WorkflowExecutionIdentifier{ + Project: nodeExecutionModel.NodeExecutionKey.ExecutionKey.Project, + Domain: nodeExecutionModel.NodeExecutionKey.ExecutionKey.Domain, + Name: nodeExecutionModel.NodeExecutionKey.ExecutionKey.Name, + }, + }, + Code: core.CacheEvictionError_INTERNAL, + Message: "Internal error", + }) + return evictionErrors + } + + logger.Debugf(ctx, "Starting to evict cache for node execution %+v", nodeExecution.Id) + t := m.metrics.CacheEvictionTime.Start() + defer t.Stop() + + if nodeExecution.Metadata.IsParentNode { + var childNodeExecutions []models.NodeExecution + if nodeExecution.Metadata.IsDynamic { + var err error + childNodeExecutions, err = m.listAllNodeExecutionsForWorkflow(ctx, nodeExecution.Id.ExecutionId, nodeExecution.Id.NodeId) + if err != nil { + logger.Warnf(ctx, "Failed to list child node executions for dynamic node execution %+v: %v", + nodeExecution.Id, err) + m.metrics.CacheEvictionFailures.Inc() + evictionErrors = append(evictionErrors, &core.CacheEvictionError{ + NodeExecutionId: nodeExecution.Id, + Source: &core.CacheEvictionError_WorkflowExecutionId{ + WorkflowExecutionId: nodeExecution.Id.ExecutionId, + }, + Code: core.CacheEvictionError_INTERNAL, + Message: "Failed to list child node executions", + }) + return evictionErrors + } + } else { + childNodeExecutions = nodeExecutionModel.ChildNodeExecutions + } + for _, childNodeExecution := range childNodeExecutions { + evictionErrors = m.evictNodeExecutionCache(ctx, childNodeExecution, evictionErrors) + } + } + + taskExecutions, err := m.listAllTaskExecutions(ctx, nodeExecution.Id) + if err != nil { + logger.Warnf(ctx, "Failed to list task executions for node execution %+v: %v", + nodeExecution.Id, err) + m.metrics.CacheEvictionFailures.Inc() + evictionErrors = append(evictionErrors, &core.CacheEvictionError{ + NodeExecutionId: nodeExecution.Id, + Source: &core.CacheEvictionError_WorkflowExecutionId{ + WorkflowExecutionId: nodeExecution.Id.ExecutionId, + }, + Code: core.CacheEvictionError_INTERNAL, + Message: "Failed to list task executions", + }) + return evictionErrors + } + + switch md := nodeExecution.GetClosure().GetTargetMetadata().(type) { + case *admin.NodeExecutionClosure_TaskNodeMetadata: + for _, taskExecutionModel := range taskExecutions { + taskExecution, err := transformers.FromTaskExecutionModel(taskExecutionModel) + if err != nil { + logger.Warnf(ctx, "Failed to transform task execution model %+v: %v", + taskExecutionModel.TaskExecutionKey, err) + m.metrics.CacheEvictionFailures.Inc() + evictionErrors = append(evictionErrors, &core.CacheEvictionError{ + NodeExecutionId: nodeExecution.Id, + Source: &core.CacheEvictionError_TaskExecutionId{ + TaskExecutionId: taskExecution.Id, + }, + Code: core.CacheEvictionError_INTERNAL, + Message: "Internal error", + }) + return evictionErrors + } + + evictionErrors = m.evictTaskNodeExecutionCache(ctx, nodeExecutionModel, nodeExecution, taskExecution, + md.TaskNodeMetadata, evictionErrors) + } + case *admin.NodeExecutionClosure_WorkflowNodeMetadata: + evictionErrors = m.evictWorkflowNodeExecutionCache(ctx, nodeExecution, md.WorkflowNodeMetadata, evictionErrors) + default: + logger.Errorf(ctx, "Invalid target metadata type %T for node execution closure %+v for node execution %+v", + md, md, nodeExecution.Id) + m.metrics.CacheEvictionFailures.Inc() + evictionErrors = append(evictionErrors, &core.CacheEvictionError{ + NodeExecutionId: nodeExecution.Id, + Source: &core.CacheEvictionError_WorkflowExecutionId{ + WorkflowExecutionId: nodeExecution.Id.ExecutionId, + }, + Code: core.CacheEvictionError_INTERNAL, + Message: "Internal error", + }) + } + + return evictionErrors +} + +func (m *CacheManager) evictTaskNodeExecutionCache(ctx context.Context, nodeExecutionModel models.NodeExecution, + nodeExecution *admin.NodeExecution, taskExecution *admin.TaskExecution, + taskNodeMetadata *admin.TaskNodeMetadata, evictionErrors []*core.CacheEvictionError) []*core.CacheEvictionError { + if taskNodeMetadata == nil || (taskNodeMetadata.GetCacheStatus() != core.CatalogCacheStatus_CACHE_HIT && + taskNodeMetadata.GetCacheStatus() != core.CatalogCacheStatus_CACHE_POPULATED) { + logger.Debugf(ctx, "Node execution %+v did not contain cached data, skipping cache eviction", + nodeExecution.Id) + return evictionErrors + } + + datasetID := datacatalog.IdentifierToDatasetID(taskNodeMetadata.GetCatalogKey().GetDatasetId()) + artifactTag := taskNodeMetadata.GetCatalogKey().GetArtifactTag().GetName() + artifactID := taskNodeMetadata.GetCatalogKey().GetArtifactTag().GetArtifactId() + ownerID := taskExecution.GetClosure().GetMetadata().GetGeneratedName() + + reservation, err := m.catalogClient.GetOrExtendReservationByArtifactTag(ctx, datasetID, artifactTag, ownerID, + reservationHeartbeat) + if err != nil { + logger.Warnf(ctx, + "Failed to acquire reservation for artifact with tag %q for dataset %+v of node execution %+v: %v", + artifactTag, datasetID, nodeExecution.Id, err) + m.metrics.CacheEvictionFailures.Inc() + evictionErrors = append(evictionErrors, &core.CacheEvictionError{ + NodeExecutionId: nodeExecution.Id, + Source: &core.CacheEvictionError_TaskExecutionId{ + TaskExecutionId: taskExecution.Id, + }, + Code: core.CacheEvictionError_RESERVATION_NOT_ACQUIRED, + Message: "Failed to acquire reservation for artifact", + }) + return evictionErrors + } + + if len(reservation.GetOwnerId()) == 0 { + logger.Debugf(ctx, "Received empty owner ID for artifact of node execution %+v, assuming NOOP catalog, skipping cache eviction", + nodeExecution.Id) + return evictionErrors + } else if reservation.GetOwnerId() != ownerID { + logger.Debugf(ctx, "Artifact of node execution %+v is reserved by different owner, cannot evict cache", + nodeExecution.Id) + m.metrics.CacheEvictionFailures.Inc() + evictionErrors = append(evictionErrors, &core.CacheEvictionError{ + NodeExecutionId: nodeExecution.Id, + Source: &core.CacheEvictionError_TaskExecutionId{ + TaskExecutionId: taskExecution.Id, + }, + Code: core.CacheEvictionError_RESERVATION_NOT_ACQUIRED, + Message: "Artifact is reserved by different owner", + }) + return evictionErrors + } + + selectedFields := []string{shared.CreatedAt} + nodeExecutionModel.CacheStatus = nil + + taskNodeMetadata.CacheStatus = core.CatalogCacheStatus_CACHE_DISABLED + taskNodeMetadata.CatalogKey = nil + nodeExecution.Closure.TargetMetadata = &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: taskNodeMetadata, + } + + marshaledClosure, err := proto.Marshal(nodeExecution.Closure) + if err != nil { + logger.Warnf(ctx, "Failed to marshal updated closure for node execution %+v: err", + nodeExecution.Id, err) + m.metrics.CacheEvictionFailures.Inc() + evictionErrors = append(evictionErrors, &core.CacheEvictionError{ + NodeExecutionId: nodeExecution.Id, + Source: &core.CacheEvictionError_TaskExecutionId{ + TaskExecutionId: taskExecution.Id, + }, + Code: core.CacheEvictionError_INTERNAL, + Message: "Failed to marshal updated node execution closure", + }) + return evictionErrors + } + + nodeExecutionModel.Closure = marshaledClosure + selectedFields = append(selectedFields, shared.Closure) + + if err := m.db.NodeExecutionRepo().UpdateSelected(ctx, &nodeExecutionModel, selectedFields); err != nil { + logger.Warnf(ctx, "Failed to update node execution model %+v before deleting artifact: %v", + nodeExecution.Id, err) + m.metrics.CacheEvictionFailures.Inc() + evictionErrors = append(evictionErrors, &core.CacheEvictionError{ + NodeExecutionId: nodeExecution.Id, + Source: &core.CacheEvictionError_TaskExecutionId{ + TaskExecutionId: taskExecution.Id, + }, + Code: core.CacheEvictionError_DATABASE_UPDATE_FAILED, + Message: "Failed to update node execution", + }) + return evictionErrors + } + + if err := m.catalogClient.DeleteByArtifactID(ctx, datasetID, artifactID); err != nil { + if catalog.IsNotFound(err) { + logger.Debugf(ctx, "Artifact with ID %s for dataset %+v of node execution %+v not found, assuming already deleted by previous eviction. Skipping...", + artifactID, datasetID, nodeExecution.Id) + } else { + logger.Warnf(ctx, "Failed to delete artifact with ID %s for dataset %+v of node execution %+v: %v", + artifactID, datasetID, nodeExecution.Id, err) + m.metrics.CacheEvictionFailures.Inc() + evictionErrors = append(evictionErrors, &core.CacheEvictionError{ + NodeExecutionId: nodeExecution.Id, + Source: &core.CacheEvictionError_TaskExecutionId{ + TaskExecutionId: taskExecution.Id, + }, + Code: core.CacheEvictionError_ARTIFACT_DELETE_FAILED, + Message: "Failed to delete artifact", + }) + return evictionErrors + } + } + + if err := m.catalogClient.ReleaseReservationByArtifactTag(ctx, datasetID, artifactTag, ownerID); err != nil { + logger.Warnf(ctx, "Failed to release reservation for artifact of node execution %+v, cannot evict cache", + nodeExecution.Id) + m.metrics.CacheEvictionFailures.Inc() + evictionErrors = append(evictionErrors, &core.CacheEvictionError{ + NodeExecutionId: nodeExecution.Id, + Source: &core.CacheEvictionError_TaskExecutionId{ + TaskExecutionId: taskExecution.Id, + }, + Code: core.CacheEvictionError_RESERVATION_NOT_RELEASED, + Message: "Failed to release reservation for artifact", + }) + return evictionErrors + } + + logger.Debugf(ctx, "Successfully evicted cache for task node execution %+v", nodeExecution.Id) + m.metrics.CacheEvictionSuccess.Inc() + + return evictionErrors +} + +func (m *CacheManager) evictWorkflowNodeExecutionCache(ctx context.Context, nodeExecution *admin.NodeExecution, + workflowNodeMetadata *admin.WorkflowNodeMetadata, evictionErrors []*core.CacheEvictionError) []*core.CacheEvictionError { + if workflowNodeMetadata == nil { + logger.Debugf(ctx, "Node execution %+v did not contain cached data, skipping cache eviction", + nodeExecution.Id) + return evictionErrors + } + + childNodeExecutions, err := m.listAllNodeExecutionsForWorkflow(ctx, workflowNodeMetadata.GetExecutionId(), "") + if err != nil { + logger.Debugf(ctx, "Failed to list child executions for node execution %+v of workflow %+v: %v", + nodeExecution.Id, workflowNodeMetadata.GetExecutionId(), err) + m.metrics.CacheEvictionFailures.Inc() + evictionErrors = append(evictionErrors, &core.CacheEvictionError{ + NodeExecutionId: nodeExecution.Id, + Source: &core.CacheEvictionError_WorkflowExecutionId{ + WorkflowExecutionId: workflowNodeMetadata.GetExecutionId(), + }, + Code: core.CacheEvictionError_INTERNAL, + Message: "Failed to evict child executions for workflow", + }) + return evictionErrors + } + for _, childNodeExecution := range childNodeExecutions { + evictionErrors = m.evictNodeExecutionCache(ctx, childNodeExecution, evictionErrors) + } + + logger.Debugf(ctx, "Successfully evicted cache for workflow node execution %+v", nodeExecution.Id) + m.metrics.CacheEvictionSuccess.Inc() + + return evictionErrors +} + +func (m *CacheManager) listAllNodeExecutionsForWorkflow(ctx context.Context, + workflowExecutionID *core.WorkflowExecutionIdentifier, uniqueParentID string) ([]models.NodeExecution, error) { + var nodeExecutions []models.NodeExecution + var token string + for { + executions, newToken, err := util.ListNodeExecutionsForWorkflow(ctx, m.db, workflowExecutionID, + uniqueParentID, "", nodeExecutionLimit, token, sortByCreatedAtAsc) + if err != nil { + return nil, err + } + + nodeExecutions = append(nodeExecutions, executions...) + if len(newToken) == 0 { + // empty token is returned once no more node executions are available + break + } + token = newToken + } + + return nodeExecutions, nil +} + +func (m *CacheManager) listAllTaskExecutions(ctx context.Context, nodeExecutionID *core.NodeExecutionIdentifier) ([]models.TaskExecution, error) { + var taskExecutions []models.TaskExecution + var token string + for { + executions, newToken, err := util.ListTaskExecutions(ctx, m.db, nodeExecutionID, "", + taskExecutionLimit, token, sortByCreatedAtAsc) + if err != nil { + return nil, err + } + + taskExecutions = append(taskExecutions, executions...) + if len(newToken) == 0 { + // empty token is returned once no more task executions are available + break + } + token = newToken + } + + return taskExecutions, nil +} + +func NewCacheManager(db repoInterfaces.Repository, config runtimeInterfaces.Configuration, catalogClient catalog.Client, + scope promutils.Scope) interfaces.CacheInterface { + metrics := cacheMetrics{ + Scope: scope, + CacheEvictionTime: scope.MustNewStopWatch("cache_eviction_duration", + "duration taken for evicting the cache of a node execution", time.Millisecond), + CacheEvictionSuccess: scope.MustNewCounter("cache_eviction_success", + "number of times cache eviction for a node execution succeeded"), + CacheEvictionFailures: scope.MustNewCounter("cache_eviction_failures", + "number of times cache eviction for a node execution failed"), + } + + return &CacheManager{ + db: db, + config: config, + catalogClient: catalogClient, + metrics: metrics, + } +} diff --git a/pkg/manager/impl/cache_manager_test.go b/pkg/manager/impl/cache_manager_test.go new file mode 100644 index 000000000..ccf62c841 --- /dev/null +++ b/pkg/manager/impl/cache_manager_test.go @@ -0,0 +1,8529 @@ +package impl + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/golang/protobuf/proto" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + flyteAdminErrors "github.com/flyteorg/flyteadmin/pkg/errors" + "github.com/flyteorg/flyteadmin/pkg/repositories/interfaces" + repositoryMocks "github.com/flyteorg/flyteadmin/pkg/repositories/mocks" + "github.com/flyteorg/flyteadmin/pkg/repositories/models" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/core" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/datacatalog" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/event" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/service" + pluginCatalog "github.com/flyteorg/flyteplugins/go/tasks/pluginmachinery/catalog" + "github.com/flyteorg/flyteplugins/go/tasks/pluginmachinery/catalog/mocks" + "github.com/flyteorg/flytestdlib/catalog" + "github.com/flyteorg/flytestdlib/promutils" +) + +func serializeNodeExecutionMetadata(t *testing.T, nodeExecutionMetadata *admin.NodeExecutionMetaData) []byte { + t.Helper() + marshalled, err := proto.Marshal(nodeExecutionMetadata) + require.NoError(t, err) + return marshalled +} + +func serializeNodeExecutionClosure(t *testing.T, nodeExecutionClosure *admin.NodeExecutionClosure) []byte { + t.Helper() + marshalled, err := proto.Marshal(nodeExecutionClosure) + require.NoError(t, err) + return marshalled +} + +func serializeTaskExecutionClosure(t *testing.T, taskExecutionClosure *admin.TaskExecutionClosure) []byte { + t.Helper() + marshalled, err := proto.Marshal(taskExecutionClosure) + require.NoError(t, err) + return marshalled +} + +func ptr[T any](val T) *T { + return &val +} + +func setupCacheEvictionMockRepositories(t *testing.T, repository interfaces.Repository, executionModel *models.Execution, + nodeExecutionModels []models.NodeExecution, taskExecutionModels map[string][]models.TaskExecution) map[string]int { + if executionModel != nil { + repository.ExecutionRepo().(*repositoryMocks.MockExecutionRepo).SetGetCallback( + func(ctx context.Context, input interfaces.Identifier) (models.Execution, error) { + assert.Equal(t, executionIdentifier.Domain, input.Domain) + assert.Equal(t, executionIdentifier.Name, input.Name) + assert.Equal(t, executionIdentifier.Project, input.Project) + return *executionModel, nil + }) + } + + repository.NodeExecutionRepo().(*repositoryMocks.MockNodeExecutionRepo).SetGetCallback( + func(ctx context.Context, input interfaces.NodeExecutionResource) (models.NodeExecution, error) { + for _, nodeExecution := range nodeExecutionModels { + if nodeExecution.NodeID == input.NodeExecutionIdentifier.NodeId { + return nodeExecution, nil + } + } + return models.NodeExecution{}, flyteAdminErrors.NewFlyteAdminErrorf(codes.NotFound, "entry not found") + }) + + repository.NodeExecutionRepo().(*repositoryMocks.MockNodeExecutionRepo).SetListCallback( + func(ctx context.Context, input interfaces.ListResourceInput) (interfaces.NodeExecutionCollectionOutput, error) { + var parentID uint + for _, filter := range input.InlineFilters { + if filter.GetField() == "parent_id" { + query, err := filter.GetGormJoinTableQueryExpr("") + require.NoError(t, err) + var ok bool + parentID, ok = query.Args.(uint) + require.True(t, ok) + } + } + if parentID == 0 { + return interfaces.NodeExecutionCollectionOutput{NodeExecutions: nodeExecutionModels}, nil + } + for _, nodeExecution := range nodeExecutionModels { + if nodeExecution.ID == parentID { + return interfaces.NodeExecutionCollectionOutput{NodeExecutions: nodeExecution.ChildNodeExecutions}, nil + } + } + return interfaces.NodeExecutionCollectionOutput{}, flyteAdminErrors.NewFlyteAdminErrorf(codes.NotFound, "entry not found") + }) + + updatedNodeExecutions := make(map[string]int) + repository.NodeExecutionRepo().(*repositoryMocks.MockNodeExecutionRepo).SetUpdateSelectedCallback( + func(ctx context.Context, nodeExecution *models.NodeExecution, selectedFields []string) error { + assert.Nil(t, nodeExecution.CacheStatus) + + var closure admin.NodeExecutionClosure + err := proto.Unmarshal(nodeExecution.Closure, &closure) + require.NoError(t, err) + md, ok := closure.TargetMetadata.(*admin.NodeExecutionClosure_TaskNodeMetadata) + require.True(t, ok) + require.NotNil(t, md.TaskNodeMetadata) + assert.Equal(t, core.CatalogCacheStatus_CACHE_DISABLED, md.TaskNodeMetadata.CacheStatus) + assert.Nil(t, md.TaskNodeMetadata.CatalogKey) + + updatedNodeExecutions[nodeExecution.NodeID]++ + + for i := range nodeExecutionModels { + if nodeExecutionModels[i].ID == nodeExecution.ID { + nodeExecutionModels[i] = *nodeExecution + break + } + } + return nil + }) + + repository.TaskExecutionRepo().(*repositoryMocks.MockTaskExecutionRepo).SetListCallback( + func(ctx context.Context, input interfaces.ListResourceInput) (interfaces.TaskExecutionCollectionOutput, error) { + var nodeID string + for _, filter := range input.InlineFilters { + if filter.GetField() == "node_id" { + query, err := filter.GetGormJoinTableQueryExpr("") + require.NoError(t, err) + var ok bool + nodeID, ok = query.Args.(string) + require.True(t, ok) + } + } + require.NotEmpty(t, nodeID) + taskExecutions, ok := taskExecutionModels[nodeID] + require.True(t, ok) + return interfaces.TaskExecutionCollectionOutput{TaskExecutions: taskExecutions}, nil + }) + + repository.TaskExecutionRepo().(*repositoryMocks.MockTaskExecutionRepo).SetGetCallback( + func(ctx context.Context, input interfaces.GetTaskExecutionInput) (models.TaskExecution, error) { + for nodeID := range taskExecutionModels { + if nodeID == input.TaskExecutionID.NodeExecutionId.NodeId { + return taskExecutionModels[nodeID][0], nil + } + } + return models.TaskExecution{}, flyteAdminErrors.NewFlyteAdminErrorf(codes.NotFound, "entry not found") + }) + + return updatedNodeExecutions +} + +func setupCacheEvictionCatalogClient(t *testing.T, catalogClient *mocks.Client, artifactTags []*core.CatalogArtifactTag, + taskExecutionModels map[string][]models.TaskExecution) map[string]int { + for nodeID := range taskExecutionModels { + for _, taskExecution := range taskExecutionModels[nodeID] { + require.NotNil(t, taskExecution.RetryAttempt) + ownerID := fmt.Sprintf("%s-%s-%d", executionIdentifier.Name, nodeID, *taskExecution.RetryAttempt) + for _, artifactTag := range artifactTags { + catalogClient.On("GetOrExtendReservationByArtifactTag", mock.Anything, mock.Anything, + artifactTag.GetName(), ownerID, mock.Anything).Return(&datacatalog.Reservation{OwnerId: ownerID}, nil) + catalogClient.On("ReleaseReservationByArtifactTag", mock.Anything, mock.Anything, + artifactTag.GetName(), ownerID).Return(nil) + } + } + } + + deletedArtifactIDs := make(map[string]int) + for _, artifactTag := range artifactTags { + catalogClient.On("DeleteByArtifactID", mock.Anything, mock.Anything, artifactTag.GetArtifactId()). + Run(func(args mock.Arguments) { + deletedArtifactIDs[args.Get(2).(string)] = deletedArtifactIDs[args.Get(2).(string)] + 1 + }). + Return(nil) + } + + return deletedArtifactIDs +} + +func TestEvictExecutionCache(t *testing.T) { + t.Run("single task", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + for nodeID := range taskExecutionModels { + assert.Contains(t, updatedNodeExecutions, nodeID) + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + + for _, artifactID := range artifactTags { + assert.Equal(t, 1, deletedArtifactIDs[artifactID.GetArtifactId()]) + } + assert.Len(t, deletedArtifactIDs, len(artifactTags)) + }) + + t.Run("multiple tasks", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + { + ArtifactId: "4074be3e-7cee-4a7b-8c45-56577fa32f24", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYN", + }, + { + ArtifactId: "a8bd60d5-b2bb-4b06-a2ac-240d183a4ca8", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYO", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n1", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n1", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[1], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 4, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n2", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n2", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[2], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 5, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + "n1": { + { + BaseModel: models.BaseModel{ + ID: 2, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n1", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n1-0", + }, + }), + }, + }, + "n2": { + { + BaseModel: models.BaseModel{ + ID: 3, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n2", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n2-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + for nodeID := range taskExecutionModels { + assert.Contains(t, updatedNodeExecutions, nodeID) + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + + for _, artifactTag := range artifactTags { + assert.Equal(t, 1, deletedArtifactIDs[artifactTag.GetArtifactId()]) + } + assert.Len(t, deletedArtifactIDs, len(artifactTags)) + }) + + t.Run("single subtask", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + { + ArtifactId: "4074be3e-7cee-4a7b-8c45-56577fa32f24", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYN", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: true, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + ChildNodeExecutions: []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 4, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_sub", + Version: "version", + }, + ArtifactTag: artifactTags[1], + SourceExecution: &core.CatalogMetadata_SourceTaskExecution{ + SourceTaskExecution: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + NodeId: "dn0", + ExecutionId: &executionIdentifier, + }, + RetryAttempt: 0, + }, + }, + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 5, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + }, + }, + { + BaseModel: models.BaseModel{ + ID: 6, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 2, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-n0-0", + }, + }), + }, + }, + "n0-0-n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + for nodeID := range taskExecutionModels { + if len(taskExecutionModels[nodeID]) > 0 { + assert.Contains(t, updatedNodeExecutions, nodeID) + } else { + assert.NotContains(t, updatedNodeExecutions, nodeID) + } + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + + for _, artifactTag := range artifactTags { + assert.Equal(t, 1, deletedArtifactIDs[artifactTag.GetArtifactId()]) + } + assert.Len(t, deletedArtifactIDs, len(artifactTags)) + }) + + t.Run("multiple subtasks", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + { + ArtifactId: "4074be3e-7cee-4a7b-8c45-56577fa32f24", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYN", + }, + { + ArtifactId: "a8bd60d5-b2bb-4b06-a2ac-240d183a4ca8", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYO", + }, + { + ArtifactId: "8a47c342-ff71-481e-9c7b-0e6ecb57e742", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYP", + }, + { + ArtifactId: "dafdef15-0aba-4f7c-a4aa-deba89568277", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYQ", + }, + { + ArtifactId: "55bbd39e-ff7d-42c8-a03b-bcc5f4019a0f", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYR", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: true, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + ChildNodeExecutions: []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 4, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_sub", + Version: "version", + }, + ArtifactTag: artifactTags[1], + SourceExecution: &core.CatalogMetadata_SourceTaskExecution{ + SourceTaskExecution: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + NodeId: "dn0", + ExecutionId: &executionIdentifier, + }, + RetryAttempt: 0, + }, + }, + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 5, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + }, + }, + { + BaseModel: models.BaseModel{ + ID: 6, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n1", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: true, + IsDynamic: false, + SpecNodeId: "n1", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[2], + }, + }, + }, + }), + ChildNodeExecutions: []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 7, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n1-0-start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 8, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n1-0-n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_sub", + Version: "version", + }, + ArtifactTag: artifactTags[3], + SourceExecution: &core.CatalogMetadata_SourceTaskExecution{ + SourceTaskExecution: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + NodeId: "dn0", + ExecutionId: &executionIdentifier, + }, + RetryAttempt: 0, + }, + }, + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 9, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n1-0-end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + }, + }, + { + BaseModel: models.BaseModel{ + ID: 10, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n2", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: true, + IsDynamic: false, + SpecNodeId: "n2", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[4], + }, + }, + }, + }), + ChildNodeExecutions: []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 11, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n2-0-start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 12, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n2-0-n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_sub", + Version: "version", + }, + ArtifactTag: artifactTags[5], + SourceExecution: &core.CatalogMetadata_SourceTaskExecution{ + SourceTaskExecution: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + NodeId: "dn0", + ExecutionId: &executionIdentifier, + }, + RetryAttempt: 0, + }, + }, + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 13, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n2-0-end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + }, + }, + { + BaseModel: models.BaseModel{ + ID: 14, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 4, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-n0-0", + }, + }), + }, + }, + "n1": { + { + BaseModel: models.BaseModel{ + ID: 5, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n1", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n1-0-n0-0", + }, + }), + }, + }, + "n2": { + { + BaseModel: models.BaseModel{ + ID: 6, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n2", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n2-0-n0-0", + }, + }), + }, + }, + "n0-0-n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-n0-0", + }, + }), + }, + }, + "n1-0-n0": { + { + BaseModel: models.BaseModel{ + ID: 2, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n1-0-n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n1-0-n0-0", + }, + }), + }, + }, + "n2-0-n0": { + { + BaseModel: models.BaseModel{ + ID: 3, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n2-0-n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n2-0-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + for nodeID := range taskExecutionModels { + if len(taskExecutionModels[nodeID]) > 0 { + assert.Contains(t, updatedNodeExecutions, nodeID) + } else { + assert.NotContains(t, updatedNodeExecutions, nodeID) + } + } + assert.Len(t, updatedNodeExecutions, 6) + + for _, artifactTag := range artifactTags { + assert.Equal(t, 1, deletedArtifactIDs[artifactTag.GetArtifactId()]) + } + assert.Len(t, deletedArtifactIDs, len(artifactTags)) + }) + + t.Run("single launch plan", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + { + ArtifactId: "4074be3e-7cee-4a7b-8c45-56577fa32f24", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYN", + }, + } + + childExecutionIdentifier := core.WorkflowExecutionIdentifier{ + Project: "project", + Domain: "domain", + Name: "childname", + } + + executionModels := map[string]models.Execution{ + executionIdentifier.Name: { + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + }, + childExecutionIdentifier.Name: { + BaseModel: models.BaseModel{ + ID: 2, + }, + ExecutionKey: models.ExecutionKey{ + Project: childExecutionIdentifier.Project, + Domain: childExecutionIdentifier.Domain, + Name: childExecutionIdentifier.Name, + }, + LaunchPlanID: 7, + WorkflowID: 5, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + }, + } + + nodeExecutionModels := map[string][]models.NodeExecution{ + executionIdentifier.Name: { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: true, + IsDynamic: true, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + ChildNodeExecutions: []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 4, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "dn0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_WorkflowNodeMetadata{ + WorkflowNodeMetadata: &admin.WorkflowNodeMetadata{ + ExecutionId: &childExecutionIdentifier, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 5, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + }, + }, + { + BaseModel: models.BaseModel{ + ID: 6, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + }, + childExecutionIdentifier.Name: { + { + BaseModel: models.BaseModel{ + ID: 7, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: childExecutionIdentifier.Project, + Domain: childExecutionIdentifier.Domain, + Name: childExecutionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 8, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: childExecutionIdentifier.Project, + Domain: childExecutionIdentifier.Domain, + Name: childExecutionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: childExecutionIdentifier.Project, + Domain: childExecutionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[1], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 9, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: childExecutionIdentifier.Project, + Domain: childExecutionIdentifier.Domain, + Name: childExecutionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + }, + } + + taskExecutionModels := map[string]map[string][]models.TaskExecution{ + executionIdentifier.Name: { + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + "n0-0-dn0": {}, + }, + childExecutionIdentifier.Name: { + "n0": { + { + BaseModel: models.BaseModel{ + ID: 2, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "childname-n0-0", + }, + }), + }, + }, + }, + } + + repository.ExecutionRepo().(*repositoryMocks.MockExecutionRepo).SetGetCallback( + func(ctx context.Context, input interfaces.Identifier) (models.Execution, error) { + execution, ok := executionModels[input.Name] + require.True(t, ok) + return execution, nil + }) + + repository.NodeExecutionRepo().(*repositoryMocks.MockNodeExecutionRepo).SetGetCallback( + func(ctx context.Context, input interfaces.NodeExecutionResource) (models.NodeExecution, error) { + nodeExecutions, ok := nodeExecutionModels[input.NodeExecutionIdentifier.ExecutionId.Name] + require.True(t, ok) + for _, nodeExecution := range nodeExecutions { + if nodeExecution.NodeID == input.NodeExecutionIdentifier.NodeId { + return nodeExecution, nil + } + } + return models.NodeExecution{}, errors.New("not found") + }) + + repository.NodeExecutionRepo().(*repositoryMocks.MockNodeExecutionRepo).SetListCallback( + func(ctx context.Context, input interfaces.ListResourceInput) (interfaces.NodeExecutionCollectionOutput, error) { + var executionName string + var parentID uint + for _, filter := range input.InlineFilters { + if filter.GetField() == "execution_name" { + query, err := filter.GetGormJoinTableQueryExpr("") + require.NoError(t, err) + var ok bool + executionName, ok = query.Args.(string) + require.True(t, ok) + } else if filter.GetField() == "parent_id" { + query, err := filter.GetGormJoinTableQueryExpr("") + require.NoError(t, err) + var ok bool + parentID, ok = query.Args.(uint) + require.True(t, ok) + } + } + + nodeExecutions, ok := nodeExecutionModels[executionName] + require.True(t, ok) + + if parentID == 0 { + return interfaces.NodeExecutionCollectionOutput{NodeExecutions: nodeExecutions}, nil + } + for _, nodeExecution := range nodeExecutions { + if nodeExecution.ID == parentID { + return interfaces.NodeExecutionCollectionOutput{NodeExecutions: nodeExecution.ChildNodeExecutions}, nil + } + } + return interfaces.NodeExecutionCollectionOutput{}, errors.New("not found") + }) + + updatedNodeExecutions := make(map[string]map[string]struct{}) + repository.NodeExecutionRepo().(*repositoryMocks.MockNodeExecutionRepo).SetUpdateSelectedCallback( + func(ctx context.Context, nodeExecution *models.NodeExecution, selectedFields []string) error { + assert.Nil(t, nodeExecution.CacheStatus) + + var closure admin.NodeExecutionClosure + err := proto.Unmarshal(nodeExecution.Closure, &closure) + require.NoError(t, err) + md, ok := closure.TargetMetadata.(*admin.NodeExecutionClosure_TaskNodeMetadata) + require.True(t, ok) + require.NotNil(t, md.TaskNodeMetadata) + assert.Equal(t, core.CatalogCacheStatus_CACHE_DISABLED, md.TaskNodeMetadata.CacheStatus) + assert.Nil(t, md.TaskNodeMetadata.CatalogKey) + + if _, ok := updatedNodeExecutions[nodeExecution.Name]; !ok { + updatedNodeExecutions[nodeExecution.Name] = make(map[string]struct{}) + } + updatedNodeExecutions[nodeExecution.Name][nodeExecution.NodeID] = struct{}{} + return nil + }) + + repository.TaskExecutionRepo().(*repositoryMocks.MockTaskExecutionRepo).SetListCallback( + func(ctx context.Context, input interfaces.ListResourceInput) (interfaces.TaskExecutionCollectionOutput, error) { + var executionName string + var nodeID string + for _, filter := range input.InlineFilters { + if filter.GetField() == "execution_name" { + query, err := filter.GetGormJoinTableQueryExpr("") + require.NoError(t, err) + var ok bool + executionName, ok = query.Args.(string) + require.True(t, ok) + } else if filter.GetField() == "node_id" { + query, err := filter.GetGormJoinTableQueryExpr("") + require.NoError(t, err) + var ok bool + nodeID, ok = query.Args.(string) + require.True(t, ok) + } + } + require.NotEmpty(t, nodeID) + taskExecutions, ok := taskExecutionModels[executionName] + require.True(t, ok) + executions, ok := taskExecutions[nodeID] + require.True(t, ok) + return interfaces.TaskExecutionCollectionOutput{TaskExecutions: executions}, nil + }) + + repository.TaskExecutionRepo().(*repositoryMocks.MockTaskExecutionRepo).SetGetCallback( + func(ctx context.Context, input interfaces.GetTaskExecutionInput) (models.TaskExecution, error) { + taskExecutions, ok := taskExecutionModels[input.TaskExecutionID.NodeExecutionId.ExecutionId.Name] + require.True(t, ok) + executions, ok := taskExecutions[input.TaskExecutionID.NodeExecutionId.NodeId] + require.True(t, ok) + return executions[0], nil + }) + + for executionName := range taskExecutionModels { + for nodeID := range taskExecutionModels[executionName] { + for _, taskExecution := range taskExecutionModels[executionName][nodeID] { + require.NotNil(t, taskExecution.RetryAttempt) + ownerID := fmt.Sprintf("%s-%s-%d", executionName, nodeID, *taskExecution.RetryAttempt) + for _, artifactTag := range artifactTags { + catalogClient.On("GetOrExtendReservationByArtifactTag", mock.Anything, mock.Anything, + artifactTag.GetName(), ownerID, mock.Anything).Return(&datacatalog.Reservation{OwnerId: ownerID}, nil) + catalogClient.On("ReleaseReservationByArtifactTag", mock.Anything, mock.Anything, + artifactTag.GetName(), ownerID).Return(nil) + } + } + } + } + + deletedArtifactIDs := make(map[string]int) + for _, artifactTag := range artifactTags { + catalogClient.On("DeleteByArtifactID", mock.Anything, mock.Anything, artifactTag.GetArtifactId()). + Run(func(args mock.Arguments) { + deletedArtifactIDs[args.Get(2).(string)] = deletedArtifactIDs[args.Get(2).(string)] + 1 + }). + Return(nil) + } + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + for executionName := range taskExecutionModels { + require.Contains(t, updatedNodeExecutions, executionName) + for nodeID := range taskExecutionModels[executionName] { + if len(taskExecutionModels[executionName][nodeID]) > 0 { + assert.Contains(t, updatedNodeExecutions[executionName], nodeID) + } else { + assert.NotContains(t, updatedNodeExecutions[executionName], nodeID) + } + } + assert.Len(t, updatedNodeExecutions[executionName], 1) + } + + for _, artifactTag := range artifactTags { + assert.Equal(t, 1, deletedArtifactIDs[artifactTag.GetArtifactId()]) + } + assert.Len(t, deletedArtifactIDs, len(artifactTags)) + }) + + t.Run("single dynamic task", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + { + ArtifactId: "4074be3e-7cee-4a7b-8c45-56577fa32f24", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYN", + }, + { + ArtifactId: "a8bd60d5-b2bb-4b06-a2ac-240d183a4ca8", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYO", + }, + { + ArtifactId: "8a47c342-ff71-481e-9c7b-0e6ecb57e742", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYP", + }, + { + ArtifactId: "dafdef15-0aba-4f7c-a4aa-deba89568277", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYQ", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: true, + IsDynamic: true, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_dynamic", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + ChildNodeExecutions: []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + ParentID: ptr[uint](2), + }, + { + BaseModel: models.BaseModel{ + ID: 4, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "dn0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + ArtifactTag: artifactTags[1], + }, + }, + }, + }), + ParentID: ptr[uint](2), + CacheStatus: ptr[string](core.CatalogCacheStatus_CACHE_POPULATED.String()), + }, + { + BaseModel: models.BaseModel{ + ID: 5, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn1", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "dn1", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + ArtifactTag: artifactTags[2], + }, + }, + }, + }), + ParentID: ptr[uint](2), + CacheStatus: ptr[string](core.CatalogCacheStatus_CACHE_POPULATED.String()), + }, + { + BaseModel: models.BaseModel{ + ID: 6, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn2", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "dn2", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + ArtifactTag: artifactTags[3], + }, + }, + }, + }), + ParentID: ptr[uint](2), + CacheStatus: ptr[string](core.CatalogCacheStatus_CACHE_POPULATED.String()), + }, + { + BaseModel: models.BaseModel{ + ID: 7, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn3", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "dn3", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + ArtifactTag: artifactTags[4], + }, + }, + }, + }), + ParentID: ptr[uint](2), + CacheStatus: ptr[string](core.CatalogCacheStatus_CACHE_POPULATED.String()), + }, + { + BaseModel: models.BaseModel{ + ID: 8, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + ParentID: ptr[uint](2), + }, + }, + }, + { + BaseModel: models.BaseModel{ + ID: 9, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + "n0-0-dn0": { + { + BaseModel: models.BaseModel{ + ID: 2, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-dn0-0", + }, + }), + }, + }, + "n0-0-dn1": { + { + BaseModel: models.BaseModel{ + ID: 3, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn1", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-dn1-0", + }, + }), + }, + }, + "n0-0-dn2": { + { + BaseModel: models.BaseModel{ + ID: 4, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn2", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-dn2-0", + }, + }), + }, + }, + "n0-0-dn3": { + { + BaseModel: models.BaseModel{ + ID: 5, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn3", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-dn3-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + for nodeID := range taskExecutionModels { + assert.Contains(t, updatedNodeExecutions, nodeID) + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + + for _, artifactTag := range artifactTags { + assert.Equal(t, 1, deletedArtifactIDs[artifactTag.GetArtifactId()]) + } + assert.Len(t, deletedArtifactIDs, len(artifactTags)) + }) + + t.Run("noop catalog", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := catalog.NOOPCatalog{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []string{"flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM"} + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: &core.CatalogArtifactTag{ + ArtifactId: "c7cc868e-767f-4896-a97d-9f4887826cdd", + Name: artifactTags[0], + }, + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + assert.Empty(t, updatedNodeExecutions) + }) + + t.Run("unknown execution", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + mockConfig := getMockExecutionsConfigProvider() + + repository.ExecutionRepo().(*repositoryMocks.MockExecutionRepo).SetGetCallback( + func(ctx context.Context, input interfaces.Identifier) (models.Execution, error) { + return models.Execution{}, flyteAdminErrors.NewFlyteAdminErrorf(codes.NotFound, "entry not found") + }) + + catalogClient := &mocks.Client{} + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + assert.Error(t, err) + assert.True(t, pluginCatalog.IsNotFound(err)) + assert.Nil(t, resp) + }) + + t.Run("single task without cached results", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_DISABLED, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + assert.Empty(t, updatedNodeExecutions) + }) + + t.Run("multiple tasks with partially cached results", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + { + ArtifactId: "4074be3e-7cee-4a7b-8c45-56577fa32f24", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYN", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n1", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n1", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_DISABLED, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 4, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n2", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n2", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[1], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 5, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + "n1": { + { + BaseModel: models.BaseModel{ + ID: 2, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n1", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n1-0", + }, + }), + }, + }, + "n2": { + { + BaseModel: models.BaseModel{ + ID: 3, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n2", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n2-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + assert.Contains(t, updatedNodeExecutions, "n0") + assert.Contains(t, updatedNodeExecutions, "n2") + assert.Len(t, updatedNodeExecutions, 2) + + for _, artifactTag := range artifactTags { + assert.Equal(t, 1, deletedArtifactIDs[artifactTag.GetArtifactId()]) + } + assert.Len(t, deletedArtifactIDs, len(artifactTags)) + }) + + t.Run("idempotency", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + resp, err = cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + resp, err = cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + for nodeID := range taskExecutionModels { + assert.Contains(t, updatedNodeExecutions, nodeID) + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + + for _, artifactTag := range artifactTags { + assert.Equal(t, 1, deletedArtifactIDs[artifactTag.GetArtifactId()]) + } + assert.Len(t, deletedArtifactIDs, len(artifactTags)) + }) + + t.Run("reserved artifact", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + + catalogClient.On("GetOrExtendReservationByArtifactTag", mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything).Return(&datacatalog.Reservation{OwnerId: "differentOwnerID"}, nil) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Len(t, resp.GetErrors().GetErrors(), len(artifactTags)) + eErr := resp.GetErrors().GetErrors()[0] + assert.Equal(t, core.CacheEvictionError_RESERVATION_NOT_ACQUIRED, eErr.Code) + assert.Equal(t, "n0", eErr.NodeExecutionId.NodeId) + assert.True(t, proto.Equal(&executionIdentifier, eErr.NodeExecutionId.ExecutionId)) + require.NotNil(t, eErr.Source) + assert.IsType(t, &core.CacheEvictionError_TaskExecutionId{}, eErr.Source) + + assert.Empty(t, updatedNodeExecutions) + }) + + t.Run("unknown artifact", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + + for nodeID := range taskExecutionModels { + for _, taskExecution := range taskExecutionModels[nodeID] { + require.NotNil(t, taskExecution.RetryAttempt) + ownerID := fmt.Sprintf("%s-%s-%d", executionIdentifier.Name, nodeID, *taskExecution.RetryAttempt) + for _, artifactTag := range artifactTags { + catalogClient.On("GetOrExtendReservationByArtifactTag", mock.Anything, mock.Anything, + artifactTag.GetName(), ownerID, mock.Anything).Return(&datacatalog.Reservation{OwnerId: ownerID}, nil) + catalogClient.On("ReleaseReservationByArtifactTag", mock.Anything, mock.Anything, + artifactTag.GetName(), ownerID).Return(nil) + } + } + } + + catalogClient.On("DeleteByArtifactID", mock.Anything, mock.Anything, mock.Anything). + Return(status.Error(codes.NotFound, "not found")) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + for nodeID := range taskExecutionModels { + assert.Contains(t, updatedNodeExecutions, nodeID) + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + }) + + t.Run("datacatalog error", func(t *testing.T) { + t.Run("GetOrExtendReservationByArtifactTag", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + + catalogClient.On("GetOrExtendReservationByArtifactTag", mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything).Return(nil, status.Error(codes.Internal, "error")) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Len(t, resp.GetErrors().GetErrors(), len(artifactTags)) + eErr := resp.GetErrors().GetErrors()[0] + assert.Equal(t, core.CacheEvictionError_RESERVATION_NOT_ACQUIRED, eErr.Code) + assert.Equal(t, "n0", eErr.NodeExecutionId.NodeId) + assert.True(t, proto.Equal(&executionIdentifier, eErr.NodeExecutionId.ExecutionId)) + require.NotNil(t, eErr.Source) + assert.IsType(t, &core.CacheEvictionError_TaskExecutionId{}, eErr.Source) + + assert.Empty(t, updatedNodeExecutions) + }) + + t.Run("DeleteByArtifactID", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + + for nodeID := range taskExecutionModels { + for _, taskExecution := range taskExecutionModels[nodeID] { + require.NotNil(t, taskExecution.RetryAttempt) + ownerID := fmt.Sprintf("%s-%s-%d", executionIdentifier.Name, nodeID, *taskExecution.RetryAttempt) + for _, artifactTag := range artifactTags { + catalogClient.On("GetOrExtendReservationByArtifactTag", mock.Anything, mock.Anything, + artifactTag.GetName(), ownerID, mock.Anything).Return(&datacatalog.Reservation{OwnerId: ownerID}, nil) + } + } + } + + catalogClient.On("DeleteByArtifactID", mock.Anything, mock.Anything, mock.Anything). + Return(status.Error(codes.Internal, "error")) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Len(t, resp.GetErrors().GetErrors(), len(artifactTags)) + eErr := resp.GetErrors().GetErrors()[0] + assert.Equal(t, core.CacheEvictionError_ARTIFACT_DELETE_FAILED, eErr.Code) + assert.Equal(t, "n0", eErr.NodeExecutionId.NodeId) + assert.True(t, proto.Equal(&executionIdentifier, eErr.NodeExecutionId.ExecutionId)) + require.NotNil(t, eErr.Source) + assert.IsType(t, &core.CacheEvictionError_TaskExecutionId{}, eErr.Source) + + for nodeID := range taskExecutionModels { + assert.Contains(t, updatedNodeExecutions, nodeID) + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + }) + + t.Run("ReleaseReservationByArtifactTag", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + + for nodeID := range taskExecutionModels { + for _, taskExecution := range taskExecutionModels[nodeID] { + require.NotNil(t, taskExecution.RetryAttempt) + ownerID := fmt.Sprintf("%s-%s-%d", executionIdentifier.Name, nodeID, *taskExecution.RetryAttempt) + for _, artifactTag := range artifactTags { + catalogClient.On("GetOrExtendReservationByArtifactTag", mock.Anything, mock.Anything, + artifactTag.GetName(), ownerID, mock.Anything).Return(&datacatalog.Reservation{OwnerId: ownerID}, nil) + } + } + } + + deletedArtifactIDs := make(map[string]int) + for _, artifactTag := range artifactTags { + catalogClient.On("DeleteByArtifactID", mock.Anything, mock.Anything, artifactTag.GetArtifactId()). + Run(func(args mock.Arguments) { + deletedArtifactIDs[args.Get(2).(string)] = deletedArtifactIDs[args.Get(2).(string)] + 1 + }). + Return(nil) + } + + catalogClient.On("ReleaseReservationByArtifactTag", mock.Anything, mock.Anything, + mock.Anything, mock.Anything).Return(status.Error(codes.Internal, "error")) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Len(t, resp.GetErrors().GetErrors(), len(artifactTags)) + eErr := resp.GetErrors().GetErrors()[0] + assert.Equal(t, core.CacheEvictionError_RESERVATION_NOT_RELEASED, eErr.Code) + assert.Equal(t, "n0", eErr.NodeExecutionId.NodeId) + assert.True(t, proto.Equal(&executionIdentifier, eErr.NodeExecutionId.ExecutionId)) + require.NotNil(t, eErr.Source) + assert.IsType(t, &core.CacheEvictionError_TaskExecutionId{}, eErr.Source) + + for nodeID := range taskExecutionModels { + assert.Contains(t, updatedNodeExecutions, nodeID) + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + }) + }) + + t.Run("repository error", func(t *testing.T) { + t.Run("ExecutionRepo", func(t *testing.T) { + t.Run("Get", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + + repository.ExecutionRepo().(*repositoryMocks.MockExecutionRepo).SetGetCallback( + func(ctx context.Context, input interfaces.Identifier) (models.Execution, error) { + return models.Execution{}, flyteAdminErrors.NewFlyteAdminErrorf(codes.Internal, "error") + }) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.Error(t, err) + s, ok := status.FromError(err) + require.True(t, ok) + assert.Equal(t, codes.Internal, s.Code()) + assert.Nil(t, resp) + + assert.Empty(t, updatedNodeExecutions) + }) + }) + + t.Run("NodeExecutionRepo", func(t *testing.T) { + t.Run("List", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + + repository.NodeExecutionRepo().(*repositoryMocks.MockNodeExecutionRepo).SetListCallback( + func(ctx context.Context, input interfaces.ListResourceInput) (interfaces.NodeExecutionCollectionOutput, error) { + return interfaces.NodeExecutionCollectionOutput{}, flyteAdminErrors.NewFlyteAdminErrorf(codes.Internal, "error") + }) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.Error(t, err) + s, ok := status.FromError(err) + require.True(t, ok) + assert.Equal(t, codes.Internal, s.Code()) + assert.Nil(t, resp) + + assert.Empty(t, updatedNodeExecutions) + }) + + t.Run("UpdateSelected", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + + repository.NodeExecutionRepo().(*repositoryMocks.MockNodeExecutionRepo).SetUpdateSelectedCallback( + func(ctx context.Context, nodeExecution *models.NodeExecution, selectedFields []string) error { + return flyteAdminErrors.NewFlyteAdminError(codes.Internal, "error") + }) + + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Len(t, resp.GetErrors().GetErrors(), len(artifactTags)) + eErr := resp.GetErrors().GetErrors()[0] + assert.Equal(t, core.CacheEvictionError_DATABASE_UPDATE_FAILED, eErr.Code) + assert.Equal(t, "n0", eErr.NodeExecutionId.NodeId) + assert.True(t, proto.Equal(&executionIdentifier, eErr.NodeExecutionId.ExecutionId)) + require.NotNil(t, eErr.Source) + assert.IsType(t, &core.CacheEvictionError_TaskExecutionId{}, eErr.Source) + + assert.Empty(t, updatedNodeExecutions) + assert.Empty(t, deletedArtifactIDs) + }) + }) + + t.Run("TaskExecutionRepo", func(t *testing.T) { + t.Run("List", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + + repository.TaskExecutionRepo().(*repositoryMocks.MockTaskExecutionRepo).SetListCallback( + func(ctx context.Context, input interfaces.ListResourceInput) (interfaces.TaskExecutionCollectionOutput, error) { + return interfaces.TaskExecutionCollectionOutput{}, flyteAdminErrors.NewFlyteAdminError(codes.Internal, "error") + }) + + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Len(t, resp.GetErrors().GetErrors(), len(artifactTags)) + eErr := resp.GetErrors().GetErrors()[0] + assert.Equal(t, core.CacheEvictionError_INTERNAL, eErr.Code) + assert.Equal(t, "n0", eErr.NodeExecutionId.NodeId) + assert.True(t, proto.Equal(&executionIdentifier, eErr.NodeExecutionId.ExecutionId)) + require.NotNil(t, eErr.Source) + assert.IsType(t, &core.CacheEvictionError_WorkflowExecutionId{}, eErr.Source) + + assert.Empty(t, updatedNodeExecutions) + assert.Empty(t, deletedArtifactIDs) + }) + }) + }) + + t.Run("multiple tasks with identical artifact tags", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + { + ArtifactId: "4074be3e-7cee-4a7b-8c45-56577fa32f24", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + { + ArtifactId: "a8bd60d5-b2bb-4b06-a2ac-240d183a4ca8", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + { + ArtifactId: "8a47c342-ff71-481e-9c7b-0e6ecb57e742", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + executionModel := models.Execution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + LaunchPlanID: 6, + WorkflowID: 4, + TaskID: 0, + Phase: core.NodeExecution_SUCCEEDED.String(), + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n1", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n1", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[1], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 4, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n2", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n1", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[2], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 5, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n3", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n3", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[3], + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 6, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + "n1": { + { + BaseModel: models.BaseModel{ + ID: 2, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n1", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n1-0", + }, + }), + }, + }, + "n2": { + { + BaseModel: models.BaseModel{ + ID: 3, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n2", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n2-0", + }, + }), + }, + }, + "n3": { + { + BaseModel: models.BaseModel{ + ID: 4, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n3", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n3-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, &executionModel, nodeExecutionModels, + taskExecutionModels) + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + for nodeID := range taskExecutionModels { + assert.Contains(t, updatedNodeExecutions, nodeID) + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + + for _, artifactTag := range artifactTags { + assert.Equal(t, 1, deletedArtifactIDs[artifactTag.GetArtifactId()]) + } + assert.Len(t, deletedArtifactIDs, len(artifactTags)) + }) +} + +func TestEvictTaskExecutionCache(t *testing.T) { + t.Run("task", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + for nodeID := range taskExecutionModels { + assert.Contains(t, updatedNodeExecutions, nodeID) + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + + for _, artifactTag := range artifactTags { + assert.Equal(t, 1, deletedArtifactIDs[artifactTag.GetArtifactId()]) + } + assert.Len(t, deletedArtifactIDs, len(artifactTags)) + }) + + t.Run("subtask", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + { + ArtifactId: "4074be3e-7cee-4a7b-8c45-56577fa32f24", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYN", + }, + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: true, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + ChildNodeExecutions: []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_sub", + Version: "version", + }, + ArtifactTag: artifactTags[1], + SourceExecution: &core.CatalogMetadata_SourceTaskExecution{ + SourceTaskExecution: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + NodeId: "dn0", + ExecutionId: &executionIdentifier, + }, + RetryAttempt: 0, + }, + }, + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 4, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + }, + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-n0-0", + }, + }), + }, + }, + "n0-0-n0": { + { + BaseModel: models.BaseModel{ + ID: 2, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + for nodeID := range taskExecutionModels { + if len(taskExecutionModels[nodeID]) > 0 { + assert.Contains(t, updatedNodeExecutions, nodeID) + } else { + assert.NotContains(t, updatedNodeExecutions, nodeID) + } + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + + for _, artifactTag := range artifactTags { + assert.Equal(t, 1, deletedArtifactIDs[artifactTag.GetArtifactId()]) + } + assert.Len(t, deletedArtifactIDs, len(artifactTags)) + }) + + t.Run("dynamic task", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + { + ArtifactId: "4074be3e-7cee-4a7b-8c45-56577fa32f24", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYN", + }, + { + ArtifactId: "a8bd60d5-b2bb-4b06-a2ac-240d183a4ca8", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYO", + }, + { + ArtifactId: "8a47c342-ff71-481e-9c7b-0e6ecb57e742", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYP", + }, + { + ArtifactId: "dafdef15-0aba-4f7c-a4aa-deba89568277", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYQ", + }, + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: true, + IsDynamic: true, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_dynamic", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + ChildNodeExecutions: []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + ParentID: ptr[uint](2), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "dn0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + ArtifactTag: artifactTags[1], + }, + }, + }, + }), + ParentID: ptr[uint](2), + CacheStatus: ptr[string](core.CatalogCacheStatus_CACHE_POPULATED.String()), + }, + { + BaseModel: models.BaseModel{ + ID: 4, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn1", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "dn1", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + ArtifactTag: artifactTags[2], + }, + }, + }, + }), + ParentID: ptr[uint](2), + CacheStatus: ptr[string](core.CatalogCacheStatus_CACHE_POPULATED.String()), + }, + { + BaseModel: models.BaseModel{ + ID: 5, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn2", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "dn2", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + ArtifactTag: artifactTags[3], + }, + }, + }, + }), + ParentID: ptr[uint](2), + CacheStatus: ptr[string](core.CatalogCacheStatus_CACHE_POPULATED.String()), + }, + { + BaseModel: models.BaseModel{ + ID: 6, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn3", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "dn3", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + ArtifactTag: artifactTags[4], + }, + }, + }, + }), + ParentID: ptr[uint](2), + CacheStatus: ptr[string](core.CatalogCacheStatus_CACHE_POPULATED.String()), + }, + { + BaseModel: models.BaseModel{ + ID: 7, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + ParentID: ptr[uint](2), + }, + }, + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + "n0-0-dn0": { + { + BaseModel: models.BaseModel{ + ID: 2, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-dn0-0", + }, + }), + }, + }, + "n0-0-dn1": { + { + BaseModel: models.BaseModel{ + ID: 3, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn1", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-dn1-0", + }, + }), + }, + }, + "n0-0-dn2": { + { + BaseModel: models.BaseModel{ + ID: 4, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn2", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-dn2-0", + }, + }), + }, + }, + "n0-0-dn3": { + { + BaseModel: models.BaseModel{ + ID: 5, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-dn3", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-dn3-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictExecutionCacheRequest{ + WorkflowExecutionId: &executionIdentifier, + } + resp, err := cacheManager.EvictExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + for nodeID := range taskExecutionModels { + assert.Contains(t, updatedNodeExecutions, nodeID) + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + + for _, artifactTag := range artifactTags { + assert.Equal(t, 1, deletedArtifactIDs[artifactTag.GetArtifactId()]) + } + assert.Len(t, deletedArtifactIDs, len(artifactTags)) + }) + + t.Run("noop catalog", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := catalog.NOOPCatalog{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + assert.Empty(t, updatedNodeExecutions) + }) + + t.Run("unknown task execution", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + repository.TaskExecutionRepo().(*repositoryMocks.MockTaskExecutionRepo).SetGetCallback( + func(ctx context.Context, input interfaces.GetTaskExecutionInput) (models.TaskExecution, error) { + return models.TaskExecution{}, flyteAdminErrors.NewFlyteAdminErrorf(codes.NotFound, "entry not found") + }) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + assert.Error(t, err) + assert.True(t, pluginCatalog.IsNotFound(err)) + assert.Nil(t, resp) + }) + + t.Run("unknown node execution", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + taskExecutionModel := models.TaskExecution{ + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + } + + repository.TaskExecutionRepo().(*repositoryMocks.MockTaskExecutionRepo).SetGetCallback( + func(ctx context.Context, input interfaces.GetTaskExecutionInput) (models.TaskExecution, error) { + assert.EqualValues(t, executionIdentifier, *input.TaskExecutionID.NodeExecutionId.ExecutionId) + assert.Equal(t, taskExecutionModel.TaskExecutionKey.NodeID, input.TaskExecutionID.NodeExecutionId.NodeId) + return taskExecutionModel, nil + }) + + repository.NodeExecutionRepo().(*repositoryMocks.MockNodeExecutionRepo).SetGetCallback( + func(ctx context.Context, input interfaces.NodeExecutionResource) (models.NodeExecution, error) { + return models.NodeExecution{}, flyteAdminErrors.NewFlyteAdminErrorf(codes.NotFound, "entry not found") + }) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + assert.Error(t, err) + assert.True(t, pluginCatalog.IsNotFound(err)) + assert.Nil(t, resp) + }) + + t.Run("task without cached results", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_DISABLED, + }, + }, + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + assert.Empty(t, updatedNodeExecutions) + }) + + t.Run("subtask with partially cached results", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + { + ArtifactId: "4074be3e-7cee-4a7b-8c45-56577fa32f24", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYN", + }, + { + ArtifactId: "a8bd60d5-b2bb-4b06-a2ac-240d183a4ca8", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYO", + }, + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: true, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + ChildNodeExecutions: []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_sub", + Version: "version", + }, + ArtifactTag: artifactTags[1], + SourceExecution: &core.CatalogMetadata_SourceTaskExecution{ + SourceTaskExecution: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + NodeId: "dn0", + ExecutionId: &executionIdentifier, + }, + RetryAttempt: 0, + }, + }, + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 4, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n1", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n1", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_DISABLED, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 5, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n2", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n2", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_sub", + Version: "version", + }, + ArtifactTag: artifactTags[2], + SourceExecution: &core.CatalogMetadata_SourceTaskExecution{ + SourceTaskExecution: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + NodeId: "dn2", + ExecutionId: &executionIdentifier, + }, + RetryAttempt: 0, + }, + }, + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 6, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + }, + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-n0-0", + }, + }), + }, + }, + "n0-0-n0": { + { + BaseModel: models.BaseModel{ + ID: 2, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-n0-0", + }, + }), + }, + }, + "n0-0-n1": { + { + BaseModel: models.BaseModel{ + ID: 2, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n1", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-n1-0", + }, + }), + }, + }, + "n0-0-n2": { + { + BaseModel: models.BaseModel{ + ID: 2, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n2", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-n2-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + assert.Contains(t, updatedNodeExecutions, "n0") + assert.Contains(t, updatedNodeExecutions, "n0-0-n0") + assert.Contains(t, updatedNodeExecutions, "n0-0-n2") + assert.Len(t, updatedNodeExecutions, 3) + + for _, artifactTag := range artifactTags { + assert.Equal(t, 1, deletedArtifactIDs[artifactTag.GetArtifactId()]) + } + assert.Len(t, deletedArtifactIDs, len(artifactTags)) + }) + + t.Run("idempotency", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + for nodeID := range taskExecutionModels { + assert.Contains(t, updatedNodeExecutions, nodeID) + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + + for _, artifactTag := range artifactTags { + assert.Equal(t, 1, deletedArtifactIDs[artifactTag.GetArtifactId()]) + } + assert.Len(t, deletedArtifactIDs, len(artifactTags)) + }) + + t.Run("reserved artifact", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + + catalogClient.On("GetOrExtendReservationByArtifactTag", mock.Anything, mock.Anything, mock.Anything, + mock.Anything, mock.Anything).Return(&datacatalog.Reservation{OwnerId: "otherOwnerID"}, nil) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Len(t, resp.GetErrors().GetErrors(), len(artifactTags)) + eErr := resp.GetErrors().GetErrors()[0] + assert.Equal(t, core.CacheEvictionError_RESERVATION_NOT_ACQUIRED, eErr.Code) + assert.Equal(t, "n0", eErr.NodeExecutionId.NodeId) + assert.True(t, proto.Equal(&executionIdentifier, eErr.NodeExecutionId.ExecutionId)) + require.NotNil(t, eErr.Source) + assert.IsType(t, &core.CacheEvictionError_TaskExecutionId{}, eErr.Source) + + assert.Empty(t, updatedNodeExecutions) + }) + + t.Run("unknown artifact", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + + for nodeID := range taskExecutionModels { + for _, taskExecution := range taskExecutionModels[nodeID] { + require.NotNil(t, taskExecution.RetryAttempt) + ownerID := fmt.Sprintf("%s-%s-%d", executionIdentifier.Name, nodeID, *taskExecution.RetryAttempt) + for _, artifactTag := range artifactTags { + catalogClient.On("GetOrExtendReservationByArtifactTag", mock.Anything, mock.Anything, + artifactTag.GetName(), ownerID, mock.Anything).Return(&datacatalog.Reservation{OwnerId: ownerID}, nil) + catalogClient.On("ReleaseReservationByArtifactTag", mock.Anything, mock.Anything, + artifactTag.GetName(), ownerID).Return(nil) + } + } + } + + catalogClient.On("DeleteByArtifactID", mock.Anything, mock.Anything, mock.Anything). + Return(status.Error(codes.NotFound, "not found")) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + for nodeID := range taskExecutionModels { + assert.Contains(t, updatedNodeExecutions, nodeID) + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + }) + + t.Run("datacatalog error", func(t *testing.T) { + t.Run("GetOrExtendReservationByArtifactTag", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + + catalogClient.On("GetOrExtendReservationByArtifactTag", mock.Anything, mock.Anything, + mock.Anything, mock.Anything, mock.Anything).Return(nil, status.Error(codes.Internal, "error")) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Len(t, resp.GetErrors().GetErrors(), len(artifactTags)) + eErr := resp.GetErrors().GetErrors()[0] + assert.Equal(t, core.CacheEvictionError_RESERVATION_NOT_ACQUIRED, eErr.Code) + assert.Equal(t, "n0", eErr.NodeExecutionId.NodeId) + assert.True(t, proto.Equal(&executionIdentifier, eErr.NodeExecutionId.ExecutionId)) + require.NotNil(t, eErr.Source) + assert.IsType(t, &core.CacheEvictionError_TaskExecutionId{}, eErr.Source) + + assert.Empty(t, updatedNodeExecutions) + }) + + t.Run("DeleteByArtifactID", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + + for nodeID := range taskExecutionModels { + for _, taskExecution := range taskExecutionModels[nodeID] { + require.NotNil(t, taskExecution.RetryAttempt) + ownerID := fmt.Sprintf("%s-%s-%d", executionIdentifier.Name, nodeID, *taskExecution.RetryAttempt) + for _, artifactTag := range artifactTags { + catalogClient.On("GetOrExtendReservationByArtifactTag", mock.Anything, mock.Anything, + artifactTag.GetName(), ownerID, mock.Anything).Return(&datacatalog.Reservation{OwnerId: ownerID}, nil) + } + } + } + + catalogClient.On("DeleteByArtifactID", mock.Anything, mock.Anything, mock.Anything). + Return(status.Error(codes.Internal, "error")) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Len(t, resp.GetErrors().GetErrors(), len(artifactTags)) + eErr := resp.GetErrors().GetErrors()[0] + assert.Equal(t, core.CacheEvictionError_ARTIFACT_DELETE_FAILED, eErr.Code) + assert.Equal(t, "n0", eErr.NodeExecutionId.NodeId) + assert.True(t, proto.Equal(&executionIdentifier, eErr.NodeExecutionId.ExecutionId)) + require.NotNil(t, eErr.Source) + assert.IsType(t, &core.CacheEvictionError_TaskExecutionId{}, eErr.Source) + + for nodeID := range taskExecutionModels { + assert.Contains(t, updatedNodeExecutions, nodeID) + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + }) + + t.Run("ReleaseReservationByArtifactTag", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + + for nodeID := range taskExecutionModels { + for _, taskExecution := range taskExecutionModels[nodeID] { + require.NotNil(t, taskExecution.RetryAttempt) + ownerID := fmt.Sprintf("%s-%s-%d", executionIdentifier.Name, nodeID, *taskExecution.RetryAttempt) + for _, artifactTag := range artifactTags { + catalogClient.On("GetOrExtendReservationByArtifactTag", mock.Anything, mock.Anything, + artifactTag.GetName(), ownerID, mock.Anything).Return(&datacatalog.Reservation{OwnerId: ownerID}, nil) + } + } + } + + deletedArtifactIDs := make(map[string]int) + for _, artifactTag := range artifactTags { + catalogClient.On("DeleteByArtifactID", mock.Anything, mock.Anything, artifactTag.GetArtifactId()). + Run(func(args mock.Arguments) { + deletedArtifactIDs[args.Get(2).(string)] = deletedArtifactIDs[args.Get(2).(string)] + 1 + }). + Return(nil) + } + + catalogClient.On("ReleaseReservationByArtifactTag", mock.Anything, mock.Anything, + mock.Anything, mock.Anything).Return(status.Error(codes.Internal, "error")) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Len(t, resp.GetErrors().GetErrors(), len(artifactTags)) + eErr := resp.GetErrors().GetErrors()[0] + assert.Equal(t, core.CacheEvictionError_RESERVATION_NOT_RELEASED, eErr.Code) + assert.Equal(t, "n0", eErr.NodeExecutionId.NodeId) + assert.True(t, proto.Equal(&executionIdentifier, eErr.NodeExecutionId.ExecutionId)) + require.NotNil(t, eErr.Source) + assert.IsType(t, &core.CacheEvictionError_TaskExecutionId{}, eErr.Source) + + for nodeID := range taskExecutionModels { + assert.Contains(t, updatedNodeExecutions, nodeID) + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + }) + }) + + t.Run("repository error", func(t *testing.T) { + t.Run("NodeExecutionRepo", func(t *testing.T) { + t.Run("Get", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + + repository.NodeExecutionRepo().(*repositoryMocks.MockNodeExecutionRepo).SetGetCallback( + func(ctx context.Context, input interfaces.NodeExecutionResource) (models.NodeExecution, error) { + return models.NodeExecution{}, flyteAdminErrors.NewFlyteAdminErrorf(codes.Internal, "error") + }) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + require.Error(t, err) + s, ok := status.FromError(err) + require.True(t, ok) + assert.Equal(t, codes.Internal, s.Code()) + assert.Nil(t, resp) + + assert.Empty(t, updatedNodeExecutions) + }) + + t.Run("UpdateSelected", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + + repository.NodeExecutionRepo().(*repositoryMocks.MockNodeExecutionRepo).SetUpdateSelectedCallback( + func(ctx context.Context, nodeExecution *models.NodeExecution, selectedFields []string) error { + return flyteAdminErrors.NewFlyteAdminError(codes.Internal, "error") + }) + + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Len(t, resp.GetErrors().GetErrors(), len(artifactTags)) + eErr := resp.GetErrors().GetErrors()[0] + assert.Equal(t, core.CacheEvictionError_DATABASE_UPDATE_FAILED, eErr.Code) + assert.Equal(t, "n0", eErr.NodeExecutionId.NodeId) + assert.True(t, proto.Equal(&executionIdentifier, eErr.NodeExecutionId.ExecutionId)) + require.NotNil(t, eErr.Source) + assert.IsType(t, &core.CacheEvictionError_TaskExecutionId{}, eErr.Source) + + assert.Empty(t, updatedNodeExecutions) + assert.Empty(t, deletedArtifactIDs) + }) + }) + + t.Run("TaskExecutionRepo", func(t *testing.T) { + t.Run("List", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + + repository.TaskExecutionRepo().(*repositoryMocks.MockTaskExecutionRepo).SetListCallback( + func(ctx context.Context, input interfaces.ListResourceInput) (interfaces.TaskExecutionCollectionOutput, error) { + return interfaces.TaskExecutionCollectionOutput{}, flyteAdminErrors.NewFlyteAdminError(codes.Internal, "error") + }) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Len(t, resp.GetErrors().GetErrors(), len(artifactTags)) + eErr := resp.GetErrors().GetErrors()[0] + assert.Equal(t, core.CacheEvictionError_INTERNAL, eErr.Code) + assert.Equal(t, "n0", eErr.NodeExecutionId.NodeId) + assert.True(t, proto.Equal(&executionIdentifier, eErr.NodeExecutionId.ExecutionId)) + require.NotNil(t, eErr.Source) + assert.IsType(t, &core.CacheEvictionError_WorkflowExecutionId{}, eErr.Source) + + assert.Empty(t, updatedNodeExecutions) + }) + + t.Run("Get", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + + repository.TaskExecutionRepo().(*repositoryMocks.MockTaskExecutionRepo).SetGetCallback( + func(ctx context.Context, input interfaces.GetTaskExecutionInput) (models.TaskExecution, error) { + return models.TaskExecution{}, flyteAdminErrors.NewFlyteAdminError(codes.Internal, "error") + }) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + require.Error(t, err) + s, ok := status.FromError(err) + require.True(t, ok) + assert.Equal(t, codes.Internal, s.Code()) + assert.Nil(t, resp) + + assert.Empty(t, updatedNodeExecutions) + }) + }) + }) + + t.Run("subtask with identical artifact tags", func(t *testing.T) { + repository := repositoryMocks.NewMockRepository() + catalogClient := &mocks.Client{} + mockConfig := getMockExecutionsConfigProvider() + + artifactTags := []*core.CatalogArtifactTag{ + { + ArtifactId: "0285ddb9-ddfb-4835-bc22-80e1bdf7f560", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYM", + }, + { + ArtifactId: "4074be3e-7cee-4a7b-8c45-56577fa32f24", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYN", + }, + { + ArtifactId: "a8bd60d5-b2bb-4b06-a2ac-240d183a4ca8", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYN", + }, + { + ArtifactId: "8a47c342-ff71-481e-9c7b-0e6ecb57e742", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYN", + }, + { + ArtifactId: "dafdef15-0aba-4f7c-a4aa-deba89568277", + Name: "flyte_cached-G3ACyxqY0U3sEf99tLMta5vuLCOk7j9O7MStxubzxYN", + }, + } + + nodeExecutionModels := []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 1, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: true, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + ArtifactTag: artifactTags[0], + }, + }, + }, + }), + ChildNodeExecutions: []models.NodeExecution{ + { + BaseModel: models.BaseModel{ + ID: 2, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-start-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "start-node", + }), + }, + { + BaseModel: models.BaseModel{ + ID: 3, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n0", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n0", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_sub", + Version: "version", + }, + ArtifactTag: artifactTags[1], + SourceExecution: &core.CatalogMetadata_SourceTaskExecution{ + SourceTaskExecution: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + NodeId: "dn0", + ExecutionId: &executionIdentifier, + }, + RetryAttempt: 0, + }, + }, + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 4, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n1", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n1", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_sub", + Version: "version", + }, + ArtifactTag: artifactTags[2], + SourceExecution: &core.CatalogMetadata_SourceTaskExecution{ + SourceTaskExecution: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + NodeId: "dn0", + ExecutionId: &executionIdentifier, + }, + RetryAttempt: 0, + }, + }, + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 5, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n2", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n2", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_sub", + Version: "version", + }, + ArtifactTag: artifactTags[3], + SourceExecution: &core.CatalogMetadata_SourceTaskExecution{ + SourceTaskExecution: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + NodeId: "dn2", + ExecutionId: &executionIdentifier, + }, + RetryAttempt: 0, + }, + }, + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 6, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n3", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "n3", + }), + Closure: serializeNodeExecutionClosure(t, &admin.NodeExecutionClosure{ + TargetMetadata: &admin.NodeExecutionClosure_TaskNodeMetadata{ + TaskNodeMetadata: &admin.TaskNodeMetadata{ + CacheStatus: core.CatalogCacheStatus_CACHE_POPULATED, + CatalogKey: &core.CatalogMetadata{ + DatasetId: &core.Identifier{ + ResourceType: core.ResourceType_DATASET, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_sub", + Version: "version", + }, + ArtifactTag: artifactTags[4], + SourceExecution: &core.CatalogMetadata_SourceTaskExecution{ + SourceTaskExecution: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + NodeId: "dn3", + ExecutionId: &executionIdentifier, + }, + RetryAttempt: 0, + }, + }, + }, + }, + }, + }), + }, + { + BaseModel: models.BaseModel{ + ID: 7, + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-end-node", + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + NodeExecutionMetadata: serializeNodeExecutionMetadata(t, &admin.NodeExecutionMetaData{ + IsParentNode: false, + IsDynamic: false, + SpecNodeId: "end-node", + }), + }, + }, + }, + } + + taskExecutionModels := map[string][]models.TaskExecution{ + "n0": { + { + BaseModel: models.BaseModel{ + ID: 1, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache_single_task", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-n0-0", + }, + }), + }, + }, + "n0-0-n0": { + { + BaseModel: models.BaseModel{ + ID: 2, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n0", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-n0-0", + }, + }), + }, + }, + "n0-0-n1": { + { + BaseModel: models.BaseModel{ + ID: 2, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n1", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-n1-0", + }, + }), + }, + }, + "n0-0-n2": { + { + BaseModel: models.BaseModel{ + ID: 3, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n2", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-n2-0", + }, + }), + }, + }, + "n0-0-n3": { + { + BaseModel: models.BaseModel{ + ID: 4, + }, + TaskExecutionKey: models.TaskExecutionKey{ + TaskKey: models.TaskKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: "flyte_task-test.evict.execution_cache", + Version: "version", + }, + NodeExecutionKey: models.NodeExecutionKey{ + ExecutionKey: models.ExecutionKey{ + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + }, + NodeID: "n0-0-n3", + }, + RetryAttempt: ptr[uint32](0), + }, + Phase: core.NodeExecution_SUCCEEDED.String(), + Closure: serializeTaskExecutionClosure(t, &admin.TaskExecutionClosure{ + Metadata: &event.TaskExecutionMetadata{ + GeneratedName: "name-n0-0-n3-0", + }, + }), + }, + }, + } + + updatedNodeExecutions := setupCacheEvictionMockRepositories(t, repository, nil, nodeExecutionModels, + taskExecutionModels) + deletedArtifactIDs := setupCacheEvictionCatalogClient(t, catalogClient, artifactTags, taskExecutionModels) + + cacheManager := NewCacheManager(repository, mockConfig, catalogClient, promutils.NewTestScope()) + request := service.EvictTaskExecutionCacheRequest{ + TaskExecutionId: &core.TaskExecutionIdentifier{ + TaskId: &core.Identifier{ + ResourceType: core.ResourceType_TASK, + Project: executionIdentifier.Project, + Domain: executionIdentifier.Domain, + Name: executionIdentifier.Name, + Version: version, + }, + NodeExecutionId: &core.NodeExecutionIdentifier{ + ExecutionId: &executionIdentifier, + NodeId: "n0", + }, + RetryAttempt: uint32(0), + }, + } + resp, err := cacheManager.EvictTaskExecutionCache(context.Background(), request) + require.NoError(t, err) + require.NotNil(t, resp) + assert.Empty(t, resp.GetErrors().GetErrors()) + + for nodeID := range taskExecutionModels { + assert.Contains(t, updatedNodeExecutions, nodeID) + } + assert.Len(t, updatedNodeExecutions, len(taskExecutionModels)) + + for _, artifactTag := range artifactTags { + assert.Equal(t, 1, deletedArtifactIDs[artifactTag.GetArtifactId()]) + } + assert.Len(t, deletedArtifactIDs, len(artifactTags)) + }) +} diff --git a/pkg/manager/impl/execution_manager_test.go b/pkg/manager/impl/execution_manager_test.go index bd1c6d1ef..e9ec45556 100644 --- a/pkg/manager/impl/execution_manager_test.go +++ b/pkg/manager/impl/execution_manager_test.go @@ -367,7 +367,7 @@ func TestCreateExecution(t *testing.T) { Id: &executionIdentifier, } assert.Nil(t, err) - assert.Equal(t, expectedResponse, response) + assert.True(t, proto.Equal(expectedResponse, response)) // TODO: Check for offloaded inputs } @@ -461,7 +461,7 @@ func TestCreateExecutionFromWorkflowNode(t *testing.T) { Id: &executionIdentifier, } assert.Nil(t, err) - assert.Equal(t, expectedResponse, response) + assert.True(t, proto.Equal(expectedResponse, response)) } func TestCreateExecution_NoAssignedName(t *testing.T) { @@ -545,7 +545,7 @@ func TestCreateExecution_TaggedQueue(t *testing.T) { Id: &executionIdentifier, } assert.Nil(t, err) - assert.Equal(t, expectedResponse, response) + assert.True(t, proto.Equal(expectedResponse, response)) } func TestCreateExecutionValidationError(t *testing.T) { @@ -896,7 +896,7 @@ func TestCreateExecutionDynamicLabelsAndAnnotations(t *testing.T) { Id: &executionIdentifier, } assert.Nil(t, err) - assert.Equal(t, expectedResponse, response) + assert.True(t, proto.Equal(expectedResponse, response)) } func TestCreateExecutionInterruptible(t *testing.T) { @@ -3559,7 +3559,7 @@ func TestCreateExecution_LegacyClient(t *testing.T) { Id: &executionIdentifier, } assert.Nil(t, err) - assert.Equal(t, expectedResponse, response) + assert.True(t, proto.Equal(expectedResponse, response)) } func TestRelaunchExecution_LegacyModel(t *testing.T) { diff --git a/pkg/manager/impl/shared/constants.go b/pkg/manager/impl/shared/constants.go index 469bd3e3b..09684468b 100644 --- a/pkg/manager/impl/shared/constants.go +++ b/pkg/manager/impl/shared/constants.go @@ -35,4 +35,6 @@ const ( // Parent of a node execution in the node executions table ParentID = "parent_id" WorkflowClosure = "workflow_closure" + CreatedAt = "created_at" + Closure = "closure" ) diff --git a/pkg/manager/interfaces/cache.go b/pkg/manager/interfaces/cache.go new file mode 100644 index 000000000..c2bd3c3d0 --- /dev/null +++ b/pkg/manager/interfaces/cache.go @@ -0,0 +1,12 @@ +package interfaces + +import ( + "context" + + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/service" +) + +type CacheInterface interface { + EvictExecutionCache(ctx context.Context, request service.EvictExecutionCacheRequest) (*service.EvictCacheResponse, error) + EvictTaskExecutionCache(ctx context.Context, request service.EvictTaskExecutionCacheRequest) (*service.EvictCacheResponse, error) +} diff --git a/pkg/manager/mocks/cache.go b/pkg/manager/mocks/cache.go new file mode 100644 index 000000000..37a21df6a --- /dev/null +++ b/pkg/manager/mocks/cache.go @@ -0,0 +1,42 @@ +package mocks + +import ( + "context" + + "github.com/flyteorg/flyteadmin/pkg/manager/interfaces" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/service" +) + +var ( + _ interfaces.CacheInterface = &MockCacheManager{} +) + +type EvictExecutionCacheFunc func(ctx context.Context, req service.EvictExecutionCacheRequest) (*service.EvictCacheResponse, error) +type EvictTaskExecutionCacheFunc func(ctx context.Context, req service.EvictTaskExecutionCacheRequest) (*service.EvictCacheResponse, error) + +type MockCacheManager struct { + evictExecutionCacheFunc EvictExecutionCacheFunc + evictTaskExecutionCacheFunc EvictTaskExecutionCacheFunc +} + +func (m *MockCacheManager) SetEvictExecutionCacheFunc(evictExecutionCacheFunc EvictExecutionCacheFunc) { + m.evictExecutionCacheFunc = evictExecutionCacheFunc +} + +func (m *MockCacheManager) EvictExecutionCache(ctx context.Context, req service.EvictExecutionCacheRequest) (*service.EvictCacheResponse, error) { + if m.evictExecutionCacheFunc != nil { + return m.evictExecutionCacheFunc(ctx, req) + } + return nil, nil +} + +func (m *MockCacheManager) SetEvictTaskExecutionCacheFunc(evictTaskExecutionCacheFunc EvictTaskExecutionCacheFunc) { + m.evictTaskExecutionCacheFunc = evictTaskExecutionCacheFunc +} + +func (m *MockCacheManager) EvictTaskExecutionCache(ctx context.Context, req service.EvictTaskExecutionCacheRequest) (*service.EvictCacheResponse, error) { + if m.evictTaskExecutionCacheFunc != nil { + return m.evictTaskExecutionCacheFunc(ctx, req) + } + return nil, nil +} diff --git a/pkg/rpc/cacheservice/base.go b/pkg/rpc/cacheservice/base.go new file mode 100644 index 000000000..440504c25 --- /dev/null +++ b/pkg/rpc/cacheservice/base.go @@ -0,0 +1,86 @@ +package cacheservice + +import ( + "context" + "fmt" + + "runtime/debug" + + "github.com/golang/protobuf/proto" + "google.golang.org/grpc" + + manager "github.com/flyteorg/flyteadmin/pkg/manager/impl" + "github.com/flyteorg/flyteadmin/pkg/manager/interfaces" + "github.com/flyteorg/flyteadmin/pkg/repositories" + "github.com/flyteorg/flyteadmin/pkg/repositories/errors" + runtimeInterfaces "github.com/flyteorg/flyteadmin/pkg/runtime/interfaces" + "github.com/flyteorg/flyteidl/clients/go/admin" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/service" + "github.com/flyteorg/flytestdlib/catalog" + "github.com/flyteorg/flytestdlib/logger" + "github.com/flyteorg/flytestdlib/promutils" + "github.com/flyteorg/flytestdlib/storage" +) + +type CacheService struct { + service.UnimplementedCacheServiceServer + + CacheManager interfaces.CacheInterface + Metrics CacheMetrics +} + +// Intercepts all cache requests to handle panics during execution. +func (s *CacheService) interceptPanic(ctx context.Context, request proto.Message) { + err := recover() + if err == nil { + return + } + + s.Metrics.PanicCounter.Inc() + logger.Fatalf(ctx, "panic-ed for request: [%+v] with err: %v with Stack: %v", request, err, string(debug.Stack())) +} + +func NewCacheServer(ctx context.Context, config runtimeInterfaces.Configuration, storageClient *storage.DataStore, + cacheScope promutils.Scope) *CacheService { + panicCounter := cacheScope.MustNewCounter("initialization_panic", + "panics encountered initializing the cache service") + + defer func() { + if err := recover(); err != nil { + panicCounter.Inc() + logger.Fatalf(ctx, fmt.Sprintf("caught panic: %v [%+v]", err, string(debug.Stack()))) + } + }() + + databaseConfig := config.ApplicationConfiguration().GetDbConfig() + logConfig := logger.GetConfig() + + db, err := repositories.GetDB(ctx, databaseConfig, logConfig) + if err != nil { + logger.Fatal(ctx, err) + } + dbScope := cacheScope.NewSubScope("database") + repo := repositories.NewGormRepo( + db, errors.NewPostgresErrorTransformer(cacheScope.NewSubScope("errors")), dbScope) + + // flyteadmin config/auth optionally used by datacatalog client (if enabled) + adminCfg := admin.GetConfig(ctx) + adminCredentialsFuture := admin.NewPerRPCCredentialsFuture() + adminAuthOpts := []grpc.DialOption{ + grpc.WithChainUnaryInterceptor(admin.NewAuthInterceptor(adminCfg, nil, adminCredentialsFuture)), + grpc.WithPerRPCCredentials(adminCredentialsFuture), + } + + catalogClient, err := catalog.NewClient(ctx, adminAuthOpts...) + if err != nil { + logger.Fatal(ctx, err) + } + + cacheManager := manager.NewCacheManager(repo, config, catalogClient, cacheScope.NewSubScope("cache_manager")) + + logger.Info(ctx, "Initializing a new CacheService") + return &CacheService{ + CacheManager: cacheManager, + Metrics: InitMetrics(cacheScope), + } +} diff --git a/pkg/rpc/cacheservice/cache.go b/pkg/rpc/cacheservice/cache.go new file mode 100644 index 000000000..b8a969584 --- /dev/null +++ b/pkg/rpc/cacheservice/cache.go @@ -0,0 +1,59 @@ +package cacheservice + +import ( + "context" + + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + + "github.com/flyteorg/flyteadmin/pkg/rpc/adminservice/util" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/core" + "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/service" + "github.com/flyteorg/flytestdlib/logger" +) + +func (s *CacheService) EvictExecutionCache(ctx context.Context, req *service.EvictExecutionCacheRequest) (*service.EvictCacheResponse, error) { + defer s.interceptPanic(ctx, req) + if req == nil { + return nil, status.Errorf(codes.InvalidArgument, "Incorrect request, nil requests not allowed") + } + + var resp *service.EvictCacheResponse + var err error + s.Metrics.cacheEndpointMetrics.evictExecution.Time(func() { + resp, err = s.CacheManager.EvictExecutionCache(ctx, *req) + }) + if err != nil { + return nil, util.TransformAndRecordError(err, &s.Metrics.cacheEndpointMetrics.evictExecution) + } + s.Metrics.cacheEndpointMetrics.evictExecution.Success() + + return resp, nil +} + +func (s *CacheService) EvictTaskExecutionCache(ctx context.Context, req *service.EvictTaskExecutionCacheRequest) (*service.EvictCacheResponse, error) { + defer s.interceptPanic(ctx, req) + if req == nil { + return nil, status.Errorf(codes.InvalidArgument, "Incorrect request, nil requests not allowed") + } + + // Calling the HTTP endpoint implicitly carries the resource type information in the URL, but does not set it in the + // parsed protobuf message. Ensure task execution identifier is valid by manually setting task resource type below. + if req.TaskExecutionId != nil && req.TaskExecutionId.TaskId != nil && + req.TaskExecutionId.TaskId.ResourceType == core.ResourceType_UNSPECIFIED { + logger.Infof(ctx, "Adding task resource type for unspecified value in request: [%+v]", req) + req.TaskExecutionId.TaskId.ResourceType = core.ResourceType_TASK + } + + var resp *service.EvictCacheResponse + var err error + s.Metrics.cacheEndpointMetrics.evictTaskExecution.Time(func() { + resp, err = s.CacheManager.EvictTaskExecutionCache(ctx, *req) + }) + if err != nil { + return nil, util.TransformAndRecordError(err, &s.Metrics.cacheEndpointMetrics.evictTaskExecution) + } + s.Metrics.cacheEndpointMetrics.evictTaskExecution.Success() + + return resp, nil +} diff --git a/pkg/rpc/cacheservice/metrics.go b/pkg/rpc/cacheservice/metrics.go new file mode 100644 index 000000000..6803617b8 --- /dev/null +++ b/pkg/rpc/cacheservice/metrics.go @@ -0,0 +1,36 @@ +package cacheservice + +import ( + "github.com/prometheus/client_golang/prometheus" + + "github.com/flyteorg/flyteadmin/pkg/rpc/adminservice/util" + "github.com/flyteorg/flytestdlib/promutils" +) + +type cacheEndpointMetrics struct { + scope promutils.Scope + + evictExecution util.RequestMetrics + evictTaskExecution util.RequestMetrics +} + +type CacheMetrics struct { + Scope promutils.Scope + PanicCounter prometheus.Counter + + cacheEndpointMetrics cacheEndpointMetrics +} + +func InitMetrics(cacheScope promutils.Scope) CacheMetrics { + return CacheMetrics{ + Scope: cacheScope, + PanicCounter: cacheScope.MustNewCounter("handler_panic", + "panics encountered while handling requests to the cache service"), + + cacheEndpointMetrics: cacheEndpointMetrics{ + scope: cacheScope, + evictExecution: util.NewRequestMetrics(cacheScope, "evict_execution"), + evictTaskExecution: util.NewRequestMetrics(cacheScope, "evict_task_execution"), + }, + } +} diff --git a/pkg/server/service.go b/pkg/server/service.go index 345072123..9a4f5f447 100644 --- a/pkg/server/service.go +++ b/pkg/server/service.go @@ -27,6 +27,7 @@ import ( "github.com/flyteorg/flyteadmin/pkg/config" "github.com/flyteorg/flyteadmin/pkg/rpc" "github.com/flyteorg/flyteadmin/pkg/rpc/adminservice" + "github.com/flyteorg/flyteadmin/pkg/rpc/cacheservice" runtimeIfaces "github.com/flyteorg/flyteadmin/pkg/runtime/interfaces" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/service" "github.com/flyteorg/flytepropeller/pkg/controller/nodes/task/secretmanager" @@ -129,6 +130,8 @@ func newGRPCServer(ctx context.Context, pluginRegistry *plugins.Registry, cfg *c service.RegisterSignalServiceServer(grpcServer, rpc.NewSignalServer(ctx, configuration, scope.NewSubScope("signal"))) + service.RegisterCacheServiceServer(grpcServer, cacheservice.NewCacheServer(ctx, configuration, dataStorageClient, scope.NewSubScope("cache"))) + healthServer := health.NewServer() healthServer.SetServingStatus("flyteadmin", grpc_health_v1.HealthCheckResponse_SERVING) grpc_health_v1.RegisterHealthServer(grpcServer, healthServer) @@ -223,6 +226,11 @@ func newHTTPServer(ctx context.Context, cfg *config.ServerConfig, _ *authConfig. return nil, errors.Wrap(err, "error registering data proxy service") } + err = service.RegisterCacheServiceHandlerFromEndpoint(ctx, gwmux, grpcAddress, grpcConnectionOpts) + if err != nil { + return nil, errors.Wrap(err, "error registering cache service") + } + mux.Handle("/", gwmux) return mux, nil