Files
OpenShell/sdk/go/openshell/v1/refresh_client.go
Mrunal Patel c502be9fd7 feat(api): return typed deletion outcomes with explicit missing-target semantics (#3317)
* feat(api): return typed deletion outcomes with explicit missing-target semantics

Implement phase 2 of #3051 across the public gateway API and first-party SDKs. Preserve asynchronous sandbox deletion and observed resource identities, reserve legacy wire fields, and document the coordinated migration.

Signed-off-by: Mrunal Patel <mrunalp@gmail.com>

* fix(sdk): bind deletion waits to sandbox identity

Track accepted deletions by original sandbox identity in Rust and TypeScript. Preserve name-only waits and cover replacement races and lookup failures.

Merge the phase-one cleanup fix and adapt its interceptor regressions to typed deletion outcomes.

Refs #3051.

Signed-off-by: Mrunal Patel <mrunalp@gmail.com>

* test(e2e): accept asynchronous stopped sandbox deletion

Allow either completed or accepted deletion output, then continue polling for actual sandbox absence. This preserves the lifecycle assertion under the phase-two deletion contract.

Refs #3051.

Signed-off-by: Mrunal Patel <mrunalp@gmail.com>

---------

Signed-off-by: Mrunal Patel <mrunalp@gmail.com>
2026-09-16 22:11:19 +00:00

73 lines
2.5 KiB
Go

// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package v1
import (
"context"
"github.com/NVIDIA/OpenShell/sdk/go/openshell/v1/internal/converter"
pb "github.com/NVIDIA/OpenShell/sdk/go/proto/openshellv1"
"google.golang.org/grpc"
)
type refreshClient struct {
client pb.OpenShellClient
}
func newRefreshClient(conn grpc.ClientConnInterface) *refreshClient {
return &refreshClient{client: pb.NewOpenShellClient(conn)}
}
func (r *refreshClient) GetStatus(ctx context.Context, workspace, provider, credentialKey string) ([]*RefreshStatus, error) {
resp, err := r.client.GetProviderRefreshStatus(ctx, &pb.GetProviderRefreshStatusRequest{
Provider: provider,
CredentialKey: credentialKey,
WorkspaceScope: namedWorkspaceScope(workspace),
})
if err != nil {
return nil, converter.FromGRPCError(err)
}
statuses := make([]*RefreshStatus, 0, len(resp.GetCredentials()))
for _, s := range resp.GetCredentials() {
statuses = append(statuses, converter.RefreshStatusFromProto(s))
}
return statuses, nil
}
func (r *refreshClient) Configure(ctx context.Context, workspace string, config *RefreshConfig) (*RefreshStatus, error) {
req := converter.RefreshConfigToProto(config)
req.WorkspaceScope = namedWorkspaceScope(workspace)
resp, err := r.client.ConfigureProviderRefresh(ctx, req)
if err != nil {
return nil, converter.FromGRPCError(err)
}
return converter.RefreshStatusFromProto(resp.GetStatus()), nil
}
func (r *refreshClient) Rotate(ctx context.Context, workspace, provider, credentialKey string) (*RefreshStatus, error) {
resp, err := r.client.RotateProviderCredential(ctx, &pb.RotateProviderCredentialRequest{
Provider: provider,
CredentialKey: credentialKey,
WorkspaceScope: namedWorkspaceScope(workspace),
})
if err != nil {
return nil, converter.FromGRPCError(err)
}
return converter.RefreshStatusFromProto(resp.GetStatus()), nil
}
func (r *refreshClient) Delete(ctx context.Context, workspace, provider, credentialKey string, opts ...DeleteOptions) (*DeletionResult, error) {
resp, err := r.client.DeleteProviderRefresh(ctx, &pb.DeleteProviderRefreshRequest{
AllowMissing: allowMissing(opts),
Provider: provider,
CredentialKey: credentialKey,
WorkspaceScope: namedWorkspaceScope(workspace),
})
if err != nil {
return nil, converter.FromGRPCError(err)
}
return &DeletionResult{Outcome: DeletionOutcome(resp.GetOutcome())}, nil
}