chore: initial extraction of base vm provisioner
Created base provisioner struct for all VM based provisioners. Moved state.go and reflect.go to the common module. Signed-off-by: Artem Chernyshev <artem.0xD2@gmail.com>
This commit is contained in:
parent
8dd81b0693
commit
19cd46459b
internal/pkg/provision/providers
@ -13,12 +13,13 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/talos-systems/talos/internal/pkg/provision"
|
||||
"github.com/talos-systems/talos/internal/pkg/provision/providers/vm"
|
||||
"github.com/talos-systems/talos/internal/pkg/tail"
|
||||
)
|
||||
|
||||
// CrashDump produces debug information to help with debugging failures.
|
||||
func (p *provisioner) CrashDump(ctx context.Context, cluster provision.Cluster, out io.Writer) {
|
||||
state, ok := cluster.(*state)
|
||||
state, ok := cluster.(*vm.State)
|
||||
if !ok {
|
||||
fmt.Fprintf(out, "error inspecting firecracker state, %#+v\n", cluster)
|
||||
return
|
||||
|
@ -7,12 +7,10 @@ package firecracker
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/talos-systems/talos/internal/pkg/provision"
|
||||
"github.com/talos-systems/talos/internal/pkg/provision/providers/vm"
|
||||
)
|
||||
|
||||
// Create Talos cluster as a set of firecracker micro-VMs.
|
||||
@ -27,28 +25,17 @@ func (p *provisioner) Create(ctx context.Context, request provision.ClusterReque
|
||||
}
|
||||
}
|
||||
|
||||
state := &state{
|
||||
ProvisionerName: "firecracker",
|
||||
statePath: filepath.Join(request.StateDirectory, request.Name),
|
||||
}
|
||||
statePath := filepath.Join(request.StateDirectory, request.Name)
|
||||
|
||||
fmt.Fprintf(options.LogWriter, "creating state directory in %q\n", state.statePath)
|
||||
fmt.Fprintf(options.LogWriter, "creating state directory in %q\n", 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 talosctl 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)
|
||||
state, err := vm.NewState(
|
||||
statePath,
|
||||
p.Name,
|
||||
request.Name,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fmt.Fprintln(options.LogWriter, "creating network", request.Network.Name)
|
||||
@ -92,17 +79,10 @@ func (p *provisioner) Create(ctx context.Context, request provision.ClusterReque
|
||||
Nodes: nodeInfo,
|
||||
}
|
||||
|
||||
// save state
|
||||
stateFile, err := os.Create(filepath.Join(state.statePath, stateFileName))
|
||||
err = state.Save()
|
||||
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()
|
||||
return state, nil
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/talos-systems/talos/internal/pkg/provision"
|
||||
"github.com/talos-systems/talos/internal/pkg/provision/providers/vm"
|
||||
)
|
||||
|
||||
// Destroy Talos cluster as set of Firecracker VMs.
|
||||
@ -28,7 +29,7 @@ func (p *provisioner) Destroy(ctx context.Context, cluster provision.Cluster, op
|
||||
return err
|
||||
}
|
||||
|
||||
state, ok := cluster.(*state)
|
||||
state, ok := cluster.(*vm.State)
|
||||
if !ok {
|
||||
return fmt.Errorf("error inspecting firecracker state, %#+v", cluster)
|
||||
}
|
||||
|
@ -10,18 +10,22 @@ import (
|
||||
|
||||
"github.com/talos-systems/talos/internal/app/machined/pkg/runtime"
|
||||
"github.com/talos-systems/talos/internal/pkg/provision"
|
||||
"github.com/talos-systems/talos/internal/pkg/provision/providers/vm"
|
||||
"github.com/talos-systems/talos/pkg/config/types/v1alpha1"
|
||||
"github.com/talos-systems/talos/pkg/config/types/v1alpha1/generate"
|
||||
)
|
||||
|
||||
const stateFileName = "state.yaml"
|
||||
|
||||
type provisioner struct {
|
||||
vm.Provisioner
|
||||
}
|
||||
|
||||
// NewProvisioner initializes docker provisioner.
|
||||
func NewProvisioner(ctx context.Context) (provision.Provisioner, error) {
|
||||
p := &provisioner{}
|
||||
p := &provisioner{
|
||||
vm.Provisioner{
|
||||
Name: "firecracker",
|
||||
},
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
@ -9,12 +9,12 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/talos-systems/talos/internal/pkg/provision"
|
||||
"github.com/talos-systems/talos/internal/pkg/provision/providers/vm"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -22,10 +22,10 @@ const (
|
||||
lbLog = "lb.log"
|
||||
)
|
||||
|
||||
func (p *provisioner) createLoadBalancer(state *state, clusterReq provision.ClusterRequest) error {
|
||||
pidPath := filepath.Join(state.statePath, lbPid)
|
||||
func (p *provisioner) createLoadBalancer(state *vm.State, clusterReq provision.ClusterRequest) error {
|
||||
pidPath := state.GetRelativePath(lbPid)
|
||||
|
||||
logFile, err := os.OpenFile(filepath.Join(state.statePath, lbLog), os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o666)
|
||||
logFile, err := os.OpenFile(state.GetRelativePath(lbLog), os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -67,8 +67,8 @@ func (p *provisioner) createLoadBalancer(state *state, clusterReq provision.Clus
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *provisioner) destroyLoadBalancer(state *state) error {
|
||||
pidPath := filepath.Join(state.statePath, lbPid)
|
||||
func (p *provisioner) destroyLoadBalancer(state *vm.State) error {
|
||||
pidPath := state.GetRelativePath(lbPid)
|
||||
|
||||
return stopProcessByPidfile(pidPath)
|
||||
}
|
||||
|
@ -20,10 +20,11 @@ import (
|
||||
"github.com/jsimonetti/rtnetlink"
|
||||
|
||||
"github.com/talos-systems/talos/internal/pkg/provision"
|
||||
"github.com/talos-systems/talos/internal/pkg/provision/providers/vm"
|
||||
talosnet "github.com/talos-systems/talos/pkg/net"
|
||||
)
|
||||
|
||||
func (p *provisioner) createNetwork(ctx context.Context, state *state, network provision.NetworkRequest) error {
|
||||
func (p *provisioner) createNetwork(ctx context.Context, state *vm.State, network provision.NetworkRequest) error {
|
||||
// build bridge interface name by taking part of checksum of the network name
|
||||
// so that interface name is defined by network name, and different networks have
|
||||
// different bridge interfaces
|
||||
@ -111,14 +112,14 @@ func (p *provisioner) createNetwork(ctx context.Context, state *state, network p
|
||||
return fmt.Errorf("error templating VM CNI config: %w", err)
|
||||
}
|
||||
|
||||
if state.vmCNIConfig, err = libcni.ConfListFromBytes(buf.Bytes()); err != nil {
|
||||
if state.VMCNIConfig, err = libcni.ConfListFromBytes(buf.Bytes()); err != nil {
|
||||
return fmt.Errorf("error parsing VM CNI config: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *provisioner) destroyNetwork(state *state) error {
|
||||
func (p *provisioner) destroyNetwork(state *vm.State) error {
|
||||
// destroy bridge interface by name to clean up
|
||||
iface, err := net.InterfaceByName(state.BridgeName)
|
||||
if err != nil {
|
||||
|
@ -11,22 +11,22 @@ import (
|
||||
"math"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/firecracker-microvm/firecracker-go-sdk"
|
||||
firecracker "github.com/firecracker-microvm/firecracker-go-sdk"
|
||||
models "github.com/firecracker-microvm/firecracker-go-sdk/client/models"
|
||||
"github.com/hashicorp/go-multierror"
|
||||
multierror "github.com/hashicorp/go-multierror"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
|
||||
"github.com/talos-systems/go-procfs/procfs"
|
||||
|
||||
"github.com/talos-systems/talos/internal/pkg/provision"
|
||||
"github.com/talos-systems/talos/internal/pkg/provision/providers/vm"
|
||||
)
|
||||
|
||||
func (p *provisioner) createDisk(state *state, nodeReq provision.NodeRequest) (diskPath string, err error) {
|
||||
diskPath = filepath.Join(state.statePath, fmt.Sprintf("%s.disk", nodeReq.Name))
|
||||
func (p *provisioner) createDisk(state *vm.State, nodeReq provision.NodeRequest) (diskPath string, err error) {
|
||||
diskPath = state.GetRelativePath(fmt.Sprintf("%s.disk", nodeReq.Name))
|
||||
|
||||
var diskF *os.File
|
||||
|
||||
@ -42,7 +42,7 @@ func (p *provisioner) createDisk(state *state, nodeReq provision.NodeRequest) (d
|
||||
return
|
||||
}
|
||||
|
||||
func (p *provisioner) createNodes(state *state, clusterReq provision.ClusterRequest, nodeReqs []provision.NodeRequest, opts *provision.Options) ([]provision.NodeInfo, error) {
|
||||
func (p *provisioner) createNodes(state *vm.State, clusterReq provision.ClusterRequest, nodeReqs []provision.NodeRequest, opts *provision.Options) ([]provision.NodeInfo, error) {
|
||||
errCh := make(chan error)
|
||||
nodeCh := make(chan provision.NodeInfo, len(nodeReqs))
|
||||
|
||||
@ -74,9 +74,9 @@ func (p *provisioner) createNodes(state *state, clusterReq provision.ClusterRequ
|
||||
return nodesInfo, multiErr.ErrorOrNil()
|
||||
}
|
||||
|
||||
func (p *provisioner) createNode(state *state, clusterReq provision.ClusterRequest, nodeReq provision.NodeRequest, opts *provision.Options) (provision.NodeInfo, error) {
|
||||
socketPath := filepath.Join(state.statePath, fmt.Sprintf("%s.sock", nodeReq.Name))
|
||||
pidPath := filepath.Join(state.statePath, fmt.Sprintf("%s.pid", nodeReq.Name))
|
||||
func (p *provisioner) createNode(state *vm.State, clusterReq provision.ClusterRequest, nodeReq provision.NodeRequest, opts *provision.Options) (provision.NodeInfo, error) {
|
||||
socketPath := state.GetRelativePath(fmt.Sprintf("%s.sock", nodeReq.Name))
|
||||
pidPath := state.GetRelativePath(fmt.Sprintf("%s.pid", nodeReq.Name))
|
||||
|
||||
vcpuCount := int64(math.RoundToEven(float64(nodeReq.NanoCPUs) / 1000 / 1000 / 1000))
|
||||
if vcpuCount < 2 {
|
||||
@ -128,7 +128,7 @@ func (p *provisioner) createNode(state *state, clusterReq provision.ClusterReque
|
||||
BinPath: clusterReq.Network.CNI.BinPath,
|
||||
ConfDir: clusterReq.Network.CNI.ConfDir,
|
||||
CacheDir: clusterReq.Network.CNI.CacheDir,
|
||||
NetworkConfig: state.vmCNIConfig,
|
||||
NetworkConfig: state.VMCNIConfig,
|
||||
Args: [][2]string{
|
||||
{"IP", fmt.Sprintf("%s/%d", nodeReq.IP, ones)},
|
||||
{"GATEWAY", clusterReq.Network.GatewayAddr.String()},
|
||||
@ -148,7 +148,7 @@ func (p *provisioner) createNode(state *state, clusterReq provision.ClusterReque
|
||||
},
|
||||
}
|
||||
|
||||
logFile, err := os.OpenFile(filepath.Join(state.statePath, fmt.Sprintf("%s.log", nodeReq.Name)), os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o666)
|
||||
logFile, err := os.OpenFile(state.GetRelativePath(fmt.Sprintf("%s.log", nodeReq.Name)), os.O_APPEND|os.O_CREATE|os.O_RDWR, 0o666)
|
||||
if err != nil {
|
||||
return provision.NodeInfo{}, err
|
||||
}
|
||||
@ -167,7 +167,7 @@ func (p *provisioner) createNode(state *state, clusterReq provision.ClusterReque
|
||||
BootloaderEmulation: opts.BootloaderEmulation,
|
||||
}
|
||||
|
||||
launchConfigFile, err := os.Create(filepath.Join(state.statePath, fmt.Sprintf("%s.config", nodeReq.Name)))
|
||||
launchConfigFile, err := os.Create(state.GetRelativePath(fmt.Sprintf("%s.config", nodeReq.Name)))
|
||||
if err != nil {
|
||||
return provision.NodeInfo{}, err
|
||||
}
|
||||
|
@ -1,39 +0,0 @@
|
||||
// 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 (
|
||||
"fmt"
|
||||
|
||||
"github.com/containernetworking/cni/libcni"
|
||||
|
||||
"github.com/talos-systems/talos/internal/pkg/provision"
|
||||
)
|
||||
|
||||
type state struct {
|
||||
ProvisionerName string
|
||||
BridgeName string
|
||||
|
||||
ClusterInfo provision.ClusterInfo
|
||||
|
||||
vmCNIConfig *libcni.NetworkConfigList
|
||||
statePath string
|
||||
}
|
||||
|
||||
func (s *state) Provisioner() string {
|
||||
return "firecracker"
|
||||
}
|
||||
|
||||
func (s *state) Info() provision.ClusterInfo {
|
||||
return s.ClusterInfo
|
||||
}
|
||||
|
||||
func (s *state) StatePath() (string, error) {
|
||||
if s.statePath == "" {
|
||||
return "", fmt.Errorf("state path is not set")
|
||||
}
|
||||
|
||||
return s.statePath, nil
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
// 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
|
||||
package vm
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -10,12 +10,13 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/talos-systems/talos/internal/pkg/provision"
|
||||
)
|
||||
|
||||
func (p *provisioner) Reflect(ctx context.Context, clusterName, stateDirectory string) (provision.Cluster, error) {
|
||||
// Reflect decode state file.
|
||||
func (p *Provisioner) Reflect(ctx context.Context, clusterName, stateDirectory string) (provision.Cluster, error) {
|
||||
statePath := filepath.Join(stateDirectory, clusterName)
|
||||
|
||||
st, err := os.Stat(statePath)
|
||||
@ -38,13 +39,13 @@ func (p *provisioner) Reflect(ctx context.Context, clusterName, stateDirectory s
|
||||
|
||||
defer stateFile.Close() //nolint: errcheck
|
||||
|
||||
state := &state{}
|
||||
state := &State{}
|
||||
|
||||
if err = yaml.NewDecoder(stateFile).Decode(state); err != nil {
|
||||
return nil, fmt.Errorf("error unmarshalling state file: %w", err)
|
||||
}
|
||||
|
||||
if state.ProvisionerName != "firecracker" {
|
||||
if state.ProvisionerName != p.Name {
|
||||
return nil, fmt.Errorf("cluster %q was created with different provisioner %q", clusterName, state.ProvisionerName)
|
||||
}
|
||||
|
97
internal/pkg/provision/providers/vm/state.go
Normal file
97
internal/pkg/provision/providers/vm/state.go
Normal file
@ -0,0 +1,97 @@
|
||||
// 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 vm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/containernetworking/cni/libcni"
|
||||
|
||||
"github.com/talos-systems/talos/internal/pkg/provision"
|
||||
)
|
||||
|
||||
// State common state representation for vm provisioners.
|
||||
type State struct {
|
||||
ProvisionerName string
|
||||
BridgeName string
|
||||
|
||||
ClusterInfo provision.ClusterInfo
|
||||
|
||||
VMCNIConfig *libcni.NetworkConfigList
|
||||
statePath string
|
||||
}
|
||||
|
||||
// NewState create new vm provisioner state.
|
||||
func NewState(statePath, provisionerName, clusterName string) (*State, error) {
|
||||
s := &State{
|
||||
ProvisionerName: provisionerName,
|
||||
statePath: statePath,
|
||||
}
|
||||
|
||||
_, err := os.Stat(s.statePath)
|
||||
|
||||
if err == nil {
|
||||
return nil, fmt.Errorf(
|
||||
"state directory %q already exists, is the cluster %q already running? remove cluster state with talosctl cluster destroy",
|
||||
s.statePath,
|
||||
clusterName,
|
||||
)
|
||||
}
|
||||
|
||||
if !os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("error checking state directory: %w", err)
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(s.statePath, os.ModePerm); err != nil {
|
||||
return nil, fmt.Errorf("error creating state directory: %w", err)
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Provisioner get provisioner name.
|
||||
func (s *State) Provisioner() string {
|
||||
return s.ProvisionerName
|
||||
}
|
||||
|
||||
// Info get cluster info.
|
||||
func (s *State) Info() provision.ClusterInfo {
|
||||
return s.ClusterInfo
|
||||
}
|
||||
|
||||
// StatePath get state config file path.
|
||||
func (s *State) StatePath() (string, error) {
|
||||
if s.statePath == "" {
|
||||
return "", fmt.Errorf("state path is not set")
|
||||
}
|
||||
|
||||
return s.statePath, nil
|
||||
}
|
||||
|
||||
// Save save state to config file.
|
||||
func (s *State) Save() error {
|
||||
// save state
|
||||
stateFile, err := os.Create(filepath.Join(s.statePath, stateFileName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer stateFile.Close() //nolint: errcheck
|
||||
|
||||
if err = yaml.NewEncoder(stateFile).Encode(&s); err != nil {
|
||||
return fmt.Errorf("error marshaling state: %w", err)
|
||||
}
|
||||
|
||||
return stateFile.Close()
|
||||
}
|
||||
|
||||
// GetRelativePath get file path relative to config folder.
|
||||
func (s *State) GetRelativePath(path string) string {
|
||||
return filepath.Join(s.statePath, path)
|
||||
}
|
14
internal/pkg/provision/providers/vm/vm.go
Normal file
14
internal/pkg/provision/providers/vm/vm.go
Normal file
@ -0,0 +1,14 @@
|
||||
// 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 vm implements common methods for VM provisioners.
|
||||
package vm
|
||||
|
||||
const stateFileName = "state.yaml"
|
||||
|
||||
// Provisioner base for VM provisioners.
|
||||
type Provisioner struct {
|
||||
// Name actual provisioner type.
|
||||
Name string
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user