Andrey Smirnov db9c35b570 feat: implement AddressStatusController
This controller queries addresses of all the interfaces in the system
and presents them as resources. The idea is that can be a source for
many decisions - e.g. whether network is ready (physical interface has
scope global address assigned).

This is also good for debugging purposes.

Examples:

```
$ talosctl -n 172.20.0.2 get addresses
NODE         NAMESPACE   TYPE            ID                                          VERSION
172.20.0.2   network     AddressStatus   cni0/10.244.0.1/24                          1
172.20.0.2   network     AddressStatus   cni0/fe80::9c87:cdff:fe8e:5fdc/64           2
172.20.0.2   network     AddressStatus   eth0/172.20.0.2/24                          1
172.20.0.2   network     AddressStatus   eth0/fe80::ac1b:9cff:fe19:6b47/64           2
172.20.0.2   network     AddressStatus   flannel.1/10.244.0.0/32                     1
172.20.0.2   network     AddressStatus   flannel.1/fe80::440b:67ff:fe99:c18f/64      2
172.20.0.2   network     AddressStatus   lo/127.0.0.1/8                              1
172.20.0.2   network     AddressStatus   lo/::1/128                                  1
172.20.0.2   network     AddressStatus   veth178e9b31/fe80::6040:1dff:fe5b:ae1a/64   2
172.20.0.2   network     AddressStatus   vethb0b96a94/fe80::2473:86ff:fece:1954/64   2
```

```
$ talosctl -n 172.20.0.2 get addresses -o yaml eth0/172.20.0.2/24
node: 172.20.0.2
metadata:
    namespace: network
    type: AddressStatuses.net.talos.dev
    id: eth0/172.20.0.2/24
    version: 1
    owner: network.AddressStatusController
    phase: running
spec:
    address: 172.20.0.2/24
    local: 172.20.0.2
    broadcast: 172.20.0.255
    linkIndex: 4
    linkName: eth0
    family: inet4
    scope: global
    flags: permanent
```

Signed-off-by: Andrey Smirnov <smirnov.andrey@gmail.com>
2021-05-11 13:32:17 -07:00

133 lines
3.8 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 v1alpha2
import (
"context"
"github.com/cosi-project/runtime/pkg/resource"
"github.com/cosi-project/runtime/pkg/state"
"github.com/cosi-project/runtime/pkg/state/impl/inmem"
"github.com/cosi-project/runtime/pkg/state/impl/namespaced"
"github.com/cosi-project/runtime/pkg/state/registry"
talosconfig "github.com/talos-systems/talos/pkg/machinery/config"
"github.com/talos-systems/talos/pkg/resources/config"
"github.com/talos-systems/talos/pkg/resources/k8s"
"github.com/talos-systems/talos/pkg/resources/network"
"github.com/talos-systems/talos/pkg/resources/secrets"
"github.com/talos-systems/talos/pkg/resources/time"
"github.com/talos-systems/talos/pkg/resources/v1alpha1"
)
// State implements runtime.V1alpha2State interface.
type State struct {
resources state.State
namespaceRegistry *registry.NamespaceRegistry
resourceRegistry *registry.ResourceRegistry
}
// NewState creates State.
func NewState() (*State, error) {
s := &State{}
ctx := context.TODO()
s.resources = state.WrapCore(namespaced.NewState(inmem.Build))
s.namespaceRegistry = registry.NewNamespaceRegistry(s.resources)
s.resourceRegistry = registry.NewResourceRegistry(s.resources)
if err := s.namespaceRegistry.RegisterDefault(ctx); err != nil {
return nil, err
}
if err := s.resourceRegistry.RegisterDefault(ctx); err != nil {
return nil, err
}
// register Talos namespaces
if err := s.namespaceRegistry.Register(ctx, v1alpha1.NamespaceName, "Talos v1alpha1 subsystems glue resources."); err != nil {
return nil, err
}
if err := s.namespaceRegistry.Register(ctx, config.NamespaceName, "Talos node configuration."); err != nil {
return nil, err
}
if err := s.namespaceRegistry.Register(ctx, k8s.ControlPlaneNamespaceName, "Kubernetes control plane resources."); err != nil {
return nil, err
}
if err := s.namespaceRegistry.Register(ctx, secrets.NamespaceName, "Resources with secret material."); err != nil {
return nil, err
}
if err := s.namespaceRegistry.Register(ctx, network.NamespaceName, "Networking resources."); err != nil {
return nil, err
}
// register Talos resources
for _, r := range []resource.Resource{
&v1alpha1.BootstrapStatus{},
&v1alpha1.Service{},
&config.MachineConfig{},
&config.MachineType{},
&config.K8sControlPlane{},
&k8s.Manifest{},
&k8s.ManifestStatus{},
&k8s.StaticPod{},
&k8s.StaticPodStatus{},
&k8s.SecretsStatus{},
&network.AddressStatus{},
&network.LinkStatus{},
&secrets.Etcd{},
&secrets.Kubernetes{},
&secrets.Root{},
&time.Status{},
} {
if err := s.resourceRegistry.Register(ctx, r); err != nil {
return nil, err
}
}
return s, nil
}
// Resources implements runtime.V1alpha2State interface.
func (s *State) Resources() state.State {
return s.resources
}
// NamespaceRegistry implements runtime.V1alpha2State interface.
func (s *State) NamespaceRegistry() *registry.NamespaceRegistry {
return s.namespaceRegistry
}
// ResourceRegistry implements runtime.V1alpha2State interface.
func (s *State) ResourceRegistry() *registry.ResourceRegistry {
return s.resourceRegistry
}
// SetConfig implements runtime.V1alpha2State interface.
func (s *State) SetConfig(cfg talosconfig.Provider) error {
cfgResource := config.NewMachineConfig(cfg)
ctx := context.TODO()
oldCfg, err := s.resources.Get(ctx, cfgResource.Metadata())
if err != nil {
if state.IsNotFoundError(err) {
return s.resources.Create(ctx, cfgResource)
}
return err
}
cfgResource.Metadata().SetVersion(oldCfg.Metadata().Version())
cfgResource.Metadata().BumpVersion()
return s.resources.Update(ctx, oldCfg.Metadata().Version(), cfgResource)
}