-
Notifications
You must be signed in to change notification settings - Fork 593
feat(repository): Add Azure PIT support #3407
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
Conversation
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## master #3407 +/- ##
==========================================
+ Coverage 75.80% 75.82% +0.01%
==========================================
Files 465 465
Lines 37165 37180 +15
==========================================
+ Hits 28174 28192 +18
- Misses 7059 7061 +2
+ Partials 1932 1927 -5 ☔ View full report in Codecov by Sentry. |
|
@KastenMike see initial comments |
repo/blob/azure/azure_storage.go
Outdated
|
|
||
| func (az *azStorage) getBlobName(it *azblobmodels.BlobItem) string { | ||
| n := *it.Name | ||
| return n[len(az.Prefix):] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use strings.TrimPrefix here, it is more robust.
Also additional defensive programming should be applied here to prevent a panic due to a nil dereference. Given the Azure SDK API, where all the structs have pointers, then it makes sense to add helpers that either (a) validate and return an error; or (b) return sane default values.
| return n[len(az.Prefix):] | |
| return strings.TrimPrefix(toString(*it.Name), az.prefix) |
toString would be defined as:
func toString(s *string) string {
return stringDefault(s, "")
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code has been in kopia for a long time so I guess azure returns an error rather than null values for the common metadata. I just extracted it to a method
| return n[len(az.Prefix):] | ||
| } | ||
|
|
||
| func (az *azStorage) getBlobMeta(it *azblobmodels.BlobItem) blob.Metadata { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
check for it != nil
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same as above~ the code has been in since February without issue so I guess there is always a blob item if the loop is entered
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. The hardening can be done separately.
| func (az *azStorage) getBlobMeta(it *azblobmodels.BlobItem) blob.Metadata { | ||
| bm := blob.Metadata{ | ||
| BlobID: blob.ID(az.getBlobName(it)), | ||
| Length: *it.Properties.ContentLength, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check to ensure that:
it.Properties != nilit.Properties.ContentLength != nil
before dereferencing.
| } | ||
|
|
||
| // see if we have 'Kopiamtime' metadata, if so - trust it. | ||
| if t, ok := timestampmeta.FromValue(stringDefault(it.Metadata["kopiamtime"], "")); ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: after adding toString, then it can be used here.
| if t, ok := timestampmeta.FromValue(stringDefault(it.Metadata["kopiamtime"], "")); ok { | |
| if t, ok := timestampmeta.FromValue(toString(it.Metadata["kopiamtime"])); ok { |
| if t, ok := timestampmeta.FromValue(stringDefault(it.Metadata["kopiamtime"], "")); ok { | ||
| bm.Timestamp = t | ||
| } else { | ||
| bm.Timestamp = *it.Properties.LastModified |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto: validate the chain to ensure there are no nil components
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LG overall.
I am not completely sure about the handling of the deletion marker.
And a few inline comments.
| return n[len(az.Prefix):] | ||
| } | ||
|
|
||
| func (az *azStorage) getBlobMeta(it *azblobmodels.BlobItem) blob.Metadata { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough. The hardening can be done separately.
|
Provider tests are failing for Azure Blob |
| "github.com/kopia/kopia/repo/format" | ||
| ) | ||
|
|
||
| func TestGetBlobVersions(t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@KastenMike This test and the one below are failing in the "test/providers" job. The likely cause is that the buckets used in the test do not have the required setup, that is version-level immutability enabled.
That's the only thing left to merge this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did you re-run the tests? I cannot see run history & you didn't link a new run. Now it doesn't check for version-level immutability
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK I see it in Actions. Someone should enable versioning on the related storage account for it to work https://learn.microsoft.com/en-us/azure/storage/blobs/versioning-enable?tabs=portal
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the process whoever sets it could enable version-level immutability on the container since it seems the SDK doesn't support it and it's required for #3412 tests
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jkowalski is it something you'd be able to enable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mike: this requires a little more than that.
These 2 tests need to run in a different setup. That means:
- setting up a separate storage account with version-level immutability enabled (as you mentioned).
- create a new bucket with version-level immutability, or have the test create it with the desired settings.
- these tests need to use a separate 'credentials setting' from the environment. The actual credentials may be the same, but the storage account and bucket would be different.
- the GH environment needs to be updated with these new cred information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does it require a separate storage account? you could simply have the same one running new + existing tests but with 2 new settings changed. When turning on versioning it gives the option to use Azure's BLM which can be set to delete versions older than 1 day
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@KastenMike For what I understand, the storage account currently used in the tests does not have versioning, nor immutability enabled. I thought that version immutability needed to be enabled at the storage account level. This is what I recall but I could be mistaken. I'll double check.
Also, we don't want to enable versioning for the default tests, since the default / common use case does not require nor use versioning by default.
If no separate storage account is needed, then it is a matter of simply creating a separate container with the appropriate settings.
PTAL at https://github.com/kopia/kopia/compare/azure-immutability-setup
This contains the setup code for the storage account and the container. PLMK if that makes sense, if there's anything missing or that needs to be changed.
Thanks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting ImmutableStorageWithVersioning to true via CLI is automatically making versioning be enabled too? In the UI they make you do 2 separate actions. A policy isn’t needed on the container~ only versioning + ImmutableStorageWithVersioning
If the intention would be to run it repeatedly like the createContainer currently then it needs checks for "already exists" errors also on the SA & container
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Behavior observed using the console: attempting to enable "version immutability" in the container requires enabling "versioning" in the storage account. It wasn't clear at that moment what the implication was for existing buckets, so we created a separate storage account and bucket.
See comment below
|
@redgoat650 Do you have any comments? |
|
@KastenMike FYI #3471 was missing in the setup. All good now. |
julio-lopez
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@KastenMike 🥇Thanks for doing this.
LGTM ✅
Adds support for Azure PIT