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 }