-
Notifications
You must be signed in to change notification settings - Fork 24.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce quota-aware filesystem ES plugin (#64331)
Partial backport of #63620. Closes #61145. This PR adds a quota-aware filesystem plugin to Elasticsearch. This plugin offers a way to provide user quota limits (specifically, total quota size and available quota size) to Elasticsearch, in an implementation-agnostic manner.
- Loading branch information
1 parent
46d8c84
commit 99d703e
Showing
15 changed files
with
1,650 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
esplugin { | ||
description 'A bootstrap plugin that adds support for interfacing with filesystem that enforce user quotas.' | ||
classname '<none>' | ||
} | ||
|
||
integTest.enabled = false |
98 changes: 98 additions & 0 deletions
98
...ins/quota-aware-fs/src/main/java/org/elasticsearch/fs/quotaaware/QuotaAwareFileStore.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
/* | ||
* Licensed to Elasticsearch under one or more contributor | ||
* license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright | ||
* ownership. Elasticsearch licenses this file to you under | ||
* the Apache License, Version 2.0 (the "License"); you may | ||
* not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
package org.elasticsearch.fs.quotaaware; | ||
|
||
import java.io.IOException; | ||
import java.nio.file.FileStore; | ||
import java.nio.file.attribute.FileAttributeView; | ||
import java.nio.file.attribute.FileStoreAttributeView; | ||
|
||
/** | ||
* An implementation of {@link FileStore} that relies on | ||
* {@link QuotaAwareFileSystemProvider} for usage reporting. Other methods are | ||
* delegated to the backing instance of {@link FileStore} | ||
*/ | ||
public final class QuotaAwareFileStore extends FileStore { | ||
|
||
private final FileStore backingFS; | ||
private final QuotaAwareFileSystemProvider provider; | ||
|
||
QuotaAwareFileStore(QuotaAwareFileSystemProvider provider, FileStore backingFS) { | ||
this.provider = provider; | ||
this.backingFS = backingFS; | ||
} | ||
|
||
@Override | ||
public String name() { | ||
return backingFS.name(); | ||
} | ||
|
||
@Override | ||
public String type() { | ||
return backingFS.type(); | ||
} | ||
|
||
@Override | ||
public boolean isReadOnly() { | ||
return backingFS.isReadOnly(); | ||
} | ||
|
||
@Override | ||
public long getTotalSpace() throws IOException { | ||
return Math.min(provider.getTotal(), backingFS.getTotalSpace()); | ||
} | ||
|
||
@Override | ||
public long getUsableSpace() throws IOException { | ||
return Math.min(provider.getRemaining(), backingFS.getUsableSpace()); | ||
} | ||
|
||
@Override | ||
public long getUnallocatedSpace() throws IOException { | ||
// There is no point in telling users that the underlying | ||
// host has more capacity than what they're allowed to use so we limit | ||
// this one with remaining as well. | ||
return Math.min(provider.getRemaining(), backingFS.getUnallocatedSpace()); | ||
} | ||
|
||
@Override | ||
public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) { | ||
return backingFS.supportsFileAttributeView(type); | ||
} | ||
|
||
@Override | ||
public boolean supportsFileAttributeView(String name) { | ||
return backingFS.supportsFileAttributeView(name); | ||
} | ||
|
||
@Override | ||
public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> type) { | ||
return backingFS.getFileStoreAttributeView(type); | ||
} | ||
|
||
@Override | ||
public Object getAttribute(String attribute) throws IOException { | ||
return backingFS.getAttribute(attribute); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "QuotaAwareFileStore(" + backingFS.toString() + ")"; | ||
} | ||
} |
144 changes: 144 additions & 0 deletions
144
...ns/quota-aware-fs/src/main/java/org/elasticsearch/fs/quotaaware/QuotaAwareFileSystem.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
/* | ||
* Licensed to Elasticsearch under one or more contributor | ||
* license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright | ||
* ownership. Elasticsearch licenses this file to you under | ||
* the Apache License, Version 2.0 (the "License"); you may | ||
* not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
|
||
package org.elasticsearch.fs.quotaaware; | ||
|
||
import org.elasticsearch.common.SuppressForbidden; | ||
|
||
import java.io.IOException; | ||
import java.nio.file.FileStore; | ||
import java.nio.file.FileSystem; | ||
import java.nio.file.FileSystems; | ||
import java.nio.file.Path; | ||
import java.nio.file.PathMatcher; | ||
import java.nio.file.WatchService; | ||
import java.nio.file.attribute.UserPrincipalLookupService; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
import java.util.function.Function; | ||
import java.util.stream.StreamSupport; | ||
|
||
/** | ||
* An implementation of {@link FileSystem} that returns the given | ||
* {@link QuotaAwareFileSystemProvider} provider {@link #provider()}. | ||
* | ||
* Other methods are delegated to given instance of {@link FileSystem} and | ||
* wrapped where result types are either @link {@link QuotaAwareFileSystem} | ||
* or @link {@link QuotaAwareFileStore}. | ||
* | ||
*/ | ||
public final class QuotaAwareFileSystem extends FileSystem { | ||
private final FileSystem delegate; | ||
private final QuotaAwareFileSystemProvider provider; | ||
|
||
QuotaAwareFileSystem(QuotaAwareFileSystemProvider provider, FileSystem delegate) { | ||
this.provider = Objects.requireNonNull(provider, "Provider is required"); | ||
this.delegate = Objects.requireNonNull(delegate, "FileSystem is required"); | ||
} | ||
|
||
@Override | ||
public QuotaAwareFileSystemProvider provider() { | ||
return provider; | ||
} | ||
|
||
@Override | ||
@SuppressForbidden(reason = "accesses the default filesystem by design") | ||
public void close() throws IOException { | ||
if (this == FileSystems.getDefault()) { | ||
throw new UnsupportedOperationException("The default file system cannot be closed"); | ||
} else if (delegate != FileSystems.getDefault()) { | ||
delegate.close(); | ||
} | ||
provider.purge(delegate); | ||
} | ||
|
||
@Override | ||
public boolean isOpen() { | ||
return delegate.isOpen(); | ||
} | ||
|
||
@Override | ||
public boolean isReadOnly() { | ||
return delegate.isReadOnly(); | ||
} | ||
|
||
@Override | ||
public String getSeparator() { | ||
return delegate.getSeparator(); | ||
} | ||
|
||
@Override | ||
public Iterable<Path> getRootDirectories() { | ||
return StreamSupport.stream(delegate.getRootDirectories().spliterator(), false).map((Function<Path, Path>) this::wrap)::iterator; | ||
} | ||
|
||
@Override | ||
public Iterable<FileStore> getFileStores() { | ||
return StreamSupport.stream(delegate.getFileStores().spliterator(), false) | ||
.map((Function<FileStore, FileStore>) provider::getFileStore)::iterator; | ||
} | ||
|
||
@Override | ||
public Set<String> supportedFileAttributeViews() { | ||
return delegate.supportedFileAttributeViews(); | ||
} | ||
|
||
@Override | ||
public Path getPath(String first, String... more) { | ||
return wrap(delegate.getPath(first, more)); | ||
} | ||
|
||
private QuotaAwarePath wrap(Path delegatePath) { | ||
if (delegatePath == null) return null; | ||
else return new QuotaAwarePath(this, delegatePath); | ||
} | ||
|
||
@Override | ||
public PathMatcher getPathMatcher(String syntaxAndPattern) { | ||
PathMatcher matcher = delegate.getPathMatcher(syntaxAndPattern); | ||
return (path) -> matcher.matches(QuotaAwarePath.unwrap(path)); | ||
} | ||
|
||
@Override | ||
public UserPrincipalLookupService getUserPrincipalLookupService() { | ||
return delegate.getUserPrincipalLookupService(); | ||
} | ||
|
||
@Override | ||
public WatchService newWatchService() throws IOException { | ||
return delegate.newWatchService(); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object obj) { | ||
if (this == obj) return true; | ||
if (obj == null) return false; | ||
if (getClass() != obj.getClass()) return false; | ||
QuotaAwareFileSystem other = (QuotaAwareFileSystem) obj; | ||
if (!delegate.equals(other.delegate)) return false; | ||
if (!provider.equals(other.provider)) return false; | ||
return true; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return delegate.hashCode(); | ||
} | ||
|
||
} |
Oops, something went wrong.