Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UploadStreamToBlockBlob: blob access conditions are ignored #17152

Closed
ItalyPaleAle opened this issue Feb 23, 2022 · 3 comments
Closed

UploadStreamToBlockBlob: blob access conditions are ignored #17152

ItalyPaleAle opened this issue Feb 23, 2022 · 3 comments
Assignees
Labels
bug This issue requires a change to an existing behavior in the product in order to be resolved. Client This issue points to a problem in the data-plane of the library. Storage Storage Service (Queues, Blobs, Files)

Comments

@ItalyPaleAle
Copy link
Member

Bug Report

  • import path of package in question: github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0
  • output of go version: go version go1.17.5 linux/arm64

(This is a spin-off from #17131 which identified the error as something different than I originally thought)

You can repro with the code below (fill the constants at the top):

package main

import (
	"context"
	"fmt"
	"io"
	"math/rand"
	"os"
	"time"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
	"github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
)

// Set these
const account = "***"
const accessKey = "***"

// For these tests, I used 2 random images from Unsplash (because those are relatively large files and are free)
// Feel free to use any other file name here
const testFile1 = "dave-goudreau--W_vDl5Ll8M-unsplash.jpg"
const testFile2 = "katharina-bill-dSc2aoQmaZk-unsplash.jpg"

func main() {
	rand.Seed(time.Now().UnixNano())

	containerClient, err := setupContainer("c" + RandString(5))
	if err != nil {
		panic(err)
	}

	in := openFile(testFile1)
	defer in.Close()

	err = uploadToAzure(
		containerClient,
		"testblob",
		in,
		nil,
	)
	if err != nil {
		panic(err)
	}

	// Upload again: this should return an error
	in = openFile(testFile2)
	defer in.Close()
	err = uploadToAzure(
		containerClient,
		"testblob",
		in,
		nil,
	)
	if err == nil {
		panic("Expected error, got nil")
	}
	fmt.Println(err)
}

const letters = "abcdefghijklmnopqrstuvwxyz0123456789"

func RandString(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func openFile(name string) io.ReadCloser {
	in, err := os.Open(name)
	if err != nil {
		panic(err)
	}
	return in
}

func setupContainer(container string) (*azblob.ContainerClient, error) {
	storageURL := fmt.Sprintf("https://%s.blob.core.windows.net", account)
	cred, err := azblob.NewSharedKeyCredential(account, accessKey)
	if err != nil {
		return nil, err
	}
	service, err := azblob.NewServiceClientWithSharedKey(storageURL, cred, &azblob.ClientOptions{
		Telemetry: policy.TelemetryOptions{
			Disabled: true,
		},
	})
	if err != nil {
		return nil, err
	}
	containerClient := service.NewContainerClient(container)
	_, err = containerClient.Create(context.Background(), &azblob.CreateContainerOptions{
		Access: nil,
	})
	if err != nil {
		return nil, err
	}
	return &containerClient, nil
}

func uploadToAzure(containerClient *azblob.ContainerClient, name string, in io.Reader, metadata map[string]string) error {
	blob := containerClient.NewBlockBlobClient(name)
	ifNoneMatch := "*"
	opts := azblob.UploadStreamToBlockBlobOptions{
		BufferSize: 5 * 1024 * 1024,
		MaxBuffers: 2,
		BlobAccessConditions: &azblob.BlobAccessConditions{
			ModifiedAccessConditions: &azblob.ModifiedAccessConditions{
				IfNoneMatch: &ifNoneMatch,
			},
		},
		Metadata: metadata,
	}
	res, err := blob.UploadStreamToBlockBlob(context.Background(), in, opts)
	if err != nil {
		return err
	}
	fmt.Println(res.RawResponse.StatusCode)

	return nil
}

Expected result:

  • First file should be uploaded correctly
  • Second file should fail to be uploaded because of the ifNoneMatch condition set to "*"
  • Second invocation of uploadToAzure should return an error, and the status code shown from the second method should not be 2xx

Actual result:

  • First file is uploaded then overwritten by the second file
  • uploadToAzure never returns an error, and status code is always 2xx

CC: @zezha-msft

@ghost ghost added the needs-triage This is a new issue that needs to be triaged to the appropriate team. label Feb 23, 2022
@zezha-msft zezha-msft added bug This issue requires a change to an existing behavior in the product in order to be resolved. and removed needs-triage This is a new issue that needs to be triaged to the appropriate team. labels Feb 23, 2022
@RickWinter RickWinter added Storage Storage Service (Queues, Blobs, Files) Client This issue points to a problem in the data-plane of the library. labels Mar 31, 2022
@mohsha-msft
Copy link
Contributor

Hey @ItalyPaleAle ,

Thanks for reaching out!
I have fixed this issue and will be releasing it in the next release.

@ItalyPaleAle
Copy link
Member Author

Thanks for the update! This is great news

@mohsha-msft
Copy link
Contributor

Hey @ItalyPaleAle ,
azblob v0.4.0 is now publically available. I have fixed the issue here and here.

Please reach out and reopen the issue if it still persists.

Thanks a lot for your feedbacks!

@github-actions github-actions bot locked and limited conversation to collaborators Apr 11, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug This issue requires a change to an existing behavior in the product in order to be resolved. Client This issue points to a problem in the data-plane of the library. Storage Storage Service (Queues, Blobs, Files)
Projects
None yet
Development

No branches or pull requests

4 participants