package schema import ( "encoding/json" "fmt" "os" "path/filepath" "strings" "sync" "time" "github.com/sirupsen/logrus" ) // DebianSchemaManager handles Debian-adapted blue-build schemas type DebianSchemaManager struct { logger *logrus.Logger config *SchemaConfig schemas map[string]DebianSchema validations map[string]SchemaValidation adaptations map[string]SchemaAdaptation mu sync.RWMutex } // SchemaConfig holds schema configuration type SchemaConfig struct { Enabled bool `json:"enabled"` SchemasPath string `json:"schemas_path"` Validation bool `json:"validation"` Adaptations bool `json:"adaptations"` Metadata map[string]string `json:"metadata"` } // DebianSchema represents a Debian-adapted schema type DebianSchema struct { ID string `json:"id"` Name string `json:"name"` Description string `json:"description"` Type string `json:"type"` Version string `json:"version"` Source string `json:"source"` Adapted bool `json:"adapted"` Enabled bool `json:"enabled"` Metadata map[string]interface{} `json:"metadata"` } // SchemaValidation represents schema validation rules type SchemaValidation struct { ID string `json:"id"` SchemaID string `json:"schema_id"` Name string `json:"name"` Description string `json:"description"` Type string `json:"type"` Rules map[string]interface{} `json:"rules"` Enabled bool `json:"enabled"` Metadata map[string]interface{} `json:"metadata"` } // SchemaAdaptation represents schema adaptation from blue-build type SchemaAdaptation struct { ID string `json:"id"` OriginalID string `json:"original_id"` Name string `json:"name"` Description string `json:"description"` Type string `json:"type"` Changes []string `json:"changes"` Status string `json:"status"` Enabled bool `json:"enabled"` Metadata map[string]interface{} `json:"metadata"` } // NewDebianSchemaManager creates a new Debian schema manager func NewDebianSchemaManager(config *SchemaConfig, logger *logrus.Logger) *DebianSchemaManager { manager := &DebianSchemaManager{ logger: logger, config: config, schemas: make(map[string]DebianSchema), validations: make(map[string]SchemaValidation), adaptations: make(map[string]SchemaAdaptation), } // Initialize Debian schemas manager.initializeDebianSchemas() manager.initializeSchemaValidations() manager.initializeSchemaAdaptations() return manager } // initializeDebianSchemas initializes Debian-specific schemas func (dsm *DebianSchemaManager) initializeDebianSchemas() { // Recipe schema (Debian-adapted) dsm.schemas["recipe-v1"] = DebianSchema{ ID: "recipe-v1", Name: "Debian Recipe Schema v1", Description: "Schema for Debian atomic image recipes", Type: "recipe", Version: "1.0.0", Source: "debian-adapted", Adapted: true, Enabled: true, Metadata: map[string]interface{}{ "base_schema": "blue-build-recipe-v1", "target_os": "debian", }, } // Module schema (Debian-adapted) dsm.schemas["module-v1"] = DebianSchema{ ID: "module-v1", Name: "Debian Module Schema v1", Description: "Schema for Debian atomic image modules", Type: "module", Version: "1.0.0", Source: "debian-adapted", Adapted: true, Enabled: true, Metadata: map[string]interface{}{ "base_schema": "blue-build-module-v1", "target_os": "debian", }, } // Stage schema (Debian-adapted) dsm.schemas["stage-v1"] = DebianSchema{ ID: "stage-v1", Name: "Debian Stage Schema v1", Description: "Schema for Debian atomic image build stages", Type: "stage", Version: "1.0.0", Source: "debian-adapted", Adapted: true, Enabled: true, Metadata: map[string]interface{}{ "base_schema": "blue-build-stage-v1", "target_os": "debian", }, } // Debian-specific schemas dsm.schemas["debian-package-v1"] = DebianSchema{ ID: "debian-package-v1", Name: "Debian Package Schema v1", Description: "Schema for Debian package management", Type: "debian-package", Version: "1.0.0", Source: "debian-native", Adapted: false, Enabled: true, Metadata: map[string]interface{}{ "package_manager": "apt", "package_format": "deb", }, } dsm.schemas["debian-repository-v1"] = DebianSchema{ ID: "debian-repository-v1", Name: "Debian Repository Schema v1", Description: "Schema for Debian repository management", Type: "debian-repository", Version: "1.0.0", Source: "debian-native", Adapted: false, Enabled: true, Metadata: map[string]interface{}{ "repository_type": "deb", "key_format": "gpg", }, } } // initializeSchemaValidations initializes schema validation rules func (dsm *DebianSchemaManager) initializeSchemaValidations() { // Recipe validation dsm.validations["recipe-validation"] = SchemaValidation{ ID: "recipe-validation", SchemaID: "recipe-v1", Name: "Recipe Validation Rules", Description: "Validation rules for Debian recipe schemas", Type: "validation", Rules: map[string]interface{}{ "required_fields": []string{"name", "description", "base-image", "modules"}, "field_types": map[string]string{ "name": "string", "description": "string", "base-image": "string", "modules": "array", }, "constraints": map[string]interface{}{ "name_min_length": 3, "name_max_length": 50, }, }, Enabled: true, } // Module validation dsm.validations["module-validation"] = SchemaValidation{ ID: "module-validation", SchemaID: "module-v1", Name: "Module Validation Rules", Description: "Validation rules for Debian module schemas", Type: "validation", Rules: map[string]interface{}{ "required_fields": []string{"type"}, "field_types": map[string]string{ "type": "string", }, "valid_types": []string{"apt", "dpkg", "debian-release", "debian-kernel", "debian-initramfs"}, }, Enabled: true, } // Debian package validation dsm.validations["debian-package-validation"] = SchemaValidation{ ID: "debian-package-validation", SchemaID: "debian-package-v1", Name: "Debian Package Validation Rules", Description: "Validation rules for Debian package schemas", Type: "validation", Rules: map[string]interface{}{ "required_fields": []string{"packages"}, "field_types": map[string]string{ "packages": "array", }, "constraints": map[string]interface{}{ "package_name_format": "^[a-z0-9][a-z0-9+.-]*$", }, }, Enabled: true, } } // initializeSchemaAdaptations initializes adaptations from blue-build schemas func (dsm *DebianSchemaManager) initializeSchemaAdaptations() { // Recipe schema adaptation dsm.adaptations["recipe-adaptation"] = SchemaAdaptation{ ID: "recipe-adaptation", OriginalID: "blue-build-recipe-v1", Name: "Recipe Schema Adaptation", Description: "Adapt blue-build recipe schema for Debian", Type: "adaptation", Changes: []string{ "Replace Fedora base images with Debian base images", "Update platform definitions for Debian", "Adapt module types for Debian compatibility", "Update validation rules for Debian requirements", }, Status: "completed", Enabled: true, Metadata: map[string]interface{}{ "original_schema": "blue-build-recipe-v1", "target_schema": "debian-recipe-v1", "compatibility": "high", }, } // Module schema adaptation dsm.adaptations["module-adaptation"] = SchemaAdaptation{ ID: "module-adaptation", OriginalID: "blue-build-module-v1", Name: "Module Schema Adaptation", Description: "Adapt blue-build module schema for Debian", Type: "adaptation", Changes: []string{ "Replace DNF module with APT module", "Replace RPM-OSTree module with DPKG module", "Add Debian-specific module types", "Update validation rules for Debian modules", }, Status: "completed", Enabled: true, Metadata: map[string]interface{}{ "original_schema": "blue-build-module-v1", "target_schema": "debian-module-v1", "compatibility": "high", }, } // Stage schema adaptation dsm.adaptations["stage-adaptation"] = SchemaAdaptation{ ID: "stage-adaptation", OriginalID: "blue-build-stage-v1", Name: "Stage Schema Adaptation", Description: "Adapt blue-build stage schema for Debian", Type: "adaptation", Changes: []string{ "Update base image references for Debian", "Adapt package manager commands", "Update file paths for Debian structure", "Ensure Debian compatibility in build stages", }, Status: "completed", Enabled: true, Metadata: map[string]interface{}{ "original_schema": "blue-build-stage-v1", "target_schema": "debian-stage-v1", "compatibility": "high", }, } } // GetSchema returns a schema by ID func (dsm *DebianSchemaManager) GetSchema(schemaID string) (*DebianSchema, error) { dsm.mu.RLock() defer dsm.mu.RUnlock() schema, exists := dsm.schemas[schemaID] if !exists { return nil, fmt.Errorf("schema not found: %s", schemaID) } return &schema, nil } // GetValidation returns a validation by ID func (dsm *DebianSchemaManager) GetValidation(validationID string) (*SchemaValidation, error) { dsm.mu.RLock() defer dsm.mu.RUnlock() validation, exists := dsm.validations[validationID] if !exists { return nil, fmt.Errorf("validation not found: %s", validationID) } return &validation, nil } // GetAdaptation returns an adaptation by ID func (dsm *DebianSchemaManager) GetAdaptation(adaptationID string) (*SchemaAdaptation, error) { dsm.mu.RLock() defer dsm.mu.RUnlock() adaptation, exists := dsm.adaptations[adaptationID] if !exists { return nil, fmt.Errorf("adaptation not found: %s", adaptationID) } return &adaptation, nil } // ListSchemas returns all available schemas func (dsm *DebianSchemaManager) ListSchemas() []DebianSchema { dsm.mu.RLock() defer dsm.mu.RUnlock() schemas := make([]DebianSchema, 0, len(dsm.schemas)) for _, schema := range dsm.schemas { if schema.Enabled { schemas = append(schemas, schema) } } return schemas } // ListValidations returns all available validations func (dsm *DebianSchemaManager) ListValidations() []SchemaValidation { dsm.mu.RLock() defer dsm.mu.RUnlock() validations := make([]SchemaValidation, 0, len(dsm.validations)) for _, validation := range dsm.validations { if validation.Enabled { validations = append(validations, validation) } } return validations } // ListAdaptations returns all available adaptations func (dsm *DebianSchemaManager) ListAdaptations() []SchemaAdaptation { dsm.mu.RLock() defer dsm.mu.RUnlock() adaptations := make([]SchemaAdaptation, 0, len(dsm.adaptations)) for _, adaptation := range dsm.adaptations { if adaptation.Enabled { adaptations = append(adaptations, adaptation) } } return adaptations } // ValidateSchema validates a schema against its validation rules func (dsm *DebianSchemaManager) ValidateSchema(schemaID string, data map[string]interface{}) error { schema, err := dsm.GetSchema(schemaID) if err != nil { return err } // Get validation rules for this schema validation, err := dsm.getValidationForSchema(schemaID) if err != nil { return fmt.Errorf("no validation rules found for schema: %s", schemaID) } // Apply validation rules return dsm.applyValidationRules(validation, data) } // getValidationForSchema gets validation rules for a specific schema func (dsm *DebianSchemaManager) getValidationForSchema(schemaID string) (*SchemaValidation, error) { for _, validation := range dsm.validations { if validation.SchemaID == schemaID && validation.Enabled { return &validation, nil } } return nil, fmt.Errorf("validation not found for schema: %s", schemaID) } // applyValidationRules applies validation rules to data func (dsm *DebianSchemaManager) applyValidationRules(validation *SchemaValidation, data map[string]interface{}) error { rules := validation.Rules // Check required fields if requiredFields, ok := rules["required_fields"].([]string); ok { for _, field := range requiredFields { if _, exists := data[field]; !exists { return fmt.Errorf("required field missing: %s", field) } } } // Check field types if fieldTypes, ok := rules["field_types"].(map[string]string); ok { for field, expectedType := range fieldTypes { if value, exists := data[field]; exists { if err := dsm.validateFieldType(field, value, expectedType); err != nil { return err } } } } // Check constraints if constraints, ok := rules["constraints"].(map[string]interface{}); ok { for constraint, value := range constraints { if err := dsm.validateConstraint(constraint, data, value); err != nil { return err } } } return nil } // validateFieldType validates a field's type func (dsm *DebianSchemaManager) validateFieldType(field string, value interface{}, expectedType string) error { switch expectedType { case "string": if _, ok := value.(string); !ok { return fmt.Errorf("field %s must be a string", field) } case "array": if _, ok := value.([]interface{}); !ok { return fmt.Errorf("field %s must be an array", field) } case "integer": if _, ok := value.(int); !ok { return fmt.Errorf("field %s must be an integer", field) } case "boolean": if _, ok := value.(bool); !ok { return fmt.Errorf("field %s must be a boolean", field) } default: return fmt.Errorf("unknown field type: %s", expectedType) } return nil } // validateConstraint validates a constraint func (dsm *DebianSchemaManager) validateConstraint(constraint string, data map[string]interface{}, constraintValue interface{}) error { switch constraint { case "name_min_length": if name, ok := data["name"].(string); ok { if minLength, ok := constraintValue.(int); ok { if len(name) < minLength { return fmt.Errorf("name must be at least %d characters long", minLength) } } } case "name_max_length": if name, ok := data["name"].(string); ok { if maxLength, ok := constraintValue.(int); ok { if len(name) > maxLength { return fmt.Errorf("name must be at most %d characters long", maxLength) } } } } return nil } // CreateSchemaTemplate creates a template for a schema func (dsm *DebianSchemaManager) CreateSchemaTemplate(schemaID string) (map[string]interface{}, error) { schema, err := dsm.GetSchema(schemaID) if err != nil { return nil, err } // Create schema-specific templates switch schema.Type { case "recipe": return dsm.createRecipeTemplate() case "module": return dsm.createModuleTemplate() case "stage": return dsm.createStageTemplate() case "debian-package": return dsm.createDebianPackageTemplate() case "debian-repository": return dsm.createDebianRepositoryTemplate() default: return nil, fmt.Errorf("unknown schema type: %s", schema.Type) } } // createRecipeTemplate creates a recipe schema template func (dsm *DebianSchemaManager) createRecipeTemplate() map[string]interface{} { return map[string]interface{}{ "name": "debian-atomic-example", "description": "Example Debian atomic image", "base-image": "debian:bookworm-slim", "image-version": "latest", "platforms": []string{ "linux/amd64", "linux/arm64", }, "modules": []map[string]interface{}{ { "type": "debian-release", "release": "bookworm", }, { "type": "apt", "install": map[string]interface{}{ "packages": []string{ "curl", "wget", }, }, }, }, } } // createModuleTemplate creates a module schema template func (dsm *DebianSchemaManager) createModuleTemplate() map[string]interface{} { return map[string]interface{}{ "type": "apt", "repos": map[string]interface{}{ "files": []string{ "https://example.com/debian-repo.list", }, }, "install": map[string]interface{}{ "packages": []string{ "package1", "package2", }, }, } } // createStageTemplate creates a stage schema template func (dsm *DebianSchemaManager) createStageTemplate() map[string]interface{} { return map[string]interface{}{ "name": "debian-setup", "base-image": "debian:bookworm-slim", "commands": []string{ "apt update", "apt install -y curl wget", }, } } // createDebianPackageTemplate creates a Debian package schema template func (dsm *DebianSchemaManager) createDebianPackageTemplate() map[string]interface{} { return map[string]interface{}{ "type": "debian-package", "packages": []string{ "curl", "wget", "git", }, "repositories": []string{ "main", "contrib", "non-free", }, } } // createDebianRepositoryTemplate creates a Debian repository schema template func (dsm *DebianSchemaManager) createDebianRepositoryTemplate() map[string]interface{} { return map[string]interface{}{ "type": "debian-repository", "name": "example-repo", "url": "https://example.com/debian", "distribution": "bookworm", "components": []string{ "main", "contrib", }, "key": "https://example.com/debian-repo.gpg", } }