functions

The Fool guy's FAAS
git clone git://git.lair.cx/functions
Log | Files | Refs | README

cniconf.go (2879B)


      1 package main
      2 
      3 import (
      4 	"bytes"
      5 	"encoding/json"
      6 	"fmt"
      7 	"os"
      8 	"path"
      9 	"text/template"
     10 
     11 	_ "embed"
     12 )
     13 
     14 const (
     15 	cniPluginDir = "/opt/cni/bin"
     16 )
     17 
     18 //go:embed cni.conflist
     19 var cniConfListData []byte
     20 
     21 var cniConfListTemplate = template.Must(
     22 	template.New("cni.conflist").
     23 		Parse(string(cniConfListData)),
     24 )
     25 
     26 type cniTemplateData struct {
     27 	Name       string
     28 	BridgeName string
     29 	Subnet     string
     30 }
     31 
     32 func generateCNIConfList(data *cniTemplateData) ([]byte, error) {
     33 	buf := bytes.NewBuffer(nil)
     34 
     35 	err := cniConfListTemplate.Execute(buf, data)
     36 	if err != nil {
     37 		return nil, fmt.Errorf("failed to generate fake CNI config: %w", err)
     38 	}
     39 
     40 	return buf.Bytes(), nil
     41 }
     42 
     43 type cniConfList struct {
     44 	Version string          `json:"cniVersion"`
     45 	Name    string          `json:"name"`
     46 	Plugins []cniPluginConf `json:"plugins"`
     47 }
     48 
     49 func (c *cniConfList) RequiredPlugins() []string {
     50 	var plugins []string
     51 
     52 	for _, plugin := range c.Plugins {
     53 		plugins = append(plugins, plugin.RequiredPlugins()...)
     54 	}
     55 
     56 	return plugins
     57 }
     58 
     59 type cniPluginConf struct {
     60 	Type string       `json:"type"`
     61 	IPAM *cniIPAMConf `json:"ipam,omitempty"`
     62 }
     63 
     64 func (c *cniPluginConf) RequiredPlugins() []string {
     65 	plugins := []string{c.Type}
     66 
     67 	if c.IPAM != nil {
     68 		plugins = append(plugins, c.IPAM.RequiredPlugins()...)
     69 	}
     70 
     71 	return plugins
     72 }
     73 
     74 type cniIPAMConf struct {
     75 	Type string `json:"type"`
     76 }
     77 
     78 func (c *cniIPAMConf) RequiredPlugins() []string {
     79 	return []string{c.Type}
     80 }
     81 
     82 // checkCNIPlugin checks that a CNI plugin is installed
     83 func checkCNIPlugin(plugin string) (bool, error) {
     84 	stat, err := os.Stat(path.Join(cniPluginDir, plugin))
     85 	if err != nil {
     86 		if os.IsNotExist(err) {
     87 			return false, nil
     88 		}
     89 
     90 		return false, fmt.Errorf("failed to stat CNI plugin: %w", err)
     91 	}
     92 
     93 	// Check that the plugin is a file
     94 	if !stat.Mode().IsRegular() {
     95 		return false, nil
     96 	}
     97 
     98 	// Check that the plugin is executable
     99 	if stat.Mode()&0111 != 0111 {
    100 		return false, nil
    101 	}
    102 
    103 	return true, nil
    104 }
    105 
    106 func checkCNIPlugins(conf *cniConfList) (bool, error) {
    107 	plugins := conf.RequiredPlugins()
    108 	for _, plugin := range plugins {
    109 		if ok, err := checkCNIPlugin(plugin); !ok {
    110 			return false, err
    111 		}
    112 	}
    113 
    114 	return true, nil
    115 }
    116 
    117 func checkNetwork() error {
    118 	confListBytes, err := generateCNIConfList(&cniTemplateData{
    119 		Name:       "fakenet0",
    120 		BridgeName: "fnbr0",
    121 		Subnet:     "1.2.3.0/24",
    122 	})
    123 	if err != nil {
    124 		return fmt.Errorf("failed to generate fake CNI config: %w", err)
    125 	}
    126 
    127 	var fakeConf cniConfList
    128 	err = json.Unmarshal(confListBytes, &fakeConf)
    129 	if err != nil {
    130 		return fmt.Errorf("invalid CNI configuration template: %w", err)
    131 	}
    132 
    133 	// Check that the CNI plugins are installed
    134 	if ok, err := checkCNIPlugins(&fakeConf); err != nil {
    135 		return fmt.Errorf("failed to check CNI plugins: %w", err)
    136 	} else if !ok {
    137 		return fmt.Errorf(
    138 			"CNI plugins are not installed. required: %v",
    139 			fakeConf.RequiredPlugins(),
    140 		)
    141 	}
    142 
    143 	return nil
    144 }