mirror of
https://github.com/AlchemillaHQ/Sylve.git
synced 2026-06-16 01:06:35 +03:00
basic: init: allow no-pool setup, zfs: pool: create base fs on creation
This commit is contained in:
@@ -11,6 +11,6 @@ package systemServiceInterfaces
|
||||
import "github.com/alchemillahq/sylve/internal/db/models"
|
||||
|
||||
type InitializeRequest struct {
|
||||
Pools []string `json:"pools" binding:"required"`
|
||||
Pools []string `json:"pools"`
|
||||
Services []models.AvailableService `json:"services" binding:"required"`
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/alchemillahq/gzfs"
|
||||
"github.com/alchemillahq/sylve/internal/db/models"
|
||||
@@ -56,10 +55,6 @@ func (s *Service) Initialize(ctx context.Context, req systemServiceInterfaces.In
|
||||
return []error{fmt.Errorf("system_already_initialized")}
|
||||
}
|
||||
|
||||
if len(req.Pools) == 0 {
|
||||
return []error{fmt.Errorf("no_pools_provided")}
|
||||
}
|
||||
|
||||
var newSets []*gzfs.Dataset
|
||||
|
||||
for _, poolName := range req.Pools {
|
||||
@@ -72,32 +67,16 @@ func (s *Service) Initialize(ctx context.Context, req systemServiceInterfaces.In
|
||||
return []error{fmt.Errorf("pool_not_found_%s", poolName)}
|
||||
}
|
||||
|
||||
toCreate := []string{"sylve", "sylve/virtual-machines", "sylve/jails"}
|
||||
for _, dataset := range toCreate {
|
||||
fullDatasetName := fmt.Sprintf("%s/%s", pool.Name, dataset)
|
||||
|
||||
sets, err := s.GZFS.ZFS.List(ctx, false, fullDatasetName)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "dataset does not exist") {
|
||||
return []error{fmt.Errorf("error_checking_dataset_%s: %w", fullDatasetName, err)}
|
||||
}
|
||||
created, err := s.ensureSylveDatasetsOnPool(ctx, pool.Name)
|
||||
if err != nil {
|
||||
for i := len(newSets) - 1; i >= 0; i-- {
|
||||
newSets[i].Destroy(ctx, true, false)
|
||||
}
|
||||
|
||||
exists := len(sets) > 0
|
||||
props := map[string]string{}
|
||||
|
||||
if !exists {
|
||||
created, err := s.GZFS.ZFS.CreateFilesystem(ctx, fullDatasetName, props)
|
||||
if err != nil {
|
||||
for i := len(newSets) - 1; i >= 0; i-- {
|
||||
newSets[i].Destroy(ctx, true, false)
|
||||
}
|
||||
|
||||
return []error{fmt.Errorf("error_creating_dataset_%s: %w", fullDatasetName, err)}
|
||||
}
|
||||
newSets = append(newSets, created)
|
||||
}
|
||||
return []error{err}
|
||||
}
|
||||
|
||||
newSets = append(newSets, created...)
|
||||
}
|
||||
|
||||
var errs []error
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// 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"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/alchemillahq/gzfs"
|
||||
)
|
||||
|
||||
var requiredSylveDatasets = []string{
|
||||
"sylve",
|
||||
"sylve/virtual-machines",
|
||||
"sylve/jails",
|
||||
}
|
||||
|
||||
func (s *Service) ensureSylveDatasetsOnPool(ctx context.Context, poolName string) ([]*gzfs.Dataset, error) {
|
||||
var created []*gzfs.Dataset
|
||||
|
||||
for _, dataset := range requiredSylveDatasets {
|
||||
fullDatasetName := fmt.Sprintf("%s/%s", poolName, dataset)
|
||||
found, err := s.GZFS.ZFS.Get(ctx, fullDatasetName, false)
|
||||
if err != nil && !strings.Contains(strings.ToLower(err.Error()), "does not exist") {
|
||||
return nil, fmt.Errorf("error_checking_dataset_%s: %w", fullDatasetName, err)
|
||||
}
|
||||
|
||||
if found != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
newDataset, err := s.GZFS.ZFS.CreateFilesystem(ctx, fullDatasetName, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error_creating_dataset_%s: %w", fullDatasetName, err)
|
||||
}
|
||||
|
||||
created = append(created, newDataset)
|
||||
}
|
||||
|
||||
return created, nil
|
||||
}
|
||||
@@ -13,7 +13,6 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/alchemillahq/gzfs"
|
||||
"github.com/alchemillahq/sylve/internal/db/models"
|
||||
jailModels "github.com/alchemillahq/sylve/internal/db/models/jail"
|
||||
vmModels "github.com/alchemillahq/sylve/internal/db/models/vm"
|
||||
@@ -99,24 +98,22 @@ func (s *Service) AddUsablePools(ctx context.Context, pools []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
toCreate := []string{"sylve", "sylve/virtual-machines", "sylve/jails"}
|
||||
var newSets []*gzfs.Dataset
|
||||
var newSets []string
|
||||
|
||||
for _, poolName := range pools {
|
||||
for _, dataset := range toCreate {
|
||||
datasetPath := fmt.Sprintf("%s/%s", poolName, dataset)
|
||||
_, err := s.GZFS.ZFS.Get(ctx, datasetPath, false)
|
||||
if err != nil {
|
||||
created, err := s.GZFS.ZFS.CreateFilesystem(ctx, datasetPath, nil)
|
||||
if err != nil {
|
||||
for i := len(newSets) - 1; i >= 0; i-- {
|
||||
newSets[i].Destroy(ctx, true, false)
|
||||
}
|
||||
return fmt.Errorf("failed_to_create_dataset_%s: %w", datasetPath, err)
|
||||
created, err := s.ensureSylveDatasetsOnPool(ctx, poolName)
|
||||
if err != nil {
|
||||
for i := len(newSets) - 1; i >= 0; i-- {
|
||||
if ds, getErr := s.GZFS.ZFS.Get(ctx, newSets[i], false); getErr == nil && ds != nil {
|
||||
_ = ds.Destroy(ctx, true, false)
|
||||
}
|
||||
|
||||
newSets = append(newSets, created)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
for _, ds := range created {
|
||||
newSets = append(newSets, ds.Name)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -128,12 +128,18 @@ func (s *Service) CreatePool(ctx context.Context, req zfsServiceInterfaces.Creat
|
||||
return fmt.Errorf("zpool_create_failed: %v", err)
|
||||
}
|
||||
|
||||
if err := s.ensureSylveDatasetsOnPool(ctx, req.Name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var basicSettings models.BasicSettings
|
||||
if err := s.DB.First(&basicSettings).Error; err != nil {
|
||||
return fmt.Errorf("failed_to_get_basic_settings: %v", err)
|
||||
}
|
||||
|
||||
basicSettings.Pools = append(basicSettings.Pools, req.Name)
|
||||
if !slices.Contains(basicSettings.Pools, req.Name) {
|
||||
basicSettings.Pools = append(basicSettings.Pools, req.Name)
|
||||
}
|
||||
|
||||
if err := s.DB.Save(&basicSettings).Error; err != nil {
|
||||
return fmt.Errorf("failed_to_update_basic_settings: %v", err)
|
||||
@@ -142,6 +148,32 @@ func (s *Service) CreatePool(ctx context.Context, req zfsServiceInterfaces.Creat
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) ensureSylveDatasetsOnPool(ctx context.Context, poolName string) error {
|
||||
requiredDatasets := []string{
|
||||
"sylve",
|
||||
"sylve/virtual-machines",
|
||||
"sylve/jails",
|
||||
}
|
||||
|
||||
for _, dataset := range requiredDatasets {
|
||||
fullDatasetName := fmt.Sprintf("%s/%s", poolName, dataset)
|
||||
found, err := s.GZFS.ZFS.Get(ctx, fullDatasetName, false)
|
||||
if err != nil && !strings.Contains(strings.ToLower(err.Error()), "does not exist") {
|
||||
return fmt.Errorf("failed_to_check_dataset_%s: %w", fullDatasetName, err)
|
||||
}
|
||||
|
||||
if found != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, err := s.GZFS.ZFS.CreateFilesystem(ctx, fullDatasetName, nil); err != nil {
|
||||
return fmt.Errorf("failed_to_create_dataset_%s: %w", fullDatasetName, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) EditPool(ctx context.Context, name string, props map[string]string, spares []string) error {
|
||||
s.syncMutex.Lock()
|
||||
defer s.syncMutex.Unlock()
|
||||
|
||||
Reference in New Issue
Block a user