Artem Chernyshev 5d48bd5f6a feat: allow disabling NoSchedule taint on masters using TUI installer
I think this should come handy for setting up single node SBC clusters.

Signed-off-by: Artem Chernyshev <artem.0xD2@gmail.com>
2020-12-07 07:31:54 -08:00

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)
})
}
}