package cmd import ( "os" "fmt" "strings" "github.com/spf13/viper" log "github.com/sirupsen/logrus" ) /******************************************************************************** * Initialize datastore(s) /iocage, /iocage/jails * Put defaults.json, * Update it with hostid, interfaces, and maybe other necessary fields * Initialize bridge *******************************************************************************/ func InitGoCage(args []string) { // Create datastores for _, dstore := range viper.GetStringSlice("datastore") { log.Debugf("Ranging over %v\n", dstore) dset, err := zfsGetDatasetByMountpoint(dstore) if err != nil && strings.HasSuffix(err.Error(), "No such file or directory\"") { if len(gZPool) == 0 { log.Errorf("Datastore mountpoint \"%s\" does not exist. Specify a pool if you want to create it.", dstore) return } // Create dataset /iocage rootDSName := fmt.Sprintf("%s%s", gZPool, dstore) log.Debugf("Creating dataset %s mounted on %s\n", rootDSName, dstore) if err = zfsCreateDataset(rootDSName, dstore, ""); err != nil { log.Errorf("Error creating dataset %s: %v\n", rootDSName, err) return } // Create /iocage/jail, releases, templates for _, l := range []string{"jails","releases","templates"} { cds := fmt.Sprintf("%s/%s", rootDSName, l) cmp := fmt.Sprintf("%s/%s", dstore, l) log.Debugf("Creating dataset %s mounted on %s\n", cds, cmp) if err = zfsCreateDataset(cds, cmp, ""); err != nil { log.Errorf("Error creating dataset %s: %v\n", cds, err) return } } // Create /iocage/defaults.json exists, err := doFileExist(fmt.Sprintf("%s/defaults.json", dstore)) if err != nil { log.Errorf("Error checking defaults.json: %v\n", err) return } if !exists { if err = createDefaultsJson(dstore, gBridge); err != nil { log.Errorf("%v\n", err) } } } else if err != nil { log.Errorf("Error checking datastore existence: %v\n", err) return } else { log.Debugf("Datastore dataset exist: %s\n", dset) } } // Check and create bridge // FIXME: What if bridge name is invalid, as we already wrote it in defaults.json in dstore loop? if len(gBridge) > 0 && len(gInterface) > 0 { if err := initBridge(); err != nil { log.Errorf("%v\n", err) } } } func createDefaultsJson(rootDirectory string, bridge string) error { hostid, err := os.ReadFile("/etc/hostid") if err != nil { log.Fatalf("Unable to read /etc/hostid: %v\n", err) } json := strings.Replace(gDefaultsJson, "TO-BE-REPLACED-WITH-HOSTID", strings.Trim(string(hostid), "\n"), 1) json = strings.Replace(json, "TO-BE-REPLACED-WITH-BRIDGE", bridge, 1) if err := os.WriteFile(fmt.Sprintf("%s/defaults.json", rootDirectory), []byte(json), 0640); err != nil { log.Fatal(err) } return nil } func createInterface(iface string) error { log.Debugf("creating interface \"%s\"\n", iface) cmd := fmt.Sprintf("/sbin/ifconfig %s create", iface) _, err := executeCommand(cmd) if err != nil { return err } return nil } func bringUpInterface(iface string) error { log.Debugf("bringing up interface \"%s\"\n", iface) cmd := fmt.Sprintf("/sbin/ifconfig %s up", iface) _, err := executeCommand(cmd) if err != nil { return err } return nil } func addMemberToBridge(bridge string, iface string) error { log.Debugf("adding member interface \"%s\" to bridge \"%s\"\n", iface, bridge) cmd := fmt.Sprintf("/sbin/ifconfig %s addm %s", bridge, iface) _, err := executeCommand(cmd) if err != nil { return err } return nil } func initBridge() error { hostInt, err := gJailHost.GetInterfaces() if err != nil { return fmt.Errorf("Error listing interfaces: %v\n", err) } if !isStringInArray(hostInt, gInterface) { return fmt.Errorf("Interface not found: %s\n", gInterface) } if !isStringInArray(hostInt, gBridge) { if err := createInterface(gBridge); err != nil { return fmt.Errorf("Error creating bridge: %v\n", err) } if err := bringUpInterface(gBridge); err != nil { return fmt.Errorf("Error bringing up bridge: %v\n", err) } log.Infof("bridge was created, but it won't persist reboot. Configure rc.conf to persist. See https://docs.freebsd.org/en/books/handbook/advanced-networking/#network-bridging\n") log.Infof("It is strongly suggested you move interface %s IP to bridge %s\n", gInterface, gBridge) } // FIXME: Need to check if not already member members, err := getBridgeMembers(gBridge) if err != nil { return fmt.Errorf("Error getting bridge members: %v\n", err) } // Return if interface already member of the bridge for _, m := range members { log.Debugf("Bridge member: %s\n", m) if strings.EqualFold(m, gInterface) { return nil } } if err := addMemberToBridge(gBridge, gInterface); err != nil { return fmt.Errorf("Error adding interface to bridge: %v\n", err) } return nil }