package handlers import ( // Keep context for future use in actual cloud calls "fmt" "net/http" "git.linuxforward.com/byop/byop-engine/cloud" "git.linuxforward.com/byop/byop-engine/models" "github.com/gin-gonic/gin" ) // ProviderHandler handles provider-related operations type ProviderHandler struct { // No specific dependencies for now, but a ProviderService might be added later // for more complex logic or if providers are stored in a DB. } // NewProviderHandler creates a new ProviderHandler func NewProviderHandler() *ProviderHandler { return &ProviderHandler{} } // RegisterRoutes registers routes for provider operations func (h *ProviderHandler) RegisterRoutes(r *gin.RouterGroup) { r.GET("/", h.ListProviders) // r.POST("/", h.CreateProvider) // Assuming CreateProvider would involve DB interaction r.GET("/:id", h.GetProvider) // r.PUT("/:id", h.UpdateProvider) // Assuming UpdateProvider would involve DB interaction // r.DELETE("/:id", h.DeleteProvider) // Assuming DeleteProvider would involve DB interaction r.GET("/:id/regions", h.GetProviderRegions) r.POST("/:id/validate", h.ValidateProviderCredentials) } // ListProviders returns all supported providers func (h *ProviderHandler) ListProviders(c *gin.Context) { providers := cloud.GetSupportedProviders() // This returns []string if len(providers) == 0 { appErr := models.NewErrNotFound("no_providers_found", fmt.Errorf("No supported providers found")) models.RespondWithError(c, appErr) return } c.JSON(http.StatusOK, providers) // Returns a JSON array of strings } // GetProvider returns a specific provider by its ID (name) func (h *ProviderHandler) GetProvider(c *gin.Context) { ctx := c.Request.Context() // Get context, though not used for current static implementation _ = ctx // Avoid unused variable error if not used yet in this specific function providerName := c.Param("id") supportedProviders := cloud.GetSupportedProviders() found := false for _, sp := range supportedProviders { if sp == providerName { found = true break } } if !found { appErr := models.NewErrNotFound("provider_not_found", fmt.Errorf("Provider with name '%s' not found or not supported", providerName)) models.RespondWithError(c, appErr) return } // Return basic information about the provider c.JSON(http.StatusOK, gin.H{"name": providerName, "status": "supported"}) } // GetProviderRegions returns available regions for a provider func (h *ProviderHandler) GetProviderRegions(c *gin.Context) { ctx := c.Request.Context() // Get context, to be used for actual cloud calls providerName := c.Param("id") // Validate if provider is supported supportedProviders := cloud.GetSupportedProviders() isSupported := false for _, sp := range supportedProviders { if sp == providerName { isSupported = true break } } if !isSupported { appErr := models.NewErrNotFound("provider_not_supported", fmt.Errorf("Provider '%s' is not supported", providerName)) models.RespondWithError(c, appErr) return } // Placeholder: Replace with actual calls to cloud.Provider.ListRegions(ctx) // For now, using static list. ctx is available for when real calls are made. _ = ctx // Explicitly use ctx to avoid "unused" error if no cloud calls yet var regions []string switch providerName { case "aws": regions = []string{"us-east-1", "us-west-2", "eu-west-1"} // Example static regions case "digitalocean": regions = []string{"nyc1", "sfo3", "lon1"} // Example static regions case "ovh": regions = []string{"GRA", "SBG", "BHS"} // Example static regions default: // This case should ideally not be hit if validation above is correct // and the switch covers all supported providers from cloud.GetSupportedProviders(). appErr := models.NewErrInternalServer("provider_regions_not_implemented", fmt.Errorf("Regions not implemented for provider '%s'", providerName)) models.RespondWithError(c, appErr) return } c.JSON(http.StatusOK, regions) } // ValidateProviderCredentials validates provider credentials func (h *ProviderHandler) ValidateProviderCredentials(c *gin.Context) { ctx := c.Request.Context() // Get context, to be used for actual cloud calls providerName := c.Param("id") // Validate if provider is supported supportedProviders := cloud.GetSupportedProviders() isSupported := false for _, sp := range supportedProviders { if sp == providerName { isSupported = true break } } if !isSupported { appErr := models.NewErrNotFound("provider_not_supported_for_validation", fmt.Errorf("Provider '%s' is not supported for credential validation", providerName)) models.RespondWithError(c, appErr) return } var credsBody struct { AccessKeyID string `json:"access_key_id"` SecretAccessKey string `json:"secret_access_key"` Token string `json:"token"` // For AWS STS, DO API token, OVH tokens etc. ProjectID string `json:"project_id"` // For GCP, OVH Region string `json:"region"` // Optional, might be needed for some validation endpoints } if err := c.ShouldBindJSON(&credsBody); err != nil { appErr := models.NewErrValidation("invalid_credentials_format", map[string]string{"body": "Invalid request body for credentials"}, err) models.RespondWithError(c, appErr) return } // Placeholder: Replace with actual calls to a provider method like provider.ValidateCredentials(ctx, creds) // ctx is available for when real calls are made. _ = ctx // Explicitly use ctx to avoid "unused" error if no cloud calls yet var isValid bool var validationError error // To store error from actual validation logic switch providerName { case "aws": // e.g., isValid, validationError = cloud.ValidateAWSCredentials(ctx, credsBody.AccessKeyID, credsBody.SecretAccessKey, credsBody.Token, credsBody.Region) isValid = true // Assume valid for now case "digitalocean": // e.g., isValid, validationError = cloud.ValidateDOCredentials(ctx, credsBody.Token) isValid = true // Assume valid for now case "ovh": // e.g., isValid, validationError = cloud.ValidateOVHCredentials(ctx, ...) isValid = true // Assume valid for now default: // This case should ideally not be hit if validation above is correct. appErr := models.NewErrInternalServer("provider_validation_not_implemented", fmt.Errorf("Credential validation not implemented for provider '%s'", providerName)) models.RespondWithError(c, appErr) return } if validationError != nil { appErr := models.NewErrInternalServer("credential_validation_error", fmt.Errorf("Error validating credentials for %s: %w", providerName, validationError)) models.RespondWithError(c, appErr) return } if !isValid { appErr := models.NewErrUnauthorized("invalid_provider_credentials", fmt.Errorf("Credentials for provider %s are invalid", providerName)) models.RespondWithError(c, appErr) return } c.JSON(http.StatusOK, gin.H{"valid": true, "message": "Credentials validated successfully"}) }