edge-connect-client/internal/delete/v1/manager.go
Richard Robert Reitz 9363277532
All checks were successful
test / test (push) Successful in 48s
fix(sdk): correct delete payload structure for v2 API and add delete command
The v2 API requires a different JSON payload structure than what was being sent.
Both DeleteApp and DeleteAppInstance needed to wrap their parameters properly.

SDK Changes:
- Update DeleteAppInput to use {region, app: {key}} structure
- Update DeleteAppInstanceInput to use {region, appinst: {key}} structure
- Fix DeleteApp method to populate new payload structure
- Fix DeleteAppInstance method to populate new payload structure

CLI Changes:
- Add delete command with -f flag for config file specification
- Support --dry-run to preview deletions
- Support --auto-approve to skip confirmation
- Implement v1 and v2 API support following same pattern as apply
- Add deletion planner to discover resources matching config
- Add resource manager to execute deletions (instances first, then app)

Test Changes:
- Update example_test.go to use EdgeConnectConfig_v1.yaml
- All tests passing including comprehensive delete test coverage

Verified working with manual API testing against live endpoint.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 15:15:23 +02:00

166 lines
4.9 KiB
Go

// ABOUTME: Resource management for EdgeConnect delete command with deletion execution
// ABOUTME: Handles actual deletion operations with proper ordering (instances first, then app)
package v1
import (
"context"
"fmt"
"time"
"edp.buildth.ing/DevFW-CICD/edge-connect-client/sdk/edgeconnect"
)
// ResourceManagerInterface defines the interface for resource management
type ResourceManagerInterface interface {
// ExecuteDeletion executes a deletion plan
ExecuteDeletion(ctx context.Context, plan *DeletionPlan) (*DeletionResult, error)
}
// EdgeConnectResourceManager implements resource management for EdgeConnect
type EdgeConnectResourceManager struct {
client EdgeConnectClientInterface
logger Logger
}
// Logger interface for deletion logging
type Logger interface {
Printf(format string, v ...interface{})
}
// ResourceManagerOptions configures the resource manager behavior
type ResourceManagerOptions struct {
// Logger for deletion operations
Logger Logger
}
// DefaultResourceManagerOptions returns sensible defaults
func DefaultResourceManagerOptions() ResourceManagerOptions {
return ResourceManagerOptions{
Logger: nil,
}
}
// NewResourceManager creates a new EdgeConnect resource manager
func NewResourceManager(client EdgeConnectClientInterface, opts ...func(*ResourceManagerOptions)) ResourceManagerInterface {
options := DefaultResourceManagerOptions()
for _, opt := range opts {
opt(&options)
}
return &EdgeConnectResourceManager{
client: client,
logger: options.Logger,
}
}
// WithLogger sets a logger for deletion operations
func WithLogger(logger Logger) func(*ResourceManagerOptions) {
return func(opts *ResourceManagerOptions) {
opts.Logger = logger
}
}
// ExecuteDeletion executes a deletion plan
// Important: Instances must be deleted before the app
func (rm *EdgeConnectResourceManager) ExecuteDeletion(ctx context.Context, plan *DeletionPlan) (*DeletionResult, error) {
startTime := time.Now()
rm.logf("Starting deletion: %s", plan.ConfigName)
result := &DeletionResult{
Plan: plan,
Success: true,
CompletedActions: []DeletionActionResult{},
FailedActions: []DeletionActionResult{},
}
// If plan is empty, return success immediately
if plan.IsEmpty() {
rm.logf("No resources to delete")
result.Duration = time.Since(startTime)
return result, nil
}
// Step 1: Delete all instances first
for _, instance := range plan.InstancesToDelete {
actionStart := time.Now()
rm.logf("Deleting instance: %s", instance.Name)
instanceKey := edgeconnect.AppInstanceKey{
Organization: instance.Organization,
Name: instance.Name,
CloudletKey: edgeconnect.CloudletKey{
Organization: instance.CloudletOrg,
Name: instance.CloudletName,
},
}
err := rm.client.DeleteAppInstance(ctx, instanceKey, instance.Region)
actionResult := DeletionActionResult{
Type: "instance",
Target: instance.Name,
Duration: time.Since(actionStart),
}
if err != nil {
rm.logf("Failed to delete instance %s: %v", instance.Name, err)
actionResult.Success = false
actionResult.Error = err
result.FailedActions = append(result.FailedActions, actionResult)
result.Success = false
result.Error = fmt.Errorf("failed to delete instance %s: %w", instance.Name, err)
result.Duration = time.Since(startTime)
return result, result.Error
}
rm.logf("Successfully deleted instance: %s", instance.Name)
actionResult.Success = true
result.CompletedActions = append(result.CompletedActions, actionResult)
}
// Step 2: Delete the app (only after all instances are deleted)
if plan.AppToDelete != nil {
actionStart := time.Now()
app := plan.AppToDelete
rm.logf("Deleting app: %s version %s", app.Name, app.Version)
appKey := edgeconnect.AppKey{
Organization: app.Organization,
Name: app.Name,
Version: app.Version,
}
err := rm.client.DeleteApp(ctx, appKey, app.Region)
actionResult := DeletionActionResult{
Type: "app",
Target: fmt.Sprintf("%s:%s", app.Name, app.Version),
Duration: time.Since(actionStart),
}
if err != nil {
rm.logf("Failed to delete app %s: %v", app.Name, err)
actionResult.Success = false
actionResult.Error = err
result.FailedActions = append(result.FailedActions, actionResult)
result.Success = false
result.Error = fmt.Errorf("failed to delete app %s: %w", app.Name, err)
result.Duration = time.Since(startTime)
return result, result.Error
}
rm.logf("Successfully deleted app: %s", app.Name)
actionResult.Success = true
result.CompletedActions = append(result.CompletedActions, actionResult)
}
result.Duration = time.Since(startTime)
rm.logf("Deletion completed successfully in %v", result.Duration)
return result, nil
}
// logf logs a message if a logger is configured
func (rm *EdgeConnectResourceManager) logf(format string, v ...interface{}) {
if rm.logger != nil {
rm.logger.Printf(format, v...)
}
}