mirror of
https://github.com/siderolabs/talos.git
synced 2025-08-21 22:51:13 +02:00
Firecracker launches tries to open VM disk image before every boot, parses partition table, finds boot partition, tries to read it as FAT32 filesystem, extracts uncompressed kernel from `bzImage` (firecracker doesn't support `bzImage` yet), extracts initramfs and passes it to firecracker binary. This flow allows for extended tests, e.g. testing installer, upgrade and downgrade tests, etc. Bootloader emulation is disabled by default for now, can be enabled via `--with-bootloader-emulation` flag to `osctl cluster create`. Signed-off-by: Andrey Smirnov <smirnov.andrey@gmail.com>
109 lines
2.9 KiB
Go
109 lines
2.9 KiB
Go
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
package firecracker
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"gopkg.in/yaml.v2"
|
|
|
|
"github.com/talos-systems/talos/internal/pkg/provision"
|
|
)
|
|
|
|
// Create Talos cluster as a set of firecracker micro-VMs.
|
|
//
|
|
//nolint: gocyclo
|
|
func (p *provisioner) Create(ctx context.Context, request provision.ClusterRequest, opts ...provision.Option) (provision.Cluster, error) {
|
|
options := provision.DefaultOptions()
|
|
|
|
for _, opt := range opts {
|
|
if err := opt(&options); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
state := &state{
|
|
ProvisionerName: "firecracker",
|
|
statePath: filepath.Join(request.StateDirectory, request.Name),
|
|
}
|
|
|
|
fmt.Fprintf(options.LogWriter, "creating state directory in %q\n", state.statePath)
|
|
|
|
_, err := os.Stat(state.statePath)
|
|
if err == nil {
|
|
return nil, fmt.Errorf(
|
|
"state directory %q already exists, is the cluster %q already running? remove cluster state with osctl cluster destroy",
|
|
state.statePath,
|
|
request.Name,
|
|
)
|
|
}
|
|
|
|
if !os.IsNotExist(err) {
|
|
return nil, fmt.Errorf("error checking state directory: %w", err)
|
|
}
|
|
|
|
if err = os.MkdirAll(state.statePath, os.ModePerm); err != nil {
|
|
return nil, fmt.Errorf("error creating state directory: %w", err)
|
|
}
|
|
|
|
fmt.Fprintln(options.LogWriter, "creating network", request.Network.Name)
|
|
|
|
if err = p.createNetwork(ctx, state, request.Network); err != nil {
|
|
return nil, fmt.Errorf("unable to provision CNI network: %w", err)
|
|
}
|
|
|
|
fmt.Fprintln(options.LogWriter, "creating load balancer")
|
|
|
|
if err = p.createLoadBalancer(state, request); err != nil {
|
|
return nil, fmt.Errorf("error creating loadbalancer: %w", err)
|
|
}
|
|
|
|
var nodeInfo []provision.NodeInfo
|
|
|
|
fmt.Fprintln(options.LogWriter, "creating master nodes")
|
|
|
|
if nodeInfo, err = p.createNodes(state, request, request.Nodes.MasterNodes(), &options); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
fmt.Fprintln(options.LogWriter, "creating worker nodes")
|
|
|
|
var workerNodeInfo []provision.NodeInfo
|
|
|
|
if workerNodeInfo, err = p.createNodes(state, request, request.Nodes.WorkerNodes(), &options); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
nodeInfo = append(nodeInfo, workerNodeInfo...)
|
|
|
|
state.ClusterInfo = provision.ClusterInfo{
|
|
ClusterName: request.Name,
|
|
Network: provision.NetworkInfo{
|
|
Name: request.Network.Name,
|
|
CIDR: request.Network.CIDR,
|
|
GatewayAddr: request.Network.GatewayAddr,
|
|
MTU: request.Network.MTU,
|
|
},
|
|
Nodes: nodeInfo,
|
|
}
|
|
|
|
// save state
|
|
stateFile, err := os.Create(filepath.Join(state.statePath, stateFileName))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defer stateFile.Close() //nolint: errcheck
|
|
|
|
if err = yaml.NewEncoder(stateFile).Encode(&state); err != nil {
|
|
return nil, fmt.Errorf("error marshaling state: %w", err)
|
|
}
|
|
|
|
return state, stateFile.Close()
|
|
}
|