package info import ( "context" "errors" "net" corev1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" calico "edge-infra.dev/pkg/k8s/net/calico" "edge-infra.dev/pkg/sds/ien" ) const ( clusterDNSKey = "cluster-dns-ip" podSubnetKey = "pod-network-cidr" serviceSubnetKey = "service-network-cidr" egressTunnelSubnetKey = "egress-tunnels-cidr" // Default subnet for pod networks PodSubnetDefault string = "100.127.0.0/16" // Default IP address for CoreDNS service ClusterDNSDefault string = "10.96.0.10" // Default subnet for services ServiceSubnetDefault string = "10.96.0.0/16" // Default subnet for egress gateway EgressTunnelSubnetDefault string = "10.80.0.0/22" ) const ( Namespace string = "sds" Name string = "network-service-ips" ) var ( ErrInvalidClusterDNSIP = errors.New("invalid cluster dns ip address") ErrInvalidPodSubnet = errors.New("invalid pod subnet") ErrInvalidServiceSubnet = errors.New("invalid service subnet") ErrInvalidEgressTunnelSubnet = errors.New("invalid egress gateway tunnel subnet") ) type Info struct { PodSubnet string ClusterDNSIP string ServiceSubnet string EgressTunnelSubnet string } // Instantiates a new network info object set with default values func New() *Info { return &Info{ PodSubnet: PodSubnetDefault, ServiceSubnet: ServiceSubnetDefault, ClusterDNSIP: ClusterDNSDefault, EgressTunnelSubnet: EgressTunnelSubnetDefault, } } // FromClient constructs the Info object from a kubernetes client func (i *Info) FromClient(ctx context.Context, k8sClient client.Client) (*Info, error) { cm := &corev1.ConfigMap{} if err := k8sClient.Get(ctx, configMapKey(), cm); kerrors.IsNotFound(err) { return New(), nil } else if err != nil { return nil, err } return i.FromConfigMap(cm), nil } // FromConfigMap constructs the Info object from a k8s config map func (i *Info) FromConfigMap(cm *corev1.ConfigMap) *Info { i = New() if cm.Data[clusterDNSKey] != "" { i.ClusterDNSIP = cm.Data[clusterDNSKey] } if cm.Data[podSubnetKey] != "" { i.PodSubnet = cm.Data[podSubnetKey] } if cm.Data[serviceSubnetKey] != "" { i.ServiceSubnet = cm.Data[serviceSubnetKey] } if cm.Data[egressTunnelSubnetKey] != "" { i.EgressTunnelSubnet = cm.Data[egressTunnelSubnetKey] } return i } func (i *Info) ToConfigMap() *corev1.ConfigMap { return &corev1.ConfigMap{ TypeMeta: typemeta(), ObjectMeta: metadata(), Data: map[string]string{ clusterDNSKey: i.ClusterDNSIP, podSubnetKey: i.PodSubnet, serviceSubnetKey: i.ServiceSubnet, egressTunnelSubnetKey: i.EgressTunnelSubnet, }, } } // Verfies that the info struct contains valid subnets func (i *Info) Validate() error { if ip := net.ParseIP(i.ClusterDNSIP); ip == nil { return ErrInvalidClusterDNSIP } if _, _, err := net.ParseCIDR(i.EgressTunnelSubnet); err != nil { return ErrInvalidEgressTunnelSubnet } if _, _, err := net.ParseCIDR(i.PodSubnet); err != nil { return ErrInvalidPodSubnet } if _, _, err := net.ParseCIDR(i.ServiceSubnet); err != nil { return ErrInvalidServiceSubnet } return nil } func configMapKey() client.ObjectKey { return client.ObjectKey{Namespace: Namespace, Name: Name} } // generates a blank network info config map func newNetworkInfoConfigMap() corev1.ConfigMap { return corev1.ConfigMap{ TypeMeta: typemeta(), ObjectMeta: metadata(), } } // network info config map type meta func typemeta() metav1.TypeMeta { return metav1.TypeMeta{ Kind: "ConfigMap", APIVersion: corev1.SchemeGroupVersion.String(), } } // network info config map meta data func metadata() metav1.ObjectMeta { return metav1.ObjectMeta{ Name: configMapKey().Name, Namespace: configMapKey().Namespace, } } var ( ErrNodeCIDRNotFound = errors.New("could not find a unique CIDR for the host node") ) // HostCIDRFromClient returns the CIDR of the host node if it exists func HostCIDRFromClient(ctx context.Context, client client.Reader) (string, error) { hostname, err := ien.GetHostname() if err != nil { return "", err } node := corev1.Node{} if err := client.Get(ctx, types.NamespacedName{Name: hostname}, &node); err != nil { return "", err } cidrs, err := calico.ParseNodeCIDRs(node) if err != nil { return "", err } if len(cidrs) != 1 { return "", ErrNodeCIDRNotFound } return cidrs[0].String(), nil }