github.com/looshlee/beatles@v0.0.0-20220727174639-742810ab631c/pkg/node/node.go (about)

     1  // Copyright 2016-2019 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package node
    16  
    17  import (
    18  	"encoding/json"
    19  	"net"
    20  	"path"
    21  
    22  	"github.com/cilium/cilium/api/v1/models"
    23  	"github.com/cilium/cilium/pkg/cidr"
    24  	"github.com/cilium/cilium/pkg/defaults"
    25  	ciliumv2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2"
    26  	"github.com/cilium/cilium/pkg/kvstore/store"
    27  	"github.com/cilium/cilium/pkg/node/addressing"
    28  	"github.com/cilium/cilium/pkg/option"
    29  	"github.com/cilium/cilium/pkg/source"
    30  )
    31  
    32  // Identity represents the node identity of a node.
    33  type Identity struct {
    34  	Name    string
    35  	Cluster string
    36  }
    37  
    38  // String returns the string representation on NodeIdentity.
    39  func (nn Identity) String() string {
    40  	return path.Join(nn.Cluster, nn.Name)
    41  }
    42  
    43  // ParseCiliumNode parses a CiliumNode custom resource and returns a Node
    44  // instance. Invalid IP and CIDRs are silently ignored
    45  func ParseCiliumNode(n *ciliumv2.CiliumNode) (node Node) {
    46  	node = Node{
    47  		Name:          n.Name,
    48  		EncryptionKey: uint8(n.Spec.Encryption.Key),
    49  		Cluster:       option.Config.ClusterName,
    50  		ClusterID:     option.Config.ClusterID,
    51  		Source:        source.CustomResource,
    52  	}
    53  
    54  	for _, cidrString := range n.Spec.IPAM.PodCIDRs {
    55  		ipnet, err := cidr.ParseCIDR(cidrString)
    56  		if err == nil {
    57  			if ipnet.IP.To4() != nil {
    58  				node.IPv4AllocCIDR = ipnet
    59  			} else {
    60  				node.IPv6AllocCIDR = ipnet
    61  			}
    62  		}
    63  	}
    64  
    65  	if healthIP := n.Spec.HealthAddressing.IPv4; healthIP != "" {
    66  		node.IPv4HealthIP = net.ParseIP(healthIP)
    67  	}
    68  
    69  	if healthIP := n.Spec.HealthAddressing.IPv6; healthIP != "" {
    70  		node.IPv6HealthIP = net.ParseIP(healthIP)
    71  	}
    72  
    73  	for _, address := range n.Spec.Addresses {
    74  		if ip := net.ParseIP(address.IP); ip != nil {
    75  			node.IPAddresses = append(node.IPAddresses, Address{Type: address.Type, IP: ip})
    76  		}
    77  	}
    78  
    79  	return
    80  }
    81  
    82  // Node contains the nodes name, the list of addresses to this address
    83  //
    84  // +k8s:deepcopy-gen=true
    85  type Node struct {
    86  	// Name is the name of the node. This is typically the hostname of the node.
    87  	Name string
    88  
    89  	// Cluster is the name of the cluster the node is associated with
    90  	Cluster string
    91  
    92  	IPAddresses []Address
    93  
    94  	// IPv4AllocCIDR if set, is the IPv4 address pool out of which the node
    95  	// allocates IPs for local endpoints from
    96  	IPv4AllocCIDR *cidr.CIDR
    97  
    98  	// IPv6AllocCIDR if set, is the IPv6 address pool out of which the node
    99  	// allocates IPs for local endpoints from
   100  	IPv6AllocCIDR *cidr.CIDR
   101  
   102  	// IPv4HealthIP if not nil, this is the IPv4 address of the
   103  	// cilium-health endpoint located on the node.
   104  	IPv4HealthIP net.IP
   105  
   106  	// IPv6HealthIP if not nil, this is the IPv6 address of the
   107  	// cilium-health endpoint located on the node.
   108  	IPv6HealthIP net.IP
   109  
   110  	// ClusterID is the unique identifier of the cluster
   111  	ClusterID int
   112  
   113  	// Source is the source where the node configuration was generated / created.
   114  	Source source.Source
   115  
   116  	// Key index used for transparent encryption or 0 for no encryption
   117  	EncryptionKey uint8
   118  }
   119  
   120  // Fullname returns the node's full name including the cluster name if a
   121  // cluster name value other than the default value has been specified
   122  func (n *Node) Fullname() string {
   123  	if n.Cluster != defaults.ClusterName {
   124  		return path.Join(n.Cluster, n.Name)
   125  	}
   126  
   127  	return n.Name
   128  }
   129  
   130  // Address is a node address which contains an IP and the address type.
   131  //
   132  // +k8s:deepcopy-gen=true
   133  type Address struct {
   134  	Type addressing.AddressType
   135  	IP   net.IP
   136  }
   137  
   138  func (n *Node) getNodeIP(ipv6 bool) (net.IP, addressing.AddressType) {
   139  	var (
   140  		backupIP net.IP
   141  		ipType   addressing.AddressType
   142  	)
   143  	for _, addr := range n.IPAddresses {
   144  		if (ipv6 && addr.IP.To4() != nil) ||
   145  			(!ipv6 && addr.IP.To4() == nil) {
   146  			continue
   147  		}
   148  		switch addr.Type {
   149  		// Ignore CiliumInternalIPs
   150  		case addressing.NodeCiliumInternalIP:
   151  			continue
   152  		// Always prefer a cluster internal IP
   153  		case addressing.NodeInternalIP:
   154  			return addr.IP, addr.Type
   155  		case addressing.NodeExternalIP:
   156  			// Fall back to external Node IP
   157  			// if no internal IP could be found
   158  			backupIP = addr.IP
   159  			ipType = addr.Type
   160  		default:
   161  			// As a last resort, if no internal or external
   162  			// IP was found, use any node address available
   163  			if backupIP == nil {
   164  				backupIP = addr.IP
   165  				ipType = addr.Type
   166  			}
   167  		}
   168  	}
   169  	return backupIP, ipType
   170  }
   171  
   172  // GetNodeIP returns one of the node's IP addresses available with the
   173  // following priority:
   174  // - NodeInternalIP
   175  // - NodeExternalIP
   176  // - other IP address type
   177  func (n *Node) GetNodeIP(ipv6 bool) net.IP {
   178  	result, _ := n.getNodeIP(ipv6)
   179  	return result
   180  }
   181  
   182  // GetCiliumInternalIP returns the CiliumInternalIP e.g. the IP associated
   183  // with cilium_host on the node.
   184  func (n *Node) GetCiliumInternalIP(ipv6 bool) net.IP {
   185  	for _, addr := range n.IPAddresses {
   186  		if (ipv6 && addr.IP.To4() != nil) ||
   187  			(!ipv6 && addr.IP.To4() == nil) {
   188  			continue
   189  		}
   190  		if addr.Type == addressing.NodeCiliumInternalIP {
   191  			return addr.IP
   192  		}
   193  	}
   194  	return nil
   195  }
   196  
   197  func (n *Node) getPrimaryAddress() *models.NodeAddressing {
   198  	v4, v4Type := n.getNodeIP(false)
   199  	v6, v6Type := n.getNodeIP(true)
   200  
   201  	var ipv4AllocStr, ipv6AllocStr string
   202  	if n.IPv4AllocCIDR != nil {
   203  		ipv4AllocStr = n.IPv4AllocCIDR.String()
   204  	}
   205  	if n.IPv6AllocCIDR != nil {
   206  		ipv6AllocStr = n.IPv6AllocCIDR.String()
   207  	}
   208  
   209  	var v4Str, v6Str string
   210  	if v4 != nil {
   211  		v4Str = v4.String()
   212  	}
   213  	if v6 != nil {
   214  		v6Str = v6.String()
   215  	}
   216  
   217  	return &models.NodeAddressing{
   218  		IPV4: &models.NodeAddressingElement{
   219  			Enabled:     option.Config.EnableIPv4,
   220  			IP:          v4Str,
   221  			AllocRange:  ipv4AllocStr,
   222  			AddressType: string(v4Type),
   223  		},
   224  		IPV6: &models.NodeAddressingElement{
   225  			Enabled:     option.Config.EnableIPv6,
   226  			IP:          v6Str,
   227  			AllocRange:  ipv6AllocStr,
   228  			AddressType: string(v6Type),
   229  		},
   230  	}
   231  }
   232  
   233  func (n *Node) isPrimaryAddress(addr Address, ipv4 bool) bool {
   234  	return addr.IP.String() == n.GetNodeIP(!ipv4).String()
   235  }
   236  
   237  func (n *Node) getSecondaryAddresses() []*models.NodeAddressingElement {
   238  	result := []*models.NodeAddressingElement{}
   239  
   240  	for _, addr := range n.IPAddresses {
   241  		ipv4 := false
   242  		if addr.IP.To4() != nil {
   243  			ipv4 = true
   244  		}
   245  		if !n.isPrimaryAddress(addr, ipv4) {
   246  			result = append(result, &models.NodeAddressingElement{
   247  				IP:          addr.IP.String(),
   248  				AddressType: string(addr.Type),
   249  			})
   250  		}
   251  	}
   252  
   253  	return result
   254  }
   255  
   256  func (n *Node) getHealthAddresses() *models.NodeAddressing {
   257  	if n.IPv4HealthIP == nil && n.IPv6HealthIP == nil {
   258  		return nil
   259  	}
   260  
   261  	var v4Str, v6Str string
   262  	if n.IPv4HealthIP != nil {
   263  		v4Str = n.IPv4HealthIP.String()
   264  	}
   265  	if n.IPv6HealthIP != nil {
   266  		v6Str = n.IPv6HealthIP.String()
   267  	}
   268  
   269  	return &models.NodeAddressing{
   270  		IPV4: &models.NodeAddressingElement{
   271  			Enabled: option.Config.EnableIPv4,
   272  			IP:      v4Str,
   273  		},
   274  		IPV6: &models.NodeAddressingElement{
   275  			Enabled: option.Config.EnableIPv6,
   276  			IP:      v6Str,
   277  		},
   278  	}
   279  }
   280  
   281  // GetModel returns the API model representation of a node.
   282  func (n *Node) GetModel() *models.NodeElement {
   283  	return &models.NodeElement{
   284  		Name:                  n.Fullname(),
   285  		PrimaryAddress:        n.getPrimaryAddress(),
   286  		SecondaryAddresses:    n.getSecondaryAddresses(),
   287  		HealthEndpointAddress: n.getHealthAddresses(),
   288  	}
   289  }
   290  
   291  // Identity returns the identity of the node
   292  func (n *Node) Identity() Identity {
   293  	return Identity{
   294  		Name:    n.Name,
   295  		Cluster: n.Cluster,
   296  	}
   297  }
   298  
   299  func getCluster() string {
   300  	return option.Config.ClusterName
   301  }
   302  
   303  // IsLocal returns true if this is the node on which the agent itself is
   304  // running on
   305  func (n *Node) IsLocal() bool {
   306  	return n != nil && n.Name == GetName() && n.Cluster == getCluster()
   307  }
   308  
   309  // PublicAttrEquals returns true only if the public attributes of both nodes
   310  // are the same otherwise returns false.
   311  func (n *Node) PublicAttrEquals(o *Node) bool {
   312  	if (n == nil) != (o == nil) {
   313  		return false
   314  	}
   315  
   316  	if n.Name == o.Name &&
   317  		n.Cluster == o.Cluster &&
   318  		n.IPv4HealthIP.Equal(o.IPv4HealthIP) &&
   319  		n.IPv6HealthIP.Equal(o.IPv6HealthIP) &&
   320  		n.ClusterID == o.ClusterID &&
   321  		n.Source == o.Source {
   322  
   323  		if len(n.IPAddresses) != len(o.IPAddresses) {
   324  			return false
   325  		}
   326  
   327  		for i := range n.IPAddresses {
   328  			if (n.IPAddresses[i].Type != o.IPAddresses[i].Type) ||
   329  				!n.IPAddresses[i].IP.Equal(o.IPAddresses[i].IP) {
   330  				return false
   331  			}
   332  		}
   333  
   334  		if (n.IPv4AllocCIDR == nil) != (o.IPv4AllocCIDR == nil) {
   335  			return false
   336  		}
   337  		if n.IPv4AllocCIDR.String() != o.IPv4AllocCIDR.String() {
   338  			return false
   339  		}
   340  
   341  		if (n.IPv6AllocCIDR == nil) != (o.IPv6AllocCIDR == nil) {
   342  			return false
   343  		}
   344  		if n.IPv6AllocCIDR.String() != o.IPv6AllocCIDR.String() {
   345  			return false
   346  		}
   347  
   348  		return true
   349  	}
   350  
   351  	return false
   352  }
   353  
   354  // GetKeyNodeName constructs the API name for the given cluster and node name.
   355  func GetKeyNodeName(cluster, node string) string {
   356  	// WARNING - STABLE API: Changing the structure of the key may break
   357  	// backwards compatibility
   358  	return path.Join(cluster, node)
   359  }
   360  
   361  // GetKeyName returns the kvstore key to be used for the node
   362  func (n *Node) GetKeyName() string {
   363  	return GetKeyNodeName(n.Cluster, n.Name)
   364  }
   365  
   366  // DeepKeyCopy creates a deep copy of the LocalKey
   367  func (n *Node) DeepKeyCopy() store.LocalKey {
   368  	return n.DeepCopy()
   369  }
   370  
   371  // Marshal returns the node object as JSON byte slice
   372  func (n *Node) Marshal() ([]byte, error) {
   373  	return json.Marshal(n)
   374  }
   375  
   376  // Unmarshal parses the JSON byte slice and updates the node receiver
   377  func (n *Node) Unmarshal(data []byte) error {
   378  	newNode := Node{}
   379  	if err := json.Unmarshal(data, &newNode); err != nil {
   380  		return err
   381  	}
   382  
   383  	*n = newNode
   384  
   385  	return nil
   386  }