...

Source file src/edge-infra.dev/pkg/sds/ien/k8s/controllers/nodeagent/plugins/networking/iptables/iptables.go

Documentation: edge-infra.dev/pkg/sds/ien/k8s/controllers/nodeagent/plugins/networking/iptables

     1  package iptables
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"embed"
     7  	"io/fs"
     8  	"os"
     9  	"path/filepath"
    10  	"sort"
    11  	"text/template"
    12  
    13  	"github.com/spf13/afero"
    14  
    15  	v1 "k8s.io/api/core/v1"
    16  
    17  	k8snet "edge-infra.dev/pkg/k8s/net/calico"
    18  	"edge-infra.dev/pkg/k8s/runtime/controller/reconcile"
    19  	v1ien "edge-infra.dev/pkg/sds/ien/k8s/apis/v1"
    20  	"edge-infra.dev/pkg/sds/ien/k8s/controllers/nodeagent/config"
    21  	"edge-infra.dev/pkg/sds/ien/k8s/controllers/nodeagent/plugins/networking/netplan"
    22  	network "edge-infra.dev/pkg/sds/ien/network/info"
    23  	nodemeta "edge-infra.dev/pkg/sds/ien/node"
    24  )
    25  
    26  var (
    27  	//go:embed rules/*
    28  	targetRules embed.FS
    29  	fwDirectory = "/etc/ien-fw/ipv4/dynamic"
    30  )
    31  
    32  type Plugin struct {
    33  	config config.Config
    34  	ienode *v1ien.IENode
    35  }
    36  
    37  type renderingParameters struct {
    38  	IsGateway       bool
    39  	DefaultLinkName string
    40  	TunnelNetwork   string
    41  	ServiceNetwork  string
    42  	ClusterNetwork  string
    43  	LocalNodeIP     string
    44  	GatewayNodeIP   string
    45  	OtherNodeIPs    []string
    46  	KubeVip         string
    47  }
    48  
    49  func (p Plugin) Reconcile(ctx context.Context, ienode *v1ien.IENode, cfg config.Config) (reconcile.Result, error) {
    50  	p.ienode = ienode
    51  	p.config = cfg
    52  	renderingParameters, err := p.compileRenderingParameters(ctx)
    53  	if err != nil {
    54  		return reconcile.ResultRequeue, err
    55  	}
    56  	if err := p.renderRules(renderingParameters); err != nil {
    57  		return reconcile.ResultRequeue, err
    58  	}
    59  	return reconcile.ResultSuccess, nil
    60  }
    61  
    62  func (p Plugin) renderRules(params *renderingParameters) error {
    63  	return fs.WalkDir(targetRules, "rules", func(path string, dir os.DirEntry, err error) error {
    64  		if dir.IsDir() || err != nil {
    65  			return err
    66  		}
    67  		template, err := template.ParseFS(targetRules, path)
    68  		if err != nil {
    69  			return err
    70  		}
    71  
    72  		basename := filepath.Base(path)
    73  		fwPath := filepath.Join(fwDirectory, basename)
    74  
    75  		var output bytes.Buffer
    76  		if err = template.ExecuteTemplate(&output, basename, params); err != nil {
    77  			return err
    78  		}
    79  
    80  		if equal, err := p.isFileContentsEqual(output.Bytes(), fwPath); err != nil || equal {
    81  			return err
    82  		}
    83  
    84  		return afero.WriteFile(p.config.Fs(), fwPath, output.Bytes(), 0644)
    85  	})
    86  }
    87  
    88  func (p Plugin) compileRenderingParameters(ctx context.Context) (*renderingParameters, error) {
    89  	params := &renderingParameters{}
    90  	params.IsGateway = p.ienode.Spec.IsGatewayNode()
    91  	tunnelNet, err := netplan.GetTunnelSubnet(ctx, p.config.GetClient())
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  
    96  	params.TunnelNetwork = tunnelNet.String()
    97  	params.KubeVip = p.ienode.Spec.KubeVip
    98  
    99  	if err := p.compileNetworkServiceParameters(ctx, params); err != nil {
   100  		return nil, err
   101  	}
   102  	if err := p.compileNodeParameters(ctx, params); err != nil {
   103  		return nil, err
   104  	}
   105  	return params, nil
   106  }
   107  
   108  func (p Plugin) compileNetworkServiceParameters(ctx context.Context, params *renderingParameters) error {
   109  	info := &network.Info{}
   110  	info, err := info.FromClient(ctx, p.config.GetClient())
   111  	if err != nil {
   112  		return err
   113  	}
   114  	params.ClusterNetwork = info.PodSubnet
   115  	params.ServiceNetwork = info.ServiceSubnet
   116  	return nil
   117  }
   118  
   119  // return list node networks to ignore rate limiting class
   120  func (p Plugin) compileNodeParameters(ctx context.Context, params *renderingParameters) error {
   121  	nodes, err := p.getNodes(ctx)
   122  	if err != nil {
   123  		return err
   124  	}
   125  
   126  	for _, node := range nodes {
   127  		node := node
   128  		ip, err := k8snet.ParseNodeIPs(node)
   129  		if err != nil {
   130  			return err
   131  		}
   132  		isGatewayNode, err := nodemeta.IsControlPlaneNode(&node)
   133  		if err != nil {
   134  			return err
   135  		}
   136  		if isGatewayNode {
   137  			params.GatewayNodeIP = ip[0].String()
   138  		}
   139  		if node.ObjectMeta.Name == p.ienode.ObjectMeta.Name {
   140  			params.LocalNodeIP = ip[0].String()
   141  			continue
   142  		}
   143  		params.OtherNodeIPs = append(params.OtherNodeIPs, ip[0].String())
   144  	}
   145  
   146  	address, err := p.ienode.Spec.DefaultMacAddress()
   147  	if err != nil {
   148  		return err
   149  	}
   150  
   151  	defaultLink, err := p.config.GetInterfaceFromHardwareAddress(address)
   152  	if err != nil {
   153  		return err
   154  	}
   155  	params.DefaultLinkName = defaultLink.Attrs().Name
   156  	return nil
   157  }
   158  
   159  func (p Plugin) isFileContentsEqual(contents []byte, path string) (bool, error) {
   160  	exists, err := afero.Exists(p.config.Fs(), path)
   161  	if err != nil || !exists {
   162  		return false, err
   163  	}
   164  
   165  	oldContents, err := afero.ReadFile(p.config.Fs(), path)
   166  	if err != nil {
   167  		return false, err
   168  	}
   169  
   170  	return bytes.Equal(oldContents, contents), nil
   171  }
   172  
   173  func (p Plugin) getNodes(ctx context.Context) ([]v1.Node, error) {
   174  	nodeList := &v1.NodeList{}
   175  	if err := p.config.GetClient().List(ctx, nodeList); err != nil {
   176  		return nil, err
   177  	}
   178  
   179  	nodes := nodeList.Items
   180  	sortNodesByName(nodes)
   181  
   182  	return nodes, nil
   183  }
   184  
   185  func sortNodesByName(nodes []v1.Node) {
   186  	sort.Slice(nodes, func(i, j int) bool {
   187  		return nodes[i].GetName() < nodes[j].GetName()
   188  	})
   189  }
   190  

View as plain text