296 lines
8.8 KiB
Go
296 lines
8.8 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
// RegistryConfig represents the configuration for a container registry
|
|
type RegistryConfig struct {
|
|
BaseURL string `yaml:"base_url"`
|
|
Namespace string `yaml:"namespace"`
|
|
AuthRequired bool `yaml:"auth_required"`
|
|
Description string `yaml:"description"`
|
|
}
|
|
|
|
// ContainerTemplates defines naming templates for containers
|
|
type ContainerTemplates struct {
|
|
BootcBase string `yaml:"bootc_base"`
|
|
BootcBuilder string `yaml:"bootc_builder"`
|
|
}
|
|
|
|
// VersionMappings defines version mappings for different distributions
|
|
type VersionMappings struct {
|
|
Debian map[string]string `yaml:"debian"`
|
|
}
|
|
|
|
// DefaultSettings contains default configuration values
|
|
type DefaultSettings struct {
|
|
DebianVersion string `yaml:"debian_version"`
|
|
ImageTypes []string `yaml:"image_types"`
|
|
OutputDir string `yaml:"output_dir"`
|
|
RootfsType string `yaml:"rootfs_type"`
|
|
Architecture string `yaml:"architecture"`
|
|
}
|
|
|
|
// BuildSettings contains build-specific configuration
|
|
type BuildSettings struct {
|
|
ContainerSizeMultiplier int `yaml:"container_size_multiplier"`
|
|
MinRootfsSizeGB int `yaml:"min_rootfs_size_gb"`
|
|
DefaultKernelOptions []string `yaml:"default_kernel_options"`
|
|
ExperimentalFeatures map[string]bool `yaml:"experimental_features"`
|
|
}
|
|
|
|
// RepositoryConfig defines APT repository configuration
|
|
type RepositoryConfig struct {
|
|
Debian map[string]string `yaml:"debian"`
|
|
DebianForge struct {
|
|
BaseURL string `yaml:"base_url"`
|
|
Components []string `yaml:"components"`
|
|
} `yaml:"debian_forge"`
|
|
Priorities map[string]int `yaml:"priorities"`
|
|
}
|
|
|
|
// CloudConfig contains cloud upload settings
|
|
type CloudConfig struct {
|
|
AWS struct {
|
|
DefaultRegion string `yaml:"default_region"`
|
|
BucketTemplate string `yaml:"bucket_template"`
|
|
} `yaml:"aws"`
|
|
}
|
|
|
|
// LoggingConfig defines logging configuration
|
|
type LoggingConfig struct {
|
|
Level string `yaml:"level"`
|
|
Format string `yaml:"format"`
|
|
Verbose bool `yaml:"verbose"`
|
|
}
|
|
|
|
// SecurityConfig defines security settings
|
|
type SecurityConfig struct {
|
|
RequireHTTPS bool `yaml:"require_https"`
|
|
VerifyTLS bool `yaml:"verify_tls"`
|
|
AllowInsecure bool `yaml:"allow_insecure"`
|
|
}
|
|
|
|
// Config represents the complete configuration structure
|
|
type Config struct {
|
|
Registries map[string]RegistryConfig `yaml:"registries"`
|
|
ActiveRegistry string `yaml:"active_registry"`
|
|
Containers ContainerTemplates `yaml:"containers"`
|
|
Versions VersionMappings `yaml:"versions"`
|
|
Defaults DefaultSettings `yaml:"defaults"`
|
|
Build BuildSettings `yaml:"build"`
|
|
Repositories RepositoryConfig `yaml:"repositories"`
|
|
Cloud CloudConfig `yaml:"cloud"`
|
|
Logging LoggingConfig `yaml:"logging"`
|
|
Security SecurityConfig `yaml:"security"`
|
|
}
|
|
|
|
// LoadConfig loads configuration from the specified file path
|
|
func LoadConfig(configPath string) (*Config, error) {
|
|
if configPath == "" {
|
|
// Try to find config in standard locations
|
|
configPath = findConfigFile()
|
|
}
|
|
|
|
if configPath == "" {
|
|
return nil, fmt.Errorf("no configuration file found")
|
|
}
|
|
|
|
data, err := os.ReadFile(configPath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to read config file %s: %w", configPath, err)
|
|
}
|
|
|
|
var config Config
|
|
if err := yaml.Unmarshal(data, &config); err != nil {
|
|
return nil, fmt.Errorf("failed to parse config file %s: %w", configPath, err)
|
|
}
|
|
|
|
// Validate configuration
|
|
if err := config.Validate(); err != nil {
|
|
return nil, fmt.Errorf("invalid configuration: %w", err)
|
|
}
|
|
|
|
return &config, nil
|
|
}
|
|
|
|
// findConfigFile searches for configuration file in standard locations
|
|
func findConfigFile() string {
|
|
// Search paths in order of preference
|
|
searchPaths := []string{
|
|
"./.config/registry.yaml",
|
|
"./registry.yaml",
|
|
"~/.config/debian-bootc-image-builder/registry.yaml",
|
|
"/etc/debian-bootc-image-builder/registry.yaml",
|
|
}
|
|
|
|
for _, path := range searchPaths {
|
|
if strings.HasPrefix(path, "~/") {
|
|
homeDir, err := os.UserHomeDir()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
path = filepath.Join(homeDir, path[2:])
|
|
}
|
|
|
|
if _, err := os.Stat(path); err == nil {
|
|
return path
|
|
}
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
// Validate checks if the configuration is valid
|
|
func (c *Config) Validate() error {
|
|
// Check if active registry exists
|
|
if c.ActiveRegistry == "" {
|
|
return fmt.Errorf("active_registry is required")
|
|
}
|
|
|
|
if _, exists := c.Registries[c.ActiveRegistry]; !exists {
|
|
return fmt.Errorf("active registry '%s' not found in registries", c.ActiveRegistry)
|
|
}
|
|
|
|
// Validate registry configurations
|
|
for name, registry := range c.Registries {
|
|
if registry.BaseURL == "" {
|
|
return fmt.Errorf("registry '%s' missing base_url", name)
|
|
}
|
|
if registry.Namespace == "" {
|
|
return fmt.Errorf("registry '%s' missing namespace", name)
|
|
}
|
|
}
|
|
|
|
// Validate container templates
|
|
if c.Containers.BootcBase == "" {
|
|
return fmt.Errorf("bootc_base container template is required")
|
|
}
|
|
if c.Containers.BootcBuilder == "" {
|
|
return fmt.Errorf("bootc_builder container template is required")
|
|
}
|
|
|
|
// Validate version mappings
|
|
if len(c.Versions.Debian) == 0 {
|
|
return fmt.Errorf("debian version mappings are required")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetActiveRegistry returns the currently active registry configuration
|
|
func (c *Config) GetActiveRegistry() (*RegistryConfig, error) {
|
|
registry, exists := c.Registries[c.ActiveRegistry]
|
|
if !exists {
|
|
return nil, fmt.Errorf("active registry '%s' not found", c.ActiveRegistry)
|
|
}
|
|
return ®istry, nil
|
|
}
|
|
|
|
// GetContainerName generates a container name using the specified template
|
|
func (c *Config) GetContainerName(template string, variables map[string]string) (string, error) {
|
|
registry, err := c.GetActiveRegistry()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
// Add default variables
|
|
if variables == nil {
|
|
variables = make(map[string]string)
|
|
}
|
|
variables["registry"] = registry.BaseURL
|
|
variables["namespace"] = registry.Namespace
|
|
|
|
// Replace variables in template
|
|
result := template
|
|
for key, value := range variables {
|
|
placeholder := "{" + key + "}"
|
|
result = strings.ReplaceAll(result, placeholder, value)
|
|
}
|
|
|
|
// Check for unresolved variables
|
|
if strings.Contains(result, "{") {
|
|
return "", fmt.Errorf("unresolved variables in template: %s", result)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// GetBootcBaseName generates the bootc base container name
|
|
func (c *Config) GetBootcBaseName(version string) (string, error) {
|
|
variables := map[string]string{
|
|
"version": version,
|
|
}
|
|
return c.GetContainerName(c.Containers.BootcBase, variables)
|
|
}
|
|
|
|
// GetBootcBuilderName generates the bootc builder container name
|
|
func (c *Config) GetBootcBuilderName(tag string) (string, error) {
|
|
variables := map[string]string{
|
|
"tag": tag,
|
|
}
|
|
return c.GetContainerName(c.Containers.BootcBuilder, variables)
|
|
}
|
|
|
|
// GetDebianVersion returns the actual Debian version for a given version name
|
|
func (c *Config) GetDebianVersion(versionName string) (string, error) {
|
|
if version, exists := c.Versions.Debian[versionName]; exists {
|
|
return version, nil
|
|
}
|
|
return "", fmt.Errorf("unknown Debian version: %s", versionName)
|
|
}
|
|
|
|
// GetDefaultDebianVersion returns the default Debian version
|
|
func (c *Config) GetDefaultDebianVersion() (string, error) {
|
|
return c.GetDebianVersion(c.Defaults.DebianVersion)
|
|
}
|
|
|
|
// IsExperimentalFeatureEnabled checks if an experimental feature is enabled
|
|
func (c *Config) IsExperimentalFeatureEnabled(feature string) bool {
|
|
if enabled, exists := c.Build.ExperimentalFeatures[feature]; exists {
|
|
return enabled
|
|
}
|
|
return false
|
|
}
|
|
|
|
// GetRepositoryURL returns the URL for a specific repository
|
|
func (c *Config) GetRepositoryURL(repoName string) (string, error) {
|
|
if url, exists := c.Repositories.Debian[repoName]; exists {
|
|
return url, nil
|
|
}
|
|
return "", fmt.Errorf("unknown repository: %s", repoName)
|
|
}
|
|
|
|
// GetRepositoryPriority returns the priority for a specific repository
|
|
func (c *Config) GetRepositoryPriority(repoName string) int {
|
|
if priority, exists := c.Repositories.Priorities[repoName]; exists {
|
|
return priority
|
|
}
|
|
return 500 // default priority
|
|
}
|
|
|
|
// GetDebianForgeRepository returns the debian-forge repository configuration
|
|
func (c *Config) GetDebianForgeRepository() (string, []string) {
|
|
return c.Repositories.DebianForge.BaseURL, c.Repositories.DebianForge.Components
|
|
}
|
|
|
|
// GetDefaultKernelOptions returns the default kernel options
|
|
func (c *Config) GetDefaultKernelOptions() []string {
|
|
return c.Build.DefaultKernelOptions
|
|
}
|
|
|
|
// GetContainerSizeMultiplier returns the container size multiplier
|
|
func (c *Config) GetContainerSizeMultiplier() int {
|
|
return c.Build.ContainerSizeMultiplier
|
|
}
|
|
|
|
// GetMinRootfsSizeGB returns the minimum root filesystem size in GB
|
|
func (c *Config) GetMinRootfsSizeGB() int {
|
|
return c.Build.MinRootfsSizeGB
|
|
}
|