Files
Sylve/internal/services/system/basic.go
T
2026-03-26 21:41:05 +05:30

159 lines
3.9 KiB
Go

// SPDX-License-Identifier: BSD-2-Clause
//
// Copyright (c) 2025 The FreeBSD Foundation.
//
// This software was developed by Hayzam Sherif <hayzam@alchemilla.io>
// of Alchemilla Ventures Pvt. Ltd. <hello@alchemilla.io>,
// under sponsorship from the FreeBSD Foundation.
package system
import (
"context"
"errors"
"fmt"
"github.com/alchemillahq/gzfs"
"github.com/alchemillahq/sylve/internal/db/models"
systemServiceInterfaces "github.com/alchemillahq/sylve/internal/interfaces/services/system"
"github.com/alchemillahq/sylve/internal/logger"
"gorm.io/gorm"
)
func (s *Service) GetUsablePools(ctx context.Context) ([]*gzfs.ZPool, error) {
var basicSettings models.BasicSettings
var pools []*gzfs.ZPool
if err := s.DB.First(&basicSettings).Error; err != nil {
return pools, err
}
for _, name := range basicSettings.Pools {
pool, err := s.GZFS.Zpool.Get(ctx, name)
if err != nil {
return pools, err
}
pools = append(pools, pool)
}
return pools, nil
}
func (s *Service) Initialize(ctx context.Context, req systemServiceInterfaces.InitializeRequest) []error {
var basicSettings models.BasicSettings
err := s.DB.First(&basicSettings).Error
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return []error{err}
}
basicSettings = models.BasicSettings{}
}
if basicSettings.Initialized {
return []error{fmt.Errorf("system_already_initialized")}
}
var newSets []*gzfs.Dataset
for _, poolName := range req.Pools {
pool, err := s.GZFS.Zpool.Get(ctx, poolName)
if err != nil {
return []error{fmt.Errorf("invalid_pool_%s: %w", poolName, err)}
}
if pool == nil {
return []error{fmt.Errorf("pool_not_found_%s", poolName)}
}
created, err := s.ensureSylveDatasetsOnPool(ctx, pool.Name)
if err != nil {
for i := len(newSets) - 1; i >= 0; i-- {
newSets[i].Destroy(ctx, true, false)
}
return []error{err}
}
newSets = append(newSets, created...)
}
var errs []error
if !s.IsSupportedArch() {
errs = append(errs, fmt.Errorf("unsupported_architecture"))
}
for _, service := range req.Services {
if service == models.Virtualization {
if err := s.CheckVirtualization(); err != nil {
errs = append(errs, fmt.Errorf("virtualization_check_failed: %w", err))
}
}
if service == models.Jails {
if err := s.CheckJails(); err != nil {
if err.Error() == "jails_racct_not_enabled" {
updated, updateErr := s.ensureJailRacctEnabledAtBoot()
if updateErr != nil {
errs = append(errs, fmt.Errorf("jails_check_failed: jails_racct_autoconfig_failed: %w", updateErr))
continue
}
if updated {
logger.L.Warn().Msg("jails_racct_auto_configured_in_loader_conf_reboot_required")
} else {
logger.L.Warn().Msg("jails_racct_not_enabled_runtime_loader_conf_already_set_reboot_required")
}
continue
}
errs = append(errs, fmt.Errorf("jails_check_failed: %w", err))
}
}
if service == models.DHCPServer {
if err := s.CheckDHCPServer(); err != nil {
errs = append(errs, fmt.Errorf("dhcp_server_check_failed: %w", err))
}
}
if service == models.SambaServer {
if err := s.CheckSambaServer(); err != nil {
errs = append(errs, fmt.Errorf("samba_server_check_failed: %w", err))
}
}
}
if len(errs) > 0 {
return errs
}
basicSettings.Pools = req.Pools
basicSettings.Services = req.Services
basicSettings.Initialized = true
basicSettings.Restarted = false
if err := s.DB.Create(&basicSettings).Error; err != nil {
return []error{fmt.Errorf("failed_to_create_basic_settings: %w", err)}
}
return nil
}
func (s *Service) GetBasicSettings() (models.BasicSettings, error) {
var settings models.BasicSettings
if err := s.DB.First(&settings).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return settings, fmt.Errorf("basic_settings_not_found")
}
return settings, fmt.Errorf("failed_to_fetch_basic_settings: %v", err)
}
return settings, nil
}