mirror of
https://github.com/rustfs/rustfs.git
synced 2026-01-17 17:40:38 +00:00
Compare commits
8 Commits
1.0.0-alph
...
fix/window
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
813b48484d | ||
|
|
e614e530cf | ||
|
|
00119548d2 | ||
|
|
d532c7c972 | ||
|
|
04f441361e | ||
|
|
9e162b6e9e | ||
|
|
900f7724b8 | ||
|
|
4f5653e656 |
1
.github/workflows/helm-package.yml
vendored
1
.github/workflows/helm-package.yml
vendored
@@ -44,7 +44,6 @@ jobs:
|
||||
set -x
|
||||
old_version=$(grep "^appVersion:" helm/rustfs/Chart.yaml | awk '{print $2}')
|
||||
sed -i "s/$old_version/$new_version/g" helm/rustfs/Chart.yaml
|
||||
sed -i "/^image:/,/^[^ ]/ s/tag:.*/tag: "$new_version"/" helm/rustfs/values.yaml
|
||||
|
||||
- name: Set up Helm
|
||||
uses: azure/setup-helm@v4.3.0
|
||||
|
||||
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -7974,6 +7974,7 @@ dependencies = [
|
||||
"bytesize",
|
||||
"chrono",
|
||||
"criterion",
|
||||
"dunce",
|
||||
"enumset",
|
||||
"faster-hex",
|
||||
"flatbuffers",
|
||||
@@ -8410,7 +8411,7 @@ dependencies = [
|
||||
"tracing",
|
||||
"transform-stream",
|
||||
"url",
|
||||
"winapi",
|
||||
"windows 0.62.2",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
|
||||
@@ -184,6 +184,7 @@ criterion = { version = "0.8", features = ["html_reports"] }
|
||||
crossbeam-queue = "0.3.12"
|
||||
datafusion = "51.0.0"
|
||||
derive_builder = "0.20.2"
|
||||
dunce = "1.0.5"
|
||||
enumset = "1.1.10"
|
||||
faster-hex = "0.10.0"
|
||||
flate2 = "1.1.5"
|
||||
@@ -251,7 +252,7 @@ uuid = { version = "1.19.0", features = ["v4", "fast-rng", "macro-diagnostics"]
|
||||
vaultrs = { version = "0.7.4" }
|
||||
walkdir = "2.5.0"
|
||||
wildmatch = { version = "2.6.1", features = ["serde"] }
|
||||
winapi = { version = "0.3.9" }
|
||||
windows = { version = "0.62.2" }
|
||||
xxhash-rust = { version = "0.8.15", features = ["xxh64", "xxh3"] }
|
||||
zip = "7.0.0"
|
||||
zstd = "0.13.3"
|
||||
|
||||
@@ -83,6 +83,13 @@ Unlike other storage systems, RustFS is released under the permissible Apache 2.
|
||||
| **Edge & IoT** | **Strong Edge Support**<br>Ideal for secure, innovative edge devices. | **Weak Edge Support**<br>Often too heavy for edge gateways. |
|
||||
| **Risk Profile** | **Enterprise Risk Mitigation**<br>Clear IP rights and safe for commercial use. | **Legal Risks**<br>Intellectual property ambiguity and usage restrictions. |
|
||||
|
||||
|
||||
## Staying ahead
|
||||
|
||||
Star RustFS on GitHub and be instantly notified of new releases.
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/7ee40bb4-3e46-4eac-b0d0-5fbeb85ff8f3" />
|
||||
|
||||
## Quickstart
|
||||
|
||||
To get started with RustFS, follow these steps:
|
||||
|
||||
@@ -86,6 +86,15 @@ RustFS 是一个基于 Rust 构建的高性能分布式对象存储系统。Rust
|
||||
| **成本** | **稳定且免费**<br>免费社区支持,稳定的商业定价。 | **高昂成本**<br>1PiB 的成本可能高达 250,000 美元。 |
|
||||
| **风险控制** | **企业级风险规避**<br>清晰的知识产权,商业使用安全无忧。 | **法律风险**<br>知识产权归属模糊及使用限制风险。 |
|
||||
|
||||
|
||||
## 保持领先
|
||||
|
||||
在 GitHub 上为 RustFS 点赞,即可第一时间收到新版本发布通知。
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/7ee40bb4-3e46-4eac-b0d0-5fbeb85ff8f3" />
|
||||
|
||||
|
||||
|
||||
## 快速开始
|
||||
|
||||
请按照以下步骤快速上手 RustFS:
|
||||
|
||||
@@ -108,6 +108,7 @@ google-cloud-storage = { workspace = true }
|
||||
google-cloud-auth = { workspace = true }
|
||||
aws-config = { workspace = true }
|
||||
faster-hex = { workspace = true }
|
||||
dunce = { workspace = true }
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -129,7 +129,8 @@ impl LocalDisk {
|
||||
pub async fn new(ep: &Endpoint, cleanup: bool) -> Result<Self> {
|
||||
debug!("Creating local disk");
|
||||
// Use optimized path resolution instead of absolutize() for better performance
|
||||
let root = match std::fs::canonicalize(ep.get_file_path()) {
|
||||
// Use dunce::canonicalize instead of std::fs::canonicalize to avoid UNC paths on Windows
|
||||
let root = match dunce::canonicalize(ep.get_file_path()) {
|
||||
Ok(path) => path,
|
||||
Err(e) => {
|
||||
if e.kind() == ErrorKind::NotFound {
|
||||
|
||||
@@ -72,7 +72,7 @@ rand = { workspace = true }
|
||||
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { workspace = true, optional = true, features = ["std", "fileapi", "minwindef", "ntdef", "winnt"] }
|
||||
windows = { workspace = true, optional = true, features = ["Win32_Storage_FileSystem", "Win32_Foundation"] }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -89,7 +89,7 @@ compress = ["dep:flate2", "dep:brotli", "dep:snap", "dep:lz4", "dep:zstd"]
|
||||
string = ["dep:regex"]
|
||||
crypto = ["dep:base64-simd", "dep:hex-simd", "dep:hmac", "dep:hyper", "dep:sha1"]
|
||||
hash = ["dep:highway", "dep:md-5", "dep:sha2", "dep:blake3", "dep:serde", "dep:siphasher", "dep:hex-simd", "dep:crc-fast"]
|
||||
os = ["dep:nix", "dep:tempfile", "winapi"] # operating system utilities
|
||||
os = ["dep:nix", "dep:tempfile", "dep:windows"] # operating system utilities
|
||||
integration = [] # integration test features
|
||||
sys = ["dep:sysinfo"] # system information features
|
||||
http = ["dep:convert_case", "dep:http", "dep:regex"]
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
use bytes::Bytes;
|
||||
use futures::{Stream, StreamExt, pin_mut};
|
||||
#[cfg(test)]
|
||||
use std::sync::MutexGuard;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
fmt::Display,
|
||||
@@ -83,7 +81,7 @@ fn reset_dns_resolver_inner() {
|
||||
|
||||
#[cfg(test)]
|
||||
pub struct MockResolverGuard {
|
||||
_lock: MutexGuard<'static, ()>,
|
||||
_lock: std::sync::MutexGuard<'static, ()>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#![allow(unsafe_code)] // TODO: audit unsafe code
|
||||
// Copyright 2024 RustFS Team
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -13,149 +12,232 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use super::{DiskInfo, IOStats};
|
||||
#![allow(unsafe_code)] // TODO: audit unsafe code
|
||||
|
||||
use crate::os::{DiskInfo, IOStats};
|
||||
use std::io::Error;
|
||||
use std::mem;
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
use std::path::Path;
|
||||
use winapi::shared::minwindef::{DWORD, MAX_PATH};
|
||||
use winapi::shared::ntdef::ULARGE_INTEGER;
|
||||
use winapi::um::fileapi::{GetDiskFreeSpaceExW, GetDiskFreeSpaceW, GetVolumeInformationW, GetVolumePathNameW};
|
||||
use winapi::um::winnt::{LPCWSTR, WCHAR};
|
||||
use windows::Win32::Foundation::MAX_PATH;
|
||||
use windows::Win32::Storage::FileSystem::{GetDiskFreeSpaceExW, GetDiskFreeSpaceW, GetVolumeInformationW, GetVolumePathNameW};
|
||||
|
||||
/// Returns total and free bytes available in a directory, e.g. `C:\`.
|
||||
pub fn get_info(p: impl AsRef<Path>) -> std::io::Result<DiskInfo> {
|
||||
let path_display = p.as_ref().display();
|
||||
let path_wide: Vec<WCHAR> = p
|
||||
let path_wide = p
|
||||
.as_ref()
|
||||
.to_path_buf()
|
||||
.into_os_string()
|
||||
.encode_wide()
|
||||
.chain(std::iter::once(0)) // Null-terminate the string
|
||||
.collect();
|
||||
.to_string_lossy()
|
||||
.encode_utf16()
|
||||
.chain(std::iter::once(0))
|
||||
.collect::<Vec<u16>>();
|
||||
|
||||
let mut lp_free_bytes_available: ULARGE_INTEGER = unsafe { mem::zeroed() };
|
||||
let mut lp_total_number_of_bytes: ULARGE_INTEGER = unsafe { mem::zeroed() };
|
||||
let mut lp_total_number_of_free_bytes: ULARGE_INTEGER = unsafe { mem::zeroed() };
|
||||
let mut free_bytes_available = 0u64;
|
||||
let mut total_number_of_bytes = 0u64;
|
||||
let mut total_number_of_free_bytes = 0u64;
|
||||
|
||||
let success = unsafe {
|
||||
unsafe {
|
||||
GetDiskFreeSpaceExW(
|
||||
path_wide.as_ptr(),
|
||||
&mut lp_free_bytes_available,
|
||||
&mut lp_total_number_of_bytes,
|
||||
&mut lp_total_number_of_free_bytes,
|
||||
windows::core::PCWSTR::from_raw(path_wide.as_ptr()),
|
||||
Some(&mut free_bytes_available),
|
||||
Some(&mut total_number_of_bytes),
|
||||
Some(&mut total_number_of_free_bytes),
|
||||
)
|
||||
};
|
||||
if success == 0 {
|
||||
return Err(Error::last_os_error());
|
||||
.map_err(|e| Error::from_raw_os_error(e.code().0 as i32))?;
|
||||
}
|
||||
|
||||
let total = unsafe { *lp_total_number_of_bytes.QuadPart() };
|
||||
let free = unsafe { *lp_total_number_of_free_bytes.QuadPart() };
|
||||
let total = total_number_of_bytes;
|
||||
let free = total_number_of_free_bytes;
|
||||
|
||||
if free > total {
|
||||
return Err(Error::other(format!(
|
||||
"detected free space ({free}) > total drive space ({total}), fs corruption at ({path_display}). please run 'fsck'"
|
||||
"detected free space ({free}) > total drive space ({total}), fs corruption at ({}). please run 'fsck'",
|
||||
p.as_ref().display()
|
||||
)));
|
||||
}
|
||||
|
||||
let mut lp_sectors_per_cluster: DWORD = 0;
|
||||
let mut lp_bytes_per_sector: DWORD = 0;
|
||||
let mut lp_number_of_free_clusters: DWORD = 0;
|
||||
let mut lp_total_number_of_clusters: DWORD = 0;
|
||||
let mut sectors_per_cluster = 0u32;
|
||||
let mut bytes_per_sector = 0u32;
|
||||
let mut number_of_free_clusters = 0u32;
|
||||
let mut total_number_of_clusters = 0u32;
|
||||
|
||||
let success = unsafe {
|
||||
unsafe {
|
||||
GetDiskFreeSpaceW(
|
||||
path_wide.as_ptr(),
|
||||
&mut lp_sectors_per_cluster,
|
||||
&mut lp_bytes_per_sector,
|
||||
&mut lp_number_of_free_clusters,
|
||||
&mut lp_total_number_of_clusters,
|
||||
windows::core::PCWSTR::from_raw(path_wide.as_ptr()),
|
||||
Some(&mut sectors_per_cluster),
|
||||
Some(&mut bytes_per_sector),
|
||||
Some(&mut number_of_free_clusters),
|
||||
Some(&mut total_number_of_clusters),
|
||||
)
|
||||
};
|
||||
if success == 0 {
|
||||
return Err(Error::last_os_error());
|
||||
.map_err(|e| Error::from_raw_os_error(e.code().0 as i32))?;
|
||||
}
|
||||
|
||||
Ok(DiskInfo {
|
||||
total,
|
||||
free,
|
||||
used: total - free,
|
||||
files: lp_total_number_of_clusters as u64,
|
||||
ffree: lp_number_of_free_clusters as u64,
|
||||
|
||||
// TODO This field is currently unused, and since this logic causes a
|
||||
// NotFound error during startup on Windows systems, it has been commented out here
|
||||
//
|
||||
// The error occurs in GetVolumeInformationW where the path parameter
|
||||
// is of type [WCHAR; MAX_PATH]. For a drive letter, there are excessive
|
||||
// trailing zeros, which causes the failure here.
|
||||
//
|
||||
// fstype: get_fs_type(&path_wide)?,
|
||||
files: total_number_of_clusters as u64,
|
||||
ffree: number_of_free_clusters as u64,
|
||||
fstype: get_fs_type(&path_wide).unwrap_or_default(),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns leading volume name.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `v` - A slice of u16 representing the path in UTF-16 encoding
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Ok(Vec<u16>)` containing the volume name in UTF-16 encoding.
|
||||
/// * `Err` if an error occurs during the operation.
|
||||
#[allow(dead_code)]
|
||||
fn get_volume_name(v: &[WCHAR]) -> std::io::Result<LPCWSTR> {
|
||||
let volume_name_size: DWORD = MAX_PATH as _;
|
||||
let mut lp_volume_name_buffer: [WCHAR; MAX_PATH] = [0; MAX_PATH];
|
||||
fn get_volume_name(v: &[u16]) -> std::io::Result<Vec<u16>> {
|
||||
let mut volume_name_buffer = [0u16; MAX_PATH as usize];
|
||||
|
||||
let success = unsafe { GetVolumePathNameW(v.as_ptr(), lp_volume_name_buffer.as_mut_ptr(), volume_name_size) };
|
||||
|
||||
if success == 0 {
|
||||
return Err(Error::last_os_error());
|
||||
unsafe {
|
||||
GetVolumePathNameW(windows::core::PCWSTR::from_raw(v.as_ptr()), &mut volume_name_buffer)
|
||||
.map_err(|e| Error::from_raw_os_error(e.code().0 as i32))?;
|
||||
}
|
||||
|
||||
Ok(lp_volume_name_buffer.as_ptr())
|
||||
let len = volume_name_buffer
|
||||
.iter()
|
||||
.position(|&x| x == 0)
|
||||
.unwrap_or(volume_name_buffer.len());
|
||||
Ok(volume_name_buffer[..len].to_vec())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn utf16_to_string(v: &[WCHAR]) -> String {
|
||||
fn utf16_to_string(v: &[u16]) -> String {
|
||||
let len = v.iter().position(|&x| x == 0).unwrap_or(v.len());
|
||||
String::from_utf16_lossy(&v[..len])
|
||||
}
|
||||
|
||||
/// Returns the filesystem type of the underlying mounted filesystem
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `p` - A slice of u16 representing the path in UTF-16 encoding
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Ok(String)` containing the filesystem type (e.g., "NTFS", "FAT32").
|
||||
/// * `Err` if an error occurs during the operation.
|
||||
#[allow(dead_code)]
|
||||
fn get_fs_type(p: &[WCHAR]) -> std::io::Result<String> {
|
||||
fn get_fs_type(p: &[u16]) -> std::io::Result<String> {
|
||||
let path = get_volume_name(p)?;
|
||||
|
||||
let volume_name_size: DWORD = MAX_PATH as _;
|
||||
let n_file_system_name_size: DWORD = MAX_PATH as _;
|
||||
let mut volume_serial_number = 0u32;
|
||||
let mut maximum_component_length = 0u32;
|
||||
let mut file_system_flags = 0u32;
|
||||
let mut volume_name_buffer = [0u16; MAX_PATH as usize];
|
||||
let mut file_system_name_buffer = [0u16; MAX_PATH as usize];
|
||||
|
||||
let mut lp_volume_serial_number: DWORD = 0;
|
||||
let mut lp_maximum_component_length: DWORD = 0;
|
||||
let mut lp_file_system_flags: DWORD = 0;
|
||||
|
||||
let mut lp_volume_name_buffer: [WCHAR; MAX_PATH] = [0; MAX_PATH];
|
||||
let mut lp_file_system_name_buffer: [WCHAR; MAX_PATH] = [0; MAX_PATH];
|
||||
|
||||
let success = unsafe {
|
||||
unsafe {
|
||||
GetVolumeInformationW(
|
||||
path,
|
||||
lp_volume_name_buffer.as_mut_ptr(),
|
||||
volume_name_size,
|
||||
&mut lp_volume_serial_number,
|
||||
&mut lp_maximum_component_length,
|
||||
&mut lp_file_system_flags,
|
||||
lp_file_system_name_buffer.as_mut_ptr(),
|
||||
n_file_system_name_size,
|
||||
windows::core::PCWSTR::from_raw(path.as_ptr()),
|
||||
Some(&mut volume_name_buffer),
|
||||
Some(&mut volume_serial_number),
|
||||
Some(&mut maximum_component_length),
|
||||
Some(&mut file_system_flags),
|
||||
Some(&mut file_system_name_buffer),
|
||||
)
|
||||
};
|
||||
|
||||
if success == 0 {
|
||||
return Err(Error::last_os_error());
|
||||
.map_err(|e| Error::from_raw_os_error(e.code().0 as i32))?;
|
||||
}
|
||||
|
||||
Ok(utf16_to_string(&lp_file_system_name_buffer))
|
||||
Ok(utf16_to_string(&file_system_name_buffer))
|
||||
}
|
||||
|
||||
pub fn same_disk(_disk1: &str, _disk2: &str) -> std::io::Result<bool> {
|
||||
Ok(false)
|
||||
/// Determines if two paths are on the same disk.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `disk1` - The first disk path as a string slice.
|
||||
/// * `disk2` - The second disk path as a string slice.
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Ok(true)` if both paths are on the same disk.
|
||||
/// * `Ok(false)` if both paths are on different disks.
|
||||
/// * `Err` if an error occurs during the operation.
|
||||
pub fn same_disk(disk1: &str, disk2: &str) -> std::io::Result<bool> {
|
||||
let path1_wide: Vec<u16> = disk1.encode_utf16().chain(std::iter::once(0)).collect();
|
||||
let path2_wide: Vec<u16> = disk2.encode_utf16().chain(std::iter::once(0)).collect();
|
||||
|
||||
let volume1 = get_volume_name(&path1_wide)?;
|
||||
let volume2 = get_volume_name(&path2_wide)?;
|
||||
|
||||
Ok(volume1 == volume2)
|
||||
}
|
||||
|
||||
/// Retrieves I/O statistics for a drive identified by its major and minor numbers.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `major` - The major number of the drive.
|
||||
/// * `minor` - The minor number of the drive.
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Ok(IOStats)` containing the I/O statistics.
|
||||
/// * `Err` if an error occurs during the operation.
|
||||
pub fn get_drive_stats(_major: u32, _minor: u32) -> std::io::Result<IOStats> {
|
||||
// Windows does not provide direct IO stats via simple API; this is a stub
|
||||
// For full implementation, consider using PDH or WMI, but that adds complexity
|
||||
Ok(IOStats::default())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::os::{get_info, same_disk};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[test]
|
||||
fn test_get_info_valid_path() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let info = get_info(temp_dir.path()).unwrap();
|
||||
|
||||
// Verify disk info is valid
|
||||
assert!(info.total > 0);
|
||||
assert!(info.free > 0);
|
||||
assert!(info.used > 0);
|
||||
assert!(info.files > 0);
|
||||
assert!(info.ffree > 0);
|
||||
assert!(!info.fstype.is_empty());
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
#[test]
|
||||
fn test_get_info_invalid_path() {
|
||||
use std::path::PathBuf;
|
||||
let invalid_path = PathBuf::from("Z:\\invalid\\path");
|
||||
let result = get_info(&invalid_path);
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
#[test]
|
||||
fn test_same_disk_same_path() {
|
||||
let temp_dir = tempfile::tempdir().unwrap();
|
||||
let path = temp_dir.path().to_str().unwrap();
|
||||
|
||||
let result = same_disk(path, path).unwrap();
|
||||
assert!(result);
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
#[test]
|
||||
fn test_same_disk_different_paths() {
|
||||
let temp_dir1 = tempfile::tempdir().unwrap();
|
||||
let temp_dir2 = tempfile::tempdir().unwrap();
|
||||
|
||||
let path1 = temp_dir1.path().to_str().unwrap();
|
||||
let path2 = temp_dir2.path().to_str().unwrap();
|
||||
|
||||
let _result = same_disk(path1, path2).unwrap();
|
||||
// Since both temporary directories are created in the same file system,
|
||||
// they should be on the same disk in most cases
|
||||
// Test passes if the function doesn't panic - the actual result depends on test environment
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[test]
|
||||
fn get_info_with_root_drive() {
|
||||
let info = get_info("C:\\").unwrap();
|
||||
assert!(info.total > 0);
|
||||
assert!(info.free > 0);
|
||||
assert!(info.used > 0);
|
||||
assert!(info.files > 0);
|
||||
assert!(info.ffree > 0);
|
||||
assert!(!info.fstype.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +110,10 @@ RustFS helm chart supports **standalone and distributed mode**. For standalone m
|
||||
| storageclass.logStorageSize | string | `"256Mi"` | The storage size for logs PVC. |
|
||||
| storageclass.name | string | `"local-path"` | The name for StorageClass. |
|
||||
| tolerations | list | `[]` | |
|
||||
| gatewayApi.enabled | bool | `false` | To enable/disable gateway api support. |
|
||||
| gatewayApi.gatewayClass | string | `traefik` | Gateway class implementation. |
|
||||
| gatewayApi.hostname | string | Hostname to access RustFS via gateway api. |
|
||||
| gatewayApi.secretName | string | Secret tls to via RustFS using HTTPS. |
|
||||
|
||||
---
|
||||
|
||||
@@ -207,6 +211,22 @@ You should use `--set-file` parameter when running `helm install` command, for e
|
||||
helm install rustfs rustfs/rustfs -n rustfs --set tls.enabled=true,--set-file tls.crt=./tls.crt,--set-file tls.key=./tls.key
|
||||
```
|
||||
|
||||
# Gateway API support (alpha)
|
||||
|
||||
Due to [ingress nginx retirement](https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/) in March 2026, so RustFS adds support for [gateway api](https://gateway-api.sigs.k8s.io/). Currently, RustFS only supports traefik as gateway class, more and more gateway class support will be added in the future after those classes are tested. If you want to enable gateway api, specify `gatewayApi.enabled` to `true` while specify `ingress.enabled` to `false`. After installation, you can find the `Gateway` and `HttpRoute` resources,
|
||||
|
||||
```
|
||||
$ kubectl -n rustfs get gateway
|
||||
NAME CLASS ADDRESS PROGRAMMED AGE
|
||||
rustfs-gateway traefik True 169m
|
||||
|
||||
$ kubectl -n rustfs get httproute
|
||||
NAME HOSTNAMES AGE
|
||||
rustfs-route ["example.rustfs.com"] 172m
|
||||
```
|
||||
|
||||
Then, via RustFS instance via `https://example.rustfs.com` or `http://example.rustfs.com`.
|
||||
|
||||
# Uninstall
|
||||
|
||||
Uninstalling the rustfs installation with command,
|
||||
|
||||
@@ -10,6 +10,10 @@ metadata:
|
||||
{{- end }}
|
||||
spec:
|
||||
replicas: 1
|
||||
{{- with .Values.mode.standalone.strategy }}
|
||||
strategy:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "rustfs.selectorLabels" . | nindent 6 }}
|
||||
|
||||
23
helm/rustfs/templates/gateway-api/gateway.yml
Normal file
23
helm/rustfs/templates/gateway-api/gateway.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
{{- if .Values.gatewayApi.enabled }}
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: Gateway
|
||||
metadata:
|
||||
name: {{ include "rustfs.fullname" . }}-gateway
|
||||
spec:
|
||||
gatewayClassName: {{ .Values.gatewayApi.gatewayClass }}
|
||||
listeners:
|
||||
- name: http
|
||||
port: 80
|
||||
protocol: HTTP
|
||||
allowedRoutes:
|
||||
namespaces:
|
||||
from: Same
|
||||
- name: https
|
||||
port: 443
|
||||
protocol: HTTPS
|
||||
tls:
|
||||
mode: Terminate
|
||||
certificateRefs:
|
||||
- name: {{ .Values.gatewayApi.secretName }}
|
||||
kind: Secret
|
||||
{{- end }}
|
||||
19
helm/rustfs/templates/gateway-api/httproute.yml
Normal file
19
helm/rustfs/templates/gateway-api/httproute.yml
Normal file
@@ -0,0 +1,19 @@
|
||||
{{- if .Values.gatewayApi.enabled -}}
|
||||
apiVersion: gateway.networking.k8s.io/v1
|
||||
kind: HTTPRoute
|
||||
metadata:
|
||||
name: {{ include "rustfs.fullname" . }}-route
|
||||
spec:
|
||||
parentRefs:
|
||||
- name: {{ include "rustfs.fullname" . }}-gateway
|
||||
hostnames:
|
||||
- {{ .Values.gatewayApi.hostname }}
|
||||
rules:
|
||||
- matches:
|
||||
- path:
|
||||
type: PathPrefix
|
||||
value: /
|
||||
backendRefs:
|
||||
- name: rustfs-svc
|
||||
port: 9001
|
||||
{{- end }}
|
||||
@@ -1,4 +1,4 @@
|
||||
{{- if and .Values.ingress.tls.enabled (not .Values.ingress.tls.certManager.enabled) }}
|
||||
{{- if and (or .Values.gatewayApi.enabled .Values.ingress.tls.enabled) (not .Values.ingress.tls.certManager.enabled) }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
|
||||
@@ -11,7 +11,7 @@ image:
|
||||
# This sets the pull policy for images.
|
||||
pullPolicy: IfNotPresent
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: "latest"
|
||||
tag: ""
|
||||
|
||||
# This is for the secrets for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
|
||||
imagePullSecrets: []
|
||||
@@ -30,6 +30,11 @@ fullnameOverride: ""
|
||||
mode:
|
||||
standalone:
|
||||
enabled: false
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxSurge: 0
|
||||
maxUnavailable: 1
|
||||
distributed:
|
||||
enabled: true
|
||||
|
||||
@@ -130,6 +135,12 @@ ingress:
|
||||
crt: tls.crt
|
||||
key: tls.key
|
||||
|
||||
gatewayApi:
|
||||
enabled: false
|
||||
gatewayClass: traefik
|
||||
hostname: example.rustfs.com
|
||||
secretName: secret-tls
|
||||
|
||||
resources:
|
||||
# We usually recommend not to specify default resources and to leave this as a conscious
|
||||
# choice for the user. This also increases chances charts run on environments with little
|
||||
|
||||
@@ -817,11 +817,14 @@ impl S3Access for FS {
|
||||
authorize_request(req, Action::S3Action(S3Action::ListBucketMultipartUploadsAction)).await
|
||||
}
|
||||
|
||||
/// Checks whether the ListObjectVersions request has accesses to the resources.
|
||||
/// Checks whether the `ListObjectVersions` request is authorized for the requested bucket.
|
||||
///
|
||||
/// This method returns `Ok(())` by default.
|
||||
async fn list_object_versions(&self, _req: &mut S3Request<ListObjectVersionsInput>) -> S3Result<()> {
|
||||
Ok(())
|
||||
/// Returns `Ok(())` if the request is allowed, or an error if access is denied or another
|
||||
/// authorization-related issue occurs.
|
||||
async fn list_object_versions(&self, req: &mut S3Request<ListObjectVersionsInput>) -> S3Result<()> {
|
||||
let req_info = req.extensions.get_mut::<ReqInfo>().expect("ReqInfo not found");
|
||||
req_info.bucket = Some(req.input.bucket.clone());
|
||||
authorize_request(req, Action::S3Action(S3Action::ListBucketVersionsAction)).await
|
||||
}
|
||||
|
||||
/// Checks whether the ListObjects request has accesses to the resources.
|
||||
|
||||
Reference in New Issue
Block a user