From 180bf4836e4b2c41dcf505a5b5a0bd7145ec2882 Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Mon, 15 Jun 2026 16:36:59 +0800 Subject: [PATCH 1/5] support fsType for data mover Signed-off-by: Lyndon-Li --- .../bases/velero.io_datadownloads.yaml | 3 +++ .../v2alpha1/bases/velero.io_datauploads.yaml | 3 +++ config/crd/v2alpha1/crds/crds.go | 4 ++-- .../velero/v2alpha1/data_download_types.go | 4 ++++ pkg/apis/velero/v2alpha1/data_upload_types.go | 8 ++++++++ pkg/backup/actions/csi/pvc_action.go | 20 +++++++++++++------ pkg/controller/data_download_controller.go | 1 + pkg/exposer/generic_restore.go | 3 +++ pkg/restore/actions/csi/pvc_action.go | 1 + .../actions/dataupload_retrieve_action.go | 1 + 10 files changed, 40 insertions(+), 8 deletions(-) diff --git a/config/crd/v2alpha1/bases/velero.io_datadownloads.yaml b/config/crd/v2alpha1/bases/velero.io_datadownloads.yaml index 2f24f7e81..7a8b9441a 100644 --- a/config/crd/v2alpha1/bases/velero.io_datadownloads.yaml +++ b/config/crd/v2alpha1/bases/velero.io_datadownloads.yaml @@ -121,6 +121,9 @@ spec: description: TargetVolume is the information of the target PVC and PV. properties: + fsType: + description: FSType is the file system type of the target volume. + type: string namespace: description: Namespace is the target namespace type: string diff --git a/config/crd/v2alpha1/bases/velero.io_datauploads.yaml b/config/crd/v2alpha1/bases/velero.io_datauploads.yaml index c4c25cce6..556272aac 100644 --- a/config/crd/v2alpha1/bases/velero.io_datauploads.yaml +++ b/config/crd/v2alpha1/bases/velero.io_datauploads.yaml @@ -133,6 +133,9 @@ spec: description: SnapshotType is the type of the snapshot to be backed up. type: string + sourceFSType: + description: SourceFSType is the file system type of the source volume. + type: string sourceNamespace: description: |- SourceNamespace is the original namespace where the volume is backed up from. diff --git a/config/crd/v2alpha1/crds/crds.go b/config/crd/v2alpha1/crds/crds.go index 53e1958e8..4c62c3c08 100644 --- a/config/crd/v2alpha1/crds/crds.go +++ b/config/crd/v2alpha1/crds/crds.go @@ -29,8 +29,8 @@ import ( ) var rawCRDs = [][]byte{ - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcYK\x93\xe3\xb8\r\xbe\xf7\xaf@M\x0es\x19\xbb3yl\xa5|\x9bq'U]\xd9\xe9q\xad;}\xa7$X\xe6\x0eE2|\xd8\xebM\xf2\xdfS %\x99\x92\xe8\xe7>|3\t\x82\x1f\x01\x10\xf8@\xcdf\xb3\a\xa6\xf9\x1b\x1a˕\\\x00\xd3\x1c\x7fr(韝\x7f\xfb\x9b\x9ds\xf5\xb8\xfb\xf8\xf0\x8d\xcbj\x01Ko\x9dj~@\xab\xbc)\xf1\t7\\rǕ|hб\x8a9\xb6x\x00`R*\xc7h\xd8\xd2_\x80RIg\x94\x10hf5\xca\xf97_`Ṩ\xd0\x04\xe5\xddֻ?\xce?~7\xff\xeb\x03\x80d\r.\x80\xf4Uj/\x85b\x95\x9d\xefP\xa0Qs\xae\x1e\xacƒ\x14\xd7Fy\xbd\x80\xe3D\\\xd8n\x1a\x01?1ǞZ\x1daXp\xeb\xfe9\x99\xfa\x9e[\x17\xa6\xb5\xf0\x86\x89\xd1\xdea\xc6rY{\xc1\xccp\xee\x01\xc0\x96J\xe3\x02^hk\xcdJ\xa4\xb1\xf6L\x01\xca\fXU\x05+1\xb12\\:4K%|\xd3Yg\x06\x15\xda\xd2p\xed\x82\x15RX`\x1dsނ\xf5\xe5\x16\x98\x85\x17\xdc?>˕Q\xb5A\x1ba\x01\xfch\x95\\1\xb7]\xc0<\x8a\xcf\xf5\x96Ylg\xa3)\xd7a\xa2\x1dr\a\xc2k\x9d\xe1\xb2\xce!x\xe5\rB\xe5Mp!\x9d\xbbDp[n\x87\xd0\xf6\xcc\x12<\xe3\xb0:\t$̓:\xebX\xa3Lj\x92\xa5\x11R\xc5\x1c\xe6\x00-U\xa3\x05:\xac\xa088쎱Q\xa6an\x01\\\xba\xef\xfer\xda\x16\xad\xb1\xe6a铒C\xc3|\xa6QH\x86#\x12\xf2R\x8d&k\x1d\xe5\x98\xf8%@\x1c)\xf8\x9c\xac\x8fH\xa2\xdet\xfc\"\x14\n9P\x1bp[\x84Ϭ\xfc\xe65\xac\x9d2\xacF\xf8^\x95\xd1}\xfb-\x1a\f\x12E\x94\xa0\xe8\x05N\xbeS&\xeb:\x8d\xe5<ʶ\xca:]#\xff\r7\xfa\xd5c\xab4Ȳ\xb1ե\x9ay\x90\xe0J\xe6\x03\xecS\x8dW\x05WjD\xa9*L,6\xc0\xc4-h\xa3J\xb4\xf6L\xc0\x93\x82\x01\x8a\x97\xe3\xc0\xc44Qb\xf7'&\xf4\x96}\x8cI\xa6\xdcb\xc3\x16\xed\n\xa5Q~Z=\xbf\xfdy=\x18\x863\t\x83\x95\xceR\xa6 \xf8\xda(\xa7J%\xa0@\xb7G\x94\xd1\xf5\x8dڡ\xa1\x9a\x8d\x93\x06C\xf4\x10@\x93z\x1fhO\x8d\xc6\xf1.\v\xb7\xba\x8f\x05&\x19\x1d\x9d㿳\xc1\x1c\x00\x1d=\xae\x82\x8a*\r\xc6c\xb5\xb9\x15\xab\xd6Z\xd1y܂AmТ\x8c\xb5\x87\x86\x99\x04U\xfc\x88\xa5\x9b\x8fT\xafѐ\x1a\xb0[\xe5EE\x87ݡq`\xb0T\xb5\xe4?\xf7\xba-8\x156\x15̡u\xe12\x1a\xc9\x04\xec\x98\xf0\xf8\x81\x8c6\xd2ܰ\x03\x18\xa4=\xc1\xcbD_X`\xc78\xbe\x90\x15\xb9ܨ\x05l\x9d\xd3v\xf1\xf8Xsו\xddR5\x8d\x97\xdc\x1d\x1e\x837x\xe1\x9d2\xf6\xb1\xc2\x1d\x8aG\xcb\xeb\x193\xe5\x96;,\x9d7\xf8\xc84\x9f\x85\x83\xc8Pz\xe7M\xf5\a\xd3\x16j;\xd8v\x12\x88\xf1\x17\n\xe6\r\xee\xa1*J\xb7\x82\xb5\xaa\xe2\x11\x8f^\xa0!2\xdd\x0f\x7f_\xbfB\x87$z*:\xe5(:\xb1K\xe7\x1f\xb2&\x97\x1b4q\xddƨ&\xe8DYiť\v\x7fJ\xc1Q:\xb0\xbeh\xb8\xa30\xf8\xb7G\xeb\xc8uc\xb5\xcb@M\xa0@\xf0\x9a\xf2A5\x16x\x96\xb0d\r\x8a%\xb3\xf8;\xfb\x8a\xbcbg䄫\xbc\x95\x12\xae\xb1p4o2\xd11\xa6\x13\xaeM3\xc8ZcI^%\xc3\xd22\xbe\xe1m%\xa14\xc0\x06\xb2C\v\xe5\xaf>\xfd\xb2\xd5d,t)\xdc\xe8\xf79\xa7\xa8C+\x93D\xde\xd6:\xdb\x16)1,R\xe9oR\x1f\rje\xb9S\xe6p\xac\x92\xe3P8\xe9\x15\xfa\x95L\x96(\xee9\xde2\xac\x04.+\xb29\xf6\xa1LI(j\r@\x95\xac\x15]\xae\x81+\xe0ّ\fŶE\x97?\xa8\xccV5.\xe1\xc8)!\xe5\x8e\xe3\xe3\x16J\tdc+R\x14~\xa1\xb2\xb0Tr\xc3\xeb\xe9\xc1S\xfa{*D.\xd84\x13\xb0ɖt\n\x8aNB2\v\x15jօ.\xa5\xf6\r\xaf\xbd9\xe5\xff\rGQM\xf2\xcfɛ\xd4\x1d8\xecr\x8f\x8f{\xe8\xdd\xedj\xabZRz\x9d\n\x19\xca\x06\xbe\x9b\x84\xe6\x14$\xc0\xf3&\xd1\xc8-\xbc{\a\xca\xc0\xbb\xd8\x13\xbd\xfb\x10W{.܌\x0f\xea\xff\x9e\v\xd1\xedrSt\x13\xc3\xf9\xba\xbep\xf2\x97 Dx\xbe\xaeo\xe5VS4(}3\xddp\x06\xcc;\x95\x19\x16\\\xfa\x9f2\xe3{.+\xb5\xb7\xb7\x1c\xb6\xe77D1\x95w\xf78\xfc\xebH\xc7\xc8\xef\x8e\bq\xf0\xb5S\xb0g<\xe1\x18\xfd\xee\xf6CFo\x81\x1b*H\x06\x9d7\x92\xd2\x01\x1aC\x19\xda\x06\x95\xcaO8\xcfٓZɴ\xdd*\xf7\xfct\xe1\x8c\xeb^\xb0˻\xcfO\x9d\x8b\xdfB\xd4\xf5ɷ\x95\x84\x8c\x97\b~\xc7\"\xabP\xd6\xefB\xbb\xe6?\xe3\x95xI\xb4C,T\xcdK&\xc0\x861\xd96\x81\xed!:\xddS@\xb9>o\f7\xed\xd6\x12\xbc\x81\xfb\xf4/\x04\xf7\x84\xd1z\xa8\xa2;\x8a2\xbc\xe6\x14,\xb2\x9f9ޱ\x9d\x12\xbe\t\xa2\xe4\x12\xac\xc0\xeb\x13\xb6\x06*\x1fD\xb6\n\x84\x8ao6h\x88Q\x05\xba\x157^\xbd-\xdf\xdbd\x13\xbeI\xffP\xa5j\x98\xd6XQoG\xc1\xd8\xfa\xf6&\xaf:fjto\x01\xf4\x05\x13\xbd&\xa2\x9d)\x88\x9a\x91\x83Z\xee\x1f.W\x10\x83\xd5\xdb2\xc3\xd4\xe9\xb7z\x9b\"<\xcdc\xa0m\xdaN8q\x82r\xe2\xad\x16O\xaf#\xab\xe2l\x19\x04л+v^\xbd\xe5XQo\x0ep[\xe6H\xa2m\xb2\xa18duBw\xa5[wއ\xb7\xbc\n\xf0\xf2,\xe2\xe5\x18\xf2\t\xbc\xc5\xe1\x17C&\xd2\xc5\rV\xb9\x92s\xdas3л\xec`y=\xb5\xc8\xef<\xcb\xf3\xe7\x91̸T\x8d\xa6\x8f\xf9}<1\xcc+\xa3\xd9\xf4J^\xd5h\x84g\x90k[\x8d\xf8\xb8ٺ\xbd\xf4&$\x9d\xf6ɓ\xba\xf7\xbb\x9a\rV\x96\xa8\x1dV\x9f\x0f\xc4B\xae *\x04@\x9e\x7f\x04\xfa\x97>\xd2\x14\xd4\xec֎\xa0\x83\xd4?T\xddS\x00>\x8d\x95\x84\xd7\nS%4b\n7R\xc9Ӡ\x01^\xa9\xe4\x85n\xfb}d\x0e\xb4,\xf0\x11bԓMO\x16Ej\xa7g\xb4~\"!\xbd\x10\xac\x10\xb8\x00g\xfc\xa9\xd6\"\xdfI\xc5w\xdf\xf4\x89﮶j\xaafj;\xd6?j\x85\xc7\xc7\xee\xc59g\xb2\xa3\xbe\xde`Q\x1dV\x80;\x94@\xcd2\xe3\x02\xabNg\xa6\xbf\xb8d\xf9\f\xe8)u\xfd-\x8dߠ\xb5\xac\xbet\x81\xbeD\xa9\xf8\x0e\xd4.\x01V\x10\xcf\x1d\xb3\xfc\xf7\xb6\xbd\xdb7\xf7\x1b\xbf\xce%\xbe\xb2\xdb8\x83%\xf4\xc6\x17\xc0\xacH&\x97\xd3zh\xa7\x93\x1a\x9civ^p\x9f\x19\xed\xeegfj\xd5^\xfa\xcc\xd4\xe4\x13R:\x19\x1f!r\x85\xb1\x9b\xcb\xea\xec\xbf\xd1d\xe6\xfe\x11.\xc3M\x96n\xf1\xdds\xdd\xfb\xa7\x8c\xad\x12\xdd\r\x0f\xdfV\xa4o\n4\xe4\x86\"G\xf8\xc3\vx\xe2\xb5\x1c\xf9\xeb5\xf4\xbdKP5\x87\xd7-Q\x93\xf8\xfe\xd2us\x15\xb7Z\xb0C\x7f\x98\x94\xa1f\x94\x1fo\xcd\xe4y\xfdV\x92\xda\x7f\xeb\xca3\xaf\xf3\x8d\f\\hf\xc2|\xff\r\xeb\xb7\xd9\xe1\xcc\xeb\xcb\xf0\x9b\xe2]\xad\xd4@åR\xd0~\xe3\xbc=\x83\x0f\xb7\xf9=\x93w\xd6z\x93\xc1\x80\xbcJt\xb7\xaf\xa5\xe9\x88/\xfaO\b\v\xf8\xcf\xff\x1e\xfe\x1f\x00\x00\xff\xff73Hq. \x00\x00"), - []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcZIs\xe3\xb8\x15\xbe\xfbW\xbc\xea\x1c\xe6Ғ\xa7\xb3L\xa5tk\xcbI\x95*3nW\xcb\xf1\x1d\"\x9fD\x8cA\x80\xc1\"\x8d\xb3\xfc\xf7\xd4\x03\b\n$!Q\xd2\xf4\f\x0f]-,\x0fo\xc3\xf7\x16x6\x9bݱ\x86\xbf\xa26\\\xc9\x05\xb0\x86\xe3/\x16%\xfd2\U000f7fda9W\xf7\xfbOwo\\\x96\vX:cU\xfd\x15\x8dr\xba\xc0G\xdcr\xc9-W\xf2\xaeF\xcbJf\xd9\xe2\x0e\x80I\xa9,\xa3aC?\x01\n%\xadVB\xa0\x9e\xedP\xce\xdf\xdc\x067\x8e\x8b\x12\xb5'\x1e\x8f\xde\x7f?\xff\xf4\xc3\xfc/w\x00\x92ո\x00\xa2\xe7\x1a\xa1Xi\xe6{\x14\xa8՜\xab;\xd3`AdwZ\xb9f\x01lj\xb0\xad=2\xb0\xfb\xc8,\xfb\xa7\xa7\xe0\a\x057\xf6\x1f\x83\x89\x1f\xb9\xb1~\xb2\x11N3\xd1;Տ\x1b.wN0\x9d\xce\xdc\x01\x98B5\xb8\x80':\xb2a\x05\xd2X+\x89ga\x06\xac,\xbdn\x98x\xd6\\Z\xd4K%\\\x1du2\x83\x12M\xa1yc\xbd\xecG\x86\xc0Xf\x9d\x01\xe3\x8a\n\x98\x81'<ܯ\xe4\xb3V;\x8d&\xb0\x04\xf0\xb3Q\xf2\x99\xd9j\x01\xf3\xb0|\xdeT\xcc`;\x1bԷ\xf6\x13\xed\x90}'n\x8d\xd5\\\xeer\xe7\xbf\xf0\x1a\xa1tڛ\x8dd.\x10l\xc5M\xca\u0601\x19bN[,O\xb2\xe1牘\xb1\xacn\x86\xfc$[\x03C%\xb3\x98cg\xa9\xeaF\xa0\xc5\x126\xef\x16\xa3\x10[\xa5kf\x17\xc0\xa5\xfd\xe1ϧ5Ѫj\xee\xb7>*\xd9W\xcb\x03\x8dB2\x1c8!\v\xedPgu\xa3,\x13\xbf\x86\x11K\x04\x1e\x92\xfd\x81\x93@7\x1d\x9fde%\v\x8d5\xca\xdb\x18\xe2\xc7\xddcnR\xd2\xe9l\xa3\xb9\xd2ܾ/\xe0\xd3\xf7\x97\xb2I\xb7\x02\xd4\x16l\x85\xf0\xc0\x8a7\xd7\xc0\xda*\xcdv\b?\xaa\"\xf8ءB\xdd\xfa\xd8&,1\x95r\xa2\x84M4\f\x80\xb1Jg\x9d\xad\xc1b\x1ev\xb5t#ف\xc7\xf5\xcf\xfc\xc6w\xa1\xd0Ȳw!\x82\xe1ܯ\xe0J\xe6/\xc4\xe7\x1d^t\x19RmJUb\xa7:L9\xe2\x06\x1a\xad\n4\xe6\xcc\xf5\xa4\xed=\x1e\x9e\x8e\x03#\xb5\x84\x15\xfb?2\xd1T\xecS\x00â\u009a-\xda\x1d\xaaA\xf9\xf9y\xf5\xfa\xa7uo\x18NB\x1b+\xac!L#\xd6\x1b\xad\xac*\x94\x80\r\xda\x03\xa2\xf4\xf0\n\xb5ڣ&,\xdeqi\x80ɲ\xa3\t\xe9\x82cD!\xd7\xf7\xf4h6L\xb6\xee\xa4\x1aԩ\xd9ɕi\xcc\xf2\x18$\u0097D\xbfdt \xc4\x7fg\xbd9\x00\x92;삒\xc2 \x06\xa9\xda\x10\x80e\xab\xaa`7n@c\xa3\xd1\xd0\xf5\xf2^\xa5\xb6\xc0$\xa8\xcd\xcfX\xd8\xf9\x80\xf4\x1a5\x91\x89\xf7\xa1Pr\x8fڂ\xc6B\xed$\xffwGۀU\xfeP\xc1,\x1a\xeb/\xa4\x96L\xc0\x9e\t\x87\x1f\aڣ\xaff\uf811\xce\x04'\x13z~\x83\x19\xf2\xf1\x93\xd2\b\\n\xd5\x02*k\x1b\xb3\xb8\xbf\xdfq\x1bs\x82Bյ\x93ܾ\xdf{c\xf0\x8d\xb3J\x9b\xfb\x12\xf7(\xee\r\xdf͘.*n\xb1\xb0N\xe3=k\xf8\xcc\v\"}^0\xaf\xcb?\xe86\x8b0\xbdcG^\x18>\x1fϯ0\x0f\x85y\xba\x12\xac%\x15D\xa4M.\xb7\xa8þ\xadV\xb5\xa7\x89\xb2l\x14\x97\xd6\xff(\x04Gi\xc1\xb8M\xcd-\xb9\xc1\xbf\x1c\x1aK\xa6\x1b\x92]\xfa\xbc\t6\b\xae!((\x87\vV\x12\x96\xacF\xb1d\x06\x7fg[\x91Ǔ\x8cp\x91\xb5\xd2lp\xb88\xa87\x99\x88\t\xdd\t\xd3\x1e\xe1c\xdd`A6%\xb5\xd2&\xbe\xe5m,!\f`\xc9ʾv\xf2מ\xbel\b\x19.\x9ar5\xfa\x1er\x84\"\xaf2\xc1\xef\x18\xea\xda\xc8$\xfa\x91)\xfd\x8e \xdf\xee\xd1\xd8(í\xd2\xefD8\x84ơ\x1b\x9c\xb4\b}\x05\x93\x05\x8a[\xc4[\xfa\x9d\xc0eI\x1a\xc7\u038d\t\x80\x02UϨ\x92;E\x17+1\x04\xac,\xad \xaf6h\xf3b\xcaL(\xe3\x12\x8eI/\xa4\xc9\xedPԍR\x02\xd9P\x83\x85\xe1k\xc9\x1aS);!\xf0j\vq\xe5\xcb{\x83t\xf8r\xbd\xfaH\xff\xc4q\xf2\xa0=/[\x88\xa7[F\xd9V\xdel\xad\x9d\x97\xeb\x15\x98v\xfb\xd8H\xd2\t\xc16\x02\x17`\xb5\x1b\vv\xdaa=\xf7\x9a\xefQ\xe7f\x867\xc7/\x8c^\x18\xb6\x813>\xa9\xf6C\xafT\x90`\x94r\xa9\xa4E\x99\xb3\xd1Y\xaf\xa2/J\xba\x14\xccdy\x1ep\xb6N\xd7\xe7\xaeI$\b\x85_a+\x96\xe7\vB\xd0\xf5r\x1c7\xf1.7\x83\x03\xb7\xd5M\x12\x85\vz\xb1@\xc9\xf2\xac<\xed}\x0f\xe2\xa8\xed\x19a\x9e_\x97^\xde)\xc9(\xdc\xdc\"پg\xf4\vd\xeb{IN\xba\x01\x97\xa7\x84S\x84\x02\x04fX\x82k\xae\xe7\x9d@\x87k,\xc7<\xcfz\xf6\xcaL\xf7\x85>\x81$\xa3\xc8\x04m\xd2\xf9\x13\xa5\x95K%\xb7|7>;-\xf3\xcf]۳\xa2\x8d\"^r$i\x9c\x02\x1cq2\xf3\x19\xee,F?\xca\r\xb7|\xe7\xf4)4\xdar\x14\xe5(\x81\x99\x04\xa0\t}x&n\x89#\x9dd1~\xb7\x90\x9ad\xf6\xc1KR\x94\n\xe1o,\x03\x10t\x1f)r\x03\x1f>\x80\xd2\xf0!\xb4\x84>|\f\xbb\x1d\x17v\xc6{\xe5Ł\v\x11O\xb9*\x82v%\x05\x15t\xcaM\x85\x96\xac\x0e\xbe\fh\fTa\xa9\xf8\xf4\xe2[\x05\aƓ\xb4\xbe;\xdd|\xcc\xd0\xdd\xe0\x96r@\x8d\xd6iIQ\x18\xb5\xa6\xb4\xc8x\x92\xcae\xc2\xd0\x19IM\x12\x12'\xa4\x1cFO/\x05\xfd\x7f\x88\xe5)\x00d\x04\xc8\xd9\xf8\x1c\x87>e\xef\xfao\xb7\x98b\xdd'\x11\x99W\x9a\xef8)\\v3\xc7d\xacź\xb6k\xe1\x91\xccCq\xd6?;\xb44\x84\x96Grt\x9d\xc3\xe1\x84\xf6L\x96>_\xe8\xe6\xcb\xf6\xeae.\xee\xa4B\x9e_\x97S\xf6\xea\x0e\xce@9\r\x1f*^T}\xd3\xf11\xa8\x02X\xf6\x86>\xf7\xbe\x82\xcd<\x86\xcf\xf2\x99\xf8`\xcd\xf0\xf6\r\xa6S\x97\x1dN\xf5\r\x9d\x9d}~]^T\xad\xf8F\xcae\xf5Jh\xe4\xb6Z.\x9c־\x12\f\xa3j{S\xc5\u008a\x02\x1b\x8b\xe5\xc3\xfb\x93*\xa7\x9c\xfeso11\"/i%eL\xed\x9bKذkK\x8e\xc8n\xd7\x00\xbb\xe5\x9a~\x1e\x12\xf1\xad\x10]&\x809. \x02\u061cf\x1a\xe0\x85\x1cܗ\xf2\xdf\x05\x8c\xa4m\x1ey\xe9z\x8e\x0e\x1dQ\x88=W\xaa\xd5g\xb4\xff\xb6(\x9b/\xd5B\xff;m\x1d\xdeT\xb7\x8dɌu\xc7b\x81\xe9{\x9a\xb1\xf1\x9e\xd3ؑ\\\xa7\xaf@\rK\xc0=J\xa0R\x9cqA\xb1ۓ\xcc\x00\xd8y*m\x10\v\xaf,\xb1G\x13\xfby\xd9fٴ%3J\x18\xa3\xd9oi\xcc.\x85\xfc\x8aƉL\xd2\xf0\x1b\xa6\x90\xe1\xc8\xd0-0\xd9\x14\xf2|9\xcb\f0ЁH\x8b\x1b\xa7@\xebb%e\xf3\xca\xe1\xdb\xc4T\xd5>X\x0e\x95\x12\xadSKWoP\x13\xb7\xfe\x85\x04$\x1e(-,*&w\xd9\xc4#v\xf8\x11\x043\xb6u\xb7\x93\x1e\x92>\xb1\f%K\x9fD\x8e_\x8dư\xdd\x14X\xff\x14V\x85\xa6e\xbb\x05؆2ľֿ3m\f\xb9\n\x89\xe5t\xb8\xb8*H\xf4\xde\x1b\xae\xe6\xe4\xcb\xfa\x02^\xbe\xac\xe9\x90/\xeb_\xcb\vJW\xe7jF\xe6\xac\xca\f\v.\xdd/\x99\xf1\x03\x97\xa5:\x8c\xa1㌨\r\xb3Մ\xa0\xcf\xccV1E\xd8:!\xfc\x9eQ\xea\xdcf\x9d\x1b$L\xfcV\x19\xb4\xef\xaaM\xb1Gkr)\f^\x02\a\xa74\xff\x84\x87\xcch\f\xb9\x99\xa9\xe76\x8eg\xa6Fo\xe3\xe9dh\\\xe6\xe02\xceeiv\xcfϙ\xb9\xbf\xfb\x00w\x95\x9e[\xfen\x89\xe0]\v\xf4\x88o\xfe5y\x84r\xfdV\f\x95\x14\x89\xc52\x84\x93\xfd]\x1d\xe3)\xcd\xe1\xa5\xe2&6mc%Zr\xd3\b\xf6\xde\xc92\x156:\xdc\x1a>ƍ\x9d\xe4|\xb7\xb3{\xc4\xcfw\xaaΣ2L \xb3\x9fW\xa7Cη8\xe1L̋\xd7{\xf5xa\x89\xbdz\x8cW\x91\x97(-\xdf\xf2\xe4\x01\xf4X\xac\xf9\x86zN\x97Ç\x84\xeb\xea\xcbޟv\xdcTo\xf7(Ld\xa2\xed_\x9a\xe4\xf2\xbd5\x81\x01A\x90\x7fr[\x0e\x1f\xd9?v\x11\x9d\xd9\xf6\xdd/\x04\xff\\\x11\xab$\xa57>=\xba>\xb5\xec\v\xf4{f\x95Y\xaf\x1a\rz\xce˄v\xdb&MGܦ{\x88]\xc0\x7f\xfew\xf7\xff\x00\x00\x00\xff\xff\x12=\xc7\xe9\x11&\x00\x00"), + []byte("\x1f\x8b\b\x00\x00\x00\x00\x00\x00\xff\xbcYK\x93\xe3\xb6\x11\xbeϯ\xe8\xda\x1c\xf6\xb2\xd2d\xf3p\xa5t\xdb\xd1\xc4US\xf1Ϊ\xac\xc9\xdcA\xb2E\xc1\v\x02\b\x1e\x92\xe5$\xff\xdd\xd5\x00I\x81$4z\xd8^݄n4\xbe~\xa0\x1f\xe0l6\xbbc\x9a\xbf\xa2\xb1\\\xc9\x050\xcd\xf1g\x87\x92\xfe\xd9\xf9\xd7\x7f\xd89W\xf7\xbb\x8fw_\xb9\xac\x16\xb0\xf4֩\xe6G\xb4ʛ\x12\x1fq\xc3%w\\ɻ\x06\x1d\xab\x98c\x8b;\x00&\xa5r\x8c\x96-\xfd\x05(\x95tF\t\x81fV\xa3\x9c\x7f\xf5\x05\x16\x9e\x8b\nM\x10\xde\x1d\xbd\xfb\xf3\xfc\xe3w\xf3\xbf\xdf\x01H\xd6\xe0\x02H^\xa5\xf6R(V\xd9\xf9\x0e\x05\x1a5\xe7\xea\xcej,Ipm\x94\xd7\v8\x12\xe2\xc6\xf6\xd0\b\xf8\x919\xf6\xd8\xca\b˂[\xf7\xaf\t\xe9\an] k\xe1\r\x13\xa3\xb3\x03\xc5rY{\xc1̐v\a`K\xa5q\x01\xcft\xb4f%\xd2Z\xabS\x802\x03VU\xc1JL\xac\f\x97\x0e\xcdR\t\xdft֙A\x85\xb64\\\xbb`\x85\x14\x16Xǜ\xb7`}\xb9\x05f\xe1\x19\xf7\xf7OreTm\xd0FX\x00?Y%W\xccm\x170\x8f\xecs\xbde\x16[j4\xe5:\x10\xda%w \xbc\xd6\x19.\xeb\x1c\x82\x17\xde T\xde\x04\x17\x92\xde%\x82\xdbr;\x84\xb6g\x96\xe0\x19\x87\xd5I \x81N\xe2\xacc\x8d\x1e#J\xb6FH\x15s\x98\x03\xb4T\x8d\x16谂\xe2\xe0\xb0Sc\xa3L\xc3\xdc\x02\xb8t\xdf\xfd\xed\xb4-Zc\xcd\xc3\xd6G%\x87\x86y\xa0UH\x96#\x12\xf2R\x8d&k\x1d\xe5\x98\xf8-@\x1c\txH\xf6G$Qn\xba~\x16\n\x85\x1c\xa8\r\xb8-\xc2\x03+\xbfz\rk\xa7\f\xab\x11~Pet\xdf~\x8b\x06\x03G\x119(z\x81\x93\xef\x94ɺNc9\x8f\xbc\xad\xb0N\xd6\xc8\x7fÃ~\xf7\xd8*\r\xb2llu\xa9f\x1e8\xb8\x92\xf9\x00\xfbT\xe3E\xc1\x95\x1aQ\xaa\n\x13\x8b\r0q\vڨ\x12\xad}#\xe0I\xc0\x00\xc5\xf3qab\x9aȱ\xfb\v\x13z\xcb>\xc6$Sn\xb1a\x8bv\x87\xd2(?\xad\x9e^\xff\xba\x1e,\xc3\x1b\t\x83\x95\xceR\xa6 \xf8\xda(\xa7J%\xa0@\xb7G\x94\xd1\xf5\x8dڡ\xa1\x12\xbdFCb\xc0n\x95\x17\x15)\xbbC\xe3\xc0`\xa9j\xc9\x7f\xe9e[p*\x1c*\x98C\xeb\xc2e4\x92\t\xd81\xe1\xf1\x03\x19m$\xb9a\a0Hg\x82\x97\x89\xbc\xb0\xc1\x8eq|&+r\xb9Q\v\xd8:\xa7\xed\xe2\xfe\xbe\xe6\xae+\xbb\xa5j\x1a/\xb9;\xdc\ao\xf0\xc2;e\xec}\x85;\x14\xf7\x96\xd73f\xca-wX:o\xf0\x9ei>\v\x8a\xc8Pz\xe7M\xf5'\xd3\x16j;8v\x12\x88\xf1\x17\n\xe6\x15\xee\xa1*J\xb7\x82\xb5\xa2\xa2\x8aG/\xd0\x12\x99\xee\xc7\x7f\xae_\xa0C\x12=\x15\x9drd\x9dإ\xf3\x0fY\x93\xcb\r\x9a\xb8ocT\x13d\xa2\xac\xb4\xe2҅?\xa5\xe0(\x1dX_4\xdcQ\x18\xfcǣu亱\xd8ehM\xa0@\xf0\x9a\xf2A5fx\x92\xb0d\r\x8a%\xb3\xf8\x8d}E^\xb13r\xc2E\xdeJ\x1b\xae1s4oB\xe8:\xa6\x13\xaeM3\xc8ZcI^%\xc3\xd26\xbe\xe1m%\xa14\xc0\x06\xbcC\v\xe5\xaf>\xfd\xb2\xd5d\xcct.\xdc\xe8\xf7\x90\x13ԡ\x95I\"ok\x9dm\x8b\x94\x18\x16\xa9\xf47\xa9\x8f\x06\xb5\xb2\xdc)s8V\xc9q(\x9c\xf4\n\xfdJ&K\x14\xb7\xa8\xb7\f;\x81ˊl\x8e}(S\x12\x8aR\x03P%kE\x97k\xe0\nxr\xc4C\xb1m\xd1\xe5\x15\x95٪\xc6%\x1c{JH{DZ\xba\x85R\x02\xd9؊\x14\x85\x9f\xa9,,\x95\xdc\xf0z\xaax\xda\xfe\x9e\n\x9136\xcd\x04lr$iA\xd1IHf\xa1BͺХԾ\xe1\xb57\xa7\xfc\xbf\xe1(\xaaI\xfe9y\x93:\x85\xc3)\xb7\xf8\xb8\x87\xdeݮ\xb6\xaa%\xa5ש\x90\xa1l\xe8w\x93М\x82\x04x\xda$\x12\xb9\x85w\xef@\x19x\x17g\xa2w\x1f\xe2nυ\x9b\xf1A\xfd\xdfs!\xbaS\xae\x8an\xeap\xbe\xac\xcfh\xfe\x1c\x98\bϗ\xf5\xb5\xbd\xd5\x14\rJ\xdfL\x0f\x9c\x01\xf3Ne\x96\x05\x97\xfe\xe7\xcc\xfa\x9e\xcbJ\xed\xed5\xca\xf6\xfd\r\xb5\x98ʻ[\x1c\xfee$c\xe4wG\rq\xf0\xb5S\xb0g<\xe91\xfa\xd3퇌\xdc\x027T\x90\f:o$\xa5\x034\x862\xb4\r\"\x95\x9f\xf4\xe1]\xe6\xd2\xd9'\xbe\xb6\xb6n/\xbd\tY\xb0}\x83U\x9b\x1b\xa7\x1fV\x96\xa8\x1dV\x0f\aj\x8b.\xe8\x9c\b\x80|\xfbU\xea\xdf\xfa\xd87\xa1f\u05ce(\x1d\xa4\xfe\xe5얊\xf4i,$<\x9f\x98*\xe9k\xa6pco{\x1a4\xc0\v\xd5\xe00\xfe\xbf\x8f\xad\fm\v\r\x12\xb5\xf8\x93COVi\x9a\xefg\xb4\x7f\xc2!\xbd\x10\xac\x10\xb8\x00g\xfc\xa9Y'?\xdaŇ\xe8\xf4\xcd\xf1\xa69o*fj;ֿ\xb2\x85\xd7\xd0\xee\t\x89\x88A\x80\x83E\x8af\xf9\xef\xa9\a\x10\x14HBk:ᡫ\x8d\xe5\xe1m\xf8\xde\x02M&\x93;\xd6\xf07Ԇ+9\x03\xd6p\xfcŢ\xa4\xbf\xcc\xf4\xfd\xeff\xca\xd5\xc3\xf6\xe3\xdd;\x97\xe5\f\xe6\xceXU\x7fE\xa3\x9c.\xf0\t\xd7\\r˕\xbc\xabѲ\x92Y6\xbb\x03`R*\xcbh\xd8П\x00\x85\x92V+!PO6(\xa7\xefn\x85+\xc7E\x89\xda\x13\x8fGo\xbf\x9f~\xfca\xfa\xb7;\x00\xc9j\x9c\x01\xd1s\x8dP\xac4\xd3-\n\xd4j\xca՝i\xb0 \xb2\x1b\xad\\3\x83\xc3D\xd8\xd6\x1e\x19\xd8}b\x96\xfd\xcbS\xf0\x83\x82\x1b\xfb\xcf\xc1\xc4O\xdcX?\xd9\b\xa7\x99\xe8\x9d\xea\xc7\r\x97\x1b'\x98Ng\xee\x00L\xa1\x1a\x9c\xc13\x1dٰ\x02i\xac\x95ij0\x01V\x96^7L\xbch.-\xea\xb9\x12\xae\x8e:\x99@\x89\xa6м\xb1^\xf6\x03C`,\xb3\u0380qE\x05\xcc\xc03\xee\x1e\x16\xf2E\xab\x8dF\x13X\x02\xf8\xd9(\xf9\xc2l5\x83iX>m*f\xb0\x9d\r\xea[\xfa\x89v\xc8\xee\x89[c5\x97\x9b\xdc\xf9\xaf\xbcF(\x9d\xf6f#\x99\v\x04[q\x932\xb6c\x86\x98\xd3\x16ˣl\xf8y\"f,\xab\x9b!?\xc9\xd6\xc0P\xc9,\xe6ؙ\xab\xba\x11h\xb1\x84\xd5\xdeb\x14b\xadt\xcd\xec\f\xb8\xb4?\xfc\xf5\xb8&ZUM\xfd\xd6'%\xfbjy\xa4QH\x86\x03'd\xa1\r\xea\xacn\x94e\xe2\xb70b\x89\xc0c\xb2?p\x12\xe8\xa6\xe3gYY\xc8Bc\x8d\xf26\x86\xf8a\xf7\x98\x9b\x94t:\xdbh\xae4\xb7\xfb\x19|\xfc\xfeR6\xe9V\x80Z\x83\xad\x10\x1eY\xf1\xee\x1aXZ\xa5\xd9\x06\xe1'U\x04\x1f\xdbU\xa8[\x1f[\x85%\xa6RN\x94\xb0\x8a\x86\x010V鬳5XLî\x96n$;\xf0\xb8\xfe\x99\xdf\xf8.\x14\x1aY\xf6.D0\x9c\xfa\x15\\\xc9\xfc\x85\xf8\xb4\xc1\x8b.C\xaaM\xa9J\xecT\x87)G\xdc@\xa3U\x81Ɯ\xb8\x9e\xb4\xbd\xc7\xc3\xf3a`\xa4\x96\xb0b\xfbg&\x9a\x8a}\f`XTX\xb3Y\xbbC5(?\xbd,\xde\xfe\xb2\xec\r\xc3Qhc\x855\x84i\xc4z\xa3\x95U\x85\x12\xb0B\xbbC\x94\x1e^\xa1V[Ԅ\xc5\x1b.\r0Yv4!]p\x88(\xe4\xfa\x9e\x1e͆\xc9֝T\x83:5;\xb92\x8dY\x1e\x83D\xf8\x92藌\x0e\x84\xf8ߤ7\a@r\x87]PR\x18\xc4 U\x1b\x02\xb0lU\x15\xec\xc6\rhl4\x1a\xba^ޫ\xd4\x1a\x98\x04\xb5\xfa\x19\v;\x1d\x90^\xa2&2\xf1>\x14JnQ[\xd0X\xa8\x8d\xe4\xff\xe9h\x1b\xb0\xca\x1f*\x98Ec\xfd\x85Ԓ\t\xd82\xe1\xf0~\xa0=\xfaj\xb6\a\x8dt&8\x99\xd0\xf3\x1b̐\x8f\xcfJ#p\xb9V3\xa8\xacm\xcc\xec\xe1a\xc3m\xcc\t\nU\xd7Nr\xbb\x7f\xf0\xc6\xe0+g\x956\x0f%nQ<\x18\xbe\x990]T\xdcba\x9d\xc6\a\xd6\xf0\x89\x17D\xfa\xbc`Z\x97\x7f\xd2m\x16azǎ\xbc0|>\x9e_a\x1e\n\xf3t%XK*\x88x\xb0\x02\r\x91\xea\xbe\xfec\xf9\n\x91\x93`\xa9`\x94\xc3ґ^\xa2}H\x9b\\\xaeQ\x87}k\xadjO\x13e\xd9(.\xad\xff\xa3\x10\x1c\xa5\x05\xe3V5\xb7\xe4\x06\xffvh,\x99nHv\xee\xf3&X!\xb8\x86\xa0\xa0\x1c.XH\x98\xb3\x1aŜ\x19\xfc\x83mEV1\x132\xc2E\xd6J\xb3\xc1\xe1\xe2\xa0\xded\"&tGL{\x80\x8fe\x83\x05ٔ\xd4J\x9b\xf8\x9a\xb7\xb1\x840\x80%+\xfb\xda\xc9_{\xfa\xb2!d\xb8蜫\xd1\xf7\x98#\x14y\x95\t~\xc7P\xd7F&яL\xe9w\x00\xf9v\x8f\xc6F\x19n\x95\xde\x13\xe1\x10\x1a\x87np\xd4\"\xf4\x15L\x16(n\x11o\xeew\x02\x97%i\x1c;7&\x00\nT=\xa3Jn\x14]\xac\xc4\x10\xb0\xb0\xb4\x82\xbcڠ͋)3\xa1\x8cK8$\xbd\x90&\xb7CQWJ\tdC\r\x16\x86/%kL\xa5\xec\x19\x81\x17k\x88+_\xf7\r\xd2\xe1\xf3\xe5\xe2\x9e\xfe\x89\xe3\xe4A[^\xb6\x10O\xb7\x8c\xb2\xad\xbc\xd9Z;ϗ\v0\xed\xf6\xb1\x91\xa4\x13\x82\xad\x04\xce\xc0j7\x16\xec\xb8\xc3z\xee5ߢ\xce\xcd\fo\x8e_\x18\xbd0l\x03g|R\xed\x87ި \xc1(\xe5\\I\x8b2g\xa3\x93^E_\x94t.\x98\xc9\xf2<\xe0l\x99\xae\xcf]\x93H\x10\n\xbf\xc2V,\xcf\x17\x84\xa0\xeb\xe58l\xe2]n\x06;n\xab\x9b$\n\x17\xf4b\x81\x92\xe5Yy\xda\xfb\x1e\xc4Q\xeb\x13¼\xbcͽ\xbc\xe7$\xa3ps\x8bd۞\xd1/\x90\xad\xef%9\xe9\x06\\\x1e\x13N\x11\n\x10\x98a\t\xae\xb9\x9ew\x02\x1d\xae\xb1\x1c\xf3<\xe9\xd9+3\xdd\x17\xfa\b\x92\x8c\"\x13\xb4I\xe7gJ+\xe7J\xae\xf9f|vZ柺\xb6'E\x1bE\xbc\xe4H\xd28\x058\xe2d\xe23\xdcI\x8c~\x94\x1b\xae\xf9\xc6\xe9ch\xb4\xe6(\xcaQ\x02s\x16\x80\xce\xe8\xc33qK\x1c\xe9$\x8b\xf1\xbb\x85\xd4$\xb3\x0f^\x92\xa2T\b\x7fc\x19\x80\xa0\xfb@\x91\x1b\xf8\xf0\x01\x94\x86\x0f\xa1%\xf4\xe1>\xecv\\\xd8\t\xef\x95\x17;.D<\xe5\xaa\bڕ\x14T\xd0)w.\xb4du\xf0e@c\xa0\nKŧ\x17\xdf*\xd81\x9e\xa4\xf5\xdd\xe9\xe6>Cw\x85k\xca\x015Z\xa7%EaԚ\xd2\"\xe3I*\x97\tC'$5IH<#\xe50zz)\xe8\xffC,O\x01 #@\xceƧ8\xf4)\xfb\x8f\xcbK8L\x96F\x0e\xd7\\ \x98\xbd\xb1X\xf7\xb9\r\x95@\x00\x8c\x1b\x18\xea\x1a\x82\xb7\xf8ƲO\"\xf2\xaa4\xdfp\xf2\x00\xd9\xcd\x1c\xb2\xc3\x16|\xdb6\x8a\x87V\x1f\x1b\xb2\x17\xa6\x83oC\xf0} G\xf8\x12\x0e\xa7\xf0\xc3d\xe9\x13\x98n\xbel\xb1 \x83$g\x15\xf2\xf26\xbf\xc8Fy\x00\xcb\xde\xd1\x17\x03W\xb0\x99\x0f*\x93|i0X3\x84\x83\xc1tz\x87\x86S}Cgg_\xde\xe6\x17\x95O\xbe\xb3sY\x01\x15:˭\x96\v\xa7\xb5/MèZ\xdfTB\xb1\xa2\xc0\xc6b\xf9\xb8\x7fV\xe59\xa7\xff\xd4[L\x8c\xc8Kz[\x19S\xfbn\x176\xec\xda\x1a(\xb2\xdbu\xe4n\xb9\xa6\x9f\x86D|oF\x97\t\x82\x8f+\x9a\x80~Ǚ\x06x%\a\xf7\xbd\x85\xef\x02h\xd36\x1f\n\xe8z\x8e\x0e\x1dQ\x88M\xe0\x92Y\x9c\xd0\xfe\xdb\xc2~\xbev\f\r\xf9\xb4\x97yS!9&3\xd6\x1d\x8b\x15\xafo\xb2Ɨ\x80\x9c\xc6\x0e\xe4:}\x05jX\x02nQ\x82\x92\xb0f\\P2\xe1If\x00\xec4\x956\xaa\x86g\x9f\xd84\x8a\r\xc6l\xf7\xee\xbc%3J\x18\xa3\xd9\xefi\xcc.\xa7\xfd\x8aƉL\x16\xf3;\xe6\xb4\xe1\xc8о0ٜ\xf6t}\xcd\f0ЁH\x8b\x1b\xc7@\xebb%e\x13\xdd\xe1cɹ6\xc2`9TJ\xb4N-]\xbdBM\xdc\xfa'\x1b\x90\xb8\xa3<\xb5\xa8\x98\xdcd3\xa1\xf8\xe4\x80 \x98\xb1\xad\xbb\x1d\xf5\x90\xf4\xcdg(Y\xfaFs\xf8j4\x86m\u0381\xf5\xe7\xb0*tQ\xdb-\xc0V\x94\xb2\xf6\xb5\xfe\x9dic\xc8UH,χ\x8b\xab\x82D\xef\x01\xe4jN\xbe,/\xe0\xe5˒\x0e\xf9\xb2\xfc\xad\xbc\xa0tu\xae\x88eΪ̰\xe0\xd2\xfd\x92\x19\xdfqY\xaa\xdd\x18:N\x88\xda0[\x9d\x11\xf4\x85٪K\x92\x9d\x10~\xcf(\x97o\xb3\xce\x15\x12&~\xab\x94\u07b7\xf9αGkr)\f^\x02\a\xc74\xff\x8c\xbb\xcch\f\xb9\x99\xa9\x976\x8eg\xa6F\x8f\xf5\xe9d\xe8\xa4\xe6\xe02\xceeiv\xefᙹ\x1f}\x80\xbbJ\xcf-\x7f\xb7D\xf0\xae'{\xc07\xff\xbc=B\xb9~o\x88J\x8a\xc4b\x19\xc2\xc9\xfe\xae\x8e\xf1\x94\xa6\xf0Zq\x13\xbbȱ4.\xb9i\x04\xdbw\xb2\x9c\v\x1b\x1dn\r_\a\xc7Nr\xba\xfd\xda\xfd\xaa \xdf:;\x8d\xcap\x06\x99\xfd\xbc:\x1er\xbe\xc5\t'b^\xbcދ\xa7\vk\xfe\xc5S\xbc\x8a\xbcDi\xf9\x9a'/\xb2\x87b\xcdw\xf8s\xba\x1c\xbel\\W_\xf6~krS\xbdݣp&\x13m\x7f\xfa\x92\xcb\xf7\x96\x04\x06\x04A\xfe\rp>|\xf5\xbf\xef\":\xb3\xedCd\b\xfe\xb9\"VIJo|zt}j\xd9\x17\xe8\x8f\xcc*\xb3^5\x1a\xf4\x9c\x97\t\xed\xb6o\x9b\x8e\xb8U\xf72<\x83\xff\xfe\xff\xee\xd7\x00\x00\x00\xff\xff\xf1\x86o_\xa2&\x00\x00"), } var CRDs = crds() diff --git a/pkg/apis/velero/v2alpha1/data_download_types.go b/pkg/apis/velero/v2alpha1/data_download_types.go index 4ea7128ec..616876563 100644 --- a/pkg/apis/velero/v2alpha1/data_download_types.go +++ b/pkg/apis/velero/v2alpha1/data_download_types.go @@ -74,6 +74,10 @@ type TargetVolumeSpec struct { // Namespace is the target namespace Namespace string `json:"namespace"` + + // FSType is the file system type of the target volume. + // +optional + FSType string `json:"fsType,omitempty"` } // DataDownloadPhase represents the lifecycle phase of a DataDownload. diff --git a/pkg/apis/velero/v2alpha1/data_upload_types.go b/pkg/apis/velero/v2alpha1/data_upload_types.go index 751da4555..39ae349d6 100644 --- a/pkg/apis/velero/v2alpha1/data_upload_types.go +++ b/pkg/apis/velero/v2alpha1/data_upload_types.go @@ -60,6 +60,10 @@ type DataUploadSpec struct { // OperationTimeout specifies the time used to wait internal operations, // before returning error as timeout. OperationTimeout metav1.Duration `json:"operationTimeout"` + + // SourceFSType is the file system type of the source volume. + // +optional + SourceFSType string `json:"sourceFSType,omitempty"` } type SnapshotType string @@ -253,4 +257,8 @@ type DataUploadResult struct { // SnapshotSize is the logical size in Bytes of the snapshot. // +optional SnapshotSize int64 `json:"snapshotSize,omitempty"` + + // FSType is the file system type of the volume. + // +optional + FSType string `json:"fsType,omitempty"` } diff --git a/pkg/backup/actions/csi/pvc_action.go b/pkg/backup/actions/csi/pvc_action.go index da690626b..073ea4965 100644 --- a/pkg/backup/actions/csi/pvc_action.go +++ b/pkg/backup/actions/csi/pvc_action.go @@ -166,6 +166,7 @@ func (p *pvcBackupItemAction) validatePVCandPV( ) ( valid bool, updateItem runtime.Unstructured, + fsType string, err error, ) { updateItem = item @@ -174,6 +175,7 @@ func (p *pvcBackupItemAction) validatePVCandPV( if pvc.Spec.StorageClassName == nil { return false, updateItem, + "", errors.Errorf( "Cannot snapshot PVC %s/%s, PVC has no storage class.", pvc.Namespace, pvc.Name) @@ -187,7 +189,7 @@ func (p *pvcBackupItemAction) validatePVCandPV( // Do nothing if this is not a CSI provisioned volume pv, err := kubeutil.GetPVForPVC(&pvc, p.crClient) if err != nil { - return false, updateItem, errors.WithStack(err) + return false, updateItem, "", errors.WithStack(err) } if pv.Spec.PersistentVolumeSource.CSI == nil { @@ -202,10 +204,10 @@ func (p *pvcBackupItemAction) validatePVCandPV( }) data, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&pvc) updateItem = &unstructured.Unstructured{Object: data} - return false, updateItem, err + return false, updateItem, "", err } - return true, updateItem, nil + return true, updateItem, pv.Spec.PersistentVolumeSource.CSI.FSType, nil } func (p *pvcBackupItemAction) createVolumeSnapshot( @@ -301,10 +303,12 @@ func (p *pvcBackupItemAction) Execute( ); err != nil { return nil, nil, "", nil, errors.WithStack(err) } - if valid, item, err := p.validatePVCandPV( + + valid, item, fsType, err := p.validatePVCandPV( pvc, item, - ); !valid { + ) + if !valid { if err != nil { return nil, nil, "", nil, err } @@ -392,6 +396,7 @@ func (p *pvcBackupItemAction) Execute( &pvc, operationID, vsc, + fsType, ) if err != nil { dataUploadLog.WithError(err).Error("failed to submit DataUpload") @@ -530,6 +535,7 @@ func newDataUpload( pvc *corev1api.PersistentVolumeClaim, operationID string, vsc *snapshotv1api.VolumeSnapshotContent, + fsType string, ) *velerov2alpha1.DataUpload { dataUpload := &velerov2alpha1.DataUpload{ TypeMeta: metav1.TypeMeta{ @@ -567,6 +573,7 @@ func newDataUpload( BackupStorageLocation: backup.Spec.StorageLocation, SourceNamespace: pvc.Namespace, OperationTimeout: backup.Spec.CSISnapshotTimeout, + SourceFSType: fsType, }, } @@ -591,8 +598,9 @@ func createDataUpload( pvc *corev1api.PersistentVolumeClaim, operationID string, vsc *snapshotv1api.VolumeSnapshotContent, + fsType string, ) (*velerov2alpha1.DataUpload, error) { - dataUpload := newDataUpload(backup, vs, pvc, operationID, vsc) + dataUpload := newDataUpload(backup, vs, pvc, operationID, vsc, fsType) err := crClient.Create(ctx, dataUpload) if err != nil { diff --git a/pkg/controller/data_download_controller.go b/pkg/controller/data_download_controller.go index f98345bc0..1f442ecd9 100644 --- a/pkg/controller/data_download_controller.go +++ b/pkg/controller/data_download_controller.go @@ -479,6 +479,7 @@ func (r *DataDownloadReconciler) OnDataDownloadCompleted(ctx context.Context, na TargetPVCName: dd.Spec.TargetVolume.PVC, TargetNamespace: dd.Spec.TargetVolume.Namespace, OperationTimeout: dd.Spec.OperationTimeout.Duration, + TargetFSType: dd.Spec.TargetVolume.FSType, }) if err != nil { log.WithError(err).Error("Failed to rebind PV to target PVC on completion") diff --git a/pkg/exposer/generic_restore.go b/pkg/exposer/generic_restore.go index 1015c4e66..8091d18a5 100644 --- a/pkg/exposer/generic_restore.go +++ b/pkg/exposer/generic_restore.go @@ -91,6 +91,9 @@ type GenericRestoreRebindVolumeParam struct { // OperationTimeout specifies the time wait for resources operations in Expose OperationTimeout time.Duration + + // TargetFSType is the file system type of the target volume + TargetFSType string } // GenericRestoreExposer is the interfaces for a generic restore exposer diff --git a/pkg/restore/actions/csi/pvc_action.go b/pkg/restore/actions/csi/pvc_action.go index 76d296239..6dd98c6b6 100644 --- a/pkg/restore/actions/csi/pvc_action.go +++ b/pkg/restore/actions/csi/pvc_action.go @@ -427,6 +427,7 @@ func newDataDownload( TargetVolume: velerov2alpha1.TargetVolumeSpec{ PVC: pvc.Name, Namespace: newNamespace, + FSType: dataUploadResult.FSType, }, BackupStorageLocation: dataUploadResult.BackupStorageLocation, DataMover: dataUploadResult.DataMover, diff --git a/pkg/restore/actions/dataupload_retrieve_action.go b/pkg/restore/actions/dataupload_retrieve_action.go index 4d750d055..77e4766f5 100644 --- a/pkg/restore/actions/dataupload_retrieve_action.go +++ b/pkg/restore/actions/dataupload_retrieve_action.go @@ -80,6 +80,7 @@ func (d *DataUploadRetrieveAction) Execute(input *velero.RestoreItemActionExecut SourceNamespace: dataUpload.Spec.SourceNamespace, DataMoverResult: dataUpload.Status.DataMoverResult, NodeOS: dataUpload.Status.NodeOS, + FSType: dataUpload.Spec.SourceFSType, } jsonBytes, err := json.Marshal(dataUploadResult) From 8a31544a64de5d74b4f18e094d90410e95142671 Mon Sep 17 00:00:00 2001 From: Daniel Jiang Date: Wed, 10 Jun 2026 19:51:23 +0800 Subject: [PATCH 2/5] Design for global volume policies Add the design for global volume policies to address the requirement in #9858 Signed-off-by: Daniel Jiang --- design/global-backup-volume-policies.md | 162 ++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 design/global-backup-volume-policies.md diff --git a/design/global-backup-volume-policies.md b/design/global-backup-volume-policies.md new file mode 100644 index 000000000..3f0ae3722 --- /dev/null +++ b/design/global-backup-volume-policies.md @@ -0,0 +1,162 @@ +# Global Backup Volume Policies for Velero + +## Background + +Velero supports [resource policies](./Implemented/handle-backup-of-volumes-by-resources-filters.md) (commonly referred to as "volume policies") that let a user control how volumes are handled during a backup — for example, whether a volume is skipped, backed up via file-system backup (`fs-backup`), snapshotted, or handled by a custom plugin. + +Today these policies are defined per-backup: + +1. A user creates a ConfigMap in the Velero install namespace whose single data key holds a `ResourcePolicies` YAML document (`volumePolicies` and the related include/exclude and fine-grained filter policies). +2. The user opts a specific backup into that ConfigMap with the CLI flag `--resource-policies-configmap`, which sets `Backup.Spec.ResourcePolicy` as a reference to the ConfigMap. +3. When the backup is processed, velero loads the referenced ConfigMap, unmarshals the YAML, builds a `Policies` object, and applies it when performing the backup. + +The limitation today is that volume policies are strictly opt-in **per backup**. An administrator, who usually has the best knowledge of the environment, may want a baseline behavior to apply to *every* backup in the cluster (for example, "always skip volumes from the `gp2` storage class", or "always use `fs-backup` for NFS volumes"). However, today they must remember to attach the same ConfigMap to every backup and every schedule. There is no way to express a cluster-wide default volume policy that is enforced regardless of what an individual backup requests. + +## Goals + +- Introduce "global backup volume policies" that an administrator configures once when the Velero server starts. +- Expose it as a Velero server CLI parameter that points to a ConfigMap in the Velero install namespace. +- When a backup runs, merge the global backup volume policies with the backup's own resource policies ConfigMap (if any) and use the merged result as the effective resource policies for that backup. +- Keep the existing per-backup `--resource-policies-configmap` behavior fully backward compatible when no global policy is configured. + +## Non Goals + +- Changing the schema of the `ResourcePolicies`/`volumePolicies` YAML itself. +- Defining global defaults for anything other than resource policies (e.g. it does not introduce new global backup spec defaults). +- Supporting per-namespace or per-schedule global policy overrides. The "global policies" is a single, server-wide configuration. +- Hot-reloading the global policies ConfigMap without a server restart is out of scope for the initial implementation. +- Support setting other filters in "resource policies" (e.g. include/exclude or fine-grained filters) in the global policy is out of scope for the initial implementation. Only `volumePolicies` will be supported in the global policy for now. + +## Design + +A new Velero server flag, `--global-backup-volume-policies-configmap`, accepts the name of a ConfigMap that lives in the Velero install namespace. The ConfigMap has the exact same format as an existing per-backup resource policies ConfigMap (a single data key holding a `ResourcePolicies` YAML document). + +The flag value is plumbed from the server `Config` into the `backupReconciler`. During `prepareBackupRequest`, in addition to loading the backup's own resource policy (referenced by `Backup.Spec.ResourcePolicy`), Velero loads the global policy ConfigMap. The two `ResourcePolicies` documents are then **merged** into a single effective `ResourcePolicies`, which is compiled into a `Policies` object, validated, and stored on `request.ResPolicies` exactly as today. The rest of the backup pipeline is unchanged because it only consumes `request.ResPolicies`. + +``` + server flag --global-backup-volume-policies-configmap + | + v + Backup.Spec.ResourcePolicy global policies ConfigMap (install ns) + | | + v v + backup-level ResourcePolicies global ResourcePolicies + \ / + \ / + v v + merge() -> effective ResourcePolicies + | + v + Policies (compiled + validated) + | + v + request.ResPolicies (unchanged consumers) +``` + +### Volume Policy only + +The resource policies ConfigMap schema includes both volume policies and include/exclude/fine-grained filter policies. The global backup volume policy only applies to the `volumePolicies` section of the schema. If the global ConfigMap includes any include/exclude/fine-grained filter policies, they are ignored and not merged into the effective policy. In this case, a warning message will be printed in the Velero server logs. +This is a design choice because only the volume policies are more tied to the environment where velero runs, and are more likely to be something an administrator would want to enforce globally. The include/exclude/fine-grained filter policies are more tied to the specific backup use case, and it would be less intuitive for an administrator to have those apply globally across all backups. + +### Validation + +Velero will validate the global backup volume policies ConfigMap at server startup. If the ConfigMap is missing or invalid, the server will fail to start and log an error. This ensures any mistakes in configuration will be caught early. +It should also make sure the validation happens for each backup, because the ConfigMap could be updated or removed after the server starts. If the global policies ConfigMap is missing or invalid at backup time, the backup CR will be put into "FailedValidation" phase, with an appropriate error message in the logs. + +### Merge semantics + +The merge combines two `ResourcePolicies` documents: the global policy (`G`) and the backup-level policy (`B`). The guiding principle is that the global policy provides a baseline, and the backup-level policy is layered with it. + +- **`volumePolicies`**: `volumePolicies` is an ordered list where the *first* matching policy wins (per the existing `Policies.match` logic). The merged list is the concatenation of the backup-level policies followed by the global policies: + + ``` + merged.volumePolicies = B.volumePolicies ++ G.volumePolicies + ``` + + This gives a backup the ability to override the global baseline for a specific volume (because its policy is evaluated first), while still inheriting all global rules that the backup does not override. + +When only the global policy is configured (the backup does not reference a resource policy), the effective policy is the global policy alone. When only the backup policy exists (no global policy configured), behavior is identical to today. + +#### Example + +Global policy ConfigMap (set on the server with `--global-backup-volume-policies-configmap=global-volume-policy`): + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: global-volume-policy + namespace: velero +data: + policies.yaml: | + version: v1 + volumePolicies: + - conditions: + storageClass: + - gp2 + action: + type: skip +``` + +Backup-level policy ConfigMap (referenced with `velero backup create --resource-policies-configmap backup01`): + +```yaml +apiVersion: v1 +kind: ConfigMap +metadata: + name: backup01 + namespace: velero +data: + policies.yaml: | + version: v1 + volumePolicies: + - conditions: + nfs: {} + action: + type: fs-backup +``` + +Effective (merged) volume policies used for the backup — backup rules first, then global: + +```yaml +version: v1 +volumePolicies: + - conditions: + nfs: {} + action: + type: fs-backup + - conditions: + storageClass: + - gp2 + action: + type: skip +``` + +### Output of `velero backup describe` + +Currently, the `velero backup describe` command shows the backup-level resource policy. We should update the CLI to make sure the global volume policies are also shown in the output, so that user will not need to check the parameter of velero server. + +## Implementation + +- **Server flag and config.** Add a new field (e.g. `GlobalBackupVolumePoliciesConfigMap`) to the server `Config` struct in `pkg/cmd/server/config/config.go`, register the `--global-backup-volume-policies-configmap` flag in `Config.BindFlags`, and leave its default empty in `GetDefaultConfig` so the feature stays opt-in. +- **Plumb the value into the reconciler.** In `pkg/cmd/server/server.go`, pass the configured ConfigMap name (along with the Velero install namespace) into `controller.NewBackupReconciler`. Add a corresponding parameter and store it as a field on the `backupReconciler` struct in `pkg/controller/backup_controller.go`. +- **Load and merge the policies.** In `internal/resourcepolicies/resource_policies.go`, add a new function (e.g. `GetResourcePoliciesFromBackupWithGlobal`) that, in addition to loading the backup-referenced ConfigMap as `GetResourcePoliciesFromBackup` does today, also loads the global ConfigMap from the install namespace via the existing `getResourcePoliciesFromConfig` helper. After that the function merges the two `ResourcePolicies` documents according to the semantics described above. +- **Call site.** Update `prepareBackupRequest` in `pkg/controller/backup_controller.go` (currently calling `GetResourcePoliciesFromBackup`) to apply the merged policies from the new function. The rest of the backup pipeline remains unchanged. +- **CLI describe output.** Update `DescribeResourcePolicies` in `pkg/cmd/util/output/backup_describer.go` and `DescribeResourcePoliciesInSF` in `pkg/cmd/util/output/backup_structured_describer.go` to also surface the global volume policy ConfigMap that contributed to the backup. + +## Security Considerations + +The Global Backup Volume Policy is read from a ConfigMap in the Velero install namespace, the same trust boundary as existing resource policy ConfigMaps and Velero's own configuration. Setting it requires the ability to pass server flags / edit the Velero deployment, which is already an administrative privilege. No new data is exposed and no new external access patterns are introduced. + +## Compatibility + +- The feature is fully opt-in. If `--global-backup-volume-policies-configmap` is not set (the default), behavior is byte-for-byte identical to today. +- Existing per-backup `--resource-policies-configmap` usage is unchanged; it is simply merged with the global baseline when one is configured. +- Backups created before this feature, and backups that reference no resource policy, transparently start honoring the global policy once it is configured. This is the intended behavior of a "global" policy, but operators should be aware that introducing a global policy changes the effective behavior of backups that previously had no resource policy. +- The behavior of scheduled backup may change when a global backup volume policy is introduced, because the scheduled backup will start honoring the global volume policies. This is an expected change, but administrators should be aware of this when introducing a global policy to an existing velero instance with scheduled backups. +- The merged policy is computed at backup time and is reflected wherever `request.ResPolicies` is consumed. `velero backup describe` should be updated to indicate when a global policy contributed to a backup. + +## Alternatives Considered + +- **Global policies applied only when a backup has no policy of its own.** Simpler, but it makes the global policy a fallback default rather than an enforced baseline, and it cannot express "always do X in addition to whatever the backup wants". Merging is more expressive. +- **Global precedence over backup-level policies** (global volume policies evaluated first). Rejected as the default because it would prevent backups from overriding the baseline for specific volumes. From 483becaa7b761e4f137243f0ab21e1181da91152 Mon Sep 17 00:00:00 2001 From: Joseph Antony Vaikath Date: Wed, 17 Jun 2026 08:29:01 -0400 Subject: [PATCH 3/5] Add CONTAINER_TOOL variable to Makefile for podman support (#9904) * Add CONTAINER_TOOL variable to Makefile for podman support Local development targets (shell, lint, build-image, clean, serve-docs) hardcode `docker`, preventing developers who use podman from running them. Add a CONTAINER_TOOL variable that defaults to `docker` and can be overridden: make lint CONTAINER_TOOL=podman CI/release targets (container builds, manifest push, buildx instance management) are left unchanged since they use Docker-specific features like `docker buildx` and `docker manifest`. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Joseph * Add changelog for PR #9904 Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Joseph * Add guards to prevent podman on docker-only targets Multi-arch image targets (container, push-manifest, etc.) require docker buildx/manifest which podman does not support. Add explicit guards that fail fast with a clear error message instead of producing cryptic runtime failures. Guarded targets: container, container-linux, container-windows, push-manifest, push-build-image, and the buildx path in build-image. Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: Joseph * Trigger CI rebuild Signed-off-by: Joseph --------- Signed-off-by: Joseph Co-authored-by: Claude Opus 4.6 (1M context) --- Makefile | 53 +++++++++++++++++++------- changelogs/unreleased/9904-Joeavaikath | 1 + 2 files changed, 41 insertions(+), 13 deletions(-) create mode 100644 changelogs/unreleased/9904-Joeavaikath diff --git a/Makefile b/Makefile index 80db72e3a..515abf88d 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,10 @@ BIN ?= velero # This repo's root import path (under GOPATH). PKG := github.com/vmware-tanzu/velero +# Container tool for local development targets (shell, lint, build-image, etc.) +# Override with CONTAINER_TOOL=podman to use podman instead of docker. +CONTAINER_TOOL ?= docker + # Where to push the docker image. REGISTRY ?= velero # In order to push images to an insecure registry, follow the two steps: @@ -63,7 +67,7 @@ else endif BUILDER_IMAGE := $(REGISTRY)/build-image:$(BUILDER_IMAGE_TAG) -BUILDER_IMAGE_CACHED := $(shell docker images -q ${BUILDER_IMAGE} 2>/dev/null ) +BUILDER_IMAGE_CACHED := $(shell $(CONTAINER_TOOL) images -q ${BUILDER_IMAGE} 2>/dev/null ) HUGO_IMAGE := ghcr.io/gohugoio/hugo @@ -103,6 +107,11 @@ define BUILDX_ERROR buildx not enabled, refusing to run this recipe see: https://velero.io/docs/main/build-from-source/#making-images-and-updating-velero for more info endef + +define DOCKER_ONLY_ERROR +this target requires docker buildx/manifest and is not supported with CONTAINER_TOOL=$(CONTAINER_TOOL). +use docker for multi-arch image targets, or build single-arch images with podman directly. +endef # comma cannot be escaped and can only be used in Make function arguments by putting into variable comma=, @@ -198,7 +207,7 @@ shell: build-dirs build-env @# because the Kubernetes code-generator tools require the project to @# exist in a directory hierarchy ending like this (but *NOT* necessarily @# under $GOPATH). - @docker run \ + @$(CONTAINER_TOOL) run \ -e GOFLAGS \ -e GOPROXY \ -i $(TTY) \ @@ -217,6 +226,9 @@ shell: build-dirs build-env /bin/sh $(CMD) container: +ifneq ($(CONTAINER_TOOL),docker) + $(error $(DOCKER_ONLY_ERROR)) +endif ifneq ($(BUILDX_ENABLED), true) $(error $(BUILDX_ERROR)) endif @@ -246,6 +258,9 @@ container-linux-%: @BUILDX_ARCH=$* $(MAKE) container-linux container-linux: +ifneq ($(CONTAINER_TOOL),docker) + $(error $(DOCKER_ONLY_ERROR)) +endif @echo "building container: $(IMAGE):$(VERSION)-linux-$(BUILDX_ARCH)" @docker buildx build --pull \ @@ -269,6 +284,9 @@ container-windows-%: @BUILDX_OSVERSION=$(firstword $(subst -, ,$*)) BUILDX_ARCH=$(lastword $(subst -, ,$*)) $(MAKE) container-windows container-windows: +ifneq ($(CONTAINER_TOOL),docker) + $(error $(DOCKER_ONLY_ERROR)) +endif @echo "building container: $(IMAGE):$(VERSION)-windows-$(BUILDX_OSVERSION)-$(BUILDX_ARCH)" @docker buildx build --pull \ @@ -290,6 +308,9 @@ container-windows: @echo "built container: $(IMAGE):$(VERSION)-windows-$(BUILDX_OSVERSION)-$(BUILDX_ARCH)" push-manifest: +ifneq ($(CONTAINER_TOOL),docker) + $(error $(DOCKER_ONLY_ERROR)) +endif @echo "building manifest: $(IMAGE_TAG) for $(foreach osarch, $(ALL_OS_ARCH), $(IMAGE_TAG)-${osarch})" @docker manifest create --amend --insecure=$(INSECURE_REGISTRY) $(IMAGE_TAG) $(foreach osarch, $(ALL_OS_ARCH), $(IMAGE_TAG)-${osarch}) @@ -363,24 +384,30 @@ else ifneq ($(BUILDER_IMAGE_CACHED),) @echo "Using Cached Image: $(BUILDER_IMAGE)" else @echo "Trying to pull build-image: $(BUILDER_IMAGE)" - docker pull -q $(BUILDER_IMAGE) || $(MAKE) build-image + $(CONTAINER_TOOL) pull -q $(BUILDER_IMAGE) || $(MAKE) build-image endif build-image: @# When we build a new image we just untag the old one. @# This makes sure we don't leave the orphaned image behind. - $(eval old_id=$(shell docker image inspect --format '{{ .ID }}' ${BUILDER_IMAGE} 2>/dev/null)) + $(eval old_id=$(shell $(CONTAINER_TOOL) image inspect --format '{{ .ID }}' ${BUILDER_IMAGE} 2>/dev/null)) ifeq ($(BUILDX_ENABLED), true) - @cd hack/build-image && docker buildx build --build-arg=GOPROXY=$(GOPROXY) --output=type=docker --pull -t $(BUILDER_IMAGE) -f $(BUILDER_IMAGE_DOCKERFILE_REALPATH) . -else - @cd hack/build-image && docker build --build-arg=GOPROXY=$(GOPROXY) --pull -t $(BUILDER_IMAGE) -f $(BUILDER_IMAGE_DOCKERFILE_REALPATH) . +ifneq ($(CONTAINER_TOOL),docker) + $(error $(DOCKER_ONLY_ERROR)) endif - $(eval new_id=$(shell docker image inspect --format '{{ .ID }}' ${BUILDER_IMAGE} 2>/dev/null)) + @cd hack/build-image && $(CONTAINER_TOOL) buildx build --build-arg=GOPROXY=$(GOPROXY) --output=type=docker --pull -t $(BUILDER_IMAGE) -f $(BUILDER_IMAGE_DOCKERFILE_REALPATH) . +else + @cd hack/build-image && $(CONTAINER_TOOL) build --build-arg=GOPROXY=$(GOPROXY) --pull -t $(BUILDER_IMAGE) -f $(BUILDER_IMAGE_DOCKERFILE_REALPATH) . +endif + $(eval new_id=$(shell $(CONTAINER_TOOL) image inspect --format '{{ .ID }}' ${BUILDER_IMAGE} 2>/dev/null)) @if [ "$(old_id)" != "" ] && [ "$(old_id)" != "$(new_id)" ]; then \ - docker rmi -f $$id || true; \ + $(CONTAINER_TOOL) rmi -f $$id || true; \ fi push-build-image: +ifneq ($(CONTAINER_TOOL),docker) + $(error $(DOCKER_ONLY_ERROR)) +endif @# this target will push the build-image it assumes you already have docker @# credentials needed to accomplish this. @# Pushing will be skipped if a custom Dockerfile was used to build the image. @@ -392,17 +419,17 @@ else endif build-image-hugo: - cd site && docker build --pull -t $(HUGO_IMAGE) . + cd site && $(CONTAINER_TOOL) build --pull -t $(HUGO_IMAGE) . clean: # if we have a cached image then use it to run go clean --modcache # this test checks if we there is an image id in the BUILDER_IMAGE_CACHED variable. ifneq ($(strip $(BUILDER_IMAGE_CACHED)),) $(MAKE) shell CMD="-c 'go clean --modcache'" - docker rmi -f $(BUILDER_IMAGE) || true + $(CONTAINER_TOOL) rmi -f $(BUILDER_IMAGE) || true endif rm -rf .go _output - docker rmi $(HUGO_IMAGE) + $(CONTAINER_TOOL) rmi $(HUGO_IMAGE) .PHONY: modules @@ -447,7 +474,7 @@ release: ./hack/release-tools/goreleaser.sh'" serve-docs: build-image-hugo - docker run \ + $(CONTAINER_TOOL) run \ --rm \ -v "$$(pwd)/site:/project" \ -it -p 1313:1313 \ diff --git a/changelogs/unreleased/9904-Joeavaikath b/changelogs/unreleased/9904-Joeavaikath new file mode 100644 index 000000000..9ef1cfae5 --- /dev/null +++ b/changelogs/unreleased/9904-Joeavaikath @@ -0,0 +1 @@ +Add CONTAINER_TOOL variable to Makefile for podman support From 2826b98190ec16cf7bfc7e153bb61e8dff23644b Mon Sep 17 00:00:00 2001 From: Joseph Antony Vaikath Date: Wed, 17 Jun 2026 08:30:33 -0400 Subject: [PATCH 4/5] Fix restore finalization overwriting dynamically provisioned PV labels (#9903) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Merge backup PV labels instead of wholesale replacement during restore finalization Change patchDynamicPVWithVolumeInfo to merge backup labels into the dynamically provisioned PV rather than overwriting its entire label map. Labels already present on the new PV (e.g. topology labels set by the provisioner) are preserved, and only missing labels from the backup are added. This prevents stale topology labels from the source cluster from overwriting correct values set by the target cluster's provisioner. Update needPatch to only trigger when backup labels are absent from the new PV, not when values differ — since differing values now intentionally favour the dynamically provisioned PV. Signed-off-by: Joseph Signed-off-by: Joseph * Add changelog Signed-off-by: Joseph * Update changelog to reflect new approach Signed-off-by: Joseph Signed-off-by: Joseph * Trigger CI rebuild Signed-off-by: Joseph Signed-off-by: Joseph --------- Signed-off-by: Joseph Signed-off-by: Joseph --- changelogs/unreleased/9903-Joeavaikath | 1 + .../restore_finalizer_controller.go | 16 ++-- .../restore_finalizer_controller_test.go | 81 +++++++++++++++++++ 3 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 changelogs/unreleased/9903-Joeavaikath diff --git a/changelogs/unreleased/9903-Joeavaikath b/changelogs/unreleased/9903-Joeavaikath new file mode 100644 index 000000000..d586acfaa --- /dev/null +++ b/changelogs/unreleased/9903-Joeavaikath @@ -0,0 +1 @@ +Fix restore finalization overwriting dynamically provisioned PV labels with stale backup values diff --git a/pkg/controller/restore_finalizer_controller.go b/pkg/controller/restore_finalizer_controller.go index 20e4bc849..4e02bb0ef 100644 --- a/pkg/controller/restore_finalizer_controller.go +++ b/pkg/controller/restore_finalizer_controller.go @@ -421,7 +421,16 @@ func (ctx *finalizerContext) patchDynamicPVWithVolumeInfo() (errs results.Result // patch PV's reclaim policy and label using the corresponding data stored in volume info if needPatch(pv, volInfo.PVInfo) { updatedPV := pv.DeepCopy() - updatedPV.Labels = volInfo.PVInfo.Labels + + if updatedPV.Labels == nil { + updatedPV.Labels = make(map[string]string) + } + for k, v := range volInfo.PVInfo.Labels { + if _, exists := updatedPV.Labels[k]; !exists { + updatedPV.Labels[k] = v + } + } + updatedPV.Spec.PersistentVolumeReclaimPolicy = corev1api.PersistentVolumeReclaimPolicy(volInfo.PVInfo.ReclaimPolicy) if err := kubeutil.PatchResource(pv, updatedPV, ctx.crClient); err != nil { return false, err @@ -553,13 +562,10 @@ func needPatch(newPV *corev1api.PersistentVolume, pvInfo *volume.PVInfo) bool { } newPVLabels, pvLabels := newPV.Labels, pvInfo.Labels - for k, v := range pvLabels { + for k := range pvLabels { if _, ok := newPVLabels[k]; !ok { return true } - if newPVLabels[k] != v { - return true - } } return false diff --git a/pkg/controller/restore_finalizer_controller_test.go b/pkg/controller/restore_finalizer_controller_test.go index f07d2576c..8f2618f9d 100644 --- a/pkg/controller/restore_finalizer_controller_test.go +++ b/pkg/controller/restore_finalizer_controller_test.go @@ -634,6 +634,87 @@ func Test_restoreFinalizerReconciler_finishProcessing(t *testing.T) { } } +func TestNeedPatch(t *testing.T) { + tests := []struct { + name string + newPV *corev1api.PersistentVolume + pvInfo *volume.PVInfo + expected bool + }{ + { + name: "reclaim policy differs", + newPV: builder.ForPersistentVolume("pv1"). + ReclaimPolicy(corev1api.PersistentVolumeReclaimDelete).Result(), + pvInfo: &volume.PVInfo{ + ReclaimPolicy: string(corev1api.PersistentVolumeReclaimRetain), + Labels: map[string]string{}, + }, + expected: true, + }, + { + name: "backup has label new PV does not", + newPV: builder.ForPersistentVolume("pv1"). + ObjectMeta(builder.WithLabels("existing", "val")). + ReclaimPolicy(corev1api.PersistentVolumeReclaimDelete).Result(), + pvInfo: &volume.PVInfo{ + ReclaimPolicy: string(corev1api.PersistentVolumeReclaimDelete), + Labels: map[string]string{"existing": "val", "missing": "val"}, + }, + expected: true, + }, + { + name: "same labels same values", + newPV: builder.ForPersistentVolume("pv1"). + ObjectMeta(builder.WithLabels("key", "val")). + ReclaimPolicy(corev1api.PersistentVolumeReclaimDelete).Result(), + pvInfo: &volume.PVInfo{ + ReclaimPolicy: string(corev1api.PersistentVolumeReclaimDelete), + Labels: map[string]string{"key": "val"}, + }, + expected: false, + }, + { + name: "same label key different values", + newPV: builder.ForPersistentVolume("pv1"). + ObjectMeta(builder.WithLabels("topology.kubernetes.io/zone", "us-west-2a")). + ReclaimPolicy(corev1api.PersistentVolumeReclaimDelete).Result(), + pvInfo: &volume.PVInfo{ + ReclaimPolicy: string(corev1api.PersistentVolumeReclaimDelete), + Labels: map[string]string{"topology.kubernetes.io/zone": "us-east-1a"}, + }, + expected: false, + }, + { + name: "new PV has labels backup does not", + newPV: builder.ForPersistentVolume("pv1"). + ObjectMeta(builder.WithLabels("provisioner-label", "val")). + ReclaimPolicy(corev1api.PersistentVolumeReclaimDelete).Result(), + pvInfo: &volume.PVInfo{ + ReclaimPolicy: string(corev1api.PersistentVolumeReclaimDelete), + Labels: map[string]string{}, + }, + expected: false, + }, + { + name: "both labels nil", + newPV: builder.ForPersistentVolume("pv1"). + ReclaimPolicy(corev1api.PersistentVolumeReclaimDelete).Result(), + pvInfo: &volume.PVInfo{ + ReclaimPolicy: string(corev1api.PersistentVolumeReclaimDelete), + Labels: nil, + }, + expected: false, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + result := needPatch(tc.newPV, tc.pvInfo) + assert.Equal(t, tc.expected, result) + }) + } +} + func TestRestoreOperationList(t *testing.T) { var empty []*itemoperation.RestoreOperation tests := []struct { From 4f2204847267d66a26a53a352919c056fc5d24fa Mon Sep 17 00:00:00 2001 From: Lyndon-Li Date: Thu, 18 Jun 2026 15:39:44 +0800 Subject: [PATCH 5/5] support fsType for data mover Signed-off-by: Lyndon-Li --- changelogs/unreleased/9930-Lyndon-Li | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelogs/unreleased/9930-Lyndon-Li diff --git a/changelogs/unreleased/9930-Lyndon-Li b/changelogs/unreleased/9930-Lyndon-Li new file mode 100644 index 000000000..e8b21c2b8 --- /dev/null +++ b/changelogs/unreleased/9930-Lyndon-Li @@ -0,0 +1 @@ +Support fsType in DUCR and DDCR for data mover \ No newline at end of file