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

Add s3 disk validation step #22

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open

Conversation

lehecht
Copy link
Contributor

@lehecht lehecht commented Feb 6, 2025

  • Update Tests

Closes #4.

@lehecht
Copy link
Contributor Author

lehecht commented Feb 6, 2025

@mzur
Could you give some feedback on my validation method?
I had to use Storage::build() instead of Storage::disk()because disk() makes the update method unnecessarily complex. With disk(), I would need to use DB::transaction() to first save the updated fields, then validating them and maybe rolling everything back if there is an error. Relying solely on the request wasn’t an option because disk() uses the disk from the database, which hadn’t been updated, yet.

@mzur
Copy link
Member

mzur commented Feb 6, 2025

I think using a database transaction for this would be quite elegant! Then you can use disk() too, which should work with other types than S3 in the future.

I would advise against using allFiles() to check the disk. If there are a lot of files, the memory limit could be reached. I recently had a case where a user had 100k files and it crashed. I implemented a more efficient check for content that you could use here, too. I would not throw en error if the disk is empty, though. Maybe users want to prepare the disk before they upload data to it. Use the test only to check for configuration errors.

@mzur
Copy link
Member

mzur commented Feb 6, 2025

It just came to my mind: You can probably use the VolumeUrl validation rule directly here. No need to duplicate code (unless it prevents you from showing a helpful error message).

@lehecht
Copy link
Contributor Author

lehecht commented Feb 7, 2025

@mzur
The code you mentioned is located in passesDiskUrl(), but when I use VolumeUrl with the disk endpoint, it uses passesRemoteUrl().
After duplicating the code, I no longer get an error if the endpoint URL is incorrect; instead, it just returns an empty list.

@lehecht
Copy link
Contributor Author

lehecht commented Feb 7, 2025

I found that an exception is only thrown if the host url is incorrect. If the bucket name is missing or wrong, it just returns an empty list.

@mzur
Copy link
Member

mzur commented Feb 10, 2025

When I place the listContents() before the try/catch in your validateS3Config() I get errors as expected. The only thing that is not validated properly, it seems, is when I enter a wrong bucket name in the endpoint URL. This runs into the execution timeout. Please push your current code so I can have a look.

Make code more elegant by using Storage::disk and DB::transaction.
@lehecht
Copy link
Contributor Author

lehecht commented Feb 11, 2025

@mzur
My problem is resolved. I'm not sure what I did differently this time, but incorrect bucket names trigger errors now.
I've pushed my code, so you can review it again. Everything should be working, but I need some feedback on my error messages. Thank you for your help!

I'll add tests later after my method doesn't need to be changed any more. So I'm not finished, yet.

@lehecht lehecht force-pushed the add-s3-disk-validation-step branch 2 times, most recently from 15e96e7 to fb8a21f Compare February 24, 2025 07:27
@lehecht lehecht force-pushed the add-s3-disk-validation-step branch from fb8a21f to 16ee9be Compare February 24, 2025 07:28
@lehecht lehecht requested a review from mzur February 24, 2025 07:31
@lehecht
Copy link
Contributor Author

lehecht commented Feb 24, 2025

The tests are failing because they still use docker-compose instead of docker compose. Can I update the command in this PR or should I open a new one?

@mzur
Copy link
Member

mzur commented Feb 24, 2025

You can update the command in this PR.

@lehecht lehecht marked this pull request as ready for review February 25, 2025 08:09
Copy link
Member

@mzur mzur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comments left. Please be a little more diligent next time.

use Biigle\Modules\UserDisks\Http\Requests\StoreUserDisk;
use Biigle\Modules\UserDisks\Http\Requests\ExtendUserDisk;
use Biigle\Modules\UserDisks\Http\Requests\UpdateUserDisk;
use Biigle\Modules\UserDisks\Exceptions\DiskValidationException;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this thrown? I only find ValidationException.

$options = $disk->options;
$endpoint = $options['endpoint'];
$bucket = $options['bucket'];

// Check if endpoint contains bucket name
if (!preg_match("/(\b\/" . $bucket . "\.|\b" . $bucket . "\b)/", $endpoint)) {
$errors['endpoint'] = 'Endpoint url requires bucket name';
return $errors;
throw ValidationException::withMessages(['endpoint' => 'Endpoint url must contain bucket name. Please check if name is present and spelled correctly.']);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please check if proper English is used 😜 Seriously, these kinds of things must be user-friendly.

Suggested change
throw ValidationException::withMessages(['endpoint' => 'Endpoint url must contain bucket name. Please check if name is present and spelled correctly.']);
throw ValidationException::withMessages(['endpoint' => 'The endpoint URL must contain the bucket name. Please check if the name is present and spelled correctly.']);

$files = $disk->getAdapter()->listContents('/', false);
// Need to access an element to check if endpoint url is valid
$files->current();
$this->canAccessDisk($disk);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why put this in an extra method if it is only used once?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah it's for testing. Please add a docblock to the method (which should be there anyway) and explain this in the comment.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method name may be a little misleading because the method returns void and not bool. Maybe call it validateDiskAccess?

@@ -171,42 +172,41 @@ public function destroy($id)
protected function validateS3Config(UserDisk $disk)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a docblock to this method.

Comment on lines +47 to +55
<div class="col-xs-12" @error('error') has-error @enderror>
@error('error')
<div class="panel panel-danger">
<div class="panel-body text-danger">
{{$message}}
</div>
</div>
@enderror
</div>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please still apply the same change than in update.blade.php. And please take a little more care next time when you work through my review comments, you are our "senior" dev after all 😉

Comment on lines +66 to +70
} catch (DiskValidationException $e) {
return $this->fuzzyRedirect()
->withErrors($e->getValidationError())
->withInput();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the DiskValidationException doesn't seem to exist, the try/catch can probably be removed. Please be a little more careful about something like this. Mistakes like these shouldn't exist any more in a review-ready PR.

$this->postJson("/api/v1/user-disks", [
'name' => 'my disk',
'type' => 's3',
])
->assertStatus(422);

$this->mockS3->shouldReceive('canAccessDisk')->once()->andReturn([]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why return an array when the original method returns void?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't find any test where canAccessDisk() actually throws an exception. Didn't you test these (most important) cases at all?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add validation of new storage disks
2 participants