blueprints.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. package services
  2. import (
  3. "fmt"
  4. "git.linuxforward.com/byop/byop-engine/dbstore"
  5. "git.linuxforward.com/byop/byop-engine/models"
  6. "github.com/google/uuid"
  7. )
  8. // BlueprintService handles business logic for Blueprints
  9. type BlueprintService struct {
  10. store *dbstore.BlueprintStore
  11. }
  12. // NewBlueprintService creates a new BlueprintService
  13. func NewBlueprintService(store *dbstore.BlueprintStore) *BlueprintService {
  14. return &BlueprintService{store: store}
  15. }
  16. // CreateBlueprint creates a new deployment Blueprint
  17. func (s *BlueprintService) CreateBlueprint(Blueprint *models.Blueprint) error {
  18. // Generate UUID if not provided
  19. if Blueprint.ID == "" {
  20. Blueprint.ID = uuid.New().String()
  21. }
  22. // Validate Blueprint configuration
  23. if err := validateBlueprintConfig(Blueprint.Config); err != nil {
  24. return fmt.Errorf("invalid Blueprint configuration: %w", err)
  25. }
  26. // Persist the Blueprint
  27. return s.store.Create(Blueprint)
  28. }
  29. // GetBlueprint retrieves a Blueprint by ID
  30. func (s *BlueprintService) GetBlueprint(id string) (*models.Blueprint, error) {
  31. Blueprint, err := s.store.GetByID(id)
  32. if err != nil {
  33. return nil, fmt.Errorf("failed to retrieve Blueprint: %w", err)
  34. }
  35. return Blueprint, nil
  36. }
  37. // UpdateBlueprint updates an existing Blueprint
  38. func (s *BlueprintService) UpdateBlueprint(Blueprint *models.Blueprint) error {
  39. if Blueprint.ID == "" {
  40. return fmt.Errorf("Blueprint ID is required for update")
  41. }
  42. // Check if Blueprint exists
  43. existingBlueprint, err := s.store.GetByID(Blueprint.ID)
  44. if err != nil {
  45. return fmt.Errorf("failed to check if Blueprint exists: %w", err)
  46. }
  47. if existingBlueprint == nil {
  48. return fmt.Errorf("Blueprint with ID %s not found", Blueprint.ID)
  49. }
  50. // Validate Blueprint configuration
  51. if err := validateBlueprintConfig(Blueprint.Config); err != nil {
  52. return fmt.Errorf("invalid Blueprint configuration: %w", err)
  53. }
  54. return s.store.Update(Blueprint)
  55. }
  56. // DeleteBlueprint deletes a Blueprint by ID
  57. func (s *BlueprintService) DeleteBlueprint(id string) error {
  58. // Check if Blueprint exists
  59. Blueprint, err := s.store.GetByID(id)
  60. if err != nil {
  61. return fmt.Errorf("failed to check if Blueprint exists: %w", err)
  62. }
  63. if Blueprint == nil {
  64. return fmt.Errorf("Blueprint with ID %s not found", id)
  65. }
  66. // Check if the Blueprint has deployments
  67. BlueprintWithDeployments, err := s.store.GetBlueprintWithDeployments(id)
  68. if err != nil {
  69. return fmt.Errorf("failed to check Blueprint deployments: %w", err)
  70. }
  71. // Don't allow deletion if there are active deployments
  72. if len(BlueprintWithDeployments.Deployments) > 0 {
  73. return fmt.Errorf("cannot delete Blueprint with active deployments")
  74. }
  75. return s.store.Delete(id)
  76. }
  77. // ListBlueprints retrieves all Blueprints with optional filtering
  78. func (s *BlueprintService) ListBlueprints(filter map[string]interface{}) ([]*models.Blueprint, error) {
  79. return s.store.List(filter)
  80. }
  81. // GetBlueprintDeployments retrieves all deployments for a Blueprint
  82. func (s *BlueprintService) GetBlueprintDeployments(id string) ([]models.Deployment, error) {
  83. // First check if the Blueprint exists
  84. Blueprint, err := s.store.GetByID(id)
  85. if err != nil {
  86. return nil, fmt.Errorf("failed to check if Blueprint exists: %w", err)
  87. }
  88. if Blueprint == nil {
  89. return nil, fmt.Errorf("Blueprint with ID %s not found", id)
  90. }
  91. // Get Blueprint with deployments
  92. BlueprintWithDeployments, err := s.store.GetBlueprintWithDeployments(id)
  93. if err != nil {
  94. return nil, fmt.Errorf("failed to retrieve Blueprint deployments: %w", err)
  95. }
  96. return BlueprintWithDeployments.Deployments, nil
  97. }
  98. // GetBlueprintByVersion retrieves a Blueprint by name and version
  99. func (s *BlueprintService) GetBlueprintByVersion(name, version string) (*models.Blueprint, error) {
  100. Blueprint, err := s.store.GetByVersion(name, version)
  101. if err != nil {
  102. return nil, fmt.Errorf("failed to retrieve Blueprint: %w", err)
  103. }
  104. return Blueprint, nil
  105. }
  106. // validateBlueprintConfig validates the Blueprint configuration
  107. func validateBlueprintConfig(config models.BlueprintConfig) error {
  108. // Validate that at least one app is defined
  109. if len(config.Components) == 0 {
  110. return fmt.Errorf("Blueprint must define at least one app")
  111. }
  112. // Validate each app in the Blueprint
  113. for i, app := range config.Components {
  114. if app.Name == "" {
  115. return fmt.Errorf("app at index %d must have a name", i)
  116. }
  117. // Validate resource configuration
  118. if app.Resources.CPU == "" {
  119. return fmt.Errorf("app '%s' must specify CPU resources", app.Name)
  120. }
  121. if app.Resources.Memory == "" {
  122. return fmt.Errorf("app '%s' must specify memory resources", app.Name)
  123. }
  124. }
  125. // Add additional validation logic as needed
  126. return nil
  127. }