mirror of
https://github.com/vmware-tanzu/velero.git
synced 2026-08-17 20:56:08 +00:00
Cap the unzip of metadata download to avoid OOM kill (#10258)
* cap the unzip of metadata download to avoid oom kill Signed-off-by: Lyndon-Li <lyonghui@vmware.com> * detect when EOF is retuend because of cap Signed-off-by: Lyndon-Li <lyonghui@vmware.com> --------- Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
Cap the unzip of metadata download to avoid OOM kill
|
||||
@@ -40,6 +40,7 @@ import (
|
||||
// not found
|
||||
var ErrNotFound = errors.New("file not found")
|
||||
var ErrDownloadRequestDownloadURLTimeout = errors.New("download request download url timeout, check velero server logs for errors. backup storage location may not be available")
|
||||
var unzipLimit int64 = 1024 * 1024 * 1024 // 1GB limit
|
||||
|
||||
func Stream(
|
||||
ctx context.Context,
|
||||
@@ -202,17 +203,35 @@ func download(
|
||||
return errors.Errorf("request failed: %v", string(body))
|
||||
}
|
||||
|
||||
reader := resp.Body
|
||||
var r io.Reader = resp.Body
|
||||
var gzipReader *gzip.Reader
|
||||
if kind != veleroV1api.DownloadTargetKindBackupContents {
|
||||
// need to decompress logs
|
||||
gzipReader, err := gzip.NewReader(resp.Body)
|
||||
var err error
|
||||
gzipReader, err = gzip.NewReader(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer gzipReader.Close()
|
||||
reader = gzipReader
|
||||
|
||||
r = io.LimitReader(gzipReader, unzipLimit)
|
||||
}
|
||||
|
||||
_, err = io.Copy(w, reader)
|
||||
return err
|
||||
_, err = io.Copy(w, r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if gzipReader != nil {
|
||||
var buf [1]byte
|
||||
n, err := gzipReader.Read(buf[:])
|
||||
if n > 0 || err == nil {
|
||||
return errors.Errorf("decompressed data exceeds the limit")
|
||||
}
|
||||
if err != io.EOF {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -463,6 +463,7 @@ func TestDownload(t *testing.T) {
|
||||
expectedContent string
|
||||
expectedError bool
|
||||
errorType error
|
||||
expectedErrMsg string
|
||||
}{
|
||||
{
|
||||
name: "successful download with gzip for logs",
|
||||
@@ -474,6 +475,16 @@ func TestDownload(t *testing.T) {
|
||||
expectedContent: testContent,
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "error decompressed data exceeds the limit",
|
||||
serverHandler: func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(compressedContent.Bytes())
|
||||
},
|
||||
target: velerov1api.DownloadTargetKindBackupLog,
|
||||
expectedError: true,
|
||||
expectedErrMsg: "decompressed data exceeds the limit",
|
||||
},
|
||||
{
|
||||
name: "successful download without gzip for backup contents",
|
||||
serverHandler: func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -506,6 +517,12 @@ func TestDownload(t *testing.T) {
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
originalLimit := unzipLimit
|
||||
if tc.expectedErrMsg == "decompressed data exceeds the limit" {
|
||||
unzipLimit = 10
|
||||
}
|
||||
defer func() { unzipLimit = originalLimit }()
|
||||
|
||||
server := httptest.NewServer(tc.serverHandler)
|
||||
defer server.Close()
|
||||
|
||||
@@ -525,6 +542,9 @@ func TestDownload(t *testing.T) {
|
||||
if tc.errorType != nil {
|
||||
assert.Equal(t, tc.errorType, err)
|
||||
}
|
||||
if tc.expectedErrMsg != "" {
|
||||
assert.Contains(t, err.Error(), tc.expectedErrMsg)
|
||||
}
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tc.expectedContent, buf.String())
|
||||
|
||||
Reference in New Issue
Block a user