OpenAPI spec for admin API #379
31 changed files with 3538 additions and 684 deletions
17
doc/api/README.md
Normal file
17
doc/api/README.md
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# Browse doc
|
||||||
|
|
||||||
|
Run in this directory:
|
||||||
|
|
||||||
|
```
|
||||||
|
python3 -m http.server
|
||||||
|
```
|
||||||
|
|
||||||
|
And open in your browser:
|
||||||
|
- http://localhost:8000/garage-admin-v0.html
|
||||||
|
|
||||||
|
# Validate doc
|
||||||
|
|
||||||
|
```
|
||||||
|
wget https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/6.1.0/openapi-generator-cli-6.1.0.jar -O openapi-generator-cli.jar
|
||||||
|
java -jar openapi-generator-cli.jar validate -i garage-admin-v0.yml
|
||||||
|
```
|
59
doc/api/css/redoc.css
Normal file
59
doc/api/css/redoc.css
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/* montserrat-300 - latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local(''),
|
||||||
|
url('../fonts/montserrat-v25-latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
||||||
|
url('../fonts/montserrat-v25-latin-300.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* montserrat-regular - latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local(''),
|
||||||
|
url('../fonts/montserrat-v25-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
||||||
|
url('../fonts/montserrat-v25-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* montserrat-700 - latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Montserrat';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local(''),
|
||||||
|
url('../fonts/montserrat-v25-latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
||||||
|
url('../fonts/montserrat-v25-latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
||||||
|
}
|
||||||
|
/* roboto-300 - latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
src: local(''),
|
||||||
|
url('../fonts/roboto-v30-latin-300.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
||||||
|
url('../fonts/roboto-v30-latin-300.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* roboto-regular - latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 400;
|
||||||
|
src: local(''),
|
||||||
|
url('../fonts/roboto-v30-latin-regular.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
||||||
|
url('../fonts/roboto-v30-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* roboto-700 - latin */
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Roboto';
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 700;
|
||||||
|
src: local(''),
|
||||||
|
url('../fonts/roboto-v30-latin-700.woff2') format('woff2'), /* Chrome 26+, Opera 23+, Firefox 39+ */
|
||||||
|
url('../fonts/roboto-v30-latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
||||||
|
}
|
||||||
|
|
BIN
doc/api/fonts/montserrat-v25-latin-300.woff
Normal file
BIN
doc/api/fonts/montserrat-v25-latin-300.woff
Normal file
Binary file not shown.
BIN
doc/api/fonts/montserrat-v25-latin-300.woff2
Normal file
BIN
doc/api/fonts/montserrat-v25-latin-300.woff2
Normal file
Binary file not shown.
BIN
doc/api/fonts/montserrat-v25-latin-700.woff
Normal file
BIN
doc/api/fonts/montserrat-v25-latin-700.woff
Normal file
Binary file not shown.
BIN
doc/api/fonts/montserrat-v25-latin-700.woff2
Normal file
BIN
doc/api/fonts/montserrat-v25-latin-700.woff2
Normal file
Binary file not shown.
BIN
doc/api/fonts/montserrat-v25-latin-regular.woff
Normal file
BIN
doc/api/fonts/montserrat-v25-latin-regular.woff
Normal file
Binary file not shown.
BIN
doc/api/fonts/montserrat-v25-latin-regular.woff2
Normal file
BIN
doc/api/fonts/montserrat-v25-latin-regular.woff2
Normal file
Binary file not shown.
BIN
doc/api/fonts/roboto-v30-latin-300.woff
Normal file
BIN
doc/api/fonts/roboto-v30-latin-300.woff
Normal file
Binary file not shown.
BIN
doc/api/fonts/roboto-v30-latin-300.woff2
Normal file
BIN
doc/api/fonts/roboto-v30-latin-300.woff2
Normal file
Binary file not shown.
BIN
doc/api/fonts/roboto-v30-latin-700.woff
Normal file
BIN
doc/api/fonts/roboto-v30-latin-700.woff
Normal file
Binary file not shown.
BIN
doc/api/fonts/roboto-v30-latin-700.woff2
Normal file
BIN
doc/api/fonts/roboto-v30-latin-700.woff2
Normal file
Binary file not shown.
BIN
doc/api/fonts/roboto-v30-latin-regular.woff
Normal file
BIN
doc/api/fonts/roboto-v30-latin-regular.woff
Normal file
Binary file not shown.
BIN
doc/api/fonts/roboto-v30-latin-regular.woff2
Normal file
BIN
doc/api/fonts/roboto-v30-latin-regular.woff2
Normal file
Binary file not shown.
24
doc/api/garage-admin-v0.html
Normal file
24
doc/api/garage-admin-v0.html
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Garage Adminstration API v0</title>
|
||||||
|
<!-- needed for adaptive design -->
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link href="./css/redoc.css" rel="stylesheet">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Redoc doesn't change outer page styles
|
||||||
|
-->
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<redoc spec-url='./garage-admin-v0.yml'></redoc>
|
||||||
|
<script src="./redoc.standalone.js"> </script>
|
||||||
|
</body>
|
||||||
|
</html>
|
1212
doc/api/garage-admin-v0.yml
Normal file
1212
doc/api/garage-admin-v0.yml
Normal file
File diff suppressed because it is too large
Load diff
1806
doc/api/redoc.standalone.js
Normal file
1806
doc/api/redoc.standalone.js
Normal file
File diff suppressed because one or more lines are too long
54
doc/book/build/_index.md
Normal file
54
doc/book/build/_index.md
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
+++
|
||||||
|
title = "Build your own app"
|
||||||
|
weight = 4
|
||||||
|
sort_by = "weight"
|
||||||
|
template = "documentation.html"
|
||||||
|
+++
|
||||||
|
|
||||||
|
Garage has many API that you can rely on to build complex applications.
|
||||||
|
In this section, we reference the existing SDKs and give some code examples.
|
||||||
|
|
||||||
|
|
||||||
|
## ⚠️ DISCLAIMER
|
||||||
|
|
||||||
|
**K2V AND ADMIN SDK ARE TECHNICAL PREVIEWS**. The following limitations apply:
|
||||||
|
- The API is not complete, some actions are possible only through the `garage` binary
|
||||||
|
- The underlying admin API is not yet stable nor complete, it can breaks at any time
|
||||||
|
- The generator configuration is currently tweaked, the library might break at any time due to a generator change
|
||||||
|
- Because the API and the library are not stable, none of them are published in a package manager (npm, pypi, etc.)
|
||||||
|
- This code has not been extensively tested, some things might not work (please report!)
|
||||||
|
|
||||||
|
To have the best experience possible, please consider:
|
||||||
|
- Make sure that the version of the library you are using is pinned (`go.sum`, `package-lock.json`, `requirements.txt`).
|
||||||
|
- Before upgrading your Garage cluster, make sure that you can find a version of this SDK that works with your targeted version and that you are able to update your own code to work with this new version of the library.
|
||||||
|
- Join our Matrix channel at `#garage:deuxfleurs.fr`, say that you are interested by this SDK, and report any friction.
|
||||||
|
- If stability is critical, mirror this repository on your own infrastructure, regenerate the SDKs and upgrade them at your own pace.
|
||||||
|
|
||||||
|
|
||||||
|
## About the APIs
|
||||||
|
|
||||||
|
Code can interact with Garage through 3 different APIs: S3, K2V, and Admin.
|
||||||
|
Each of them has a specific scope.
|
||||||
|
|
||||||
|
### S3
|
||||||
|
|
||||||
|
De-facto standard, introduced by Amazon, designed to store blobs of data.
|
||||||
|
|
||||||
|
### K2V
|
||||||
|
|
||||||
|
A simple database API similar to RiakKV or DynamoDB.
|
||||||
|
Think a key value store with some additional operations.
|
||||||
|
Its design is inspired by Distributed Hash Tables (DHT).
|
||||||
|
|
||||||
|
More information:
|
||||||
|
- [In the reference manual](@/documentation/reference-manual/k2v.md)
|
||||||
|
|
||||||
|
|
||||||
|
### Administration
|
||||||
|
|
||||||
|
Garage operations can also be automated through a REST API.
|
||||||
|
We are currently building this SDK for [Python](@/documentation/build/python.md#admin-api), [Javascript](@/documentation/build/javascript.md#administration) and [Golang](@/documentation/build/golang.md#administration).
|
||||||
|
|
||||||
|
More information:
|
||||||
|
- [In the reference manual](@/documentation/reference-manual/admin-api.md)
|
||||||
|
- [Full specifiction](https://garagehq.deuxfleurs.fr/api/garage-admin-v0.html)
|
69
doc/book/build/golang.md
Normal file
69
doc/book/build/golang.md
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
+++
|
||||||
|
title = "Golang"
|
||||||
|
weight = 30
|
||||||
|
+++
|
||||||
|
|
||||||
|
## S3
|
||||||
|
|
||||||
|
*Coming soon*
|
||||||
|
|
||||||
|
Some refs:
|
||||||
|
- Minio minio-go-sdk
|
||||||
|
- [Reference](https://docs.min.io/docs/golang-client-api-reference.html)
|
||||||
|
|
||||||
|
- Amazon aws-sdk-go-v2
|
||||||
|
- [Installation](https://aws.github.io/aws-sdk-go-v2/docs/getting-started/)
|
||||||
|
- [Reference](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3)
|
||||||
|
- [Example](https://aws.github.io/aws-sdk-go-v2/docs/code-examples/s3/putobject/)
|
||||||
|
|
||||||
|
## K2V
|
||||||
|
|
||||||
|
*Coming soon*
|
||||||
|
|
||||||
|
## Administration
|
||||||
|
|
||||||
|
Install the SDK with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang
|
||||||
|
```
|
||||||
|
|
||||||
|
A short example:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
garage "git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Set Host and other parameters
|
||||||
|
configuration := garage.NewConfiguration()
|
||||||
|
configuration.Host = "127.0.0.1:3903"
|
||||||
|
|
||||||
|
|
||||||
|
// We can now generate a client
|
||||||
|
client := garage.NewAPIClient(configuration)
|
||||||
|
|
||||||
|
// Authentication is handled through the context pattern
|
||||||
|
ctx := context.WithValue(context.Background(), garage.ContextAccessToken, "s3cr3t")
|
||||||
|
|
||||||
|
// Send a request
|
||||||
|
resp, r, err := client.NodesApi.GetNodes(ctx).Execute()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error when calling `NodesApi.GetNodes``: %v\n", err)
|
||||||
|
fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the response
|
||||||
|
fmt.Fprintf(os.Stdout, "Target hostname: %v\n", resp.KnownNodes[resp.Node].Hostname)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See also:
|
||||||
|
- [generated doc](https://git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang)
|
||||||
|
- [examples](https://git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-generator/src/branch/main/example/golang)
|
55
doc/book/build/javascript.md
Normal file
55
doc/book/build/javascript.md
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
+++
|
||||||
|
title = "Javascript"
|
||||||
|
weight = 10
|
||||||
|
+++
|
||||||
|
|
||||||
|
## S3
|
||||||
|
|
||||||
|
*Coming soon*.
|
||||||
|
|
||||||
|
Some refs:
|
||||||
|
- Minio SDK
|
||||||
|
- [Reference](https://docs.min.io/docs/javascript-client-api-reference.html)
|
||||||
|
|
||||||
|
- Amazon aws-sdk-js
|
||||||
|
- [Installation](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/getting-started.html)
|
||||||
|
- [Reference](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html)
|
||||||
|
- [Example](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/s3-example-creating-buckets.html)
|
||||||
|
|
||||||
|
## K2V
|
||||||
|
|
||||||
|
*Coming soon*
|
||||||
|
|
||||||
|
## Administration
|
||||||
|
|
||||||
|
Install the SDK with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install --save git+https://git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-js.git
|
||||||
|
```
|
||||||
|
|
||||||
|
A short example:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
const garage = require('garage_administration_api_v0garage_v0_8_0');
|
||||||
|
|
||||||
|
const api = new garage.ApiClient("http://127.0.0.1:3903/v0");
|
||||||
|
api.authentications['bearerAuth'].accessToken = "s3cr3t";
|
||||||
|
|
||||||
|
const [node, layout, key, bucket] = [
|
||||||
|
new garage.NodesApi(api),
|
||||||
|
new garage.LayoutApi(api),
|
||||||
|
new garage.KeyApi(api),
|
||||||
|
new garage.BucketApi(api),
|
||||||
|
];
|
||||||
|
|
||||||
|
node.getNodes().then((data) => {
|
||||||
|
console.log(`nodes: ${Object.values(data.knownNodes).map(n => n.hostname)}`)
|
||||||
|
}, (error) => {
|
||||||
|
console.error(error);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
See also:
|
||||||
|
- [sdk repository](https://git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-js)
|
||||||
|
- [examples](https://git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-generator/src/branch/main/example/javascript)
|
|
@ -1,8 +1,10 @@
|
||||||
+++
|
+++
|
||||||
title = "Your code (PHP, JS, Go...)"
|
title = "Others"
|
||||||
weight = 30
|
weight = 99
|
||||||
+++
|
+++
|
||||||
|
|
||||||
|
## S3
|
||||||
|
|
||||||
If you are developping a new application, you may want to use Garage to store your user's media.
|
If you are developping a new application, you may want to use Garage to store your user's media.
|
||||||
|
|
||||||
The S3 API that Garage uses is a standard REST API, so as long as you can make HTTP requests,
|
The S3 API that Garage uses is a standard REST API, so as long as you can make HTTP requests,
|
||||||
|
@ -13,44 +15,14 @@ Instead, there are some libraries already avalaible.
|
||||||
|
|
||||||
Some of them are maintained by Amazon, some by Minio, others by the community.
|
Some of them are maintained by Amazon, some by Minio, others by the community.
|
||||||
|
|
||||||
## PHP
|
### PHP
|
||||||
|
|
||||||
- Amazon aws-sdk-php
|
- Amazon aws-sdk-php
|
||||||
- [Installation](https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/getting-started_installation.html)
|
- [Installation](https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/getting-started_installation.html)
|
||||||
- [Reference](https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html)
|
- [Reference](https://docs.aws.amazon.com/aws-sdk-php/v3/api/api-s3-2006-03-01.html)
|
||||||
- [Example](https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/s3-examples-creating-buckets.html)
|
- [Example](https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/s3-examples-creating-buckets.html)
|
||||||
|
|
||||||
## Javascript
|
### Java
|
||||||
|
|
||||||
- Minio SDK
|
|
||||||
- [Reference](https://docs.min.io/docs/javascript-client-api-reference.html)
|
|
||||||
|
|
||||||
- Amazon aws-sdk-js
|
|
||||||
- [Installation](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/getting-started.html)
|
|
||||||
- [Reference](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html)
|
|
||||||
- [Example](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/s3-example-creating-buckets.html)
|
|
||||||
|
|
||||||
## Golang
|
|
||||||
|
|
||||||
- Minio minio-go-sdk
|
|
||||||
- [Reference](https://docs.min.io/docs/golang-client-api-reference.html)
|
|
||||||
|
|
||||||
- Amazon aws-sdk-go-v2
|
|
||||||
- [Installation](https://aws.github.io/aws-sdk-go-v2/docs/getting-started/)
|
|
||||||
- [Reference](https://pkg.go.dev/github.com/aws/aws-sdk-go-v2/service/s3)
|
|
||||||
- [Example](https://aws.github.io/aws-sdk-go-v2/docs/code-examples/s3/putobject/)
|
|
||||||
|
|
||||||
## Python
|
|
||||||
|
|
||||||
- Minio SDK
|
|
||||||
- [Reference](https://docs.min.io/docs/python-client-api-reference.html)
|
|
||||||
|
|
||||||
- Amazon boto3
|
|
||||||
- [Installation](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html)
|
|
||||||
- [Reference](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html)
|
|
||||||
- [Example](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-uploading-files.html)
|
|
||||||
|
|
||||||
## Java
|
|
||||||
|
|
||||||
- Minio SDK
|
- Minio SDK
|
||||||
- [Reference](https://docs.min.io/docs/java-client-api-reference.html)
|
- [Reference](https://docs.min.io/docs/java-client-api-reference.html)
|
||||||
|
@ -60,23 +32,18 @@ Some of them are maintained by Amazon, some by Minio, others by the community.
|
||||||
- [Reference](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html)
|
- [Reference](https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/s3/S3Client.html)
|
||||||
- [Example](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/examples-s3-objects.html)
|
- [Example](https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/examples-s3-objects.html)
|
||||||
|
|
||||||
## Rust
|
### .NET
|
||||||
|
|
||||||
- Amazon aws-rust-sdk
|
|
||||||
- [Github](https://github.com/awslabs/aws-sdk-rust)
|
|
||||||
|
|
||||||
## .NET
|
|
||||||
|
|
||||||
- Minio SDK
|
- Minio SDK
|
||||||
- [Reference](https://docs.min.io/docs/dotnet-client-api-reference.html)
|
- [Reference](https://docs.min.io/docs/dotnet-client-api-reference.html)
|
||||||
|
|
||||||
- Amazon aws-dotnet-sdk
|
- Amazon aws-dotnet-sdk
|
||||||
|
|
||||||
## C++
|
### C++
|
||||||
|
|
||||||
- Amazon aws-cpp-sdk
|
- Amazon aws-cpp-sdk
|
||||||
|
|
||||||
## Haskell
|
### Haskell
|
||||||
|
|
||||||
- Minio SDK
|
- Minio SDK
|
||||||
- [Reference](https://docs.min.io/docs/haskell-client-api-reference.html)
|
- [Reference](https://docs.min.io/docs/haskell-client-api-reference.html)
|
95
doc/book/build/python.md
Normal file
95
doc/book/build/python.md
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
+++
|
||||||
|
title = "Python"
|
||||||
|
weight = 20
|
||||||
|
+++
|
||||||
|
|
||||||
|
## S3
|
||||||
|
|
||||||
|
*Coming soon*
|
||||||
|
|
||||||
|
Some refs:
|
||||||
|
- Minio SDK
|
||||||
|
- [Reference](https://docs.min.io/docs/python-client-api-reference.html)
|
||||||
|
|
||||||
|
- Amazon boto3
|
||||||
|
- [Installation](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/quickstart.html)
|
||||||
|
- [Reference](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/s3.html)
|
||||||
|
- [Example](https://boto3.amazonaws.com/v1/documentation/api/latest/guide/s3-uploading-files.html)
|
||||||
|
|
||||||
|
## K2V
|
||||||
|
|
||||||
|
*Coming soon*
|
||||||
|
|
||||||
|
## Admin API
|
||||||
|
|
||||||
|
You need at least Python 3.6, pip, and setuptools.
|
||||||
|
Because the python package is in a subfolder, the command is a bit more complicated than usual:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip3 install --user 'git+https://git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-python'
|
||||||
|
```
|
||||||
|
|
||||||
|
Now, let imagine you have a fresh Garage instance running on localhost, with the admin API configured on port 3903 with the bearer `s3cr3t`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import garage_admin_sdk
|
||||||
|
from garage_admin_sdk.apis import *
|
||||||
|
from garage_admin_sdk.models import *
|
||||||
|
|
||||||
|
configuration = garage_admin_sdk.Configuration(
|
||||||
|
host = "http://localhost:3903/v0",
|
||||||
|
access_token = "s3cr3t"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Init APIs
|
||||||
|
api = garage_admin_sdk.ApiClient(configuration)
|
||||||
|
nodes, layout, keys, buckets = NodesApi(api), LayoutApi(api), KeyApi(api), BucketApi(api)
|
||||||
|
|
||||||
|
# Display some info on the node
|
||||||
|
status = nodes.get_nodes()
|
||||||
|
print(f"running garage {status.garage_version}, node_id {status.node}")
|
||||||
|
|
||||||
|
# Change layout of this node
|
||||||
|
current = layout.get_layout()
|
||||||
|
layout.add_layout({
|
||||||
|
status.node: NodeClusterInfo(
|
||||||
|
zone = "dc1",
|
||||||
|
capacity = 1,
|
||||||
|
tags = [ "dev" ],
|
||||||
|
)
|
||||||
|
})
|
||||||
|
layout.apply_layout(LayoutVersion(
|
||||||
|
version = current.version + 1
|
||||||
|
))
|
||||||
|
|
||||||
|
# Create key, allow it to create buckets
|
||||||
|
kinfo = keys.add_key(AddKeyRequest(name="openapi"))
|
||||||
|
|
||||||
|
allow_create = UpdateKeyRequestAllow(create_bucket=True)
|
||||||
|
keys.update_key(kinfo.access_key_id, UpdateKeyRequest(allow=allow_create))
|
||||||
|
|
||||||
|
# Create a bucket, allow key, set quotas
|
||||||
|
binfo = buckets.create_bucket(CreateBucketRequest(global_alias="documentation"))
|
||||||
|
binfo = buckets.allow_bucket_key(AllowBucketKeyRequest(
|
||||||
|
bucket_id=binfo.id,
|
||||||
|
access_key_id=kinfo.access_key_id,
|
||||||
|
permissions=AllowBucketKeyRequestPermissions(read=True, write=True, owner=True),
|
||||||
|
))
|
||||||
|
binfo = buckets.update_bucket(binfo.id, UpdateBucketRequest(
|
||||||
|
quotas=UpdateBucketRequestQuotas(max_size=19029801,max_objects=1500)))
|
||||||
|
|
||||||
|
# Display key
|
||||||
|
print(f"""
|
||||||
|
cluster ready
|
||||||
|
key id is {kinfo.access_key_id}
|
||||||
|
secret key is {kinfo.secret_access_key}
|
||||||
|
bucket {binfo.global_aliases[0]} contains {binfo.objects}/{binfo.quotas.max_objects} objects
|
||||||
|
""")
|
||||||
|
```
|
||||||
|
|
||||||
|
*This example is named `short.py` in the example folder. Other python examples are also available.*
|
||||||
|
|
||||||
|
See also:
|
||||||
|
- [sdk repo](https://git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-python)
|
||||||
|
- [examples](https://git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-generator/src/branch/main/example/python)
|
||||||
|
|
47
doc/book/build/rust.md
Normal file
47
doc/book/build/rust.md
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
+++
|
||||||
|
title = "Rust"
|
||||||
|
weight = 40
|
||||||
|
+++
|
||||||
|
|
||||||
|
## S3
|
||||||
|
|
||||||
|
*Coming soon*
|
||||||
|
|
||||||
|
Some refs:
|
||||||
|
- Amazon aws-rust-sdk
|
||||||
|
- [Github](https://github.com/awslabs/aws-sdk-rust)
|
||||||
|
|
||||||
|
## K2V
|
||||||
|
|
||||||
|
*Coming soon*
|
||||||
|
|
||||||
|
Some refs: https://git.deuxfleurs.fr/Deuxfleurs/garage/src/branch/main/src/k2v-client
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# all these values can be provided on the cli instead
|
||||||
|
export AWS_ACCESS_KEY_ID=GK123456
|
||||||
|
export AWS_SECRET_ACCESS_KEY=0123..789
|
||||||
|
export AWS_REGION=garage
|
||||||
|
export K2V_ENDPOINT=http://172.30.2.1:3903
|
||||||
|
export K2V_BUCKET=my-bucket
|
||||||
|
|
||||||
|
cargo run --features=cli -- read-range my-partition-key --all
|
||||||
|
|
||||||
|
cargo run --features=cli -- insert my-partition-key my-sort-key --text "my string1"
|
||||||
|
cargo run --features=cli -- insert my-partition-key my-sort-key --text "my string2"
|
||||||
|
cargo run --features=cli -- insert my-partition-key my-sort-key2 --text "my string"
|
||||||
|
|
||||||
|
cargo run --features=cli -- read-range my-partition-key --all
|
||||||
|
|
||||||
|
causality=$(cargo run --features=cli -- read my-partition-key my-sort-key2 -b | head -n1)
|
||||||
|
cargo run --features=cli -- delete my-partition-key my-sort-key2 -c $causality
|
||||||
|
|
||||||
|
causality=$(cargo run --features=cli -- read my-partition-key my-sort-key -b | head -n1)
|
||||||
|
cargo run --features=cli -- insert my-partition-key my-sort-key --text "my string3" -c $causality
|
||||||
|
|
||||||
|
cargo run --features=cli -- read-range my-partition-key --all
|
||||||
|
```
|
||||||
|
|
||||||
|
## Admin API
|
||||||
|
|
||||||
|
*Coming soon*
|
|
@ -1,5 +1,5 @@
|
||||||
+++
|
+++
|
||||||
title = "Integrations"
|
title = "Existing integrations"
|
||||||
weight = 3
|
weight = 3
|
||||||
sort_by = "weight"
|
sort_by = "weight"
|
||||||
template = "documentation.html"
|
template = "documentation.html"
|
||||||
|
@ -14,7 +14,6 @@ In particular, you will find here instructions to connect it with:
|
||||||
- [Applications](@/documentation/connect/apps/index.md)
|
- [Applications](@/documentation/connect/apps/index.md)
|
||||||
- [Website hosting](@/documentation/connect/websites.md)
|
- [Website hosting](@/documentation/connect/websites.md)
|
||||||
- [Software repositories](@/documentation/connect/repositories.md)
|
- [Software repositories](@/documentation/connect/repositories.md)
|
||||||
- [Your own code](@/documentation/connect/code.md)
|
|
||||||
- [FUSE](@/documentation/connect/fs.md)
|
- [FUSE](@/documentation/connect/fs.md)
|
||||||
|
|
||||||
### Generic instructions
|
### Generic instructions
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
+++
|
+++
|
||||||
title = "Design"
|
title = "Design"
|
||||||
weight = 5
|
weight = 6
|
||||||
sort_by = "weight"
|
sort_by = "weight"
|
||||||
template = "documentation.html"
|
template = "documentation.html"
|
||||||
+++
|
+++
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
+++
|
+++
|
||||||
title = "Development"
|
title = "Development"
|
||||||
weight = 6
|
weight = 7
|
||||||
sort_by = "weight"
|
sort_by = "weight"
|
||||||
template = "documentation.html"
|
template = "documentation.html"
|
||||||
+++
|
+++
|
||||||
|
|
|
@ -42,15 +42,16 @@ you can [build Garage from source](@/documentation/cookbook/from-source.md).
|
||||||
|
|
||||||
## Configuring and starting Garage
|
## Configuring and starting Garage
|
||||||
|
|
||||||
### Writing a first configuration file
|
### Generating a first configuration file
|
||||||
|
|
||||||
This first configuration file should allow you to get started easily with the simplest
|
This first configuration file should allow you to get started easily with the simplest
|
||||||
possible Garage deployment.
|
possible Garage deployment.
|
||||||
**Save it as `/etc/garage.toml`.**
|
|
||||||
You can also store it somewhere else, but you will have to specify `-c path/to/garage.toml`
|
|
||||||
at each invocation of the `garage` binary (for example: `garage -c ./garage.toml server`, `garage -c ./garage.toml status`).
|
|
||||||
|
|
||||||
```toml
|
We will create it with the following command line
|
||||||
|
to generate unique and private secrets for security reasons:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat > garage.toml <<EOF
|
||||||
metadata_dir = "/tmp/meta"
|
metadata_dir = "/tmp/meta"
|
||||||
data_dir = "/tmp/data"
|
data_dir = "/tmp/data"
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ replication_mode = "none"
|
||||||
|
|
||||||
rpc_bind_addr = "[::]:3901"
|
rpc_bind_addr = "[::]:3901"
|
||||||
rpc_public_addr = "127.0.0.1:3901"
|
rpc_public_addr = "127.0.0.1:3901"
|
||||||
rpc_secret = "1799bccfd7411eddcf9ebd316bc1f5287ad12a68094e1c6ac6abde7e6feae1ec"
|
rpc_secret = "$(openssl rand -hex 32)"
|
||||||
|
|
||||||
bootstrap_peers = []
|
bootstrap_peers = []
|
||||||
|
|
||||||
|
@ -71,12 +72,26 @@ root_domain = ".s3.garage.localhost"
|
||||||
bind_addr = "[::]:3902"
|
bind_addr = "[::]:3902"
|
||||||
root_domain = ".web.garage.localhost"
|
root_domain = ".web.garage.localhost"
|
||||||
index = "index.html"
|
index = "index.html"
|
||||||
|
|
||||||
|
[k2v_api]
|
||||||
|
api_bind_addr = "[::]:3904"
|
||||||
|
|
||||||
|
[admin]
|
||||||
|
api_bind_addr = "0.0.0.0:3903"
|
||||||
|
admin_token = "$(openssl rand -base64 32)"
|
||||||
|
EOF
|
||||||
```
|
```
|
||||||
|
|
||||||
The `rpc_secret` value provided above is just an example. It will work, but in
|
Now that your configuration file has been created, you can put
|
||||||
order to secure your cluster you will need to use another one. You can generate
|
it in the right place. By default, garage looks at **`/etc/garage.toml`.**
|
||||||
such a value with `openssl rand -hex 32`.
|
|
||||||
|
|
||||||
|
You can also store it somewhere else, but you will have to specify `-c path/to/garage.toml`
|
||||||
|
at each invocation of the `garage` binary (for example: `garage -c ./garage.toml server`, `garage -c ./garage.toml status`).
|
||||||
|
|
||||||
|
As you can see, the `rpc_secret` is a 32 bytes hexadecimal string.
|
||||||
|
You can regenerate it with `openssl rand -hex 32`.
|
||||||
|
If you target a cluster deployment with multiple nodes, make sure that
|
||||||
|
you use the same value for all nodes.
|
||||||
|
|
||||||
As you can see in the `metadata_dir` and `data_dir` parameters, we are saving Garage's data
|
As you can see in the `metadata_dir` and `data_dir` parameters, we are saving Garage's data
|
||||||
in `/tmp` which gets erased when your system reboots. This means that data stored on this
|
in `/tmp` which gets erased when your system reboots. This means that data stored on this
|
||||||
|
@ -219,6 +234,7 @@ Now that we have a bucket and a key, we need to give permissions to the key on t
|
||||||
garage bucket allow \
|
garage bucket allow \
|
||||||
--read \
|
--read \
|
||||||
--write \
|
--write \
|
||||||
|
--owner \
|
||||||
nextcloud-bucket \
|
nextcloud-bucket \
|
||||||
--key nextcloud-app-key
|
--key nextcloud-app-key
|
||||||
```
|
```
|
||||||
|
@ -232,54 +248,73 @@ garage bucket info nextcloud-bucket
|
||||||
|
|
||||||
## Uploading and downlading from Garage
|
## Uploading and downlading from Garage
|
||||||
|
|
||||||
We recommend the use of MinIO Client to interact with Garage files (`mc`).
|
To download and upload files on garage, we can use a third-party tool named `awscli`.
|
||||||
Instructions to install it and use it are provided on the
|
|
||||||
[MinIO website](https://docs.min.io/docs/minio-client-quickstart-guide.html).
|
|
||||||
Before reading the following, you need a working `mc` command on your path.
|
|
||||||
|
|
||||||
Note that on certain Linux distributions such as Arch Linux, the Minio client binary
|
|
||||||
is called `mcli` instead of `mc` (to avoid name clashes with the Midnight Commander).
|
|
||||||
|
|
||||||
### Configure `mc`
|
### Install and configure `awscli`
|
||||||
|
|
||||||
You need your access key and secret key created above.
|
If you have python on your system, you can install it with:
|
||||||
We will assume you are invoking `mc` on the same machine as the Garage server,
|
|
||||||
your S3 API endpoint is therefore `http://127.0.0.1:3900`.
|
|
||||||
For this whole configuration, you must set an alias name: we chose `my-garage`, that you will used for all commands.
|
|
||||||
|
|
||||||
Adapt the following command accordingly and run it:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mc alias set \
|
python -m pip install --user awscli
|
||||||
my-garage \
|
|
||||||
http://127.0.0.1:3900 \
|
|
||||||
<access key> \
|
|
||||||
<secret key> \
|
|
||||||
--api S3v4
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Use `mc`
|
Now that `awscli` is installed, you must configure it to talk to your Garage instance,
|
||||||
|
with your key. There are multiple ways to do that, the simplest one is to create a file
|
||||||
You can not list buckets from `mc` currently.
|
named `~/.awsrc` with this content:
|
||||||
|
|
||||||
But the following commands and many more should work:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
mc cp image.png my-garage/nextcloud-bucket
|
export AWS_ACCESS_KEY_ID=xxxx # put your Key ID here
|
||||||
mc cp my-garage/nextcloud-bucket/image.png .
|
export AWS_SECRET_ACCESS_KEY=xxxx # put your Secret key here
|
||||||
mc ls my-garage/nextcloud-bucket
|
export AWS_DEFAULT_REGION='garage'
|
||||||
mc mirror localdir/ my-garage/another-bucket
|
export AWS_ENDPOINT='http://localhost:3900'
|
||||||
|
|
||||||
|
function aws { command aws --endpoint-url $AWS_ENDPOINT $@ ; }
|
||||||
|
aws --version
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Now, each time you want to use `awscli` on this target, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
source ~/.awsrc
|
||||||
|
```
|
||||||
|
|
||||||
|
*You can create multiple files with different names if you
|
||||||
|
have multiple Garage clusters or different keys.
|
||||||
|
Switching from one cluster to another is as simple as
|
||||||
|
sourcing the right file.*
|
||||||
|
|
||||||
|
### Example usage of `awscli`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# list buckets
|
||||||
|
aws s3 ls
|
||||||
|
|
||||||
|
# list objects of a bucket
|
||||||
|
aws s3 ls s3://my_files
|
||||||
|
|
||||||
|
# copy from your filesystem to garage
|
||||||
|
aws s3 cp /proc/cpuinfo s3://my_files/cpuinfo.txt
|
||||||
|
|
||||||
|
# copy from garage to your filesystem
|
||||||
|
aws s3 cp s3/my_files/cpuinfo.txt /tmp/cpuinfo.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that you can use `awscli` for more advanced operations like
|
||||||
|
creating a bucket, pre-signing a request or managing your website.
|
||||||
|
[Read the full documentation to know more](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3/index.html).
|
||||||
|
|
||||||
|
Some features are however not implemented like ACL or policy.
|
||||||
|
Check [our s3 compatibility list](@/documentation/reference-manual/s3-compatibility.md).
|
||||||
|
|
||||||
### Other tools for interacting with Garage
|
### Other tools for interacting with Garage
|
||||||
|
|
||||||
The following tools can also be used to send and recieve files from/to Garage:
|
The following tools can also be used to send and recieve files from/to Garage:
|
||||||
|
|
||||||
- the [AWS CLI](https://aws.amazon.com/cli/)
|
- [minio-client](@/documentation/connect/cli.md#minio-client)
|
||||||
- [`rclone`](https://rclone.org/)
|
- [s3cmd](@/documentation/connect/cli.md#s3cmd)
|
||||||
- [Cyberduck](https://cyberduck.io/)
|
- [rclone](@/documentation/connect/cli.md#rclone)
|
||||||
- [`s3cmd`](https://s3tools.org/s3cmd)
|
- [Cyberduck](@/documentation/connect/cli.md#cyberduck)
|
||||||
|
- [WinSCP](@/documentation/connect/cli.md#winscp)
|
||||||
|
|
||||||
Refer to the ["Integrations" section](@/documentation/connect/_index.md) to learn how to
|
An exhaustive list is maintained in the ["Integrations" > "Browsing tools" section](@/documentation/connect/_index.md).
|
||||||
configure application and command line utilities to integrate with Garage.
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
+++
|
+++
|
||||||
title = "Reference Manual"
|
title = "Reference Manual"
|
||||||
weight = 4
|
weight = 5
|
||||||
sort_by = "weight"
|
sort_by = "weight"
|
||||||
template = "documentation.html"
|
template = "documentation.html"
|
||||||
+++
|
+++
|
||||||
|
|
|
@ -47,598 +47,13 @@ Returns internal Garage metrics in Prometheus format.
|
||||||
|
|
||||||
### Cluster operations
|
### Cluster operations
|
||||||
|
|
||||||
#### GetClusterStatus `GET /v0/status`
|
These endpoints are defined on a dedicated [Redocly page](https://garagehq.deuxfleurs.fr/api/garage-admin-v0.html). You can also download its [OpenAPI specification](https://garagehq.deuxfleurs.fr/api/garage-admin-v0.yml).
|
||||||
|
|
||||||
Returns the cluster's current status in JSON, including:
|
Requesting the API from the command line can be as simple as running:
|
||||||
|
|
||||||
- ID of the node being queried and its version of the Garage daemon
|
```bash
|
||||||
- Live nodes
|
curl -H 'Authorization: Bearer s3cr3t' http://localhost:3903/v0/status | jq
|
||||||
- Currently configured cluster layout
|
|
||||||
- Staged changes to the cluster layout
|
|
||||||
|
|
||||||
Example response body:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"node": "ec79480e0ce52ae26fd00c9da684e4fa56658d9c64cdcecb094e936de0bfe71f",
|
|
||||||
"garage_version": "git:v0.8.0",
|
|
||||||
"knownNodes": {
|
|
||||||
"ec79480e0ce52ae26fd00c9da684e4fa56658d9c64cdcecb094e936de0bfe71f": {
|
|
||||||
"addr": "10.0.0.11:3901",
|
|
||||||
"is_up": true,
|
|
||||||
"last_seen_secs_ago": 9,
|
|
||||||
"hostname": "node1"
|
|
||||||
},
|
|
||||||
"4a6ae5a1d0d33bf895f5bb4f0a418b7dc94c47c0dd2eb108d1158f3c8f60b0ff": {
|
|
||||||
"addr": "10.0.0.12:3901",
|
|
||||||
"is_up": true,
|
|
||||||
"last_seen_secs_ago": 1,
|
|
||||||
"hostname": "node2"
|
|
||||||
},
|
|
||||||
"23ffd0cdd375ebff573b20cc5cef38996b51c1a7d6dbcf2c6e619876e507cf27": {
|
|
||||||
"addr": "10.0.0.21:3901",
|
|
||||||
"is_up": true,
|
|
||||||
"last_seen_secs_ago": 7,
|
|
||||||
"hostname": "node3"
|
|
||||||
},
|
|
||||||
"e2ee7984ee65b260682086ec70026165903c86e601a4a5a501c1900afe28d84b": {
|
|
||||||
"addr": "10.0.0.22:3901",
|
|
||||||
"is_up": true,
|
|
||||||
"last_seen_secs_ago": 1,
|
|
||||||
"hostname": "node4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"layout": {
|
|
||||||
"version": 12,
|
|
||||||
"roles": {
|
|
||||||
"ec79480e0ce52ae26fd00c9da684e4fa56658d9c64cdcecb094e936de0bfe71f": {
|
|
||||||
"zone": "dc1",
|
|
||||||
"capacity": 4,
|
|
||||||
"tags": [
|
|
||||||
"node1"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"4a6ae5a1d0d33bf895f5bb4f0a418b7dc94c47c0dd2eb108d1158f3c8f60b0ff": {
|
|
||||||
"zone": "dc1",
|
|
||||||
"capacity": 6,
|
|
||||||
"tags": [
|
|
||||||
"node2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"23ffd0cdd375ebff573b20cc5cef38996b51c1a7d6dbcf2c6e619876e507cf27": {
|
|
||||||
"zone": "dc2",
|
|
||||||
"capacity": 10,
|
|
||||||
"tags": [
|
|
||||||
"node3"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"stagedRoleChanges": {
|
|
||||||
"e2ee7984ee65b260682086ec70026165903c86e601a4a5a501c1900afe28d84b": {
|
|
||||||
"zone": "dc2",
|
|
||||||
"capacity": 5,
|
|
||||||
"tags": [
|
|
||||||
"node4"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### ConnectClusterNodes `POST /v0/connect`
|
For more advanced use cases, we recommend using a SDK.
|
||||||
|
[Go to the "Build your own app" section to know how to use our SDKs](@/documentation/build/_index.md)
|
||||||
Instructs this Garage node to connect to other Garage nodes at specified addresses.
|
|
||||||
|
|
||||||
Example request body:
|
|
||||||
|
|
||||||
```json
|
|
||||||
[
|
|
||||||
"ec79480e0ce52ae26fd00c9da684e4fa56658d9c64cdcecb094e936de0bfe71f@10.0.0.11:3901",
|
|
||||||
"4a6ae5a1d0d33bf895f5bb4f0a418b7dc94c47c0dd2eb108d1158f3c8f60b0ff@10.0.0.12:3901"
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
The format of the string for a node to connect to is: `<node ID>@<ip address>:<port>`, same as in the `garage node connect` CLI call.
|
|
||||||
|
|
||||||
Example response:
|
|
||||||
|
|
||||||
```json
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"success": true,
|
|
||||||
"error": null
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"success": false,
|
|
||||||
"error": "Handshake error"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
#### GetClusterLayout `GET /v0/layout`
|
|
||||||
|
|
||||||
Returns the cluster's current layout in JSON, including:
|
|
||||||
|
|
||||||
- Currently configured cluster layout
|
|
||||||
- Staged changes to the cluster layout
|
|
||||||
|
|
||||||
(the info returned by this endpoint is a subset of the info returned by GetClusterStatus)
|
|
||||||
|
|
||||||
Example response body:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"version": 12,
|
|
||||||
"roles": {
|
|
||||||
"ec79480e0ce52ae26fd00c9da684e4fa56658d9c64cdcecb094e936de0bfe71f": {
|
|
||||||
"zone": "dc1",
|
|
||||||
"capacity": 4,
|
|
||||||
"tags": [
|
|
||||||
"node1"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"4a6ae5a1d0d33bf895f5bb4f0a418b7dc94c47c0dd2eb108d1158f3c8f60b0ff": {
|
|
||||||
"zone": "dc1",
|
|
||||||
"capacity": 6,
|
|
||||||
"tags": [
|
|
||||||
"node2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"23ffd0cdd375ebff573b20cc5cef38996b51c1a7d6dbcf2c6e619876e507cf27": {
|
|
||||||
"zone": "dc2",
|
|
||||||
"capacity": 10,
|
|
||||||
"tags": [
|
|
||||||
"node3"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"stagedRoleChanges": {
|
|
||||||
"e2ee7984ee65b260682086ec70026165903c86e601a4a5a501c1900afe28d84b": {
|
|
||||||
"zone": "dc2",
|
|
||||||
"capacity": 5,
|
|
||||||
"tags": [
|
|
||||||
"node4"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### UpdateClusterLayout `POST /v0/layout`
|
|
||||||
|
|
||||||
Send modifications to the cluster layout. These modifications will
|
|
||||||
be included in the staged role changes, visible in subsequent calls
|
|
||||||
of `GetClusterLayout`. Once the set of staged changes is satisfactory,
|
|
||||||
the user may call `ApplyClusterLayout` to apply the changed changes,
|
|
||||||
or `Revert ClusterLayout` to clear all of the staged changes in
|
|
||||||
the layout.
|
|
||||||
|
|
||||||
Request body format:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
<node_id>: {
|
|
||||||
"capacity": <new_capacity>,
|
|
||||||
"zone": <new_zone>,
|
|
||||||
"tags": [
|
|
||||||
<new_tag>,
|
|
||||||
...
|
|
||||||
]
|
|
||||||
},
|
|
||||||
<node_id_to_remove>: null,
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Contrary to the CLI that may update only a subset of the fields
|
|
||||||
`capacity`, `zone` and `tags`, when calling this API all of these
|
|
||||||
values must be specified.
|
|
||||||
|
|
||||||
|
|
||||||
#### ApplyClusterLayout `POST /v0/layout/apply`
|
|
||||||
|
|
||||||
Applies to the cluster the layout changes currently registered as
|
|
||||||
staged layout changes.
|
|
||||||
|
|
||||||
Request body format:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"version": 13
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Similarly to the CLI, the body must include the version of the new layout
|
|
||||||
that will be created, which MUST be 1 + the value of the currently
|
|
||||||
existing layout in the cluster.
|
|
||||||
|
|
||||||
#### RevertClusterLayout `POST /v0/layout/revert`
|
|
||||||
|
|
||||||
Clears all of the staged layout changes.
|
|
||||||
|
|
||||||
Request body format:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"version": 13
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Reverting the staged changes is done by incrementing the version number
|
|
||||||
and clearing the contents of the staged change list.
|
|
||||||
Similarly to the CLI, the body must include the incremented
|
|
||||||
version number, which MUST be 1 + the value of the currently
|
|
||||||
existing layout in the cluster.
|
|
||||||
|
|
||||||
|
|
||||||
### Access key operations
|
|
||||||
|
|
||||||
#### ListKeys `GET /v0/key`
|
|
||||||
|
|
||||||
Returns all API access keys in the cluster.
|
|
||||||
|
|
||||||
Example response:
|
|
||||||
|
|
||||||
```json
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"id": "GK31c2f218a2e44f485b94239e",
|
|
||||||
"name": "test"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "GKe10061ac9c2921f09e4c5540",
|
|
||||||
"name": "test2"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
#### CreateKey `POST /v0/key`
|
|
||||||
|
|
||||||
Creates a new API access key.
|
|
||||||
|
|
||||||
Request body format:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "NameOfMyKey"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### ImportKey `POST /v0/key/import`
|
|
||||||
|
|
||||||
Imports an existing API key.
|
|
||||||
|
|
||||||
Request body format:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"accessKeyId": "GK31c2f218a2e44f485b94239e",
|
|
||||||
"secretAccessKey": "b892c0665f0ada8a4755dae98baa3b133590e11dae3bcc1f9d769d67f16c3835",
|
|
||||||
"name": "NameOfMyKey"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### GetKeyInfo `GET /v0/key?id=<acces key id>`
|
|
||||||
#### GetKeyInfo `GET /v0/key?search=<pattern>`
|
|
||||||
|
|
||||||
Returns information about the requested API access key.
|
|
||||||
|
|
||||||
If `id` is set, the key is looked up using its exact identifier (faster).
|
|
||||||
If `search` is set, the key is looked up using its name or prefix
|
|
||||||
of identifier (slower, all keys are enumerated to do this).
|
|
||||||
|
|
||||||
Example response:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "test",
|
|
||||||
"accessKeyId": "GK31c2f218a2e44f485b94239e",
|
|
||||||
"secretAccessKey": "b892c0665f0ada8a4755dae98baa3b133590e11dae3bcc1f9d769d67f16c3835",
|
|
||||||
"permissions": {
|
|
||||||
"createBucket": false
|
|
||||||
},
|
|
||||||
"buckets": [
|
|
||||||
{
|
|
||||||
"id": "70dc3bed7fe83a75e46b66e7ddef7d56e65f3c02f9f80b6749fb97eccb5e1033",
|
|
||||||
"globalAliases": [
|
|
||||||
"test2"
|
|
||||||
],
|
|
||||||
"localAliases": [],
|
|
||||||
"permissions": {
|
|
||||||
"read": true,
|
|
||||||
"write": true,
|
|
||||||
"owner": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "d7452a935e663fc1914f3a5515163a6d3724010ce8dfd9e4743ca8be5974f995",
|
|
||||||
"globalAliases": [
|
|
||||||
"test3"
|
|
||||||
],
|
|
||||||
"localAliases": [],
|
|
||||||
"permissions": {
|
|
||||||
"read": true,
|
|
||||||
"write": true,
|
|
||||||
"owner": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "e6a14cd6a27f48684579ec6b381c078ab11697e6bc8513b72b2f5307e25fff9b",
|
|
||||||
"globalAliases": [],
|
|
||||||
"localAliases": [
|
|
||||||
"test"
|
|
||||||
],
|
|
||||||
"permissions": {
|
|
||||||
"read": true,
|
|
||||||
"write": true,
|
|
||||||
"owner": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "96470e0df00ec28807138daf01915cfda2bee8eccc91dea9558c0b4855b5bf95",
|
|
||||||
"globalAliases": [
|
|
||||||
"alex"
|
|
||||||
],
|
|
||||||
"localAliases": [],
|
|
||||||
"permissions": {
|
|
||||||
"read": true,
|
|
||||||
"write": true,
|
|
||||||
"owner": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### DeleteKey `DELETE /v0/key?id=<acces key id>`
|
|
||||||
|
|
||||||
Deletes an API access key.
|
|
||||||
|
|
||||||
#### UpdateKey `POST /v0/key?id=<acces key id>`
|
|
||||||
|
|
||||||
Updates information about the specified API access key.
|
|
||||||
|
|
||||||
Request body format:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "NameOfMyKey",
|
|
||||||
"allow": {
|
|
||||||
"createBucket": true,
|
|
||||||
},
|
|
||||||
"deny": {}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
All fields (`name`, `allow` and `deny`) are optionnal.
|
|
||||||
If they are present, the corresponding modifications are applied to the key, otherwise nothing is changed.
|
|
||||||
The possible flags in `allow` and `deny` are: `createBucket`.
|
|
||||||
|
|
||||||
|
|
||||||
### Bucket operations
|
|
||||||
|
|
||||||
#### ListBuckets `GET /v0/bucket`
|
|
||||||
|
|
||||||
Returns all storage buckets in the cluster.
|
|
||||||
|
|
||||||
Example response:
|
|
||||||
|
|
||||||
```json
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"id": "70dc3bed7fe83a75e46b66e7ddef7d56e65f3c02f9f80b6749fb97eccb5e1033",
|
|
||||||
"globalAliases": [
|
|
||||||
"test2"
|
|
||||||
],
|
|
||||||
"localAliases": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "96470e0df00ec28807138daf01915cfda2bee8eccc91dea9558c0b4855b5bf95",
|
|
||||||
"globalAliases": [
|
|
||||||
"alex"
|
|
||||||
],
|
|
||||||
"localAliases": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "d7452a935e663fc1914f3a5515163a6d3724010ce8dfd9e4743ca8be5974f995",
|
|
||||||
"globalAliases": [
|
|
||||||
"test3"
|
|
||||||
],
|
|
||||||
"localAliases": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "e6a14cd6a27f48684579ec6b381c078ab11697e6bc8513b72b2f5307e25fff9b",
|
|
||||||
"globalAliases": [],
|
|
||||||
"localAliases": [
|
|
||||||
{
|
|
||||||
"accessKeyId": "GK31c2f218a2e44f485b94239e",
|
|
||||||
"alias": "test"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
#### GetBucketInfo `GET /v0/bucket?id=<bucket id>`
|
|
||||||
#### GetBucketInfo `GET /v0/bucket?globalAlias=<alias>`
|
|
||||||
|
|
||||||
Returns information about the requested storage bucket.
|
|
||||||
|
|
||||||
If `id` is set, the bucket is looked up using its exact identifier.
|
|
||||||
If `globalAlias` is set, the bucket is looked up using its global alias.
|
|
||||||
(both are fast)
|
|
||||||
|
|
||||||
Example response:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"id": "afa8f0a22b40b1247ccd0affb869b0af5cff980924a20e4b5e0720a44deb8d39",
|
|
||||||
"globalAliases": [],
|
|
||||||
"websiteAccess": false,
|
|
||||||
"websiteConfig": null,
|
|
||||||
"keys": [
|
|
||||||
{
|
|
||||||
"accessKeyId": "GK31c2f218a2e44f485b94239e",
|
|
||||||
"name": "Imported key",
|
|
||||||
"permissions": {
|
|
||||||
"read": true,
|
|
||||||
"write": true,
|
|
||||||
"owner": true
|
|
||||||
},
|
|
||||||
"bucketLocalAliases": [
|
|
||||||
"debug"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"objects": 14827,
|
|
||||||
"bytes": 13189855625,
|
|
||||||
"unfinshedUploads": 0,
|
|
||||||
"quotas": {
|
|
||||||
"maxSize": null,
|
|
||||||
"maxObjects": null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### CreateBucket `POST /v0/bucket`
|
|
||||||
|
|
||||||
Creates a new storage bucket.
|
|
||||||
|
|
||||||
Request body format:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"globalAlias": "NameOfMyBucket"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
OR
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"localAlias": {
|
|
||||||
"accessKeyId": "GK31c2f218a2e44f485b94239e",
|
|
||||||
"alias": "NameOfMyBucket",
|
|
||||||
"allow": {
|
|
||||||
"read": true,
|
|
||||||
"write": true,
|
|
||||||
"owner": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
OR
|
|
||||||
|
|
||||||
```json
|
|
||||||
{}
|
|
||||||
```
|
|
||||||
|
|
||||||
Creates a new bucket, either with a global alias, a local one,
|
|
||||||
or no alias at all.
|
|
||||||
|
|
||||||
Technically, you can also specify both `globalAlias` and `localAlias` and that would create
|
|
||||||
two aliases, but I don't see why you would want to do that.
|
|
||||||
|
|
||||||
#### DeleteBucket `DELETE /v0/bucket?id=<bucket id>`
|
|
||||||
|
|
||||||
Deletes a storage bucket. A bucket cannot be deleted if it is not empty.
|
|
||||||
|
|
||||||
Warning: this will delete all aliases associated with the bucket!
|
|
||||||
|
|
||||||
#### UpdateBucket `PUT /v0/bucket?id=<bucket id>`
|
|
||||||
|
|
||||||
Updates configuration of the given bucket.
|
|
||||||
|
|
||||||
Request body format:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"websiteAccess": {
|
|
||||||
"enabled": true,
|
|
||||||
"indexDocument": "index.html",
|
|
||||||
"errorDocument": "404.html"
|
|
||||||
},
|
|
||||||
"quotas": {
|
|
||||||
"maxSize": 19029801,
|
|
||||||
"maxObjects": null,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
All fields (`websiteAccess` and `quotas`) are optionnal.
|
|
||||||
If they are present, the corresponding modifications are applied to the bucket, otherwise nothing is changed.
|
|
||||||
|
|
||||||
In `websiteAccess`: if `enabled` is `true`, `indexDocument` must be specified.
|
|
||||||
The field `errorDocument` is optional, if no error document is set a generic
|
|
||||||
error message is displayed when errors happen. Conversely, if `enabled` is
|
|
||||||
`false`, neither `indexDocument` nor `errorDocument` must be specified.
|
|
||||||
|
|
||||||
In `quotas`: new values of `maxSize` and `maxObjects` must both be specified, or set to `null`
|
|
||||||
to remove the quotas. An absent value will be considered the same as a `null`. It is not possible
|
|
||||||
to change only one of the two quotas.
|
|
||||||
|
|
||||||
### Operations on permissions for keys on buckets
|
|
||||||
|
|
||||||
#### BucketAllowKey `POST /v0/bucket/allow`
|
|
||||||
|
|
||||||
Allows a key to do read/write/owner operations on a bucket.
|
|
||||||
|
|
||||||
Request body format:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"bucketId": "e6a14cd6a27f48684579ec6b381c078ab11697e6bc8513b72b2f5307e25fff9b",
|
|
||||||
"accessKeyId": "GK31c2f218a2e44f485b94239e",
|
|
||||||
"permissions": {
|
|
||||||
"read": true,
|
|
||||||
"write": true,
|
|
||||||
"owner": true
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Flags in `permissions` which have the value `true` will be activated.
|
|
||||||
Other flags will remain unchanged.
|
|
||||||
|
|
||||||
#### BucketDenyKey `POST /v0/bucket/deny`
|
|
||||||
|
|
||||||
Denies a key from doing read/write/owner operations on a bucket.
|
|
||||||
|
|
||||||
Request body format:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"bucketId": "e6a14cd6a27f48684579ec6b381c078ab11697e6bc8513b72b2f5307e25fff9b",
|
|
||||||
"accessKeyId": "GK31c2f218a2e44f485b94239e",
|
|
||||||
"permissions": {
|
|
||||||
"read": false,
|
|
||||||
"write": false,
|
|
||||||
"owner": true
|
|
||||||
},
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Flags in `permissions` which have the value `true` will be deactivated.
|
|
||||||
Other flags will remain unchanged.
|
|
||||||
|
|
||||||
|
|
||||||
### Operations on bucket aliases
|
|
||||||
|
|
||||||
#### GlobalAliasBucket `PUT /v0/bucket/alias/global?id=<bucket id>&alias=<global alias>`
|
|
||||||
|
|
||||||
Empty body. Creates a global alias for a bucket.
|
|
||||||
|
|
||||||
#### GlobalUnaliasBucket `DELETE /v0/bucket/alias/global?id=<bucket id>&alias=<global alias>`
|
|
||||||
|
|
||||||
Removes a global alias for a bucket.
|
|
||||||
|
|
||||||
#### LocalAliasBucket `PUT /v0/bucket/alias/local?id=<bucket id>&accessKeyId=<access key ID>&alias=<local alias>`
|
|
||||||
|
|
||||||
Empty body. Creates a local alias for a bucket in the namespace of a specific access key.
|
|
||||||
|
|
||||||
#### LocalUnaliasBucket `DELETE /v0/bucket/alias/local?id=<bucket id>&accessKeyId<access key ID>&alias=<local alias>`
|
|
||||||
|
|
||||||
Removes a local alias for a bucket in the namespace of a specific access key.
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
+++
|
+++
|
||||||
title = "Working Documents"
|
title = "Working Documents"
|
||||||
weight = 7
|
weight = 8
|
||||||
sort_by = "weight"
|
sort_by = "weight"
|
||||||
template = "documentation.html"
|
template = "documentation.html"
|
||||||
+++
|
+++
|
||||||
|
|
|
@ -210,7 +210,7 @@ async fn bucket_info_results(
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
objects: counters.get(OBJECTS).cloned().unwrap_or_default(),
|
objects: counters.get(OBJECTS).cloned().unwrap_or_default(),
|
||||||
bytes: counters.get(BYTES).cloned().unwrap_or_default(),
|
bytes: counters.get(BYTES).cloned().unwrap_or_default(),
|
||||||
unfinshed_uploads: counters
|
unfinished_uploads: counters
|
||||||
.get(UNFINISHED_UPLOADS)
|
.get(UNFINISHED_UPLOADS)
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
|
@ -234,7 +234,7 @@ struct GetBucketInfoResult {
|
||||||
keys: Vec<GetBucketInfoKey>,
|
keys: Vec<GetBucketInfoKey>,
|
||||||
objects: i64,
|
objects: i64,
|
||||||
bytes: i64,
|
bytes: i64,
|
||||||
unfinshed_uploads: i64,
|
unfinished_uploads: i64,
|
||||||
quotas: ApiBucketQuotas,
|
quotas: ApiBucketQuotas,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue