# Nebius AI Cloud SDK for Go
[![go minimal version][go-img]][go-url] [![go tested version][go-latest-img]][go-latest-url] [![CI][ci-img]][ci-url] [![License][license-img]][license-url] [![Go Reference][godoc-img]][godoc-url] The Nebius AI Cloud SDK for Go is a comprehensive client library for interacting with [nebius.com](https://nebius.com) services. Built on gRPC, it supports all APIs defined in the [Nebius API repository](https://github.com/nebius/api). This SDK simplifies resource management, authorization, and communication with Nebius services, making it a valuable tool for developers. ## Installation Add the SDK to your Go project with the following command: ```bash go get github.com/nebius/gosdk ``` To update to the latest version: ```bash go get -u github.com/nebius/gosdk ``` ## Supported Go Versions - **Minimum Supported Version**: Go 1.24 - The SDK is regularly tested against the latest Go release. - New SDK versions include several breaking changes in the underlying libraries and work with go>=1.24. - If you need the older version, pin to `~v0.1, Skip ahead to the [Complete Example](#complete-example) or explore [Advanced Scenarios](SCENARIOS.md). ### SDK Initialization Initialize the SDK with appropriate options: ```go import "github.com/nebius/gosdk" sdk, err := gosdk.New(ctx /*, option1, option2, option3 */) if err != nil { return fmt.Errorf("create gosdk: %w", err) } defer sdk.Close() ``` The `gosdk.New` constructor initializes the SDK. However, **authorization is required** for functionality. Use the `gosdk.WithCredentials` option to provide credentials. To clean up resources properly, ensure you call `Close` when finished. Find all available options in [options.go](options.go) ([reference](https://pkg.go.dev/github.com/nebius/gosdk#Option)). ### Authorization and Credentials Authorization is handled by passing credentials via the `gosdk.WithCredentials` option. Commonly used credentials include `gosdk.IAMToken` and `gosdk.ServiceAccountReader`. Find all available credentials in [credentials.go](credentials.go) ([reference](https://pkg.go.dev/github.com/nebius/gosdk#Credentials)). #### Using an IAM Token The `gosdk.IAMToken` credentials allow you to use an IAM token directly for authorization. This approach is ideal for testing or tools used by end-users with their own credentials. Here's an example of initializing the SDK with an IAM token stored in an environment variable: ```go token := os.Getenv("IAM_TOKEN") sdk, err := gosdk.New( ctx, gosdk.WithCredentials( gosdk.IAMToken(token), ), ) ``` **Important**: - The SDK does not automatically manage IAM token creation or refresh for user accounts. - Use the `nebius` CLI ([documentation](https://docs.nebius.com/cli)) to obtain an IAM token manually: ```bash IAM_TOKEN=$(nebius iam get-access-token) ``` - Since tokens expire, this method requires manual token refreshes, making it less suitable for production environments. #### Using a Service Account (Recommended) Service account authorization is recommended for server-to-server communication and production use cases. This method eliminates the need for manual token management by securely handling IAM tokens in the background. To authorize with a service account, provide the service account ID, public key ID, and RSA private key. The SDK uses these details to generate a JWT and exchange it for an IAM token. The token is automatically refreshed in the background to ensure continuous validity. Use `gosdk.ServiceAccount` or `gosdk.ServiceAccountReader` with functions from [auth/service_account.go](auth/service_account.go). Here are common approaches: 1. **Using a JSON Credentials File**: ```go import "github.com/nebius/gosdk/auth" sdk, err := gosdk.New( ctx, gosdk.WithCredentials( gosdk.ServiceAccountReader( auth.NewServiceAccountCredentialsFileParser( nil, // nil to use the real file system "~/path/to/service_account.json", ), ), ), ) ``` File format: ```json { "subject-credentials": { "alg": "RS256", "private-key": "PKCS#8 PEM with new lines escaped as \n", "kid": "public-key-id", "iss": "service-account-id", "sub": "service-account-id" } } ``` 2. **Using a PEM-Encoded Private Key File**: ```go auth.NewPrivateKeyFileParser( nil, // nil to use the real file system "~/path/to/private_key.pem", "public-key-id", "service-account-id", ) ``` 3. **Providing Key Content Directly**: ```go privateKey, _ := os.ReadFile("path/to/private_key.pem") auth.NewPrivateKeyParser( privateKey, "public-key-id", "service-account-id", ) ``` ## Resources and Operations Nebius AI Cloud communicates via gRPC, with read operations such as `Get` and `List` returning protobuf messages that describe resources. Mutating operations like `Create`, `Update`, and `Delete` return an `Operation` object. Operations can be either synchronous or asynchronous. Synchronous operations are completed immediately, while asynchronous operations may take time to finish. To ensure an operation is fully completed, use the `Wait` method, which polls the operation status until it is done. > ℹ️ **Note**: If the operation fails, `Wait` will return an error. ### Create Resource The following example demonstrates how to create a compute instance and use `Wait` to verify the operation's success. ```go import common "github.com/nebius/gosdk/proto/nebius/common/v1" import compute "github.com/nebius/gosdk/proto/nebius/compute/v1" instanceService := sdk.Services().Compute().V1().Instance() operation, err := instanceService.Create(ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ ParentId: "my-project-id", Name: "my-instance", }, Spec: &compute.InstanceSpec{ // instance configuration }, }) if err != nil { return fmt.Errorf("create instance: %w", err) } operation, err = operation.Wait(ctx) if err != nil { return fmt.Errorf("wait for instance create: %w", err) } instanceID := operation.ResourceID() ``` ### Get Resource The operation doesn't contain the current state of the resource. Once it completes, fetch the resource. ```go instance, err := instanceService.Get(ctx, &compute.GetInstanceRequest{ Id: instanceID, }) if err != nil { return fmt.Errorf("get instance: %w", err) } ``` #### Get Resource by Name Most resources can also be retrieved using their names. ```go instance, err = instanceService.GetByName(ctx, &common.GetByNameRequest{ ParentId: "my-project-id", Name: "my-instance", }) if err != nil { return fmt.Errorf("get instance by name: %w", err) } ``` ### Update Resource When updating, provide a **complete resource specification**, not just the fields you wish to modify. Treat the `Update` method as having full-replace semantics. ```go operation, err := instanceService.Update(ctx, &compute.UpdateInstanceRequest{ Metadata: &common.ResourceMetadata{ Id: instanceID, ParentId: "my-project-id", Name: "my-instance", }, Spec: &compute.InstanceSpec{ // new configuration }, }) if err != nil { return fmt.Errorf("update instance: %w", err) } operation, err = operation.Wait(ctx) if err != nil { return fmt.Errorf("wait for instance update: %w", err) } ``` ### List Resources The `List` method retrieves resources within a specified container. It supports pagination, which may require additional handling for large number of resources. ```go list, err := instanceService.List(ctx, &compute.ListInstancesRequest{ ParentId: "my-project-id", }) if err != nil { return fmt.Errorf("list instances: %w", err) } for _, instance := range list.GetItems() { // process instance } if list.GetNextPageToken() != "" { list, err = instanceService.List(ctx, &compute.ListInstancesRequest{ ParentId: "my-project-id", PageToken: list.GetNextPageToken(), }) if err != nil { return fmt.Errorf("list instances: %w", err) } // repeat processing } ``` ### Filter Resources The `Filter` method simplifies resource listing by iterating over items across pages in a single loop. ```go req := &compute.ListInstancesRequest{ParentId: "my-project-id"} for instance, err := range instanceService.Filter(ctx, req) { if err != nil { return fmt.Errorf("list instances: %w", err) } // process instance } ``` ### Delete Resource The following example demonstrates how to delete a compute instance and use `Wait` to verify the operation's success. ```go operation, err := instanceService.Delete(ctx, &compute.DeleteInstanceRequest{ Id: instanceID, }) if err != nil { return fmt.Errorf("delete instance: %w", err) } operation, err = operation.Wait(ctx) if err != nil { return fmt.Errorf("wait for instance delete: %w", err) } ``` ## Complete Example This example demonstrates how to initialize the SDK with IAM token authorization and perform basic resource operations. ```go package example import ( "context" "fmt" "os" "github.com/nebius/gosdk" common "github.com/nebius/gosdk/proto/nebius/common/v1" compute "github.com/nebius/gosdk/proto/nebius/compute/v1" ) func Example() error { ctx := context.Background() // Initialize SDK with IAM token sdk, err := gosdk.New( ctx, gosdk.WithCredentials( gosdk.IAMToken(os.Getenv("IAM_TOKEN")), ), ) if err != nil { return fmt.Errorf("create gosdk: %w", err) } defer sdk.Close() instanceService := sdk.Services().Compute().V1().Instance() // Create resource operation, err := instanceService.Create(ctx, &compute.CreateInstanceRequest{ Metadata: &common.ResourceMetadata{ ParentId: "my-project-id", Name: "my-instance", }, Spec: &compute.InstanceSpec{ // configuration }, }) if err != nil { return fmt.Errorf("create instance: %w", err) } // Wait for the create operation to complete successfully operation, err = operation.Wait(ctx) if err != nil { return fmt.Errorf("wait for instance creation: %w", err) } instanceID := operation.ResourceID() // Get resource by ID instance, err := instanceService.Get(ctx, &compute.GetInstanceRequest{ Id: instanceID, }) if err != nil { return fmt.Errorf("get instance: %w", err) } // Get resource by name instance, err = instanceService.GetByName(ctx, &common.GetByNameRequest{ ParentId: "my-project-id", Name: "my-instance", }) if err != nil { return fmt.Errorf("get instance by name: %w", err) } // Update resource operation, err = instanceService.Update(ctx, &compute.UpdateInstanceRequest{ Metadata: &common.ResourceMetadata{ Id: instanceID, ParentId: "my-project-id", Name: "my-instance", }, Spec: &compute.InstanceSpec{ // updated configuration }, }) if err != nil { return fmt.Errorf("update instance: %w", err) } // Wait for update operation complete successfully operation, err = operation.Wait(ctx) if err != nil { return fmt.Errorf("wait for instance update: %w", err) } // Iterate over all resources inside container req := &compute.ListInstancesRequest{ParentId: "my-project-id"} for instance, err = range instanceService.Filter(ctx, req) { if err != nil { return fmt.Errorf("list instances: %w", err) } if instance.GetMetadata().GetId() == instanceID { continue // skip just created instance } // Delete resource operation, err = instanceService.Delete(ctx, &compute.DeleteInstanceRequest{ Id: instance.GetMetadata().GetId(), }) if err != nil { return fmt.Errorf("delete instance: %w", err) } // Wait for delete operation complete successfully operation, err = operation.Wait(ctx) if err != nil { return fmt.Errorf("wait for instance delete: %w", err) } } return nil } ``` ## Advanced Scenarios Explore advanced usage examples in [SCENARIOS.md](SCENARIOS.md). ## Contributing Contributions are welcome! Please refer to the [contributing guidelines](CONTRIBUTING.md) for more information. ## License This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details. Copyright (c) 2024 Nebius B.V. [go-img]: https://img.shields.io/github/go-mod/go-version/nebius/gosdk [go-url]: /go.mod [go-latest-img]: https://img.shields.io/github/go-mod/go-version/nebius/gosdk?filename=.github%2Flatest-deps%2Fgo.mod&label=tested [go-latest-url]: /.github/latest-deps/go.mod [ci-img]: https://github.com/nebius/gosdk/actions/workflows/ci.yml/badge.svg [ci-url]: https://github.com/nebius/gosdk/actions/workflows/ci.yml [license-img]: https://img.shields.io/github/license/nebius/gosdk.svg [license-url]: /LICENSE [godoc-img]: https://pkg.go.dev/badge/github.com/nebius/gosdk.svg [godoc-url]: https://pkg.go.dev/github.com/nebius/gosdk