gosdk

package module
v0.0.0-...-2c33cfd Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 11, 2025 License: MIT Imports: 13 Imported by: 0

README

Nebius AI Cloud SDK for Go
go minimal version go tested version CI License Go Reference

The Nebius AI Cloud SDK for Go is a comprehensive client library for interacting with nebius.com services. Built on gRPC, it supports all APIs defined in the Nebius API repository. 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:

go get github.com/nebius/gosdk

To update to the latest version:

go get -u github.com/nebius/gosdk

Supported Go Versions

  • Minimum Supported Version: Go 1.22
  • The SDK is regularly tested against the latest Go release.

Getting Started

Follow this step-by-step guide to begin using the SDK.

Skip ahead to the Complete Example or explore Advanced Scenarios.

SDK Initialization

Initialize the SDK with appropriate options:

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 (reference).

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 (reference).

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:

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) to obtain an IAM token manually:
    IAM_TOKEN=$(nebius iam get-access-token)
    
  • Since tokens expire, this method requires manual token refreshes, making it less suitable for production environments.

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.

Here are common approaches:

  1. Using a JSON Credentials File:

    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:

    {
    	"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:

    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:

    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.

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.

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.

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.

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.

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

⚠️ Requires Go 1.23 or GOEXPERIMENT=rangefunc in Go 1.22.

The Filter method simplifies resource listing by iterating over items across pages in a single loop.

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.

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.

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.

Contributing

Contributions are welcome! Please refer to the contributing guidelines for more information.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Copyright (c) 2024 Nebius B.V.

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Credentials

type Credentials interface {
	// contains filtered or unexported methods
}

Credentials are used to authenticate outgoing gRPC requests. To disable authentication for a specific request use the auth.Disable call option.

Example (UseIAMToken)
package main

import (
	"context"
	"log/slog"
	"os"

	"github.com/nebius/gosdk"
)

func main() {
	ctx := context.Background()
	logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

	sdk, err := gosdk.New(
		ctx,
		gosdk.WithLogger(logger),
		gosdk.WithCredentials(
			gosdk.IAMToken(os.Getenv("MY_ENV")),
		),
	)
	if err != nil {
		return // fmt.Errorf("create gosdk: %w", err)
	}
	defer func() {
		errX := sdk.Close()
		if errX != nil {
			logger.ErrorContext(ctx, "failed to close sdk", slog.Any("error", errX))
		}
	}()
}
Output:

Example (UseServiceAccount)
package main

import (
	"context"
	"log/slog"
	"os"

	"github.com/nebius/gosdk"
	"github.com/nebius/gosdk/auth"
)

func main() {
	ctx := context.Background()
	logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

	// you can find more ways to create a service account in the auth package
	serviceAccount := auth.NewPrivateKeyFileParser(
		nil, // or you can set up your own fs, eg: `os.DirFS("."),`
		"private/key/file/path",
		"public-key-id",
		"service-account-id",
	)

	sdk, err := gosdk.New(
		ctx,
		gosdk.WithLogger(logger),
		gosdk.WithCredentials(
			gosdk.ServiceAccountReader(serviceAccount),
		),
	)
	if err != nil {
		return // fmt.Errorf("create gosdk: %w", err)
	}
	defer func() {
		errX := sdk.Close()
		if errX != nil {
			logger.ErrorContext(ctx, "failed to close sdk", slog.Any("error", errX))
		}
	}()
}
Output:

func CustomAuthenticator

func CustomAuthenticator(auth auth.Authenticator) Credentials

CustomAuthenticator allows the user to define its own auth.Authenticator implementation.

func CustomTokener

func CustomTokener(tokener auth.BearerTokener) Credentials

CustomTokener allows the user to define its own auth.BearerTokener implementation for authentication.

func IAMToken

func IAMToken(token string) Credentials

IAMToken is a Credentials that uses a predefined token for authentication.

func NoCredentials

func NoCredentials() Credentials

NoCredentials is the default Credentials that disables authentication.

func OneOfCredentials

func OneOfCredentials(creds map[auth.Selector]Credentials) Credentials

OneOfCredentials allows you to use different credentials for different requests. Exactly one auth.Selector from creds map must be added to call options to choose one.

You can use predefined auth.Base and auth.Propagate selectors as well as auth.Select with custom name.

func PropagateAuthorizationHeader

func PropagateAuthorizationHeader() Credentials

PropagateAuthorizationHeader uses auth.AuthorizationHeader from the incoming grpc metadata and puts it into the outgoing metadata.

func ServiceAccount

func ServiceAccount(account auth.ServiceAccount) Credentials

ServiceAccount is the same as ServiceAccountReader but with constant auth.ServiceAccount.

func ServiceAccountReader

func ServiceAccountReader(reader auth.ServiceAccountReader) Credentials

ServiceAccountReader authorizes gRPC requests using auth.ServiceAccount. It receives an auth.BearerToken from the IAM by exchanging a JWT. The JWT is signed using the private key of the service account.

The SDK ensures a continuously valid bearer token by caching the current token and asynchronously requesting a new one before expiration.

Note: the reader is used only once as it is wrapped with auth.CachedServiceAccount.

type NoopHandler

type NoopHandler struct{}

func (NoopHandler) Enabled

func (NoopHandler) Handle

func (NoopHandler) WithAttrs

func (h NoopHandler) WithAttrs([]slog.Attr) slog.Handler

func (NoopHandler) WithGroup

func (h NoopHandler) WithGroup(string) slog.Handler

type Option

type Option interface {
	// contains filtered or unexported methods
}

Option is an interface combining all options for New func.

func WithAddressTemplate

func WithAddressTemplate(find string, replace string) Option

WithAddressTemplate customizes service address resolution.

func WithCredentials

func WithCredentials(creds Credentials) Option

WithCredentials enables client authentication. By default, NoCredentials is used.

Credentials are applied under the following conditions:

If either of these conditions is not met, the provided credentials will not be used.

func WithDialOptions

func WithDialOptions(opts ...grpc.DialOption) Option

WithDialOptions allows you to specify additional grpc dial options for all services. You can use conn.WithAddressDialOptions to use different options for a specific conn.Address.

func WithDomain

func WithDomain(domain string) Option

WithDomain changes the default "api.eu.nebius.cloud:443" domain.

func WithExplicitInit

func WithExplicitInit(explicitInit bool) Option

WithExplicitInit alters the behavior of the New constructor. If explicitInit is false (the default), SDK.Init is automatically called by New. If explicitInit is true, you must manually call SDK.Init yourself. This option is useful for separating the SDK instantiation from I/O operations.

func WithInit

func WithInit(fn func(context.Context, *SDK) error) Option

WithInit adds an extra fn, which will be called on init SDK.

func WithLogger

func WithLogger(logger *slog.Logger) Option

WithLogger enables logging in the SDK. By default NoopHandler is used.

func WithLoggerHandler

func WithLoggerHandler(handler slog.Handler) Option

WithLoggerHandler enables logging in the SDK. By default NoopHandler is used.

func WithLoggingOptions

func WithLoggingOptions(opts ...logging.Option) Option

WithLoggingOptions allows you to specify additional configurations for the grpc-ecosystem logging interceptor.

func WithResolvers

func WithResolvers(resolvers ...conn.Resolver) Option

WithResolvers customizes service address resolution.

type SDK

type SDK struct {
	// contains filtered or unexported fields
}

SDK is the Nebius API client.

Example

This example demonstrates how to create and configure a new gosdk.SDK instance with logging and credentials, then retrieve a list of compute instances using the gosdk API.

After usage, the SDK instance should be closed.

Note: Be sure to replace `creds` with appropriate credentials.

package main

import (
	"context"
	"fmt"
	"log/slog"
	"os"

	"github.com/nebius/gosdk"

	compute "github.com/nebius/gosdk/proto/nebius/compute/v1"
)

func main() {
	ctx := context.Background()
	logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

	var creds gosdk.Credentials // define your credentials (see other examples)

	sdk, err := gosdk.New(
		ctx,
		gosdk.WithLogger(logger),
		gosdk.WithCredentials(creds),
	)
	if err != nil {
		return // fmt.Errorf("create gosdk: %w", err)
	}
	defer func() {
		errX := sdk.Close()
		if errX != nil {
			logger.ErrorContext(ctx, "failed to close sdk", slog.Any("error", errX))
		}
	}()

	list, err := sdk.Services().Compute().V1().Instance().List(ctx, &compute.ListInstancesRequest{
		ParentId: "my-parent",
	})
	if err != nil {
		return // fmt.Errorf("list instances: %w", err)
	}

	for _, instance := range list.GetItems() {
		fmt.Println(instance.GetMetadata().GetId())
	}
}
Output:

func New

func New(ctx context.Context, opts ...Option) (*SDK, error)

New creates a new SDK with the provided options. By default, it also performs any necessary I/O operations. To separate I/O operations from instantiation, use the WithExplicitInit option.

Important: Ensure that the provided ctx is not closed before calling SDK.Close.

func (*SDK) BearerToken

func (s *SDK) BearerToken(ctx context.Context) (auth.BearerToken, error)

BearerToken returns the token used to authorize gRPC requests.

func (*SDK) Close

func (s *SDK) Close() error

Close closes connections and leans up resources.

func (*SDK) Dial

func (s *SDK) Dial(ctx context.Context, address conn.Address) (grpc.ClientConnInterface, error)

Dial returns an underlying gRPC client connection for a specific address.

func (*SDK) Init

func (s *SDK) Init(ctx context.Context) error

Init finalizes the creation of the SDK by performing all required I/O operations. It is automatically called by the New constructor by default. This method should only be called manually if the WithExplicitInit option is used.

Important: Ensure that the provided ctx is not closed before calling SDK.Close.

Example

This examples demonstrates using the gosdk.WithExplicitInit option to separate gosdk.SDK construction (gosdk.New) from IO operations performed during gosdk.SDK.Init. This allows for explicit control over initialization timing.

package main

import (
	"context"
	"log/slog"
	"os"

	"github.com/nebius/gosdk"
)

func main() {
	ctx := context.Background()
	logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

	var creds gosdk.Credentials // define your credentials (see other examples)

	sdk, err := gosdk.New(
		ctx,
		gosdk.WithLogger(logger),
		gosdk.WithCredentials(creds),
		gosdk.WithExplicitInit(true),
	)
	if err != nil {
		return // fmt.Errorf("create gosdk: %w", err)
	}
	defer func() {
		errX := sdk.Close()
		if errX != nil {
			logger.ErrorContext(ctx, "failed to close sdk", slog.Any("error", errX))
		}
	}()

	err = sdk.Init(ctx)
	if err != nil {
		return // fmt.Errorf("init gosdk: %w", err)
	}
}
Output:

func (*SDK) Resolve

func (s *SDK) Resolve(ctx context.Context, id conn.ServiceID) (conn.Address, error)

Resolve returns an address of a specific service.

func (*SDK) Services

func (s *SDK) Services() nebius.Services

Services is a fluent interface to get a Nebius service client.

Directories

Path Synopsis
internal
Package iter is created to simplify migration to iter package from stdlib when we support it.
Package iter is created to simplify migration to iter package from stdlib when we support it.
mocks
nebius/applications/v1alpha1
Package v1alpha1 is a generated GoMock package.
Package v1alpha1 is a generated GoMock package.
nebius/compute/v1
Package v1 is a generated GoMock package.
Package v1 is a generated GoMock package.
nebius/compute/v1alpha1
Package v1alpha1 is a generated GoMock package.
Package v1alpha1 is a generated GoMock package.
nebius/iam/v1
Package v1 is a generated GoMock package.
Package v1 is a generated GoMock package.
nebius/logging/v1/agentmanager
Package agentmanager is a generated GoMock package.
Package agentmanager is a generated GoMock package.
nebius/mk8s/v1
Package v1 is a generated GoMock package.
Package v1 is a generated GoMock package.
nebius/mk8s/v1alpha1
Package v1alpha1 is a generated GoMock package.
Package v1alpha1 is a generated GoMock package.
nebius/msp/mlflow/v1alpha1
Package v1alpha1 is a generated GoMock package.
Package v1alpha1 is a generated GoMock package.
nebius/msp/postgresql/v1alpha1
Package v1alpha1 is a generated GoMock package.
Package v1alpha1 is a generated GoMock package.
nebius/msp/spark/v1alpha1
Package v1alpha1 is a generated GoMock package.
Package v1alpha1 is a generated GoMock package.
nebius/msp/v1alpha1/resource
Package resource is a generated GoMock package.
Package resource is a generated GoMock package.
nebius/registry/v1
Package v1 is a generated GoMock package.
Package v1 is a generated GoMock package.
nebius/storage/v1
Package v1 is a generated GoMock package.
Package v1 is a generated GoMock package.
nebius/vpc/v1
Package v1 is a generated GoMock package.
Package v1 is a generated GoMock package.
nebius/vpc/v1alpha1
Package v1alpha1 is a generated GoMock package.
Package v1alpha1 is a generated GoMock package.
operations
Package operations is a generated GoMock package.
Package operations is a generated GoMock package.
proto
services

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL