...

Source file src/edge-infra.dev/pkg/sds/ien/network/info/info.go

Documentation: edge-infra.dev/pkg/sds/ien/network/info

     1  package info
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"net"
     7  
     8  	corev1 "k8s.io/api/core/v1"
     9  	kerrors "k8s.io/apimachinery/pkg/api/errors"
    10  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    11  	"k8s.io/apimachinery/pkg/types"
    12  
    13  	"sigs.k8s.io/controller-runtime/pkg/client"
    14  
    15  	calico "edge-infra.dev/pkg/k8s/net/calico"
    16  	"edge-infra.dev/pkg/sds/ien"
    17  )
    18  
    19  const (
    20  	clusterDNSKey         = "cluster-dns-ip"
    21  	podSubnetKey          = "pod-network-cidr"
    22  	serviceSubnetKey      = "service-network-cidr"
    23  	egressTunnelSubnetKey = "egress-tunnels-cidr"
    24  	// Default subnet for pod networks
    25  	PodSubnetDefault string = "100.127.0.0/16"
    26  	// Default IP address for CoreDNS service
    27  	ClusterDNSDefault string = "10.96.0.10"
    28  	// Default subnet for services
    29  	ServiceSubnetDefault string = "10.96.0.0/16"
    30  	// Default subnet for egress gateway
    31  	EgressTunnelSubnetDefault string = "10.80.0.0/22"
    32  )
    33  
    34  const (
    35  	Namespace string = "sds"
    36  	Name      string = "network-service-ips"
    37  )
    38  
    39  var (
    40  	ErrInvalidClusterDNSIP       = errors.New("invalid cluster dns ip address")
    41  	ErrInvalidPodSubnet          = errors.New("invalid pod subnet")
    42  	ErrInvalidServiceSubnet      = errors.New("invalid service subnet")
    43  	ErrInvalidEgressTunnelSubnet = errors.New("invalid egress gateway tunnel subnet")
    44  )
    45  
    46  type Info struct {
    47  	PodSubnet          string
    48  	ClusterDNSIP       string
    49  	ServiceSubnet      string
    50  	EgressTunnelSubnet string
    51  }
    52  
    53  // Instantiates a new network info object set with default values
    54  func New() *Info {
    55  	return &Info{
    56  		PodSubnet:          PodSubnetDefault,
    57  		ServiceSubnet:      ServiceSubnetDefault,
    58  		ClusterDNSIP:       ClusterDNSDefault,
    59  		EgressTunnelSubnet: EgressTunnelSubnetDefault,
    60  	}
    61  }
    62  
    63  // FromClient constructs the Info object from a kubernetes client
    64  func (i *Info) FromClient(ctx context.Context, k8sClient client.Client) (*Info, error) {
    65  	cm := &corev1.ConfigMap{}
    66  	if err := k8sClient.Get(ctx, configMapKey(), cm); kerrors.IsNotFound(err) {
    67  		return New(), nil
    68  	} else if err != nil {
    69  		return nil, err
    70  	}
    71  	return i.FromConfigMap(cm), nil
    72  }
    73  
    74  // FromConfigMap constructs the Info object from a k8s config map
    75  func (i *Info) FromConfigMap(cm *corev1.ConfigMap) *Info {
    76  	i = New()
    77  	if cm.Data[clusterDNSKey] != "" {
    78  		i.ClusterDNSIP = cm.Data[clusterDNSKey]
    79  	}
    80  	if cm.Data[podSubnetKey] != "" {
    81  		i.PodSubnet = cm.Data[podSubnetKey]
    82  	}
    83  	if cm.Data[serviceSubnetKey] != "" {
    84  		i.ServiceSubnet = cm.Data[serviceSubnetKey]
    85  	}
    86  	if cm.Data[egressTunnelSubnetKey] != "" {
    87  		i.EgressTunnelSubnet = cm.Data[egressTunnelSubnetKey]
    88  	}
    89  	return i
    90  }
    91  
    92  func (i *Info) ToConfigMap() *corev1.ConfigMap {
    93  	return &corev1.ConfigMap{
    94  		TypeMeta:   typemeta(),
    95  		ObjectMeta: metadata(),
    96  		Data: map[string]string{
    97  			clusterDNSKey:         i.ClusterDNSIP,
    98  			podSubnetKey:          i.PodSubnet,
    99  			serviceSubnetKey:      i.ServiceSubnet,
   100  			egressTunnelSubnetKey: i.EgressTunnelSubnet,
   101  		},
   102  	}
   103  }
   104  
   105  // Verfies that the info struct contains valid subnets
   106  func (i *Info) Validate() error {
   107  	if ip := net.ParseIP(i.ClusterDNSIP); ip == nil {
   108  		return ErrInvalidClusterDNSIP
   109  	}
   110  	if _, _, err := net.ParseCIDR(i.EgressTunnelSubnet); err != nil {
   111  		return ErrInvalidEgressTunnelSubnet
   112  	}
   113  	if _, _, err := net.ParseCIDR(i.PodSubnet); err != nil {
   114  		return ErrInvalidPodSubnet
   115  	}
   116  	if _, _, err := net.ParseCIDR(i.ServiceSubnet); err != nil {
   117  		return ErrInvalidServiceSubnet
   118  	}
   119  	return nil
   120  }
   121  
   122  func configMapKey() client.ObjectKey {
   123  	return client.ObjectKey{Namespace: Namespace, Name: Name}
   124  }
   125  
   126  // generates a blank network info config map
   127  func newNetworkInfoConfigMap() corev1.ConfigMap {
   128  	return corev1.ConfigMap{
   129  		TypeMeta:   typemeta(),
   130  		ObjectMeta: metadata(),
   131  	}
   132  }
   133  
   134  // network info config map type meta
   135  func typemeta() metav1.TypeMeta {
   136  	return metav1.TypeMeta{
   137  		Kind:       "ConfigMap",
   138  		APIVersion: corev1.SchemeGroupVersion.String(),
   139  	}
   140  }
   141  
   142  // network info config map meta data
   143  func metadata() metav1.ObjectMeta {
   144  	return metav1.ObjectMeta{
   145  		Name:      configMapKey().Name,
   146  		Namespace: configMapKey().Namespace,
   147  	}
   148  }
   149  
   150  var (
   151  	ErrNodeCIDRNotFound = errors.New("could not find a unique CIDR for the host node")
   152  )
   153  
   154  // HostCIDRFromClient returns the CIDR of the host node if it exists
   155  func HostCIDRFromClient(ctx context.Context, client client.Reader) (string, error) {
   156  	hostname, err := ien.GetHostname()
   157  	if err != nil {
   158  		return "", err
   159  	}
   160  	node := corev1.Node{}
   161  	if err := client.Get(ctx, types.NamespacedName{Name: hostname}, &node); err != nil {
   162  		return "", err
   163  	}
   164  	cidrs, err := calico.ParseNodeCIDRs(node)
   165  	if err != nil {
   166  		return "", err
   167  	}
   168  	if len(cidrs) != 1 {
   169  		return "", ErrNodeCIDRNotFound
   170  	}
   171  	return cidrs[0].String(), nil
   172  }
   173  

View as plain text