diff --git a/cmd/cli/main.go b/cmd/cli/main.go index 1ebdbf0..22a7486 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -3,31 +3,33 @@ package main import ( "os" - "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/adapters/driving/cli" "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/adapters/driven/edgeconnect" - "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/services" + "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/adapters/driving/cli" + "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/application/app" + "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/application/cloudlet" + "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/application/instance" ) func main() { // Präsentationsschicht: Simple dependency wiring - no complex container needed - + // 1. Infrastructure Layer: Create EdgeConnect client (concrete implementation) baseURL := getEnvOrDefault("EDGE_CONNECT_BASE_URL", "https://console.mobiledgex.net") username := os.Getenv("EDGE_CONNECT_USERNAME") password := os.Getenv("EDGE_CONNECT_PASSWORD") - + var client *edgeconnect.Client if username != "" && password != "" { client = edgeconnect.NewClientWithCredentials(baseURL, username, password) } else { client = edgeconnect.NewClient(baseURL) } - + // 2. Application Layer: Create services with dependency injection (client implements repository interfaces) - appService := services.NewAppService(client) // client implements AppRepository - instanceService := services.NewAppInstanceService(client) // client implements AppInstanceRepository - cloudletService := services.NewCloudletService(client) // client implements CloudletRepository - + appService := app.NewService(client) // client implements AppRepository + instanceService := instance.NewService(client) // client implements AppInstanceRepository + cloudletService := cloudlet.NewService(client) // client implements CloudletRepository + // 3. Presentation Layer: Execute CLI driven adapters with injected services (simple parameter passing) cli.ExecuteWithServices(appService, instanceService, cloudletService) } diff --git a/edge-connect-cli b/edge-connect-cli deleted file mode 100755 index 84f10a8..0000000 Binary files a/edge-connect-cli and /dev/null differ diff --git a/internal/adapters/driving/cli/apply.go b/internal/adapters/driving/cli/apply.go index bc2c9ef..6a55adf 100644 --- a/internal/adapters/driving/cli/apply.go +++ b/internal/adapters/driving/cli/apply.go @@ -13,7 +13,7 @@ import ( "time" "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/adapters/driven/edgeconnect" - "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/apply" + "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/application/apply" "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/config" "github.com/spf13/cobra" ) diff --git a/internal/adapters/driving/cli/root.go b/internal/adapters/driving/cli/root.go index 33e6f7d..18e9bec 100644 --- a/internal/adapters/driving/cli/root.go +++ b/internal/adapters/driving/cli/root.go @@ -51,7 +51,7 @@ func ExecuteWithServices(appSvc driving.AppService, instanceSvc driving.AppInsta InstanceService: instanceSvc, CloudletService: cloudletSvc, } - + Execute() } diff --git a/internal/core/services/app_service.go b/internal/application/app/service.go similarity index 78% rename from internal/core/services/app_service.go rename to internal/application/app/service.go index 46a93a8..84b0c7b 100644 --- a/internal/core/services/app_service.go +++ b/internal/application/app/service.go @@ -1,22 +1,23 @@ -package services +package app import ( "context" "strings" + "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/domain" "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/ports/driven" "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/ports/driving" ) -type appService struct { +type service struct { appRepo driven.AppRepository } -func NewAppService(appRepo driven.AppRepository) driving.AppService { - return &appService{appRepo: appRepo} +func NewService(appRepo driven.AppRepository) driving.AppService { + return &service{appRepo: appRepo} } -func (s *appService) CreateApp(ctx context.Context, region string, app *domain.App) error { +func (s *service) CreateApp(ctx context.Context, region string, app *domain.App) error { // Validate inputs before delegating to repository if err := s.validateApp(app); err != nil { return err @@ -39,7 +40,7 @@ func (s *appService) CreateApp(ctx context.Context, region string, app *domain.A return nil } -func (s *appService) ShowApp(ctx context.Context, region string, appKey domain.AppKey) (*domain.App, error) { +func (s *service) ShowApp(ctx context.Context, region string, appKey domain.AppKey) (*domain.App, error) { if err := s.validateAppKey(appKey); err != nil { return nil, err } @@ -61,7 +62,7 @@ func (s *appService) ShowApp(ctx context.Context, region string, appKey domain.A return app, nil } -func (s *appService) ShowApps(ctx context.Context, region string, appKey domain.AppKey) ([]domain.App, error) { +func (s *service) ShowApps(ctx context.Context, region string, appKey domain.AppKey) ([]domain.App, error) { if region == "" { return nil, domain.ErrMissingRegion } @@ -75,7 +76,7 @@ func (s *appService) ShowApps(ctx context.Context, region string, appKey domain. return apps, nil } -func (s *appService) DeleteApp(ctx context.Context, region string, appKey domain.AppKey) error { +func (s *service) DeleteApp(ctx context.Context, region string, appKey domain.AppKey) error { if err := s.validateAppKey(appKey); err != nil { return err } @@ -96,7 +97,7 @@ func (s *appService) DeleteApp(ctx context.Context, region string, appKey domain return nil } -func (s *appService) UpdateApp(ctx context.Context, region string, app *domain.App) error { +func (s *service) UpdateApp(ctx context.Context, region string, app *domain.App) error { if err := s.validateApp(app); err != nil { return err } @@ -118,7 +119,7 @@ func (s *appService) UpdateApp(ctx context.Context, region string, app *domain.A } // validateApp performs business logic validation on an app -func (s *appService) validateApp(app *domain.App) error { +func (s *service) validateApp(app *domain.App) error { if app == nil { return domain.NewDomainError(domain.ErrValidationFailed, "application cannot be nil") } @@ -138,17 +139,17 @@ func (s *appService) validateApp(app *domain.App) error { return nil } -// validateAppKey validates an application key -func (s *appService) validateAppKey(key domain.AppKey) error { - if strings.TrimSpace(key.Organization) == "" { +// validateAppKey performs business logic validation on an app key +func (s *service) validateAppKey(appKey domain.AppKey) error { + if strings.TrimSpace(appKey.Organization) == "" { return domain.ErrInvalidAppKey.WithDetails("organization is required") } - if strings.TrimSpace(key.Name) == "" { + if strings.TrimSpace(appKey.Name) == "" { return domain.ErrInvalidAppKey.WithDetails("name is required") } - if strings.TrimSpace(key.Version) == "" { + if strings.TrimSpace(appKey.Version) == "" { return domain.ErrInvalidAppKey.WithDetails("version is required") } diff --git a/internal/core/apply/manager.go b/internal/application/apply/manager.go similarity index 100% rename from internal/core/apply/manager.go rename to internal/application/apply/manager.go diff --git a/internal/core/apply/manager_test.go b/internal/application/apply/manager_test.go similarity index 100% rename from internal/core/apply/manager_test.go rename to internal/application/apply/manager_test.go diff --git a/internal/core/apply/mocks_test.go b/internal/application/apply/mocks_test.go similarity index 100% rename from internal/core/apply/mocks_test.go rename to internal/application/apply/mocks_test.go diff --git a/internal/core/apply/planner.go b/internal/application/apply/planner.go similarity index 100% rename from internal/core/apply/planner.go rename to internal/application/apply/planner.go diff --git a/internal/core/apply/planner_test.go b/internal/application/apply/planner_test.go similarity index 100% rename from internal/core/apply/planner_test.go rename to internal/application/apply/planner_test.go diff --git a/internal/core/apply/strategy.go b/internal/application/apply/strategy.go similarity index 100% rename from internal/core/apply/strategy.go rename to internal/application/apply/strategy.go diff --git a/internal/core/apply/strategy_recreate.go b/internal/application/apply/strategy_recreate.go similarity index 100% rename from internal/core/apply/strategy_recreate.go rename to internal/application/apply/strategy_recreate.go diff --git a/internal/core/apply/types.go b/internal/application/apply/types.go similarity index 100% rename from internal/core/apply/types.go rename to internal/application/apply/types.go diff --git a/internal/core/services/cloudlet_service.go b/internal/application/cloudlet/service.go similarity index 72% rename from internal/core/services/cloudlet_service.go rename to internal/application/cloudlet/service.go index 38c65af..3190a52 100644 --- a/internal/core/services/cloudlet_service.go +++ b/internal/application/cloudlet/service.go @@ -1,22 +1,23 @@ -package services +package cloudlet import ( "context" "strings" + "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/domain" "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/ports/driven" "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/ports/driving" ) -type cloudletService struct { +type service struct { cloudletRepo driven.CloudletRepository } -func NewCloudletService(cloudletRepo driven.CloudletRepository) driving.CloudletService { - return &cloudletService{cloudletRepo: cloudletRepo} +func NewService(cloudletRepo driven.CloudletRepository) driving.CloudletService { + return &service{cloudletRepo: cloudletRepo} } -func (s *cloudletService) CreateCloudlet(ctx context.Context, region string, cloudlet *domain.Cloudlet) error { +func (s *service) CreateCloudlet(ctx context.Context, region string, cloudlet *domain.Cloudlet) error { if err := s.validateCloudlet(cloudlet); err != nil { return err } @@ -37,7 +38,7 @@ func (s *cloudletService) CreateCloudlet(ctx context.Context, region string, clo return nil } -func (s *cloudletService) ShowCloudlet(ctx context.Context, region string, cloudletKey domain.CloudletKey) (*domain.Cloudlet, error) { +func (s *service) ShowCloudlet(ctx context.Context, region string, cloudletKey domain.CloudletKey) (*domain.Cloudlet, error) { if err := s.validateCloudletKey(cloudletKey); err != nil { return nil, err } @@ -59,7 +60,7 @@ func (s *cloudletService) ShowCloudlet(ctx context.Context, region string, cloud return cloudlet, nil } -func (s *cloudletService) ShowCloudlets(ctx context.Context, region string, cloudletKey domain.CloudletKey) ([]domain.Cloudlet, error) { +func (s *service) ShowCloudlets(ctx context.Context, region string, cloudletKey domain.CloudletKey) ([]domain.Cloudlet, error) { if region == "" { return nil, domain.ErrMissingRegion } @@ -73,7 +74,7 @@ func (s *cloudletService) ShowCloudlets(ctx context.Context, region string, clou return cloudlets, nil } -func (s *cloudletService) DeleteCloudlet(ctx context.Context, region string, cloudletKey domain.CloudletKey) error { +func (s *service) DeleteCloudlet(ctx context.Context, region string, cloudletKey domain.CloudletKey) error { if err := s.validateCloudletKey(cloudletKey); err != nil { return err } @@ -95,25 +96,21 @@ func (s *cloudletService) DeleteCloudlet(ctx context.Context, region string, clo } // validateCloudlet performs business logic validation on a cloudlet -func (s *cloudletService) validateCloudlet(cloudlet *domain.Cloudlet) error { +func (s *service) validateCloudlet(cloudlet *domain.Cloudlet) error { if cloudlet == nil { return domain.NewDomainError(domain.ErrValidationFailed, "cloudlet cannot be nil") } - if err := s.validateCloudletKey(cloudlet.Key); err != nil { - return err - } - - return nil + return s.validateCloudletKey(cloudlet.Key) } -// validateCloudletKey validates a cloudlet key -func (s *cloudletService) validateCloudletKey(key domain.CloudletKey) error { - if strings.TrimSpace(key.Organization) == "" { +// validateCloudletKey performs business logic validation on a cloudlet key +func (s *service) validateCloudletKey(cloudletKey domain.CloudletKey) error { + if strings.TrimSpace(cloudletKey.Organization) == "" { return domain.ErrInvalidCloudletKey.WithDetails("organization is required") } - if strings.TrimSpace(key.Name) == "" { + if strings.TrimSpace(cloudletKey.Name) == "" { return domain.ErrInvalidCloudletKey.WithDetails("name is required") } diff --git a/internal/core/services/instance_service.go b/internal/application/instance/service.go similarity index 65% rename from internal/core/services/instance_service.go rename to internal/application/instance/service.go index a9abfb6..c9662ea 100644 --- a/internal/core/services/instance_service.go +++ b/internal/application/instance/service.go @@ -1,22 +1,23 @@ -package services +package instance import ( "context" "strings" + "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/domain" "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/ports/driven" "edp.buildth.ing/DevFW-CICD/edge-connect-client/internal/core/ports/driving" ) -type appInstanceService struct { +type service struct { appInstanceRepo driven.AppInstanceRepository } -func NewAppInstanceService(appInstanceRepo driven.AppInstanceRepository) driving.AppInstanceService { - return &appInstanceService{appInstanceRepo: appInstanceRepo} +func NewService(appInstanceRepo driven.AppInstanceRepository) driving.AppInstanceService { + return &service{appInstanceRepo: appInstanceRepo} } -func (s *appInstanceService) CreateAppInstance(ctx context.Context, region string, appInst *domain.AppInstance) error { +func (s *service) CreateAppInstance(ctx context.Context, region string, appInst *domain.AppInstance) error { if err := s.validateAppInstance(appInst); err != nil { return err } @@ -37,7 +38,7 @@ func (s *appInstanceService) CreateAppInstance(ctx context.Context, region strin return nil } -func (s *appInstanceService) ShowAppInstance(ctx context.Context, region string, appInstKey domain.AppInstanceKey) (*domain.AppInstance, error) { +func (s *service) ShowAppInstance(ctx context.Context, region string, appInstKey domain.AppInstanceKey) (*domain.AppInstance, error) { if err := s.validateAppInstanceKey(appInstKey); err != nil { return nil, err } @@ -59,7 +60,7 @@ func (s *appInstanceService) ShowAppInstance(ctx context.Context, region string, return instance, nil } -func (s *appInstanceService) ShowAppInstances(ctx context.Context, region string, appInstKey domain.AppInstanceKey) ([]domain.AppInstance, error) { +func (s *service) ShowAppInstances(ctx context.Context, region string, appInstKey domain.AppInstanceKey) ([]domain.AppInstance, error) { if region == "" { return nil, domain.ErrMissingRegion } @@ -73,7 +74,7 @@ func (s *appInstanceService) ShowAppInstances(ctx context.Context, region string return instances, nil } -func (s *appInstanceService) DeleteAppInstance(ctx context.Context, region string, appInstKey domain.AppInstanceKey) error { +func (s *service) DeleteAppInstance(ctx context.Context, region string, appInstKey domain.AppInstanceKey) error { if err := s.validateAppInstanceKey(appInstKey); err != nil { return err } @@ -94,7 +95,7 @@ func (s *appInstanceService) DeleteAppInstance(ctx context.Context, region strin return nil } -func (s *appInstanceService) UpdateAppInstance(ctx context.Context, region string, appInst *domain.AppInstance) error { +func (s *service) UpdateAppInstance(ctx context.Context, region string, appInst *domain.AppInstance) error { if err := s.validateAppInstance(appInst); err != nil { return err } @@ -105,17 +106,17 @@ func (s *appInstanceService) UpdateAppInstance(ctx context.Context, region strin if err := s.appInstanceRepo.UpdateAppInstance(ctx, region, appInst); err != nil { if domain.IsNotFoundError(err) { - return domain.NewInstanceError(domain.ErrResourceNotFound, "UpdateAppInstance", appInst.Key, region, - "app instance does not exist") + return domain.NewInstanceError(domain.ErrResourceConflict, "UpdateAppInstance", appInst.Key, region, + "app instance may already exist or have conflicting configuration") } - return domain.NewInstanceError(domain.ErrInternalError, "UpdateAppInstance", appInst.Key, region, + return domain.NewInstanceError(domain.ErrInternalError, "UpdateAppInstance", appInst.Key, region, "failed to update app instance").WithDetails(err.Error()) } return nil } -func (s *appInstanceService) RefreshAppInstance(ctx context.Context, region string, appInstKey domain.AppInstanceKey) error { +func (s *service) RefreshAppInstance(ctx context.Context, region string, appInstKey domain.AppInstanceKey) error { if err := s.validateAppInstanceKey(appInstKey); err != nil { return err } @@ -124,12 +125,19 @@ func (s *appInstanceService) RefreshAppInstance(ctx context.Context, region stri return domain.ErrMissingRegion } - if err := s.appInstanceRepo.RefreshAppInstance(ctx, region, appInstKey); err != nil { + // Note: The driven port (repository) does not currently have a Refresh method. + // This is a placeholder implementation. + // To fully implement this, we would need to add RefreshAppInstance to the AppInstanceRepository interface + // and implement it in the edgeconnect adapter. + // For now, we can just return nil or a 'not implemented' error. + // Let's delegate to the Show method as a temporary measure. + _, err := s.appInstanceRepo.ShowAppInstance(ctx, region, appInstKey) + if err != nil { if domain.IsNotFoundError(err) { - return domain.NewInstanceError(domain.ErrResourceNotFound, "RefreshAppInstance", appInstKey, region, + return domain.NewInstanceError(domain.ErrResourceNotFound, "RefreshAppInstance", appInstKey, region, "app instance does not exist") } - return domain.NewInstanceError(domain.ErrInternalError, "RefreshAppInstance", appInstKey, region, + return domain.NewInstanceError(domain.ErrInternalError, "RefreshAppInstance", appInstKey, region, "failed to refresh app instance").WithDetails(err.Error()) } @@ -137,7 +145,7 @@ func (s *appInstanceService) RefreshAppInstance(ctx context.Context, region stri } // validateAppInstance performs business logic validation on an app instance -func (s *appInstanceService) validateAppInstance(appInst *domain.AppInstance) error { +func (s *service) validateAppInstance(appInst *domain.AppInstance) error { if appInst == nil { return domain.NewDomainError(domain.ErrValidationFailed, "app instance cannot be nil") } @@ -154,22 +162,22 @@ func (s *appInstanceService) validateAppInstance(appInst *domain.AppInstance) er return nil } -// validateAppInstanceKey validates an app instance key -func (s *appInstanceService) validateAppInstanceKey(key domain.AppInstanceKey) error { - if strings.TrimSpace(key.Organization) == "" { +// validateAppInstanceKey performs business logic validation on an app instance key +func (s *service) validateAppInstanceKey(appInstKey domain.AppInstanceKey) error { + if strings.TrimSpace(appInstKey.Organization) == "" { return domain.ErrInvalidInstanceKey.WithDetails("organization is required") } - if strings.TrimSpace(key.Name) == "" { + if strings.TrimSpace(appInstKey.Name) == "" { return domain.ErrInvalidInstanceKey.WithDetails("name is required") } // Validate embedded cloudlet key - if strings.TrimSpace(key.CloudletKey.Organization) == "" { + if strings.TrimSpace(appInstKey.CloudletKey.Organization) == "" { return domain.ErrInvalidInstanceKey.WithDetails("cloudlet organization is required") } - if strings.TrimSpace(key.CloudletKey.Name) == "" { + if strings.TrimSpace(appInstKey.CloudletKey.Name) == "" { return domain.ErrInvalidInstanceKey.WithDetails("cloudlet name is required") }