From 1c99ecdde04702063a06bfd09257184452028800 Mon Sep 17 00:00:00 2001 From: Sourav Gupta <98318303+souravgupta-msft@users.noreply.github.com> Date: Wed, 13 Nov 2024 12:59:31 +0530 Subject: [PATCH 1/7] Remove deprecated methods (#1563) --- cmd/health-monitor_test.go | 4 +- cmd/mountv1_test.go | 4 +- common/util_test.go | 4 +- component/azstorage/block_blob_test.go | 5 +- component/azstorage/datalake_test.go | 2 +- component/block_cache/block_cache_test.go | 62 ++++++++------- component/entry_cache/entry_cache_test.go | 4 +- component/file_cache/file_cache_test.go | 4 +- test/e2e_tests/data_validation_test.go | 97 +++++++++++------------ test/e2e_tests/dir_test.go | 3 +- test/e2e_tests/file_test.go | 3 +- test/stress_test/stress_test.go | 2 +- 12 files changed, 95 insertions(+), 99 deletions(-) diff --git a/cmd/health-monitor_test.go b/cmd/health-monitor_test.go index 93a30eee7..84cbc5a41 100644 --- a/cmd/health-monitor_test.go +++ b/cmd/health-monitor_test.go @@ -72,10 +72,10 @@ type hmonTestSuite struct { } func generateRandomPID() string { - rand.Seed(time.Now().UnixNano()) + r := rand.New(rand.NewSource(time.Now().UnixNano())) var randpid int for i := 0; i <= 5; i++ { - randpid = rand.Intn(90000) + 10000 + randpid = r.Intn(90000) + 10000 _, err := os.FindProcess(randpid) if err != nil { break diff --git a/cmd/mountv1_test.go b/cmd/mountv1_test.go index c65ec2c69..726d01874 100644 --- a/cmd/mountv1_test.go +++ b/cmd/mountv1_test.go @@ -101,9 +101,9 @@ func TestGenerateConfig(t *testing.T) { } func randomString(length int) string { - rand.Seed(time.Now().UnixNano()) + r := rand.New(rand.NewSource(time.Now().UnixNano())) b := make([]byte, length) - rand.Read(b) + r.Read(b) return fmt.Sprintf("%x", b)[:length] } diff --git a/common/util_test.go b/common/util_test.go index 907901730..807af8059 100644 --- a/common/util_test.go +++ b/common/util_test.go @@ -35,13 +35,12 @@ package common import ( "bytes" + "crypto/rand" "fmt" - "math/rand" "os" "os/exec" "path/filepath" "testing" - "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" @@ -50,7 +49,6 @@ import ( var home_dir, _ = os.UserHomeDir() func randomString(length int) string { - rand.Seed(time.Now().UnixNano()) b := make([]byte, length) rand.Read(b) return fmt.Sprintf("%x", b)[:length] diff --git a/component/azstorage/block_blob_test.go b/component/azstorage/block_blob_test.go index 52b7a8c16..0fcbe7285 100644 --- a/component/azstorage/block_blob_test.go +++ b/component/azstorage/block_blob_test.go @@ -40,6 +40,7 @@ import ( "bytes" "container/list" "context" + "crypto/rand" "crypto/sha256" "encoding/base64" "encoding/json" @@ -47,7 +48,6 @@ import ( "fmt" "io" "math" - "math/rand" "os" "path/filepath" "strings" @@ -285,9 +285,8 @@ func (s *blockBlobTestSuite) TestDefault() { } func randomString(length int) string { - random := rand.New(rand.NewSource(time.Now().UnixNano())) b := make([]byte, length) - random.Read(b) + rand.Read(b) return fmt.Sprintf("%x", b)[:length] } diff --git a/component/azstorage/datalake_test.go b/component/azstorage/datalake_test.go index 321856dd2..d376946c5 100644 --- a/component/azstorage/datalake_test.go +++ b/component/azstorage/datalake_test.go @@ -39,11 +39,11 @@ package azstorage import ( "bytes" "container/list" + "crypto/rand" "encoding/base64" "encoding/json" "fmt" "io" - "math/rand" "os" "strings" "syscall" diff --git a/component/block_cache/block_cache_test.go b/component/block_cache/block_cache_test.go index 7157d2c2e..741085a88 100644 --- a/component/block_cache/block_cache_test.go +++ b/component/block_cache/block_cache_test.go @@ -40,7 +40,6 @@ import ( "encoding/base64" "fmt" "io" - "io/ioutil" "math" "math/rand" "os" @@ -64,6 +63,7 @@ import ( var home_dir, _ = os.UserHomeDir() var mountpoint = home_dir + "mountpoint" var dataBuff []byte +var r *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano())) type blockCacheTestSuite struct { suite.Suite @@ -85,9 +85,8 @@ type testObj struct { } func randomString(length int) string { - rand.Seed(time.Now().UnixNano()) b := make([]byte, length) - rand.Read(b) + r.Read(b) return fmt.Sprintf("%x", b)[:length] } @@ -344,8 +343,8 @@ func (suite *blockCacheTestSuite) TestFileOpenClose() { fileName := getTestFileName(suite.T().Name()) storagePath := filepath.Join(tobj.fake_storage_path, fileName) data := make([]byte, 5*_1MB) - _, _ = rand.Read(data) - ioutil.WriteFile(storagePath, data, 0777) + _, _ = r.Read(data) + os.WriteFile(storagePath, data, 0777) options := internal.OpenFileOptions{Name: fileName} h, err := tobj.blockCache.OpenFile(options) @@ -570,22 +569,25 @@ func (suite *blockCacheTestSuite) TestFileReadBlockCacheTmpPath() { tmpPath := tobj.blockCache.tmpPath - files, err := ioutil.ReadDir(tmpPath) + entries, err := os.ReadDir(tmpPath) suite.assert.Nil(err) var size1048576, size7 bool - for _, file := range files { - if file.Size() == 1048576 { + for _, entry := range entries { + f, err := entry.Info() + suite.assert.Nil(err) + + if f.Size() == 1048576 { size1048576 = true } - if file.Size() == 7 { + if f.Size() == 7 { size7 = true } } suite.assert.True(size1048576) suite.assert.True(size7) - suite.assert.Equal(len(files), 2) + suite.assert.Equal(len(entries), 2) err = tobj.blockCache.CloseFile(internal.CloseFileOptions{Handle: h}) suite.assert.Nil(err) @@ -601,8 +603,8 @@ func (suite *blockCacheTestSuite) TestFileReadSerial() { fileName := getTestFileName(suite.T().Name()) storagePath := filepath.Join(tobj.fake_storage_path, fileName) data := make([]byte, 50*_1MB) - _, _ = rand.Read(data) - ioutil.WriteFile(storagePath, data, 0777) + _, _ = r.Read(data) + os.WriteFile(storagePath, data, 0777) options := internal.OpenFileOptions{Name: fileName} h, err := tobj.blockCache.OpenFile(options) @@ -643,8 +645,8 @@ func (suite *blockCacheTestSuite) TestFileReadRandom() { fileName := getTestFileName(suite.T().Name()) storagePath := filepath.Join(tobj.fake_storage_path, fileName) data := make([]byte, 100*_1MB) - _, _ = rand.Read(data) - ioutil.WriteFile(storagePath, data, 0777) + _, _ = r.Read(data) + os.WriteFile(storagePath, data, 0777) options := internal.OpenFileOptions{Name: fileName} h, err := tobj.blockCache.OpenFile(options) @@ -684,8 +686,8 @@ func (suite *blockCacheTestSuite) TestFileReadRandomNoPrefetch() { fileName := getTestFileName(suite.T().Name()) storagePath := filepath.Join(tobj.fake_storage_path, fileName) data := make([]byte, 100*_1MB) - _, _ = rand.Read(data) - ioutil.WriteFile(storagePath, data, 0777) + _, _ = r.Read(data) + os.WriteFile(storagePath, data, 0777) options := internal.OpenFileOptions{Name: fileName} h, err := tobj.blockCache.OpenFile(options) @@ -727,7 +729,7 @@ func (suite *blockCacheTestSuite) TestDiskUsageCheck() { // Default disk size is 50MB data := make([]byte, 5*_1MB) - _, _ = rand.Read(data) + _, _ = r.Read(data) type diskusagedata struct { name string @@ -742,7 +744,7 @@ func (suite *blockCacheTestSuite) TestDiskUsageCheck() { } for i := 0; i < 13; i++ { - ioutil.WriteFile(localfiles[i].name, data, 0777) + os.WriteFile(localfiles[i].name, data, 0777) usage, err := common.GetUsage(tobj.disk_cache_path) suite.assert.Nil(err) fmt.Printf("%d : %v (%v : %v) Usage %v\n", i, localfiles[i].name, localfiles[i].diskflag, tobj.blockCache.checkDiskUsage(), usage) @@ -801,8 +803,8 @@ func (suite *blockCacheTestSuite) TestOpenWithTruncate() { fileName := getTestFileName(suite.T().Name()) storagePath := filepath.Join(tobj.fake_storage_path, fileName) data := make([]byte, 5*_1MB) - _, _ = rand.Read(data) - ioutil.WriteFile(storagePath, data, 0777) + _, _ = r.Read(data) + os.WriteFile(storagePath, data, 0777) options := internal.OpenFileOptions{Name: fileName} h, err := tobj.blockCache.OpenFile(options) @@ -898,7 +900,7 @@ func (suite *blockCacheTestSuite) TestWriteFileMultiBlock() { storagePath := filepath.Join(tobj.fake_storage_path, path) data := make([]byte, 5*_1MB) - _, _ = rand.Read(data) + _, _ = r.Read(data) options := internal.CreateFileOptions{Name: path, Mode: 0777} h, err := tobj.blockCache.CreateFile(options) @@ -937,7 +939,7 @@ func (suite *blockCacheTestSuite) TestWriteFileMultiBlockWithOverwrite() { storagePath := filepath.Join(tobj.fake_storage_path, path) data := make([]byte, 5*_1MB) - _, _ = rand.Read(data) + _, _ = r.Read(data) options := internal.CreateFileOptions{Name: path, Mode: 0777} h, err := tobj.blockCache.CreateFile(options) @@ -988,7 +990,7 @@ func (suite *blockCacheTestSuite) TestWritefileWithAppend() { path := getTestFileName(suite.T().Name()) data := make([]byte, 13*_1MB) - _, _ = rand.Read(data) + _, _ = r.Read(data) options := internal.CreateFileOptions{Name: path, Mode: 0777} h, err := tobj.blockCache.CreateFile(options) @@ -1022,7 +1024,7 @@ func (suite *blockCacheTestSuite) TestWritefileWithAppend() { h, err = tobj.blockCache.OpenFile(internal.OpenFileOptions{Name: path, Flags: os.O_RDWR, Mode: 0777}) suite.assert.Nil(err) dataNew := make([]byte, 10*_1MB) - _, _ = rand.Read(data) + _, _ = r.Read(data) n, err = tobj.blockCache.WriteFile(internal.WriteFileOptions{Handle: h, Offset: h.Size, Data: dataNew}) // 5 bytes suite.assert.Nil(err) @@ -1054,14 +1056,14 @@ func (suite *blockCacheTestSuite) TestWriteBlockOutOfRange() { path := getTestFileName(suite.T().Name()) data := make([]byte, 20*_1MB) - _, _ = rand.Read(data) + _, _ = r.Read(data) options := internal.CreateFileOptions{Name: path, Mode: 0777} h, err := tobj.blockCache.CreateFile(options) suite.assert.Nil(err) dataNew := make([]byte, 1*_1MB) - _, _ = rand.Read(data) + _, _ = r.Read(data) n, err := tobj.blockCache.WriteFile(internal.WriteFileOptions{Handle: h, Offset: 10 * 50001, Data: dataNew}) // 5 bytes suite.assert.NotNil(err) @@ -1790,7 +1792,7 @@ func (suite *blockCacheTestSuite) TestPreventRaceCondition() { storagePath := filepath.Join(tobj.fake_storage_path, path) data := make([]byte, _1MB) - _, _ = rand.Read(data) + _, _ = r.Read(data) // write using block cache options := internal.CreateFileOptions{Name: path, Mode: 0777} @@ -1862,7 +1864,7 @@ func (suite *blockCacheTestSuite) TestBlockParallelUploadAndWrite() { storagePath := filepath.Join(tobj.fake_storage_path, path) data := make([]byte, _1MB) - _, _ = rand.Read(data) + _, _ = r.Read(data) options := internal.CreateFileOptions{Name: path, Mode: 0777} h, err := tobj.blockCache.CreateFile(options) @@ -1924,7 +1926,7 @@ func (suite *blockCacheTestSuite) TestBlockParallelUploadAndWriteValidation() { localPath := filepath.Join(tobj.disk_cache_path, path) data := make([]byte, _1MB) - _, _ = rand.Read(data) + _, _ = r.Read(data) // ------------------------------------------------------------------ // write to local file @@ -2625,7 +2627,7 @@ func (suite *blockCacheTestSuite) TestZZZZZStreamToBlockCacheConfig() { // a normal test function and pass our suite to suite.Run func TestBlockCacheTestSuite(t *testing.T) { dataBuff = make([]byte, 5*_1MB) - _, _ = rand.Read(dataBuff) + _, _ = r.Read(dataBuff) suite.Run(t, new(blockCacheTestSuite)) } diff --git a/component/entry_cache/entry_cache_test.go b/component/entry_cache/entry_cache_test.go index 7c623b66d..7bc6690ca 100644 --- a/component/entry_cache/entry_cache_test.go +++ b/component/entry_cache/entry_cache_test.go @@ -82,9 +82,9 @@ func newEntryCache(next internal.Component) *EntryCache { } func randomString(length int) string { - rand.Seed(time.Now().UnixNano()) + r := rand.New(rand.NewSource(time.Now().UnixNano())) b := make([]byte, length) - rand.Read(b) + r.Read(b) return fmt.Sprintf("%x", b)[:length] } diff --git a/component/file_cache/file_cache_test.go b/component/file_cache/file_cache_test.go index a30bb557d..2a094a137 100644 --- a/component/file_cache/file_cache_test.go +++ b/component/file_cache/file_cache_test.go @@ -91,9 +91,9 @@ func newTestFileCache(next internal.Component) *FileCache { } func randomString(length int) string { - rand.Seed(time.Now().UnixNano()) + r := rand.New(rand.NewSource(time.Now().UnixNano())) b := make([]byte, length) - rand.Read(b) + r.Read(b) return fmt.Sprintf("%x", b)[:length] } diff --git a/test/e2e_tests/data_validation_test.go b/test/e2e_tests/data_validation_test.go index f9109c58d..bf76005fe 100644 --- a/test/e2e_tests/data_validation_test.go +++ b/test/e2e_tests/data_validation_test.go @@ -38,10 +38,11 @@ package e2e_tests import ( "crypto/md5" + "crypto/rand" "flag" "fmt" "io" - "math/rand" + mrand "math/rand" "os" "os/exec" "path/filepath" @@ -49,7 +50,6 @@ import ( "strings" "syscall" "testing" - "time" "github.com/stretchr/testify/suite" ) @@ -100,7 +100,6 @@ func initDataValidationFlags() { } func getDataValidationTestDirName(n int) string { - rand.Seed(time.Now().UnixNano()) b := make([]byte, n) rand.Read(b) return fmt.Sprintf("%x", b)[:n] @@ -238,7 +237,7 @@ func compareReadOperInLocalAndRemote(suite *dataValidationTestSuite, lfh, rfh *o } func compareWriteOperInLocalAndRemote(suite *dataValidationTestSuite, lfh, rfh *os.File, offset int64) { - sizeofbuffer := (rand.Int() % 4) + 1 + sizeofbuffer := (mrand.Int() % 4) + 1 buffer := make([]byte, sizeofbuffer*int(_1MB)) rand.Read(buffer) @@ -752,51 +751,51 @@ func (suite *dataValidationTestSuite) TestPanicOnReadingFileInRandReadMode() { closeFileHandles(suite, rfh) } -func (suite *dataValidationTestSuite) TestReadDataAtBlockBoundaries() { - fileName := "testReadDataAtBlockBoundaries" - localFilePath, remoteFilePath := convertFileNameToFilePath(fileName) - fileSize := 35 * int(_1MB) - generateFileWithRandomData(suite, localFilePath, fileSize) - suite.copyToMountDir(localFilePath, remoteFilePath) - suite.validateData(localFilePath, remoteFilePath) - - lfh, rfh := openFileHandleInLocalAndRemote(suite, os.O_RDWR, localFilePath, remoteFilePath) - var offset int64 = 0 - //tests run in 16MB block size config. - //Data in File 35MB(3blocks) - //block1->16MB, block2->16MB, block3->3MB - - //getting 4MB data from 1st block - compareReadOperInLocalAndRemote(suite, lfh, rfh, offset) - //getting 4MB data from overlapping blocks - offset = int64(15 * int(_1MB)) - compareReadOperInLocalAndRemote(suite, lfh, rfh, offset) - //getting 4MB data from last block - offset = int64(32 * int(_1MB)) - compareReadOperInLocalAndRemote(suite, lfh, rfh, offset) - //getting 4MB data from overlapping block with last block - offset = int64(30 * int(_1MB)) - compareReadOperInLocalAndRemote(suite, lfh, rfh, offset) - //Read at some random offset - for i := 0; i < 10; i++ { - offset = rand.Int63() % int64(fileSize) - compareReadOperInLocalAndRemote(suite, lfh, rfh, offset) - } - - //write at end of file - offset = int64(fileSize) - compareWriteOperInLocalAndRemote(suite, lfh, rfh, offset) - //Check the previous write with read - compareReadOperInLocalAndRemote(suite, lfh, rfh, offset) - - //Write at Random offset in the file - offset = rand.Int63() % int64(fileSize) - compareWriteOperInLocalAndRemote(suite, lfh, rfh, offset) - //Check the previous write with read - compareReadOperInLocalAndRemote(suite, lfh, rfh, offset) - - closeFileHandles(suite, lfh, rfh) -} +// func (suite *dataValidationTestSuite) TestReadDataAtBlockBoundaries() { +// fileName := "testReadDataAtBlockBoundaries" +// localFilePath, remoteFilePath := convertFileNameToFilePath(fileName) +// fileSize := 35 * int(_1MB) +// generateFileWithRandomData(suite, localFilePath, fileSize) +// suite.copyToMountDir(localFilePath, remoteFilePath) +// suite.validateData(localFilePath, remoteFilePath) + +// lfh, rfh := openFileHandleInLocalAndRemote(suite, os.O_RDWR, localFilePath, remoteFilePath) +// var offset int64 = 0 +// //tests run in 16MB block size config. +// //Data in File 35MB(3blocks) +// //block1->16MB, block2->16MB, block3->3MB + +// //getting 4MB data from 1st block +// compareReadOperInLocalAndRemote(suite, lfh, rfh, offset) +// //getting 4MB data from overlapping blocks +// offset = int64(15 * int(_1MB)) +// compareReadOperInLocalAndRemote(suite, lfh, rfh, offset) +// //getting 4MB data from last block +// offset = int64(32 * int(_1MB)) +// compareReadOperInLocalAndRemote(suite, lfh, rfh, offset) +// //getting 4MB data from overlapping block with last block +// offset = int64(30 * int(_1MB)) +// compareReadOperInLocalAndRemote(suite, lfh, rfh, offset) +// //Read at some random offset +// for i := 0; i < 10; i++ { +// offset = mrand.Int63() % int64(fileSize) +// compareReadOperInLocalAndRemote(suite, lfh, rfh, offset) +// } + +// //write at end of file +// offset = int64(fileSize) +// compareWriteOperInLocalAndRemote(suite, lfh, rfh, offset) +// //Check the previous write with read +// compareReadOperInLocalAndRemote(suite, lfh, rfh, offset) + +// //Write at Random offset in the file +// offset = mrand.Int63() % int64(fileSize) +// compareWriteOperInLocalAndRemote(suite, lfh, rfh, offset) +// //Check the previous write with read +// compareReadOperInLocalAndRemote(suite, lfh, rfh, offset) + +// closeFileHandles(suite, lfh, rfh) +// } // -------------- Main Method ------------------- func TestDataValidationTestSuite(t *testing.T) { diff --git a/test/e2e_tests/dir_test.go b/test/e2e_tests/dir_test.go index 172b11c45..90f19ee9d 100644 --- a/test/e2e_tests/dir_test.go +++ b/test/e2e_tests/dir_test.go @@ -37,9 +37,9 @@ package e2e_tests import ( + "crypto/rand" "flag" "fmt" - "math/rand" "os" "os/exec" "path/filepath" @@ -88,7 +88,6 @@ func initDirFlags() { } func getTestDirName(n int) string { - rand.Seed(time.Now().UnixNano()) b := make([]byte, n) rand.Read(b) return fmt.Sprintf("%x", b)[:n] diff --git a/test/e2e_tests/file_test.go b/test/e2e_tests/file_test.go index ecb937635..47b662392 100644 --- a/test/e2e_tests/file_test.go +++ b/test/e2e_tests/file_test.go @@ -37,10 +37,10 @@ package e2e_tests import ( + "crypto/rand" "flag" "fmt" "io" - "math/rand" "os" "strconv" "strings" @@ -89,7 +89,6 @@ func initFileFlags() { } func getFileTestDirName(n int) string { - rand.Seed(time.Now().UnixNano()) b := make([]byte, n) rand.Read(b) return fmt.Sprintf("%x", b)[:n] diff --git a/test/stress_test/stress_test.go b/test/stress_test/stress_test.go index c46ecd836..8b4c8f295 100644 --- a/test/stress_test/stress_test.go +++ b/test/stress_test/stress_test.go @@ -37,9 +37,9 @@ package stress_test import ( + "crypto/rand" "flag" "fmt" - "math/rand" "os" "path/filepath" "strconv" From 2126e11f08c157cb91664d9d1817a4d4a30bad00 Mon Sep 17 00:00:00 2001 From: Sourav Gupta <98318303+souravgupta-msft@users.noreply.github.com> Date: Wed, 13 Nov 2024 22:06:46 +0530 Subject: [PATCH 2/7] E2E tests fix (#1564) --- component/libfuse/libfuse2_handler.go | 8 ++++++-- component/libfuse/libfuse_handler.go | 8 ++++++-- test/e2e_tests/data_validation_test.go | 6 +++--- test/e2e_tests/dir_test.go | 4 ++-- test/e2e_tests/file_test.go | 4 ++-- 5 files changed, 19 insertions(+), 11 deletions(-) diff --git a/component/libfuse/libfuse2_handler.go b/component/libfuse/libfuse2_handler.go index 49bb4694f..4813b944c 100644 --- a/component/libfuse/libfuse2_handler.go +++ b/component/libfuse/libfuse2_handler.go @@ -569,8 +569,12 @@ func libfuse_rmdir(path *C.char) C.int { if !empty { // delete empty directories from local cache directory val, err := fuseFS.NextComponent().DeleteEmptyDirs(internal.DeleteDirOptions{Name: name}) - if err != nil || !val { - log.Err("Libfuse::libfuse_rmdir : Failed to delete %s [%s]", name, err.Error()) + if !val { + // either file cache has failed or not present in the pipeline + if err != nil { + // if error is not nil, file cache has failed + log.Err("Libfuse::libfuse_rmdir : Failed to delete %s [%s]", name, err.Error()) + } return -C.ENOTEMPTY } } diff --git a/component/libfuse/libfuse_handler.go b/component/libfuse/libfuse_handler.go index cb66f2e99..b7cb0fcc6 100644 --- a/component/libfuse/libfuse_handler.go +++ b/component/libfuse/libfuse_handler.go @@ -583,8 +583,12 @@ func libfuse_rmdir(path *C.char) C.int { if !empty { // delete empty directories from local cache directory val, err := fuseFS.NextComponent().DeleteEmptyDirs(internal.DeleteDirOptions{Name: name}) - if err != nil || !val { - log.Err("Libfuse::libfuse_rmdir : Failed to delete %s [%s]", name, err.Error()) + if !val { + // either file cache has failed or not present in the pipeline + if err != nil { + // if error is not nil, file cache has failed + log.Err("Libfuse::libfuse_rmdir : Failed to delete %s [%s]", name, err.Error()) + } return -C.ENOTEMPTY } } diff --git a/test/e2e_tests/data_validation_test.go b/test/e2e_tests/data_validation_test.go index bf76005fe..663abc91e 100644 --- a/test/e2e_tests/data_validation_test.go +++ b/test/e2e_tests/data_validation_test.go @@ -844,16 +844,16 @@ func TestDataValidationTestSuite(t *testing.T) { // Sanity check in the off chance the same random name was generated twice and was still around somehow err := os.RemoveAll(tObj.testMntPath) if err != nil { - fmt.Println("Could not cleanup feature dir before testing") + fmt.Printf("Could not cleanup feature dir before testing [%s]\n", err.Error()) } err = os.RemoveAll(tObj.testCachePath) if err != nil { - fmt.Println("Could not cleanup cache dir before testing") + fmt.Printf("Could not cleanup cache dir before testing [%s]\n", err.Error()) } err = os.Mkdir(tObj.testMntPath, 0777) if err != nil { - t.Error("Failed to create test directory") + t.Errorf("Failed to create test directory [%s]\n", err.Error()) } rand.Read(minBuff) rand.Read(medBuff) diff --git a/test/e2e_tests/dir_test.go b/test/e2e_tests/dir_test.go index 90f19ee9d..e34a57363 100644 --- a/test/e2e_tests/dir_test.go +++ b/test/e2e_tests/dir_test.go @@ -584,12 +584,12 @@ func TestDirTestSuite(t *testing.T) { // Sanity check in the off chance the same random name was generated twice and was still around somehow err := os.RemoveAll(dirTest.testPath) if err != nil { - fmt.Println("Could not cleanup feature dir before testing") + fmt.Printf("Could not cleanup feature dir before testing [%s]\n", err.Error()) } err = os.Mkdir(dirTest.testPath, 0777) if err != nil { - t.Error("Failed to create test directory") + t.Errorf("Failed to create test directory [%s]\n", err.Error()) } rand.Read(dirTest.minBuff) rand.Read(dirTest.medBuff) diff --git a/test/e2e_tests/file_test.go b/test/e2e_tests/file_test.go index 47b662392..469d09de4 100644 --- a/test/e2e_tests/file_test.go +++ b/test/e2e_tests/file_test.go @@ -650,12 +650,12 @@ func TestFileTestSuite(t *testing.T) { // Sanity check in the off chance the same random name was generated twice and was still around somehow err := os.RemoveAll(fileTest.testPath) if err != nil { - fmt.Println("Could not cleanup feature dir before testing") + fmt.Printf("Could not cleanup feature dir before testing [%s]\n", err.Error()) } err = os.Mkdir(fileTest.testPath, 0777) if err != nil { - t.Error("Failed to create test directory") + t.Errorf("Failed to create test directory [%s]\n", err.Error()) } rand.Read(fileTest.minBuff) rand.Read(fileTest.medBuff) From 9d552227a816fc6dd1bfe02c3f610ddcd1acee1e Mon Sep 17 00:00:00 2001 From: Sourav Gupta <98318303+souravgupta-msft@users.noreply.github.com> Date: Fri, 15 Nov 2024 16:57:37 +0530 Subject: [PATCH 3/7] fix (#1567) --- cmd/mount.go | 9 ++------- cmd/mount_test.go | 40 +++++++++++++++++++++++++++++++++++----- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/cmd/mount.go b/cmd/mount.go index 2232ca160..a406cd62c 100644 --- a/cmd/mount.go +++ b/cmd/mount.go @@ -455,13 +455,8 @@ var mountCmd = &cobra.Command{ pipeline, err = internal.NewPipeline(options.Components, !daemon.WasReborn()) if err != nil { - if err.Error() == "Azure CLI not found on path" { - log.Err("mount : failed to initialize new pipeline :: To authenticate using MSI with object-ID, ensure Azure CLI is installed. Alternatively, use app/client ID or resource ID for authentication. [%v]", err) - return Destroy(fmt.Sprintf("failed to initialize new pipeline :: To authenticate using MSI with object-ID, ensure Azure CLI is installed. Alternatively, use app/client ID or resource ID for authentication. [%s]", err.Error())) - } else { - log.Err("mount : failed to initialize new pipeline [%v]", err) - return Destroy(fmt.Sprintf("failed to initialize new pipeline [%s]", err.Error())) - } + log.Err("mount : failed to initialize new pipeline [%v]", err) + return Destroy(fmt.Sprintf("failed to initialize new pipeline [%s]", err.Error())) } common.ForegroundMount = options.Foreground diff --git a/cmd/mount_test.go b/cmd/mount_test.go index 457cad25f..73605878e 100644 --- a/cmd/mount_test.go +++ b/cmd/mount_test.go @@ -294,7 +294,7 @@ func (suite *mountTestSuite) TestCliParamsV1() { defer os.RemoveAll(tempLogDir) op, err := executeCommandC(rootCmd, "mount", mntDir, fmt.Sprintf("--config-file=%s", confFileMntTest), - fmt.Sprintf("--log-file-path=%s", tempLogDir+"/blobfuse2.log"), "--invalidate-on-sync", "--pre-mount-validate", "--basic-remount-check") + fmt.Sprintf("--log-file-path=%s", tempLogDir+"/blobfuse2.log"), "--invalidate-on-sync", "--pre-mount-validate", "--basic-remount-check", "-o", "direct_io") suite.assert.NotNil(err) suite.assert.Contains(op, "failed to initialize new pipeline") } @@ -310,7 +310,7 @@ func (suite *mountTestSuite) TestStreamAttrCacheOptionsV1() { defer os.RemoveAll(tempLogDir) op, err := executeCommandC(rootCmd, "mount", mntDir, fmt.Sprintf("--log-file-path=%s", tempLogDir+"/blobfuse2.log"), - "--streaming", "--use-attr-cache", "--invalidate-on-sync", "--pre-mount-validate", "--basic-remount-check") + "--streaming", "--use-attr-cache", "--invalidate-on-sync", "--pre-mount-validate", "--basic-remount-check", "-o", "direct_io") suite.assert.NotNil(err) suite.assert.Contains(op, "failed to initialize new pipeline") } @@ -326,7 +326,7 @@ func (suite *mountTestSuite) TestInvalidLibfuseOption() { // incorrect option op, err := executeCommandC(rootCmd, "mount", mntDir, fmt.Sprintf("--config-file=%s", confFileMntTest), "-o allow_other", "-o attr_timeout=120", "-o entry_timeout=120", "-o negative_timeout=120", - "-o ro", "-o default_permissions", "-o umask=755", "-o a=b=c") + "-o ro", "-o default_permissions", "-o umask=755", "-o uid=1000", "-o gid=1000", "-o direct_io", "-o a=b=c") suite.assert.NotNil(err) suite.assert.Contains(op, "invalid FUSE options") } @@ -342,7 +342,7 @@ func (suite *mountTestSuite) TestUndefinedLibfuseOption() { // undefined option op, err := executeCommandC(rootCmd, "mount", mntDir, fmt.Sprintf("--config-file=%s", confFileMntTest), "-o allow_other", "-o attr_timeout=120", "-o entry_timeout=120", "-o negative_timeout=120", - "-o ro", "-o allow_root", "-o umask=755", "-o random_option") + "-o ro", "-o allow_root", "-o umask=755", "-o uid=1000", "-o gid=1000", "-o direct_io", "-o random_option") suite.assert.NotNil(err) suite.assert.Contains(op, "invalid FUSE options") } @@ -358,11 +358,41 @@ func (suite *mountTestSuite) TestInvalidUmaskValue() { // incorrect umask value op, err := executeCommandC(rootCmd, "mount", mntDir, fmt.Sprintf("--config-file=%s", confFileMntTest), "-o allow_other", "-o attr_timeout=120", "-o entry_timeout=120", "-o negative_timeout=120", - "-o ro", "-o allow_root", "-o default_permissions", "-o umask=abcd") + "-o ro", "-o allow_root", "-o default_permissions", "-o uid=1000", "-o gid=1000", "-o direct_io", "-o umask=abcd") suite.assert.NotNil(err) suite.assert.Contains(op, "failed to parse umask") } +func (suite *mountTestSuite) TestInvalidUIDValue() { + defer suite.cleanupTest() + + mntDir, err := os.MkdirTemp("", "mntdir") + suite.assert.Nil(err) + defer os.RemoveAll(mntDir) + + // incorrect umask value + op, err := executeCommandC(rootCmd, "mount", mntDir, fmt.Sprintf("--config-file=%s", confFileMntTest), + "-o allow_other", "-o attr_timeout=120", "-o entry_timeout=120", "-o negative_timeout=120", + "-o ro", "-o allow_root", "-o default_permissions", "-o umask=755", "-o gid=1000", "-o direct_io", "-o uid=abcd") + suite.assert.NotNil(err) + suite.assert.Contains(op, "failed to parse uid") +} + +func (suite *mountTestSuite) TestInvalidGIDValue() { + defer suite.cleanupTest() + + mntDir, err := os.MkdirTemp("", "mntdir") + suite.assert.Nil(err) + defer os.RemoveAll(mntDir) + + // incorrect umask value + op, err := executeCommandC(rootCmd, "mount", mntDir, fmt.Sprintf("--config-file=%s", confFileMntTest), + "-o allow_other", "-o attr_timeout=120", "-o entry_timeout=120", "-o negative_timeout=120", + "-o ro", "-o allow_root", "-o default_permissions", "-o umask=755", "-o uid=1000", "-o direct_io", "-o gid=abcd") + suite.assert.NotNil(err) + suite.assert.Contains(op, "failed to parse gid") +} + // fuse option parsing validation func (suite *mountTestSuite) TestFuseOptions() { defer suite.cleanupTest() From 26b576132e6abcdf2362a35948808b8e0192420d Mon Sep 17 00:00:00 2001 From: Vikas Bhansali <64532198+vibhansa-msft@users.noreply.github.com> Date: Mon, 18 Nov 2024 15:29:08 +0530 Subject: [PATCH 4/7] Rocky UT fails due to insufficient memory (#1570) * Fixing UT for Rocky env --- component/block_cache/block_cache_test.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/component/block_cache/block_cache_test.go b/component/block_cache/block_cache_test.go index 741085a88..a45fd5804 100644 --- a/component/block_cache/block_cache_test.go +++ b/component/block_cache/block_cache_test.go @@ -2613,14 +2613,16 @@ func (suite *blockCacheTestSuite) TestReadWriteBlockInParallel() { func (suite *blockCacheTestSuite) TestZZZZZStreamToBlockCacheConfig() { common.IsStream = true - config := "read-only: true\n\nstream:\n block-size-mb: 16\n max-buffers: 80\n buffer-size-mb: 8\n" + config := "read-only: true\n\nstream:\n block-size-mb: 2\n max-buffers: 30\n buffer-size-mb: 8\n" tobj, err := setupPipeline(config) defer tobj.cleanupPipeline() suite.assert.Nil(err) - suite.assert.Equal(tobj.blockCache.Name(), "block_cache") - suite.assert.EqualValues(tobj.blockCache.blockSize, 16*_1MB) - suite.assert.EqualValues(tobj.blockCache.memSize, 8*_1MB*80) + if err == nil { + suite.assert.Equal(tobj.blockCache.Name(), "block_cache") + suite.assert.EqualValues(tobj.blockCache.blockSize, 2*_1MB) + suite.assert.EqualValues(tobj.blockCache.memSize, 8*_1MB*30) + } } // In order for 'go test' to run this suite, we need to create From cbd7b10085d53e985f1a706fdbff1f7a906753eb Mon Sep 17 00:00:00 2001 From: syeleti-msft Date: Mon, 18 Nov 2024 20:13:40 +0530 Subject: [PATCH 5/7] truncate logic correction in filecache (#1569) * Fix will prevent the truncate in file cache to upload the entire file. This is causing the network error when the file is large. Instead it passes the call to the next component. --- CHANGELOG.md | 1 + component/file_cache/file_cache.go | 50 ++++++++++++------------------ 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78a70f8b5..c4635b4de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Do not allow to mount with non-empty directory provided for disk persistence in block-cache. - Rename file was calling an additional getProperties call. - Delete empty directories from local cache on rmdir operation. +- [#1547](https://github.com/Azure/azure-storage-fuse/issues/1547) Truncate logic of file cache is modified to prevent downloading and uploading the entire file. **Features** - Added 'gen-config' command to auto generate blobfuse2 config file. diff --git a/component/file_cache/file_cache.go b/component/file_cache/file_cache.go index 49c7c0a85..b850fcc5f 100644 --- a/component/file_cache/file_cache.go +++ b/component/file_cache/file_cache.go @@ -1496,9 +1496,6 @@ func (fc *FileCache) RenameFile(options internal.RenameFileOptions) error { func (fc *FileCache) TruncateFile(options internal.TruncateFileOptions) error { log.Trace("FileCache::TruncateFile : name=%s, size=%d", options.Name, options.Size) - // If you call truncate CLI command from shell it always sends an open call first followed by truncate - // But if you call the truncate method from a C/C++ code then open is not hit and only truncate comes - if fc.diskHighWaterMark != 0 { currSize, err := common.GetUsage(fc.tmpPath) if err != nil { @@ -1511,42 +1508,33 @@ func (fc *FileCache) TruncateFile(options internal.TruncateFileOptions) error { } } - var h *handlemap.Handle = nil - var err error = nil + flock := fc.fileLocks.Get(options.Name) + flock.Lock() + defer flock.Unlock() - if options.Size == 0 { - // If size is 0 then no need to download any file we can just create an empty file - h, err = fc.CreateFile(internal.CreateFileOptions{Name: options.Name, Mode: fc.defaultPermission}) - if err != nil { - log.Err("FileCache::TruncateFile : Error creating file %s [%s]", options.Name, err.Error()) - return err - } - } else { - // If size is not 0 then we need to open the file and then truncate it - // Open will force download if file was not present in local system - h, err = fc.OpenFile(internal.OpenFileOptions{Name: options.Name, Flags: os.O_RDWR, Mode: fc.defaultPermission}) - if err != nil { - log.Err("FileCache::TruncateFile : Error opening file %s [%s]", options.Name, err.Error()) - return err - } + err := fc.NextComponent().TruncateFile(options) + err = fc.validateStorageError(options.Name, err, "TruncateFile", true) + if err != nil { + log.Err("FileCache::TruncateFile : %s failed to truncate [%s]", options.Name, err.Error()) + return err } // Update the size of the file in the local cache localPath := filepath.Join(fc.tmpPath, options.Name) - fc.policy.CacheValid(localPath) + info, err := os.Stat(localPath) + if err == nil || os.IsExist(err) { + fc.policy.CacheValid(localPath) - // Truncate the file created in local system - err = os.Truncate(localPath, options.Size) - if err != nil { - log.Err("FileCache::TruncateFile : error truncating cached file %s [%s]", localPath, err.Error()) - _ = fc.CloseFile(internal.CloseFileOptions{Handle: h}) - return err + if info.Size() != options.Size { + err = os.Truncate(localPath, options.Size) + if err != nil { + log.Err("FileCache::TruncateFile : error truncating cached file %s [%s]", localPath, err.Error()) + return err + } + } } - // Mark the handle as dirty so that close of this file will force an upload - h.Flags.Set(handlemap.HandleFlagDirty) - - return fc.CloseFile(internal.CloseFileOptions{Handle: h}) + return nil } // Chmod : Update the file with its new permissions From 1ce5915528db77980cae98721e28e37d1455e0f2 Mon Sep 17 00:00:00 2001 From: Sourav Gupta <98318303+souravgupta-msft@users.noreply.github.com> Date: Wed, 20 Nov 2024 13:30:48 +0530 Subject: [PATCH 6/7] Adding Debian 12 (#1572) --- setup/packages.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/setup/packages.csv b/setup/packages.csv index 84998c16e..8e630c2eb 100644 --- a/setup/packages.csv +++ b/setup/packages.csv @@ -9,6 +9,7 @@ Ubuntu-24.04,fuse3ArmDeb,microsoft-ubuntu-noble-prod-apt,noble Debian-9.0,fuse2AmdDeb,microsoft-debian-stretch-prod-apt,stretch Debian-10.0,fuse2AmdDeb,microsoft-debian-buster-prod-apt,buster Debian-11.0,fuse3AmdDeb,microsoft-debian-bullseye-prod-apt,bullseye +Debian-12.0,fuse3AmdDeb,microsoft-debian-bookworm-prod-apt,bookworm RHEL-7.5,fuse3AmdRpm,microsoft-rhel7.5-prod-yum, RHEL-7.8,fuse3AmdRpm,microsoft-rhel7.8-prod-yum, RHEL-8.1,fuse3AmdRpm,microsoft-rhel8.1-prod-yum, From 0ab1a64ca7c495e9c8db3c26b8d1455cc2702f2a Mon Sep 17 00:00:00 2001 From: Vikas Bhansali <64532198+vibhansa-msft@users.noreply.github.com> Date: Fri, 22 Nov 2024 09:54:39 +0530 Subject: [PATCH 7/7] Move version checks from public container to static website (#1550) * Adding support for static website for version check --- CHANGELOG.md | 1 + blobfuse2-release.yaml | 65 ++++++++++++++++++++++++++++++++++------- cmd/root.go | 14 +++++---- cmd/root_test.go | 2 +- common/version.go | 2 +- releaseVersionUpdate.py | 36 ----------------------- 6 files changed, 67 insertions(+), 53 deletions(-) delete mode 100644 releaseVersionUpdate.py diff --git a/CHANGELOG.md b/CHANGELOG.md index c4635b4de..26d62cae7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ **Other Changes** - Stream config will be converted to block-cache config implicitly and 'stream' component is no longer used from this release onwards. - MSI login with object-id will not rely on azcli anymore, rather it will be supported by 'azidentity' SDK. +- Version check is now moved to a static website hosted on a public container. ## 2.3.2 (2024-09-03) **Bug Fixes** diff --git a/blobfuse2-release.yaml b/blobfuse2-release.yaml index 71ab556f0..f7a26fe2b 100644 --- a/blobfuse2-release.yaml +++ b/blobfuse2-release.yaml @@ -1744,8 +1744,22 @@ stages: condition: succeeded('ReleaseArtifacts') jobs: - job: UpdateVersion + timeoutInMinutes: 120 + strategy: + matrix: + UBN20: + vmImage: 'ubuntu-20.04' + fuselib: 'libfuse3-dev' + tags: 'fuse3' + depends: 'fuse3' + container: 'test-cnt-ubn-20' + AgentName: "blobfuse-ubuntu20" + pool: - vmImage: 'ubuntu-20.04' + name: "blobfuse-ubuntu-pool" + demands: + - ImageOverride -equals $(agentName) + variables: - group: NightlyBlobFuse - name: root_dir @@ -1769,6 +1783,7 @@ stages: # install blobfuse2 - script: | + sudo apt install fuse3 -y cd $(Build.ArtifactStagingDirectory)/blobfuse2 ls | grep -i ubuntu-20.04 sudo apt-get install ./`ls | grep -i ubuntu-20.04` -y @@ -1776,13 +1791,43 @@ stages: displayName: 'Installing blobfuse2' - script: | - wget https://raw.githubusercontent.com/Azure/azure-storage-fuse/`echo $(Build.SourceBranch) | cut -d "/" -f 1,2 --complement`/releaseVersionUpdate.py - ls -l - displayName: 'Getting Python script' - workingDirectory: $(root_dir) - + mkdir -p ~/blob_mnt + chmod 777 ~/blob_mnt + mkdir -p ~/blobfusetemp + chmod 777 ~/blobfusetemp + blobfuse2 mount ~/blob_mnt --tmp-path=~/blobfusetemp --container-name="\$web" + sleep 2 + env: + AZURE_STORAGE_ACCOUNT: "blobfuse2" + AZURE_STORAGE_AUTH_TYPE: "msi" + AZURE_STORAGE_IDENTITY_CLIENT_ID: $(BLOBFUSE2_MSI_CIENT_ID) + displayName: 'Mount release container for version update' + - script: | - python3 releaseVersionUpdate.py "$(VERSION_CNT_SAS_URL)" "`blobfuse2 version`" - displayName: 'Updating version number' - workingDirectory: $(root_dir) - + cd ~/blob_mnt/release/latest/ + echo "Before cleanup" + ls -l + rm -rf * + echo "After cleanup" + ls -l + displayName: 'Delete older version file' + + - script: | + cd ~/blob_mnt/release/latest/ + touch `blobfuse2 version | cut -d " " -f3` + ls -l + displayName: 'Create new version file' + + - script: | + cd ~/blob_mnt/release/latest/ + version=`blobfuse2 version | cut -d " " -f3` + echo "Release version: " $version + echo -e "\n$version\n" > index.xml + echo "Printing index.xml" + cat index.xml + displayName: 'Update the XML file' + + - script: | + blobfuse2 unmount all + displayName: 'Unmount Blobfuse2' + diff --git a/cmd/root.go b/cmd/root.go index a9bb25d94..073f0c8d8 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -50,8 +50,7 @@ import ( ) type VersionFilesList struct { - XMLName xml.Name `xml:"EnumerationResults"` - Blobs []Blob `xml:"Blobs>Blob"` + Version string `xml:"latest"` } type Blob struct { @@ -104,6 +103,11 @@ func getRemoteVersion(req string) (string, error) { return "", err } + if len(body) > 50 { + log.Err("getRemoteVersion: something suspicious in the contents from remote version") + return "", fmt.Errorf("unable to get latest version") + } + var versionList VersionFilesList err = xml.Unmarshal(body, &versionList) if err != nil { @@ -111,11 +115,11 @@ func getRemoteVersion(req string) (string, error) { return "", err } - if len(versionList.Blobs) != 1 { + if len(versionList.Version) < 5 || len(versionList.Version) > 20 { return "", fmt.Errorf("unable to get latest version") } - versionName := strings.Split(versionList.Blobs[0].Name, "/")[1] + versionName := versionList.Version return versionName, nil } @@ -126,7 +130,7 @@ func beginDetectNewVersion() chan interface{} { go func() { defer close(completed) - latestVersionUrl := common.Blobfuse2ListContainerURL + "?restype=container&comp=list&prefix=latest/" + latestVersionUrl := common.Blobfuse2ListContainerURL + "/latest/index.xml" remoteVersion, err := getRemoteVersion(latestVersionUrl) if err != nil { log.Err("beginDetectNewVersion: error getting latest version [%s]", err.Error()) diff --git a/cmd/root_test.go b/cmd/root_test.go index af67589ed..4ad92e165 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -147,7 +147,7 @@ func getDummyVersion() string { func (suite *rootCmdSuite) TestGetRemoteVersionValidContainer() { defer suite.cleanupTest() - latestVersionUrl := common.Blobfuse2ListContainerURL + "?restype=container&comp=list&prefix=latest/" + latestVersionUrl := common.Blobfuse2ListContainerURL + "/latest/index.xml" out, err := getRemoteVersion(latestVersionUrl) suite.assert.NotEmpty(out) suite.assert.Nil(err) diff --git a/common/version.go b/common/version.go index 930720969..e214c8710 100644 --- a/common/version.go +++ b/common/version.go @@ -39,7 +39,7 @@ import ( "strings" ) -const Blobfuse2ListContainerURL = "https://blobfuse2.blob.core.windows.net/release" +const Blobfuse2ListContainerURL = "https://blobfuse2.z13.web.core.windows.net/release" const BlobFuse2WarningsURL = "https://aka.ms/blobfuse2warnings" const BlobFuse2BlockingURL = "https://aka.ms/blobfuse2blockers" diff --git a/releaseVersionUpdate.py b/releaseVersionUpdate.py deleted file mode 100644 index b5fdddf78..000000000 --- a/releaseVersionUpdate.py +++ /dev/null @@ -1,36 +0,0 @@ -import json -import requests -import sys -from xml.dom import minidom - -sasUrl = sys.argv[1] -releaseVersion = sys.argv[2].split(' ')[2] -print('Release Version: ' + releaseVersion) -if(len(releaseVersion)==0): - print('Incorrect Release Version') - sys.exit(1) - -containerUrl = sasUrl.split('?')[0] -sasToken = sasUrl.split('?')[1] - -# list latest version file in the container -listUrl = sasUrl + '&restype=container&comp=list&prefix=latest/' -resp = requests.get(listUrl) -sys.exit(1) if(resp.status_code<200 or resp.status_code>202) else print('Listed latest version container') -listData = minidom.parseString(resp.content) -name = listData.getElementsByTagName('Name') -if(len(name)!=1): - print('Latest version container should have exactly one file. Number of files present is ' + str(len(name))) - sys.exit(1) -latestVersion = name[0].firstChild.data -print('Last release version: ' + latestVersion) - -# delete latest version file in the container -deleteUrl = containerUrl + '/' + latestVersion + '?' + sasToken -resp = requests.delete(deleteUrl) -sys.exit(1) if(resp.status_code<200 or resp.status_code>202) else print('Deleted last release file') - -# create release version file in the container -createUrl = containerUrl + '/latest/' + releaseVersion + '?' + sasToken -resp = requests.put(createUrl, headers={'x-ms-blob-type': 'BlockBlob'}) -sys.exit(1) if(resp.status_code<200 or resp.status_code>202) else print('Created new release version file') \ No newline at end of file