mirror of
https://github.com/siderolabs/omni.git
synced 2025-08-06 17:46:59 +02:00
Some checks failed
default / default (push) Has been cancelled
default / e2e-backups (push) Has been cancelled
default / e2e-forced-removal (push) Has been cancelled
default / e2e-omni-upgrade (push) Has been cancelled
default / e2e-scaling (push) Has been cancelled
default / e2e-short (push) Has been cancelled
default / e2e-short-secureboot (push) Has been cancelled
default / e2e-templates (push) Has been cancelled
default / e2e-upgrades (push) Has been cancelled
default / e2e-workload-proxy (push) Has been cancelled
- Bump some deps, namely cosi-runtime and Talos machinery. - Update `auditState` to implement the new methods in COSI's `state.State`. - Bump default Talos and Kubernetes versions to their latest. - Rekres, which brings Go 1.24.5. Also update it in go.mod files. - Fix linter errors coming from new linters. Signed-off-by: Utku Ozdemir <utku.ozdemir@siderolabs.com>
141 lines
4.0 KiB
Go
141 lines
4.0 KiB
Go
// Copyright (c) 2025 Sidero Labs, Inc.
|
|
//
|
|
// Use of this software is governed by the Business Source License
|
|
// included in the LICENSE file.
|
|
|
|
// Package imagefactory implements image factory operations, enriching them with the Omni state.
|
|
package imagefactory
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/url"
|
|
"time"
|
|
|
|
"github.com/cosi-project/runtime/pkg/safe"
|
|
"github.com/cosi-project/runtime/pkg/state"
|
|
"github.com/siderolabs/image-factory/pkg/client"
|
|
"github.com/siderolabs/image-factory/pkg/schematic"
|
|
|
|
"github.com/siderolabs/omni/client/pkg/omni/resources"
|
|
"github.com/siderolabs/omni/client/pkg/omni/resources/omni"
|
|
"github.com/siderolabs/omni/internal/pkg/auth/actor"
|
|
)
|
|
|
|
// Client is the image factory client.
|
|
type Client struct {
|
|
*client.Client
|
|
|
|
state state.State
|
|
host string
|
|
}
|
|
|
|
// NewClient creates a new image factory client.
|
|
func NewClient(omniState state.State, imageFactoryBaseURL string) (*Client, error) {
|
|
factoryClient, err := client.New(imageFactoryBaseURL)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
baseURL, err := url.Parse(imageFactoryBaseURL)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse image factory base URL %q: %w", imageFactoryBaseURL, err)
|
|
}
|
|
|
|
return &Client{
|
|
state: omniState,
|
|
Client: factoryClient,
|
|
host: baseURL.Host,
|
|
}, nil
|
|
}
|
|
|
|
// Host returns the host of the image factory client.
|
|
func (cli *Client) Host() string {
|
|
if cli == nil {
|
|
return ""
|
|
}
|
|
|
|
return cli.host
|
|
}
|
|
|
|
// EnsuredSchematic contains information on the ensured schematics.
|
|
type EnsuredSchematic struct {
|
|
// FullID is the ID of the full schematic - with the whole content of the schematic.Schematic, i.e., the extra kernel arguments, META values, and system extensions.
|
|
FullID string
|
|
|
|
// PlainID is the ID of the plain schematic - with only the system extensions.
|
|
PlainID string
|
|
}
|
|
|
|
// EnsureSchematic ensures that the given schematic exists in the image factory.
|
|
//
|
|
// It ensures two schematics: one with the full content of the schematic.Schematic, and another with only the system extensions.
|
|
//
|
|
// We do not call the image factory for the schematics that are already known to (cached by) Omni.
|
|
func (cli *Client) EnsureSchematic(ctx context.Context, inputSchematic schematic.Schematic) (EnsuredSchematic, error) {
|
|
fullSchematicID, err := cli.ensureSingleSchematic(ctx, inputSchematic)
|
|
if err != nil {
|
|
return EnsuredSchematic{}, fmt.Errorf("failed to ensure single schematic: %w", err)
|
|
}
|
|
|
|
plainSchematic := schematic.Schematic{
|
|
Customization: schematic.Customization{
|
|
SystemExtensions: schematic.SystemExtensions{
|
|
OfficialExtensions: inputSchematic.Customization.SystemExtensions.OfficialExtensions,
|
|
},
|
|
},
|
|
}
|
|
|
|
plainSchematicID, err := plainSchematic.ID()
|
|
if err != nil {
|
|
return EnsuredSchematic{}, fmt.Errorf("failed to generate plain schematic ID: %w", err)
|
|
}
|
|
|
|
if plainSchematicID != fullSchematicID {
|
|
plainSchematicID, err = cli.ensureSingleSchematic(ctx, plainSchematic)
|
|
if err != nil {
|
|
return EnsuredSchematic{}, fmt.Errorf("failed to ensure plain schematic: %w", err)
|
|
}
|
|
}
|
|
|
|
return EnsuredSchematic{
|
|
FullID: fullSchematicID,
|
|
PlainID: plainSchematicID,
|
|
}, nil
|
|
}
|
|
|
|
func (cli *Client) ensureSingleSchematic(ctx context.Context, schematic schematic.Schematic) (string, error) {
|
|
schematicID, err := schematic.ID()
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to generate schematic ID: %w", err)
|
|
}
|
|
|
|
schematicResource := omni.NewSchematic(
|
|
resources.DefaultNamespace, schematicID,
|
|
)
|
|
|
|
res, err := safe.StateGetByID[*omni.Schematic](ctx, cli.state, schematicID)
|
|
if err != nil && !state.IsNotFoundError(err) {
|
|
return "", err
|
|
}
|
|
|
|
if res != nil {
|
|
return schematicID, nil
|
|
}
|
|
|
|
callCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
|
defer cancel()
|
|
|
|
if _, err = cli.SchematicCreate(callCtx, schematic); err != nil {
|
|
return "", fmt.Errorf("failed to create schematic: %w", err)
|
|
}
|
|
|
|
ctx = actor.MarkContextAsInternalActor(ctx)
|
|
|
|
if err = cli.state.Create(ctx, schematicResource); err != nil && !state.IsConflictError(err) {
|
|
return "", err
|
|
}
|
|
|
|
return schematicID, nil
|
|
}
|