commit 0049fb818ce2e4a47e5a0744e54f8cc307579a60 Author: Joel D. Elkins Date: Thu Jul 14 13:52:28 2022 -0500 Initial commit diff --git a/cmd/ccl/ccl.go b/cmd/ccl/ccl.go new file mode 100644 index 0000000..23d2bc9 --- /dev/null +++ b/cmd/ccl/ccl.go @@ -0,0 +1,237 @@ +package main + +import ( + "fmt" + "log" + "os" + "strings" + + "github.com/emirpasic/gods/sets/hashset" + toml "github.com/pelletier/go-toml" + "golang.org/x/exp/slices" +) + +const ( + CONFIG_FILE = "/etc/containerdefs.toml" +) + +type Network struct { + Name string + DNS []string + IPv6 bool `default:true` + IPv4Address string `toml:"ipv4_address"` + IPv6Address string `toml:"ipv6_address"` +} + +type Container struct { + Category string + Name string + Image string + Hostname string + Command string + Arguments string + Networks []Network + createCommands []string + upCommands []string +} + +type command string + +const ( + CREATE command = "create" + START command = "start" +) + +var ( + networks *[]Network + containers *[]Container + categories *[]string + commands = map[command]func(*Container){ + CREATE: PrintCreate, + START: PrintStart, + } +) + +// A parsing convenience +type parse struct { + Networks []Network + Containers []Container +} + +func Categories() []string { + if categories != nil { + return *categories + } + categories = &[]string{"all"} + gs := hashset.New() + for _, c := range *containers { + gs.Add(c.Category) + } + for _, c := range gs.Values() { + *categories = append(*categories, c.(string)) + } + return *categories +} + +func Union(ids []string) (conts []Container) { + h := hashset.New() + for _, id := range ids { + for _, c := range *containers { + if id == "all" || c.Name == id || c.Category == id { + h.Add(c.Name) + } + } + } + for _, c := range h.Values() { + name := c.(string) + match := slices.IndexFunc(*containers, func(c Container) bool { return c.Name == name }) + conts = append(conts, (*containers)[match]) + } + return +} + +func Init(configFile string) { + f, err := os.ReadFile(configFile) + if err != nil { + return + } + p := parse{} + err = toml.Unmarshal(f, &p) + if err != nil { + return + } + containers, networks = &p.Containers, &p.Networks + for i, c := range p.Containers { + p.Containers[i].createCommands, p.Containers[i].upCommands = c.MakeCommands() + } +} + +func netToArgs(c *Network) string { + net := "%s%s%s" + ipv4 := "" + if c.IPv4Address != "" { + ipv4 = fmt.Sprintf(" --ip %s", c.IPv4Address) + } + ipv6 := "" + if c.IPv6Address != "" { + ipv6 = fmt.Sprintf(" --ip6 %s", c.IPv6Address) + } + net = fmt.Sprintf(net, c.Name, ipv4, ipv6) + return net +} + +func NetworkDefaults(name string) (net *Network) { + for _, n := range *networks { + if n.Name == name { + net = &n + } + } + return +} + +func ClearRACommands(c *Container) *[]string { + cmds := []string{} + for _, n := range c.Networks { + nw := NetworkDefaults(n.Name) + if !nw.IPv6 { + cmds = append(cmds, fmt.Sprintf("ip netns exec %s sysctl -w net.ipv6.conf.default.accept_ra=0", c.Name)) + cmds = append(cmds, fmt.Sprintf("ip netns exec %s sysctl -w net.ipv6.conf.all.accept_ra=0", c.Name)) + // TODO: iterate through invoices and set the accpet_ra parameter to zero for each + return &cmds + } + } + return &cmds +} + +func (c *Container) MakeCommands() ([]string, []string) { + cmd := []string{ + "podman create --name %s%s%s%s%s%s", + } + hostname := "" + if c.Hostname != "" { + hostname = fmt.Sprintf(" --hostname %s", c.Hostname) + } + net := "" + dns := "" + if len(c.Networks) > 0 { + net = " --net " + netToArgs(&c.Networks[0]) + if len(c.Networks[0].DNS) > 0 { + dns = " --dns " + strings.Join(c.Networks[0].DNS, ",") + } else if len(NetworkDefaults(c.Networks[0].Name).DNS) > 0 { + dns = " --dns " + strings.Join(NetworkDefaults(c.Networks[0].Name).DNS, ",") + } + } + args := "" + if c.Arguments != "" { + args = " " + c.Arguments + } + entry := "" + if c.Command != "" { + entry = " " + c.Command + } + cmd[0] = fmt.Sprintf(cmd[0], c.Name, hostname, net, dns, args, entry) + + if len(c.Networks) > 1 { + for i := 1; i < len(c.Networks); i++ { + n := c.Networks[i] + s := fmt.Sprintf("podman network connect %s %s", c.Name, netToArgs(&n)) + cmd = append(cmd, s) + } + } + + up := []string{} + if len(c.Networks) > 0 { + if !c.Networks[0].IPv6 || !NetworkDefaults(c.Networks[0].Name).IPv6 { + for _, k := range *ClearRACommands(c) { + up = append(up, k) + } + up = append(up, fmt.Sprintf("ip netns exec %s ip -6 address flush scope global", c.Name)) + up = append(up, fmt.Sprintf("ip netns exec %s ip -6 route flush proto ra", c.Name)) + } + } + + return cmd, up +} + +func main() { + Init(CONFIG_FILE) + containers := Union([]string{"all"}) + if len(os.Args) > 1 { + containers = Union(os.Args[1:]) + } + for _, c := range containers { + commands[CREATE](&c) + // commands[START](&c) + } + log.Printf("CATEGORIES: %v", Categories()) +} + +func PrintCreate(ct *Container) { + for _, c := range ct.createCommands { + fmt.Println(c) + } +} + +func (c *Container) Pid() int { + return 0 +} + +func (c *Container) AssureNetNS() { + // stat, _ := file.Stat("/var/run/netns") + // if !stat.IsDir() { + // os.MkdirAll("/var/run/netns", os.ModePerm) + // } +} + +func PrintStart(ct *Container) { + start_commands := []string{ + "podman start " + ct.Name, + "sleep 1", + } + for _, c := range ct.upCommands { + start_commands = append(start_commands, c) + } + for _, c := range start_commands { + fmt.Println(c) + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..f0cbcc4 --- /dev/null +++ b/go.mod @@ -0,0 +1,9 @@ +module gitea.elkins.co/Networking/ccl + +go 1.18 + +require ( + github.com/emirpasic/gods v1.18.1 + github.com/pelletier/go-toml v1.9.5 + golang.org/x/exp v0.0.0-20220713135740-79cabaa25d75 +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..3a2b991 --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +golang.org/x/exp v0.0.0-20220713135740-79cabaa25d75 h1:x03zeu7B2B11ySp+daztnwM5oBJ/8wGUSqrwcw9L0RA= +golang.org/x/exp v0.0.0-20220713135740-79cabaa25d75/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=