mirror of
https://github.com/siderolabs/talos.git
synced 2025-08-20 22:21:13 +02:00
I think this should come handy for setting up single node SBC clusters. Signed-off-by: Artem Chernyshev <artem.0xD2@gmail.com>
328 lines
9.1 KiB
Go
328 lines
9.1 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 installer contains terminal UI based talos interactive installer parts.
|
|
package installer
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/dustin/go-humanize"
|
|
"github.com/rivo/tview"
|
|
"google.golang.org/protobuf/types/known/timestamppb"
|
|
|
|
"github.com/talos-systems/talos/internal/pkg/tui/components"
|
|
"github.com/talos-systems/talos/pkg/images"
|
|
machineapi "github.com/talos-systems/talos/pkg/machinery/api/machine"
|
|
"github.com/talos-systems/talos/pkg/machinery/api/network"
|
|
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1"
|
|
"github.com/talos-systems/talos/pkg/machinery/config/types/v1alpha1/machine"
|
|
"github.com/talos-systems/talos/pkg/machinery/constants"
|
|
)
|
|
|
|
// cniPresets defines custom CNI presets.
|
|
var cniPresets = map[string]*machineapi.CNIConfig{
|
|
"cilium": {
|
|
Name: "custom",
|
|
Urls: []string{
|
|
"https://raw.githubusercontent.com/cilium/cilium/v1.8/install/kubernetes/quick-install.yaml",
|
|
},
|
|
},
|
|
}
|
|
|
|
// NewState creates new installer state.
|
|
// nolint:gocyclo
|
|
func NewState(ctx context.Context, installer *Installer, conn *Connection) (*State, error) {
|
|
opts := &machineapi.GenerateConfigurationRequest{
|
|
ConfigVersion: "v1alpha1",
|
|
MachineConfig: &machineapi.MachineConfig{
|
|
Type: machineapi.MachineConfig_MachineType(machine.TypeInit),
|
|
NetworkConfig: &machineapi.NetworkConfig{},
|
|
KubernetesVersion: constants.DefaultKubernetesVersion,
|
|
InstallConfig: &machineapi.InstallConfig{
|
|
InstallImage: images.DefaultInstallerImage,
|
|
},
|
|
},
|
|
ClusterConfig: &machineapi.ClusterConfig{
|
|
Name: "talos-default",
|
|
ControlPlane: &machineapi.ControlPlaneConfig{},
|
|
ClusterNetwork: &machineapi.ClusterNetworkConfig{
|
|
DnsDomain: "cluster.local",
|
|
},
|
|
},
|
|
}
|
|
|
|
if conn.ExpandingCluster() {
|
|
opts.ClusterConfig.ControlPlane.Endpoint = fmt.Sprintf("https://%s:%d", conn.bootstrapEndpoint, constants.DefaultControlPlanePort)
|
|
} else {
|
|
opts.ClusterConfig.ControlPlane.Endpoint = fmt.Sprintf("https://%s:%d", conn.nodeEndpoint, constants.DefaultControlPlanePort)
|
|
}
|
|
|
|
installDiskOptions := []interface{}{
|
|
components.NewTableHeaders("DEVICE NAME", "MODEL NAME", "SIZE"),
|
|
}
|
|
|
|
disks, err := conn.Disks()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for i, disk := range disks.Disks {
|
|
if i == 0 {
|
|
opts.MachineConfig.InstallConfig.InstallDisk = disk.DeviceName
|
|
}
|
|
|
|
installDiskOptions = append(installDiskOptions, disk.DeviceName, disk.Model, humanize.Bytes(disk.Size))
|
|
}
|
|
|
|
var machineTypes []interface{}
|
|
|
|
if conn.ExpandingCluster() {
|
|
machineTypes = []interface{}{
|
|
" worker ", machineapi.MachineConfig_MachineType(machine.TypeJoin),
|
|
" control plane ", machineapi.MachineConfig_MachineType(machine.TypeControlPlane),
|
|
}
|
|
opts.MachineConfig.Type = machineapi.MachineConfig_MachineType(machine.TypeControlPlane)
|
|
} else {
|
|
machineTypes = []interface{}{
|
|
" control plane ", machineapi.MachineConfig_MachineType(machine.TypeInit),
|
|
}
|
|
}
|
|
|
|
state := &State{
|
|
cni: constants.DefaultCNI,
|
|
conn: conn,
|
|
opts: opts,
|
|
}
|
|
|
|
networkConfigItems := []*components.Item{
|
|
components.NewItem(
|
|
"Hostname",
|
|
v1alpha1.NetworkConfigDoc.Describe("hostname", true),
|
|
&opts.MachineConfig.NetworkConfig.Hostname,
|
|
),
|
|
components.NewItem(
|
|
"DNS Domain",
|
|
v1alpha1.ClusterNetworkConfigDoc.Describe("dnsDomain", true),
|
|
&opts.ClusterConfig.ClusterNetwork.DnsDomain,
|
|
),
|
|
}
|
|
|
|
interfaces, err := conn.Interfaces()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
addedInterfaces := false
|
|
opts.MachineConfig.NetworkConfig.Interfaces = []*machineapi.NetworkDeviceConfig{}
|
|
|
|
for _, iface := range interfaces.Messages[0].Interfaces {
|
|
status := ""
|
|
|
|
if (net.Flags(iface.Flags) & net.FlagUp) != 0 {
|
|
status = " (UP)"
|
|
}
|
|
|
|
if !addedInterfaces {
|
|
networkConfigItems = append(networkConfigItems, components.NewSeparator("Network Interfaces Configuration"))
|
|
addedInterfaces = true
|
|
}
|
|
|
|
networkConfigItems = append(networkConfigItems, components.NewItem(
|
|
fmt.Sprintf("%s, %s%s", iface.Name, iface.Hardwareaddr, status),
|
|
"",
|
|
configureAdapter(installer, opts, iface),
|
|
))
|
|
}
|
|
|
|
if !conn.ExpandingCluster() {
|
|
networkConfigItems = append(networkConfigItems,
|
|
components.NewSeparator(v1alpha1.ClusterNetworkConfigDoc.Describe("cni", true)),
|
|
components.NewItem(
|
|
"Type",
|
|
v1alpha1.ClusterNetworkConfigDoc.Describe("cni", true),
|
|
&state.cni,
|
|
components.NewTableHeaders("CNI", "description"),
|
|
constants.DefaultCNI, "CNI used by Talos by default",
|
|
"cilium", "Cillium 1.8 installed through quick-install.yaml",
|
|
))
|
|
}
|
|
|
|
state.pages = []*Page{
|
|
NewPage("Installer Params",
|
|
components.NewItem(
|
|
"Image",
|
|
v1alpha1.InstallConfigDoc.Describe("image", true),
|
|
&opts.MachineConfig.InstallConfig.InstallImage,
|
|
),
|
|
components.NewSeparator(
|
|
v1alpha1.InstallConfigDoc.Describe("disk", true),
|
|
),
|
|
components.NewItem(
|
|
"Install Disk",
|
|
"",
|
|
&opts.MachineConfig.InstallConfig.InstallDisk,
|
|
installDiskOptions...,
|
|
),
|
|
),
|
|
NewPage("Machine Config",
|
|
components.NewItem(
|
|
"Machine Type",
|
|
v1alpha1.MachineConfigDoc.Describe("type", true),
|
|
&opts.MachineConfig.Type,
|
|
machineTypes...,
|
|
),
|
|
components.NewItem(
|
|
"Cluster Name",
|
|
v1alpha1.ClusterConfigDoc.Describe("clusterName", true),
|
|
&opts.ClusterConfig.Name,
|
|
),
|
|
components.NewItem(
|
|
"Control Plane Endpoint",
|
|
v1alpha1.ControlPlaneConfigDoc.Describe("endpoint", true),
|
|
&opts.ClusterConfig.ControlPlane.Endpoint,
|
|
),
|
|
components.NewItem(
|
|
"Kubernetes Version",
|
|
"",
|
|
&opts.MachineConfig.KubernetesVersion,
|
|
),
|
|
components.NewItem(
|
|
"Allow Scheduling on Masters",
|
|
v1alpha1.ClusterConfigDoc.Describe("allowSchedulingOnMasters", true),
|
|
&opts.ClusterConfig.AllowSchedulingOnMasters,
|
|
),
|
|
),
|
|
NewPage("Network Config",
|
|
networkConfigItems...,
|
|
),
|
|
}
|
|
|
|
return state, nil
|
|
}
|
|
|
|
// State installer state.
|
|
type State struct {
|
|
pages []*Page
|
|
opts *machineapi.GenerateConfigurationRequest
|
|
conn *Connection
|
|
cni string
|
|
}
|
|
|
|
// GenConfig returns current config encoded in yaml.
|
|
func (s *State) GenConfig() (*machineapi.GenerateConfigurationResponse, error) {
|
|
// configure custom cni from the preset
|
|
if customCNI, ok := cniPresets[s.cni]; ok {
|
|
s.opts.ClusterConfig.ClusterNetwork.CniConfig = customCNI
|
|
}
|
|
|
|
s.opts.OverrideTime = timestamppb.New(time.Now().UTC())
|
|
|
|
return s.conn.GenerateConfiguration(s.opts)
|
|
}
|
|
|
|
func configureAdapter(installer *Installer, opts *machineapi.GenerateConfigurationRequest, adapter *network.Interface) func(item *components.Item) tview.Primitive {
|
|
return func(item *components.Item) tview.Primitive {
|
|
return components.NewFormModalButton(item.Name, "configure").
|
|
SetSelectedFunc(func() {
|
|
deviceIndex := -1
|
|
var adapterSettings *machineapi.NetworkDeviceConfig
|
|
|
|
for i, iface := range opts.MachineConfig.NetworkConfig.Interfaces {
|
|
if iface.Interface == adapter.Name {
|
|
deviceIndex = i
|
|
adapterSettings = iface
|
|
|
|
break
|
|
}
|
|
}
|
|
|
|
if adapterSettings == nil {
|
|
adapterSettings = &machineapi.NetworkDeviceConfig{
|
|
Interface: adapter.Name,
|
|
Dhcp: true,
|
|
Mtu: int32(adapter.Mtu),
|
|
Ignore: false,
|
|
DhcpOptions: &machineapi.DHCPOptionsConfig{},
|
|
}
|
|
|
|
if len(adapter.Ipaddress) > 0 {
|
|
adapterSettings.Cidr = adapter.Ipaddress[0]
|
|
}
|
|
}
|
|
|
|
items := []*components.Item{
|
|
components.NewItem(
|
|
"Use DHCP",
|
|
v1alpha1.DeviceDoc.Describe("dhcp", true),
|
|
&adapterSettings.Dhcp,
|
|
),
|
|
components.NewItem(
|
|
"Ignore",
|
|
v1alpha1.DeviceDoc.Describe("ignore", true),
|
|
&adapterSettings.Ignore,
|
|
),
|
|
components.NewItem(
|
|
"CIDR",
|
|
v1alpha1.DeviceDoc.Describe("cidr", true),
|
|
&adapterSettings.Cidr,
|
|
),
|
|
components.NewItem(
|
|
"MTU",
|
|
v1alpha1.DeviceDoc.Describe("mtu", true),
|
|
&adapterSettings.Mtu,
|
|
),
|
|
components.NewItem(
|
|
"Route Metric",
|
|
v1alpha1.DeviceDoc.Describe("dhcpOptions", true),
|
|
&adapterSettings.DhcpOptions.RouteMetric,
|
|
),
|
|
}
|
|
|
|
adapterConfiguration := components.NewForm(installer.app)
|
|
if err := adapterConfiguration.AddFormItems(items); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
focused := installer.app.GetFocus()
|
|
page, _ := installer.pages.GetFrontPage()
|
|
|
|
goBack := func() {
|
|
installer.pages.SwitchToPage(page)
|
|
installer.app.SetFocus(focused)
|
|
}
|
|
|
|
adapterConfiguration.AddMenuButton("Cancel", false).SetSelectedFunc(func() {
|
|
goBack()
|
|
})
|
|
|
|
adapterConfiguration.AddMenuButton("Apply", false).SetSelectedFunc(func() {
|
|
goBack()
|
|
|
|
if deviceIndex == -1 {
|
|
opts.MachineConfig.NetworkConfig.Interfaces = append(
|
|
opts.MachineConfig.NetworkConfig.Interfaces,
|
|
adapterSettings,
|
|
)
|
|
}
|
|
})
|
|
|
|
flex := tview.NewFlex().SetDirection(tview.FlexRow)
|
|
flex.AddItem(tview.NewBox().SetBackgroundColor(color), 1, 0, false)
|
|
flex.AddItem(adapterConfiguration, 0, 1, false)
|
|
|
|
installer.addPage(
|
|
fmt.Sprintf("Adapter %s Configuration", adapter.Name),
|
|
flex,
|
|
true,
|
|
nil,
|
|
)
|
|
installer.app.SetFocus(adapterConfiguration)
|
|
})
|
|
}
|
|
}
|