Skip to content
Open
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
72 changes: 68 additions & 4 deletions cmd/api/api/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,24 @@ func (s *ApiService) CreateInstance(ctx context.Context, request oapi.CreateInst
resourceTags = toMapTags(request.Body.Tags)
}

if request.Body.Ttl != nil && request.Body.ExpiresAt != nil {
return oapi.CreateInstance400JSONResponse{
Code: "invalid_request",
Message: "ttl and expires_at are mutually exclusive",
}, nil
}
var ttl time.Duration
if request.Body.Ttl != nil {
parsedTTL, err := parseTTL(*request.Body.Ttl)
if err != nil {
return oapi.CreateInstance400JSONResponse{
Code: "invalid_ttl",
Message: err.Error(),
}, nil
}
ttl = parsedTTL
}

// Parse network enabled (default: true)
networkEnabled := true
if request.Body.Network != nil && request.Body.Network.Enabled != nil {
Expand Down Expand Up @@ -314,6 +332,8 @@ func (s *ApiService) CreateInstance(ctx context.Context, request oapi.CreateInst
NetworkBandwidthUpload: networkBandwidthUpload,
Env: env,
Tags: resourceTags,
TTL: ttl,
ExpiresAt: request.Body.ExpiresAt,
NetworkEnabled: networkEnabled,
NetworkEgress: networkEgress,
Credentials: credentials,
Expand Down Expand Up @@ -363,6 +383,11 @@ func (s *ApiService) CreateInstance(ctx context.Context, request oapi.CreateInst
Code: "insufficient_resources",
Message: err.Error(),
}, nil
case errors.Is(err, instances.ErrInvalidExpiresAt):
return oapi.CreateInstance400JSONResponse{
Code: "invalid_expires_at",
Message: err.Error(),
}, nil
case errors.Is(err, instances.ErrInvalidRequest):
return oapi.CreateInstance400JSONResponse{
Code: "invalid_request",
Expand Down Expand Up @@ -986,9 +1011,8 @@ func (s *ApiService) StatInstancePath(ctx context.Context, request oapi.StatInst
return response, nil
}

// UpdateInstance updates mutable properties of a running instance.
// Currently supports updating env vars referenced by credential policies for key rotation.
// Note: Resolution is handled by ResolveResource middleware
// UpdateInstance updates mutable instance properties.
// Note: Resolution is handled by ResolveResource middleware.
func (s *ApiService) UpdateInstance(ctx context.Context, request oapi.UpdateInstanceRequestObject) (oapi.UpdateInstanceResponseObject, error) {
inst := mw.GetResolvedInstance[instances.Instance](ctx)
if inst == nil {
Expand Down Expand Up @@ -1031,13 +1055,32 @@ func (s *ApiService) UpdateInstance(ctx context.Context, request oapi.UpdateInst
Message: err.Error(),
}, nil
}
if request.Body.Ttl != nil && request.Body.ExpiresAt != nil {
return oapi.UpdateInstance400JSONResponse{
Code: "invalid_request",
Message: "ttl and expires_at are mutually exclusive",
}, nil
}
var ttl *time.Duration
if request.Body.Ttl != nil {
parsedTTL, err := parseTTL(*request.Body.Ttl)
if err != nil {
return oapi.UpdateInstance400JSONResponse{
Code: "invalid_ttl",
Message: err.Error(),
}, nil
}
ttl = &parsedTTL
}

result, err := s.InstanceManager.UpdateInstance(ctx, inst.Id, instances.UpdateInstanceRequest{
Env: env,
AutoStandby: autoStandby,
HealthCheck: healthCheck,
RestartPolicy: restartPolicy,
RestartPolicySet: request.Body.RestartPolicy != nil,
TTL: ttl,
ExpiresAt: request.Body.ExpiresAt,
})
if err != nil {
switch {
Expand All @@ -1051,6 +1094,16 @@ func (s *ApiService) UpdateInstance(ctx context.Context, request oapi.UpdateInst
Code: "invalid_state",
Message: err.Error(),
}, nil
case errors.Is(err, instances.ErrInstanceExpired):
return oapi.UpdateInstance409JSONResponse{
Code: "instance_expired",
Message: err.Error(),
}, nil
case errors.Is(err, instances.ErrInvalidExpiresAt):
return oapi.UpdateInstance400JSONResponse{
Code: "invalid_expires_at",
Message: err.Error(),
}, nil
case errors.Is(err, instances.ErrInvalidRequest):
return oapi.UpdateInstance400JSONResponse{
Code: "invalid_request",
Expand Down Expand Up @@ -1142,6 +1195,7 @@ func instanceToOAPI(inst instances.Instance) oapi.Instance {
DiskIoBps: diskIoBpsStr,
Network: nil,
CreatedAt: inst.CreatedAt,
ExpiresAt: inst.ExpiresAt,
StartedAt: inst.StartedAt,
StoppedAt: inst.StoppedAt,
ExitCode: inst.ExitCode,
Expand All @@ -1155,7 +1209,6 @@ func instanceToOAPI(inst instances.Instance) oapi.Instance {
if inst.Platform != "" {
oapiInst.Platform = lo.ToPtr(inst.Platform)
}

if inst.ExitMessage != "" {
oapiInst.ExitMessage = lo.ToPtr(inst.ExitMessage)
}
Expand Down Expand Up @@ -1308,6 +1361,17 @@ func toOAPISnapshotPolicy(policy instances.SnapshotPolicy) oapi.SnapshotPolicy {
return out
}

func parseTTL(value string) (time.Duration, error) {
ttl, err := time.ParseDuration(value)
if err != nil {
return 0, fmt.Errorf("ttl must be a valid duration: %w", err)
}
if ttl < 0 {
return 0, fmt.Errorf("ttl cannot be negative")
}
return ttl, nil
}

func parseOptionalDuration(value string, field string) (*time.Duration, error) {
duration, err := time.ParseDuration(value)
if err != nil {
Expand Down
Loading
Loading