chore(driver/gcs): add GCS driver to store releases

Signed-off-by: Julien Breux <julienbreux@google.com>
pull/10922/head
Julien Breux 3 years ago
parent 49819b4ef7
commit 5900066f7b
No known key found for this signature in database
GPG Key ID: BA2EB0E039AE0AB3

@ -51,8 +51,10 @@ Environment variables:
| $HELM_CONFIG_HOME | set an alternative location for storing Helm configuration. |
| $HELM_DATA_HOME | set an alternative location for storing Helm data. |
| $HELM_DEBUG | indicate whether or not Helm is running in Debug mode |
| $HELM_DRIVER | set the backend storage driver. Values are: configmap, secret, memory, sql. |
| $HELM_DRIVER | set the backend storage driver. Values are: configmap, secret, memory, sql, gcs. |
| $HELM_DRIVER_SQL_CONNECTION_STRING | set the connection string the SQL storage driver should use. |
| $HELM_DRIVER_GCS_BUCKET | set the bucket identifier the GCS storage driver should use. |
| $HELM_DRIVER_GCS_PREFIX_PATH | set the prefix path the GCS storage driver should use. |
| $HELM_MAX_HISTORY | set the maximum number of helm release history. |
| $HELM_NAMESPACE | set the namespace used for the helm operations. |
| $HELM_NO_PLUGINS | disable plugins. Set HELM_NO_PLUGINS=1 to disable plugins. |

