talos/internal/pkg/tui/installer/connection.go
Andrey Smirnov 753a82188f
refactor: move pkg/resources to machinery
Fixes #4420

No functional changes, just moving packages around.

Signed-off-by: Andrey Smirnov <andrey.smirnov@talos-systems.com>
2021-11-15 19:50:35 +03:00

166 lines
4.4 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
import (
"context"
"io"
"net"
"google.golang.org/grpc"
"gopkg.in/yaml.v3"
"github.com/talos-systems/talos/pkg/machinery/api/machine"
"github.com/talos-systems/talos/pkg/machinery/api/storage"
"github.com/talos-systems/talos/pkg/machinery/client"
"github.com/talos-systems/talos/pkg/machinery/nethelpers"
"github.com/talos-systems/talos/pkg/machinery/resources/network"
)
// Connection unifies clients for bootstrap node and the node which is being configured.
type Connection struct {
nodeEndpoint string
bootstrapEndpoint string
nodeClient *client.Client
bootstrapClient *client.Client
nodeCtx context.Context
bootstrapCtx context.Context
}
// NewConnection creates new installer connection.
func NewConnection(ctx context.Context, nodeClient *client.Client, endpoint string, options ...Option) (*Connection, error) {
c := &Connection{
nodeEndpoint: endpoint,
nodeClient: nodeClient,
nodeCtx: ctx,
}
for _, opt := range options {
err := opt(c)
if err != nil {
return nil, err
}
}
return c, nil
}
// GenerateConfiguration calls GenerateConfiguration on the target/bootstrap node.
func (c *Connection) GenerateConfiguration(req *machine.GenerateConfigurationRequest, callOptions ...grpc.CallOption) (*machine.GenerateConfigurationResponse, error) {
if c.bootstrapClient != nil {
return c.bootstrapClient.GenerateConfiguration(c.bootstrapCtx, req, callOptions...)
}
return c.nodeClient.GenerateConfiguration(c.nodeCtx, req, callOptions...)
}
// ApplyConfiguration calls ApplyConfiguration on the target node using appropriate node context.
func (c *Connection) ApplyConfiguration(req *machine.ApplyConfigurationRequest, callOptions ...grpc.CallOption) (*machine.ApplyConfigurationResponse, error) {
return c.nodeClient.ApplyConfiguration(c.nodeCtx, req, callOptions...)
}
// Disks get disks list from the target node.
func (c *Connection) Disks(callOptions ...grpc.CallOption) (*storage.DisksResponse, error) {
return c.nodeClient.Disks(c.nodeCtx, callOptions...)
}
// Link a subset of fields from LinkStatus resource.
type Link struct {
Name string
Physical bool
Up bool
HardwareAddr net.HardwareAddr
MTU int
}
// Links gets a list of network interfaces.
//
//nolint:gocyclo
func (c *Connection) Links(callOptions ...grpc.CallOption) ([]Link, error) {
client, err := c.nodeClient.Resources.List(c.nodeCtx, network.NamespaceName, network.LinkStatusType, callOptions...)
if err != nil {
return nil, err
}
var links []Link
for {
msg, err := client.Recv()
if err != nil {
if err == io.EOF {
break
}
return nil, err
}
if msg.Resource == nil {
continue
}
var link Link
// this is a hack until we get proper encoding for resources in the API (protobuf!)
// plus our resources are Linux-specific and don't build on OS X (we need to solve this as well!)
link.Name = msg.Resource.Metadata().ID()
b, err := yaml.Marshal(msg.Resource.Spec())
if err != nil {
return nil, err
}
var raw map[string]interface{}
if err = yaml.Unmarshal(b, &raw); err != nil {
return nil, err
}
kind := raw["kind"].(string) //nolint:errcheck,forcetypeassert
linkType := raw["type"].(string) //nolint:errcheck,forcetypeassert
link.Physical = kind == "" && linkType == "ether"
link.MTU = raw["mtu"].(int) //nolint:errcheck,forcetypeassert
switch raw["operationalState"].(string) {
case nethelpers.OperStateUnknown.String():
link.Up = true
case nethelpers.OperStateUp.String():
link.Up = true
default:
link.Up = false
}
mac, err := net.ParseMAC(raw["hardwareAddr"].(string))
if err == nil {
link.HardwareAddr = mac
}
links = append(links, link)
}
return links, nil
}
// ExpandingCluster check if bootstrap node is set.
func (c *Connection) ExpandingCluster() bool {
return c.bootstrapClient != nil
}
// Option represents a single connection option.
type Option func(c *Connection) error
// WithBootstrapNode configures bootstrap node endpoint.
func WithBootstrapNode(ctx context.Context, bootstrapClient *client.Client, bootstrapNode string) Option {
return func(c *Connection) error {
c.bootstrapEndpoint = bootstrapNode
c.bootstrapClient = bootstrapClient
c.bootstrapCtx = ctx
return nil
}
}