# Garage Admin SDK Operate your Garage cluster programatically ## ⚠️ DISCLAIMER **THESE 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. ## For SDK users The following languages are supported: - [Python](#python) - [Javascript](#javascript) - [Golang](#golang) ### Python 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/v1", 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([ NodeRoleChange( id = status.node, zone = "dc1", capacity = 1000000000, 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: - [examples](./example/python) - [generated doc](./garage-admin-sdk-python) ### Javascript 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_v1garage_v0_9_0'); const api = new garage.ApiClient("http://127.0.0.1:3903/v1"); 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: - [examples](./example/javascript) - [generated doc](./garage-admin-sdk-js) ### Golang Install the SDK with: ```bash go get git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang ``` An example without error checking: ```go package main import ( "context" "fmt" "os" "strings" garage "git.deuxfleurs.fr/garage-sdk/garage-admin-sdk-golang" ) func main() { // Initialization configuration := garage.NewConfiguration() configuration.Host = "127.0.0.1:3903" client := garage.NewAPIClient(configuration) ctx := context.WithValue(context.Background(), garage.ContextAccessToken, "s3cr3t") // Nodes fmt.Println("--- nodes ---") nodes, _, _ := client.NodesApi.GetNodes(ctx).Execute() fmt.Fprintf(os.Stdout, "First hostname: %v\n", nodes.KnownNodes[0].Hostname) capa := int64(1000000000) change := []garage.NodeRoleChange{ garage.NodeRoleChange{NodeRoleUpdate: &garage.NodeRoleUpdate { Id: *nodes.KnownNodes[0].Id, Zone: "dc1", Capacity: *garage.NewNullableInt64(&capa), Tags: []string{ "fast", "amd64" }, }}, } staged, _, _ := client.LayoutApi.AddLayout(ctx).NodeRoleChange(change).Execute() msg, _, _ := client.LayoutApi.ApplyLayout(ctx).LayoutVersion(*garage.NewLayoutVersion(staged.Version + 1)).Execute() fmt.Printf(strings.Join(msg.Message, "\n")) // Layout configured health, _, _ := client.NodesApi.GetHealth(ctx).Execute() fmt.Printf("Status: %s, nodes: %v/%v, storage: %v/%v, partitions: %v/%v\n", health.Status, health.ConnectedNodes, health.KnownNodes, health.StorageNodesOk, health.StorageNodes, health.PartitionsAllOk, health.Partitions) // Key fmt.Println("\n--- key ---") key := "openapi-key" keyInfo, _, _ := client.KeyApi.AddKey(ctx).AddKeyRequest(garage.AddKeyRequest{Name: *garage.NewNullableString(&key) }).Execute() defer client.KeyApi.DeleteKey(ctx).Id(*keyInfo.AccessKeyId).Execute() fmt.Printf("AWS_ACCESS_KEY_ID=%s\nAWS_SECRET_ACCESS_KEY=%s\n", *keyInfo.AccessKeyId, *keyInfo.SecretAccessKey.Get()) id := *keyInfo.AccessKeyId canCreateBucket := true updateKeyRequest := *garage.NewUpdateKeyRequest() updateKeyRequest.SetName("openapi-key-updated") updateKeyRequest.SetAllow(garage.UpdateKeyRequestAllow { CreateBucket: &canCreateBucket }) update, _, _ := client.KeyApi.UpdateKey(ctx).Id(id).UpdateKeyRequest(updateKeyRequest).Execute() fmt.Printf("Updated %v with key name %v\n", *update.AccessKeyId, *update.Name) keyList, _, _ := client.KeyApi.ListKeys(ctx).Execute() fmt.Printf("Keys count: %v\n", len(keyList)) // Bucket fmt.Println("\n--- bucket ---") global_name := "global-ns-openapi-bucket" local_name := "local-ns-openapi-bucket" bucketInfo, _, _ := client.BucketApi.CreateBucket(ctx).CreateBucketRequest(garage.CreateBucketRequest{ GlobalAlias: &global_name, LocalAlias: &garage.CreateBucketRequestLocalAlias { AccessKeyId: keyInfo.AccessKeyId, Alias: &local_name, }, }).Execute() defer client.BucketApi.DeleteBucket(ctx).Id(*bucketInfo.Id).Execute() fmt.Printf("Bucket id: %s\n", *bucketInfo.Id) updateBucketRequest := *garage.NewUpdateBucketRequest() website := garage.NewUpdateBucketRequestWebsiteAccess() website.SetEnabled(true) website.SetIndexDocument("index.html") website.SetErrorDocument("errors/4xx.html") updateBucketRequest.SetWebsiteAccess(*website) quotas := garage.NewUpdateBucketRequestQuotas() quotas.SetMaxSize(1000000000) quotas.SetMaxObjects(999999999) updateBucketRequest.SetQuotas(*quotas) updatedBucket, _, _ := client.BucketApi.UpdateBucket(ctx).Id(*bucketInfo.Id).UpdateBucketRequest(updateBucketRequest).Execute() fmt.Printf("Bucket %v website activation: %v\n", *updatedBucket.Id, *updatedBucket.WebsiteAccess) bucketList, _, _ := client.BucketApi.ListBuckets(ctx).Execute() fmt.Printf("Bucket count: %v\n", len(bucketList)) } ``` See also: - [examples](./example/golang) - [generated doc](./garage-admin-sdk-golang) ## For SDK developpers PR are accepted for other languages as soon as good examples are provided. Especially, we want them to be meaningful, manually written, and covering a large range of the API. Thanks in advance :-) ### Clone this repo ```bash git clone ... git submodule update --init ``` ### (Re)generate libraries ```bash # Check the OpenAPI spec file gradle validate # (re)build the python client gradle buildPythonClient # (re)build the Go client gradle buildGoClient # (re)build the javascrit cient gradle buildJavascriptClient ``` ## Support a new language Read the doc: https://openapi-generator.tech/docs/installation We use the Gradle plugins: https://openapi-generator.tech/docs/plugins Many generators exist: https://openapi-generator.tech/docs/generators