@ -46,7 +46,10 @@ require (
)
require (
cloud.google.com/go v0.99.0 // indirect
cloud.google.com/go v0.100.2 // indirect
cloud.google.com/go/compute v1.5.0 // indirect
cloud.google.com/go/iam v0.3.0 // indirect
cloud.google.com/go/storage v1.22.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.20 // indirect
@ -87,14 +90,17 @@ require (
github.com/go-openapi/swag v0.19.14 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.0.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/gomodule/redigo v1.8.2 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/go-cmp v0.5.6 // indirect
github.com/google/go-cmp v0.5.7 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.2.0 // indirect
github.com/googleapis/gax-go/v2 v2.2.0 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/googleapis/go-type-adapters v1.0.0 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
@ -138,17 +144,20 @@ require (
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 // indirect
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 // indirect
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f // indirect
go.opencensus.io v0.23.0 // indirect
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/net v0.0.0-20220325170049-de3da57026de // indirect
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/api v0.74.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 // indirect
google.golang.org/grpc v1.43.0 // indirect
google.golang.org/protobuf v1.27.1 // indirect
google.golang.org/genproto v0.0.0-20220405205423-9d709892a2bf // indirect
google.golang.org/grpc v1.45.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect

@ -29,15 +29,23 @@ cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
cloud.google.com/go v0.99.0 h1:y/cM2iqGgGi5D5DQZl6D9STN/3dR/Vx5Mp8s752oJTY=
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
cloud.google.com/go v0.100.2 h1:t9Iw5QH5v4XtlEQaCtUY7x6sCABps8sW0acw7e2WQ6Y=
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow=
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
cloud.google.com/go/compute v1.5.0 h1:b1zWmYuuHz7gO9kDcM/EpHGr06UgsYNRpNJzI2kFiLM=
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
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/iam v0.3.0 h1:exkAomrVUuzx9kWFI1wm3KI0uoDeUFPB4kKGzx6x+Gc=
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@ -47,6 +55,8 @@ 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.22.0 h1:NUV0NNp9nkBuW66BFRLuMgldN60C57ET3dhbwLIYio8=
cloud.google.com/go/storage v1.22.0/go.mod h1:GbaLEoMqbVm6sx3Z0R++gSiBlgMv6yUi2q1DeGFKQgE=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg=
github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
@ -564,6 +574,8 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@ -599,10 +611,14 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
github.com/googleapis/gax-go/v2 v2.2.0 h1:s7jOdKSaksJVOxE0Y/S32otcfiP+UQ0cL8/GTKaONwE=
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
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 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
@ -1243,6 +1259,10 @@ golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qx
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d h1:62NvYBuaanGXR2ZOfwDFkhhl6X1DUgf8qg3GuQvxZsE=
golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220325170049-de3da57026de h1:pZB1TWnKi+o4bENlbzAgLrEbY4RMYmUIRobMcSmfeYc=
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -1261,6 +1281,9 @@ golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg=
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 h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM=
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -1378,8 +1401,14 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/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 h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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-20220328115105-d36c6a25d886 h1:eJv7u3ksNXoLbGSKuv2s/SIO4tJVxc/A+MTpzxDgz/Q=
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/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-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@ -1510,6 +1539,12 @@ google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqiv
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.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=
google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA=
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
google.golang.org/api v0.74.0 h1:ExR2D+5TYIrMphWgs5JCgwRhEDlPDXXrLwHHMgPHTXE=
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@ -1565,6 +1600,7 @@ google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
@ -1585,8 +1621,18 @@ google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ6
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=
google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 h1:Et6SkiuvnBn+SgrSYXs/BrUpGB4mbdwt4R3vaPIlicA=
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
google.golang.org/genproto v0.0.0-20220405205423-9d709892a2bf h1:JTjwKJX9erVpsw17w+OIPP7iAgEkN/r8urhWSunEDTs=
google.golang.org/genproto v0.0.0-20220405205423-9d709892a2bf/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
@ -1616,9 +1662,13 @@ google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM=
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
@ -1634,6 +1684,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

@ -407,6 +407,17 @@ func (cfg *Configuration) Init(getter genericclioptions.RESTClientGetter, namesp
panic(fmt.Sprintf("Unable to instantiate SQL driver: %v", err))
}
store = storage.Init(d)
case "gcs":
d, err := driver.NewGCS(
os.Getenv("HELM_DRIVER_GCS_BUCKET"),
namespace,
os.Getenv("HELM_DRIVER_GCS_PREFIX_PATH"),
log,
)
if err != nil {
panic(fmt.Sprintf("Unable to instantiate GCS driver: %v", err))
}
store = storage.Init(d)
default:
// Not sure what to do here.
panic("Unknown driver in HELM_DRIVER: " + helmDriver)

@ -0,0 +1,409 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package driver
import (
"context"
"errors"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"strings"
"time"
"cloud.google.com/go/storage"
"google.golang.org/api/googleapi"
"google.golang.org/api/iterator"
rspb "helm.sh/helm/v3/pkg/release"
)
const (
// GCSDriverName is the string name of this driver.
GCSDriverName = "GCS"
gcsReleaseNameMetadata = "name"
gcsReleaseNamespaceMetadata = "namespace"
gcsReleaseVersionMetadata = "version"
gcsReleaseStatusMetadata = "status"
gcsReleaseOwnerColumn = "owner"
gcsReleaseCreatedAtMetadata = "createdAt"
gcsReleaseModifiedAtMetadata = "modifiedAt"
)
// GCS is the GCS storage driver implementation.
type GCS struct {
client *storage.Client
bucket string
pathPrefix string
namespace string
Log func(string, ...interface{})
}
// NewGCS initializes a new GCS driver.
func NewGCS(bucket, pathPrefix, namespace string, logger func(string, ...interface{})) (*GCS, error) {
ctx := context.Background()
client, err := storage.NewClient(ctx)
if err != nil {
return nil, err
}
driver := &GCS{
client: client,
bucket: bucket,
pathPrefix: pathPrefix,
namespace: namespace,
Log: logger,
}
return driver, nil
}
// Name returns the name of the driver.
func (s *GCS) Name() string {
return GCSDriverName
}
// Get returns the release named by key or returns ErrReleaseNotFound.
func (s *GCS) Get(key string) (*rspb.Release, error) {
rel, _, err := s.readRelease(s.fullPathName(key, s.namespace), false)
return rel, err
}
// List returns the list of all releases such that filter(release) == true
func (s *GCS) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) {
namespaces, err := s.listNamespaces()
if err != nil {
s.Log("list: failed to list: %v", err)
return nil, err
}
var list []*rspb.Release
for _, namespace := range namespaces {
releases, err := s.listReleases(namespace)
if err != nil {
s.Log("list: failed to list releases in namespace: %v", namespace, err)
continue
}
for _, key := range releases {
release, _, err := s.readRelease(key, false)
if err != nil {
s.Log("list: failed to read release: %v: %v", release, err)
continue
}
if filter(release) {
list = append(list, release)
}
}
}
return list, nil
}
// Query returns the set of releases that match the provided set of labels
func (s *GCS) Query(labels map[string]string) ([]*rspb.Release, error) {
// List namespaces
namespaces, err := s.listNamespaces()
if err != nil {
s.Log("list: failed to list: %v", err)
return nil, err
}
// Create filter to compare labels and metadata
filter := func(metadata map[string]string) bool {
for key, val := range labels {
if metadataVal, ok := metadata[key]; !ok || metadataVal != val {
return false
}
}
return true
}
// List the releases
var list []*rspb.Release
for _, namespace := range namespaces {
releases, err := s.listReleases(namespace)
if err != nil {
s.Log("list: failed to list releases in namespace: %v", namespace, err)
continue
}
for _, key := range releases {
release, metadata, err := s.readRelease(key, true)
if err != nil {
s.Log("list: failed to read release: %v: %v", release, err)
continue
}
if filter(metadata) {
list = append(list, release)
}
}
}
if len(list) == 0 {
return nil, ErrReleaseNotFound
}
return list, nil
}
// Create creates a new release.
func (s *GCS) Create(key string, rls *rspb.Release) error {
release, err := encodeRelease(rls)
if err != nil {
s.Log("failed to encode release: %v", err)
return err
}
ctx := context.Background()
obj := s.client.Bucket(s.bucket).
Object(s.fullPathName(key, rls.Namespace)).
If(storage.Conditions{DoesNotExist: true}).
NewWriter(ctx)
obj.Metadata = s.metadata(rls, true)
if _, err := obj.Write([]byte(release)); err != nil {
s.Log("failed to write object: %v", err)
return err
}
if err := obj.Close(); err != nil {
switch e := err.(type) {
case *googleapi.Error:
if e.Code == http.StatusPreconditionFailed {
s.Log("release %s already exists", key)
return ErrReleaseExists
}
default:
s.Log("failed to close bucket: %v", err)
return err
}
}
return nil
}
// Update updates a release.
func (s *GCS) Update(key string, rls *rspb.Release) error {
release, err := encodeRelease(rls)
if err != nil {
s.Log("failed to encode release: %v", err)
return err
}
ctx := context.Background()
obj := s.client.Bucket(s.bucket).Object(s.fullPathName(key, rls.Namespace)).NewWriter(ctx)
obj.Metadata = s.metadata(rls, false)
if _, err := obj.Write([]byte(release)); err != nil {
s.Log("failed to write object: %v", err)
return err
}
if err := obj.Close(); err != nil {
s.Log("failed to close object: %v", err)
return err
}
return nil
}
// Delete deletes a release or returns ErrReleaseNotFound.
func (s *GCS) Delete(key string) (*rspb.Release, error) {
ctx := context.Background()
obj := s.client.Bucket(s.bucket).Object(s.fullPathName(key, s.namespace))
objRdr, err := obj.NewReader(ctx)
if err != nil {
if errors.Is(err, storage.ErrObjectNotExist) {
err = ErrReleaseNotFound
}
return nil, err
}
record, err := ioutil.ReadAll(objRdr)
objRdr.Close()
if err != nil {
return nil, err
}
release, err := decodeRelease(string(record))
if err != nil {
s.Log("get: failed to decode data %q: %v", key, err)
return nil, err
}
if obj.Delete(ctx); err != nil {
s.Log("failed to delete object: %v", err)
return nil, err
}
return release, nil
}
// DeletePrefixedReleases deletes all prefixed releases
func (s *GCS) DeletePrefixedReleases() error {
query := storage.Query{
Prefix: fmt.Sprintf("%s/", s.pathPrefix),
}
ctx := context.Background()
objs := s.client.Bucket(s.bucket).Objects(ctx, &query)
for {
objAttrs, err := objs.Next()
if err == iterator.Done {
break
}
if err != nil {
s.Log("unable to delete objects", err)
return err
}
obj := s.client.Bucket(s.bucket).Object(objAttrs.Name)
if obj.Delete(ctx); err != nil {
s.Log("failed to delete object: (%s) %v", objAttrs.Name, err)
}
s.Log("object deleted successfully: (%s)", objAttrs.Name)
}
return nil
}
func (s *GCS) fullPathName(name, namespace string) string {
if namespace == "" {
namespace = defaultNamespace
}
return strings.TrimLeft(
fmt.Sprintf("%s/%s/%s", s.pathPrefix, namespace, name),
"/",
)
}
func (s *GCS) metadata(rls *rspb.Release, isCreation bool) map[string]string {
ts := strconv.FormatInt(time.Now().UTC().UnixNano(), 10)
md := map[string]string{
gcsReleaseNameMetadata: rls.Name,
gcsReleaseNamespaceMetadata: rls.Namespace,
gcsReleaseStatusMetadata: rls.Info.Status.String(),
gcsReleaseVersionMetadata: strconv.Itoa(rls.Version),
gcsReleaseOwnerColumn: "helm",
gcsReleaseModifiedAtMetadata: ts,
}
if isCreation {
md[gcsReleaseCreatedAtMetadata] = ts
}
return md
}
func (s *GCS) readRelease(key string, withMetadata bool) (*rspb.Release, map[string]string, error) {
metadata := make(map[string]string)
ctx := context.Background()
objHandle := s.client.Bucket(s.bucket).Object(key)
obj, err := objHandle.NewReader(ctx)
if err != nil {
if errors.Is(err, storage.ErrObjectNotExist) {
err = ErrReleaseNotFound
}
return nil, metadata, err
}
record, err := ioutil.ReadAll(obj)
obj.Close()
if err != nil {
return nil, metadata, err
}
release, err := decodeRelease(string(record))
if err != nil {
s.Log("read release: failed to decode data %q: %v", key, err)
return nil, metadata, err
}
if withMetadata {
objAttrs, err := objHandle.Attrs(ctx)
if err != nil {
s.Log("read release: failed to read metadata %q: %v", key, err)
return nil, metadata, err
}
metadata = objAttrs.Metadata
}
return release, metadata, nil
}
func (s *GCS) listNamespaces() ([]string, error) {
if s.namespace != "" {
return []string{s.namespace}, nil
}
objectsName := make(map[string]string)
prefix := fmt.Sprintf("%s/", strings.TrimRight(s.pathPrefix, "/"))
query := storage.Query{
StartOffset: prefix,
Prefix: prefix,
}
ctx := context.Background()
objs := s.client.Bucket(s.bucket).Objects(ctx, &query)
for {
objAttrs, err := objs.Next()
if err == iterator.Done {
break
}
if err != nil {
s.Log("unable to list objects", err)
return []string{}, err
}
objectName, _, _ := strings.Cut(strings.TrimPrefix(objAttrs.Name, prefix), "/")
objectsName[objectName] = objectName
}
namespaces := []string{}
for objectName := range objectsName {
namespaces = append(namespaces, objectName)
}
return namespaces, nil
}
func (s *GCS) listReleases(namespace string) ([]string, error) {
releases := []string{}
query := storage.Query{
Prefix: strings.TrimRight(fmt.Sprintf("%s/%s", s.pathPrefix, namespace), "/"),
}
ctx := context.Background()
objs := s.client.Bucket(s.bucket).Objects(ctx, &query)
for {
objAttrs, err := objs.Next()
if err == iterator.Done {
break
}
if err != nil {
s.Log("unable to list objects", err)
return []string{}, err
}
releases = append(releases, objAttrs.Name)
}
return releases, nil
}

@ -0,0 +1,262 @@
/*
Copyright The Helm Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package driver
import (
"fmt"
"os"
"reflect"
"testing"
rspb "helm.sh/helm/v3/pkg/release"
)
var prefixes = []string{"helm-releases", "helm-releases-list"}
func TestMain(m *testing.M) {
removeReleases()
retCode := m.Run()
// removeReleases()
os.Exit(retCode)
}
func removeReleases() {
for _, prefix := range prefixes {
gcsDriver := newTestFixtureGCS(prefix, "default")
if err := gcsDriver.DeletePrefixedReleases(); err != nil {
fmt.Printf("Expected error on setup tests: %v", err)
os.Exit(1)
}
}
}
func TestGCSName(t *testing.T) {
gcsDriver := newTestFixtureGCS("helm-releases", "default")
if gcsDriver.Name() != GCSDriverName {
t.Errorf("Expected name to be %s, got %s", GCSDriverName, gcsDriver.Name())
}
}
func TestGCSGet(t *testing.T) {
vers := int(1)
name := "gcs-test-get"
key := testKey(name, vers)
rel := releaseStub(name, vers, "default", rspb.StatusDeployed)
gcsDriver := newTestFixtureGCS("helm-releases", "default")
// create stub
if err := gcsDriver.Create(key, rel); err != nil {
t.Fatalf("failed to create release with key %s: %v", key, err)
}
// test get release
got, err := gcsDriver.Get(key)
if err != nil {
t.Fatalf("Failed to get release: %v", err)
}
if !reflect.DeepEqual(rel, got) {
t.Errorf("Expected release {%v}, got {%v}", rel, got)
}
}
func TestGCSGetNotExist(t *testing.T) {
vers := int(1)
name := "gcs-test-get-not-exists"
key := testKey(name, vers)
gcsDriver := newTestFixtureGCS("helm-releases", "default")
got, err := gcsDriver.Get(key)
if err == nil || got != nil {
t.Fatal("Release must be not found")
}
}
func TestGCSCreate(t *testing.T) {
vers := 1
name := "gcs-test"
key := testKey(name, vers)
rel := releaseStub(name, vers, "default", rspb.StatusDeployed)
gcsDriver := newTestFixtureGCS("helm-releases", "default")
if err := gcsDriver.Create(key, rel); err != nil {
t.Fatalf("failed to create release with key %s: %v", key, err)
}
}
func TestGCSUpdate(t *testing.T) {
vers := 1
name := "gcs-test-update"
key := testKey(name, vers)
rel := releaseStub(name, vers, "default", rspb.StatusDeployed)
gcsDriver := newTestFixtureGCS("helm-releases", "default")
// create stub
if err := gcsDriver.Create(key, rel); err != nil {
t.Fatalf("failed to create release with key %s: %v", key, err)
}
// test update release
if err := gcsDriver.Update(key, rel); err != nil {
t.Fatalf("failed to update release with key %s: %v", key, err)
}
}
func TestGCSDelete(t *testing.T) {
vers := 1
name := "gcs-test-delete"
key := testKey(name, vers)
rel := releaseStub(name, vers, "default", rspb.StatusDeployed)
gcsDriver := newTestFixtureGCS("helm-releases", "default")
// create stub
if err := gcsDriver.Create(key, rel); err != nil {
t.Fatalf("failed to create release with key %s: %v", key, err)
}
// test delete release
deletedRelease, err := gcsDriver.Delete(key)
if err != nil {
t.Fatalf("failed to delete release with key %s: %v", key, err)
}
if !reflect.DeepEqual(rel, deletedRelease) {
t.Errorf("Expected release {%v}, got {%v}", rel, deletedRelease)
}
}
func TestGCSDeleteNotFound(t *testing.T) {
vers := 1
name := "gcs-test-delete-not-found"
key := testKey(name, vers)
gcsDriver := newTestFixtureGCS("helm-releases", "default")
if _, err := gcsDriver.Delete(key); err == nil {
t.Fatalf("release found with key %s: %v", key, err)
}
}
func TestGCSList(t *testing.T) {
namespaceA := "list-a"
namespaceB := "list-b"
tests := []struct {
key string
namespace string
status rspb.Status
}{
{"gcs-test-list-key-1", namespaceA, rspb.StatusUninstalled},
{"gcs-test-list-key-2", namespaceA, rspb.StatusUninstalled},
{"gcs-test-list-key-3", namespaceA, rspb.StatusDeployed},
{"gcs-test-list-key-4", namespaceB, rspb.StatusDeployed},
{"gcs-test-list-key-5", namespaceB, rspb.StatusSuperseded},
{"gcs-test-list-key-6", namespaceB, rspb.StatusSuperseded},
}
gcsDriver := newTestFixtureGCS("helm-releases-list", "")
// create stubs
for _, tt := range tests {
rel := releaseStub(tt.key, 1, tt.namespace, tt.status)
if err := gcsDriver.Create(tt.key, rel); err != nil {
t.Fatalf("failed to create release with key %s: %v", tt.key, err)
}
}
// list all deleted releases
del, err := gcsDriver.List(func(rel *rspb.Release) bool {
return rel.Info.Status == rspb.StatusUninstalled
})
// check
if err != nil {
t.Errorf("Failed to list deleted: %v", err)
}
if len(del) != 2 {
t.Errorf("Expected 2 deleted, got %d:\n%v\n", len(del), del)
}
// list all deployed releases
dpl, err := gcsDriver.List(func(rel *rspb.Release) bool {
return rel.Info.Status == rspb.StatusDeployed
})
// check
if err != nil {
t.Errorf("Failed to list deployed: %v", err)
}
if len(dpl) != 2 {
t.Errorf("Expected 2 deployed, got %d:\n%+v\n", len(dpl), dpl)
}
// list all superseded releases
ssd, err := gcsDriver.List(func(rel *rspb.Release) bool {
return rel.Info.Status == rspb.StatusSuperseded
})
// check
if err != nil {
t.Errorf("Failed to list superseded: %v", err)
}
if len(ssd) != 2 {
t.Errorf("Expected 2 superseded, got %d:\n%v\n", len(ssd), ssd)
}
}
func TestGCSQuery(t *testing.T) {
namespace := "default"
tests := []struct {
key string
namespace string
status rspb.Status
}{
{"gcs-test-list-key-1", namespace, rspb.StatusUninstalled},
{"gcs-test-list-key-2", namespace, rspb.StatusUninstalled},
{"gcs-test-list-key-3", namespace, rspb.StatusDeployed},
{"gcs-test-list-key-4", namespace, rspb.StatusDeployed},
{"gcs-test-list-key-5", namespace, rspb.StatusSuperseded},
{"gcs-test-list-key-6", namespace, rspb.StatusSuperseded},
}
gcsDriver := newTestFixtureGCS("helm-releases-query", "")
// create stubs
for _, tt := range tests {
rel := releaseStub(tt.key, 1, tt.namespace, tt.status)
if err := gcsDriver.Create(tt.key, rel); err != nil {
t.Fatalf("failed to create release with key %s: %v", tt.key, err)
}
}
rls, err := gcsDriver.Query(map[string]string{"status": "deployed"})
if err != nil {
t.Fatalf("Failed to query: %s", err)
}
if len(rls) != 2 {
t.Fatalf("Expected 2 results, actual %d", len(rls))
}
_, err = gcsDriver.Query(map[string]string{"name": "notExist"})
if err != ErrReleaseNotFound {
t.Errorf("Expected {%v}, got {%v}", ErrReleaseNotFound, err)
}
}

@ -21,6 +21,7 @@ import (
"fmt"
"testing"
"cloud.google.com/go/storage"
sqlmock "github.com/DATA-DOG/go-sqlmock"
sq "github.com/Masterminds/squirrel"
"github.com/jmoiron/sqlx"
@ -263,3 +264,18 @@ func newTestFixtureSQL(t *testing.T, releases ...*rspb.Release) (*SQL, sqlmock.S
statementBuilder: sq.StatementBuilder.PlaceholderFormat(sq.Dollar),
}, mock
}
// newTestFixtureGCS mocks the GCS (for testing purposes)
func newTestFixtureGCS(prefix, namespace string) *GCS {
client, _ := storage.NewClient(context.Background())
return &GCS{
client: client,
bucket: "helm-tests",
pathPrefix: prefix,
namespace: namespace,
Log: func(a string, b ...interface{}) {},
}
}

Loading…
Cancel
Save