Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 43 additions & 27 deletions internal/provider/instances_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"fmt"
"strings"
"time"

"github.com/oxidecomputer/oxide.go/oxide"
v1 "k8s.io/api/core/v1"
Expand All @@ -16,6 +17,9 @@ import (

var _ cloudprovider.InstancesV2 = (*InstancesV2)(nil)

// gibibyte is the number of bytes in a gibibyte.
const gibibyte = 1024 * 1024 * 1024

// InstancesV2 implements [cloudprovider.InstancesV2] to provide Oxide specific
// instance functionality.
type InstancesV2 struct {
Expand All @@ -28,6 +32,9 @@ type InstancesV2 struct {
// InstanceExists checks whether the provided Kubernetes node exists as instance
// in Oxide.
func (i *InstancesV2) InstanceExists(ctx context.Context, node *v1.Node) (bool, error) {
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()

instanceID, err := InstanceIDFromProviderID(node.Spec.ProviderID)
if err != nil {
return false, fmt.Errorf("failed retrieving instance id from provider id: %w", err)
Expand All @@ -49,34 +56,21 @@ func (i *InstancesV2) InstanceExists(ctx context.Context, node *v1.Node) (bool,
// InstanceMetadata populates the metadata for the provided node, notably
// setting its provider ID.
func (i *InstancesV2) InstanceMetadata(ctx context.Context, node *v1.Node) (*cloudprovider.InstanceMetadata, error) {
var (
err error
instance *oxide.Instance
instanceID string
)
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()

if node.Spec.ProviderID != "" {
instanceID, err = InstanceIDFromProviderID(node.Spec.ProviderID)
if err != nil {
return nil, fmt.Errorf("failed retrieving instance id from provider id: %w", err)
}

instance, err = i.client.InstanceView(ctx, oxide.InstanceViewParams{
Instance: oxide.NameOrId(instanceID),
})
if err != nil {
return nil, fmt.Errorf("failed viewing oxide instance by id: %v", err)
}
} else {
instance, err = i.client.InstanceView(ctx, oxide.InstanceViewParams{
Project: oxide.NameOrId(i.project),
Instance: oxide.NameOrId(node.GetName()),
})
if err != nil {
return nil, fmt.Errorf("failed viewing oxide instance by name: %v", err)
}
// Get the instance ID, either from the provider ID or by looking up by name.
instanceID, err := i.getInstanceID(ctx, node)
if err != nil {
return nil, err
}

instanceID = instance.Id
// Retrieve the instance details.
instance, err := i.client.InstanceView(ctx, oxide.InstanceViewParams{
Instance: oxide.NameOrId(instanceID),
})
if err != nil {
return nil, fmt.Errorf("failed viewing oxide instance: %v", err)
}

nics, err := i.client.InstanceNetworkInterfaceList(ctx, oxide.InstanceNetworkInterfaceListParams{
Expand Down Expand Up @@ -119,13 +113,35 @@ func (i *InstancesV2) InstanceMetadata(ctx context.Context, node *v1.Node) (*clo

return &cloudprovider.InstanceMetadata{
ProviderID: NewProviderID(instanceID),
InstanceType: fmt.Sprintf("%v-%v", instance.Ncpus, (instance.Memory / (1024 * 1024 * 1024))),
InstanceType: fmt.Sprintf("%d-%d", instance.Ncpus, instance.Memory/gibibyte),
NodeAddresses: nodeAddresses,
}, nil
}

// getInstanceID retrieves the instance ID either from the node's provider ID
// or by looking up the instance by name.
func (i *InstancesV2) getInstanceID(ctx context.Context, node *v1.Node) (string, error) {
if node.Spec.ProviderID != "" {
return InstanceIDFromProviderID(node.Spec.ProviderID)
}

// If no provider ID is set, look up the instance by name.
instance, err := i.client.InstanceView(ctx, oxide.InstanceViewParams{
Project: oxide.NameOrId(i.project),
Instance: oxide.NameOrId(node.GetName()),
})
if err != nil {
return "", fmt.Errorf("failed viewing oxide instance by name: %v", err)
}

return instance.Id, nil
}

// InstanceShutdown checks whether the provided node is shut down in Oxide.
func (i *InstancesV2) InstanceShutdown(ctx context.Context, node *v1.Node) (bool, error) {
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()

instanceID, err := InstanceIDFromProviderID(node.Spec.ProviderID)
if err != nil {
return false, fmt.Errorf("failed retrieving instance id from provider id: %w", err)
Expand Down
7 changes: 4 additions & 3 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,21 @@ func (o *Oxide) Initialize(clientBuilder cloudprovider.ControllerClientBuilder,
kubernetesClient, err := clientBuilder.Client(Name)
if err != nil {
klog.Fatalf("failed to create kubernetes client: %v", err)
return
}
o.k8sClient = kubernetesClient

oxideClient, err := oxide.NewClient(nil)
if err != nil {
klog.Fatalf("failed to create oxide client: %v", err)
return
}
o.client = oxideClient

o.project = os.Getenv("OXIDE_PROJECT")
if o.project == "" {
klog.Fatalf("OXIDE_PROJECT environment variable is required")
}

klog.InfoS("initialized cloud provider", "type", "oxide")
klog.InfoS("initialized cloud provider", "type", "oxide", "project", o.project)
}

// ProviderName returns the name of this cloud provider.
Expand Down