diff --git a/cmd/create.go b/cmd/create.go new file mode 100644 index 0000000..1bb4fb2 --- /dev/null +++ b/cmd/create.go @@ -0,0 +1,196 @@ +package cmd + +import ( + "os" + "fmt" + //"log" + "time" + "strings" + log "github.com/sirupsen/logrus" +) + +// TODO : Add a flag to specify which parts of freebsd base we want : Slim jail only need base.txz, neither lib32 nor src.txz +func CreateJail(args []string) { + var err error + var jtype []string + + if len(gCreateArgs.JailType) > 0 { + jtype = []string{gCreateArgs.JailType} + } + + for _, jname := range args { + // Check if jail exist and is distinctly named + _, err = getJailFromArray(jname, jtype, gJails) + if err != nil { + if strings.EqualFold(err.Error(), "Jail not found") { + + } else { + fmt.Printf("ERROR: %s\n", err.Error()) + return + } + } else { + fmt.Printf("Jail exist: %s\n", jname) + continue + } + + fmt.Printf(" > create jail %s\n", jname) + + var ds *Datastore + if len(gCreateArgs.Datastore) > 0 { + fmt.Printf("DEBUG: Use %s datastore\n", gCreateArgs.Datastore) + ds, err = getDatastoreFromArray(gCreateArgs.Datastore, gDatastores) + if err != nil { + fmt.Printf("ERROR Getting datastore: %s\n", gCreateArgs.Datastore, err.Error()) + return + } + } else { + ds = &gDatastores[0] + } + + /* + // Create and populate datasets + err = zfsCreateDataset(fmt.Sprintf("%s/jails/%s", ds.ZFSDataset, jname), fmt.Sprintf("%s/jails/%s", ds.Mountpoint, jname), "lz4") + if err != nil { + fmt.Printf("ERROR: %s\n", err.Error()) + return + } + err = zfsCreateDataset(fmt.Sprintf("%s/jails/%s/root", ds.ZFSDataset, jname), fmt.Sprintf("%s/jails/%s/root", ds.Mountpoint, jname), "lz4") + if err != nil { + fmt.Printf("ERROR: %s\n", err.Error()) + return + } + */ + + // Get base template if specified + if len(gCreateArgs.BaseTemplate) > 0 { + log.Debugf("Jail will be created from a base template\n") + /*bj, err := getJailFromArray(jname, []string{"template"}, gJails) + if err != nil { + if strings.EqualFold(err.Error(), "Jail not found") { + + } else { + fmt.Printf("ERROR: %s\n", err.Error()) + return + } + } else { + fmt.Printf("Jail exist: %s\n", jname) + continue + }*/ + } else { + // Normal jail with its own freebsd base + log.Debugf("Creating jail with its own freebsd base\n") + + // First check if we got release on the same datastore + _, err := os.Stat(fmt.Sprintf("%s/releases/%s/root", ds.Mountpoint, gCreateArgs.Release)) + if os.IsNotExist(err) { + fmt.Printf("ERROR: Release locally not available. Run \"gocage fetch\"\n") + return + } + + /////////////////////////////////////////////////////////////////////// + // + // Create and populate jail filesystem + dstDset := fmt.Sprintf("%s/jails/%s", ds.ZFSDataset, jname) + fmt.Printf(" > Initialize dataset %s\n", dstDset) + sNow := time.Now().Format("20060102150405") + reldset := fmt.Sprintf("%s/releases/%s", ds.ZFSDataset, gCreateArgs.Release) + err = zfsSnapshot(reldset, sNow) + if err != nil { + fmt.Printf("ERROR Creating snapshot of %s: %s\n", reldset, err.Error()) + return + } + + err = zfsCopy(fmt.Sprintf("%s@%s", reldset, sNow), dstDset) + if err != nil { + fmt.Printf("ERROR sending snapshot to %s: %s\n", dstDset, err.Error()) + return + } + // Remove snapshot of release, then snapshot of destination dataset + err = zfsDestroy(fmt.Sprintf("%s@%s", reldset, sNow)) + if err != nil { + fmt.Printf("ERROR destroying snapshot %s: %s\n", reldset, err.Error()) + return + } + err = zfsDestroy(fmt.Sprintf("%s@%s", dstDset, sNow)) + if err != nil { + fmt.Printf("ERROR destroying snapshot %s: %s\n", dstDset, err.Error()) + return + } + + dstRootDset := fmt.Sprintf("%s/jails/%s/root", ds.ZFSDataset, jname) + fmt.Printf(" > Initialize dataset %s\n", dstRootDset) + relrootdset := fmt.Sprintf("%s/releases/%s/root", ds.ZFSDataset, gCreateArgs.Release) + err = zfsSnapshot(relrootdset, sNow) + if err != nil { + fmt.Printf("ERROR Creating snapshot of %s: %s\n", relrootdset, err.Error()) + return + } + err = zfsCopy(fmt.Sprintf("%s@%s", relrootdset, sNow), dstRootDset) + if err != nil { + fmt.Printf("ERROR sending snapshot to %s: %s\n", dstRootDset, err.Error()) + return + } + // Remove snapshot of release, then snapshot of destination dataset + err = zfsDestroy(fmt.Sprintf("%s@%s", relrootdset, sNow)) + if err != nil { + fmt.Printf("ERROR destroying snapshot %s: %s\n", relrootdset, err.Error()) + return + } + err = zfsDestroy(fmt.Sprintf("%s@%s", dstRootDset, sNow)) + if err != nil { + fmt.Printf("ERROR destroying snapshot %s: %s\n", dstRootDset, err.Error()) + return + } + + fmt.Printf("Jail filesystem successfuly initalized\n") + + /////////////////////////////////////////////////////////////////////// + // + // Copy defaults.json... + jailConfPath := fmt.Sprintf("%s/jails/%s/config.json", ds.Mountpoint, jname) + err = copyFile(fmt.Sprintf("%s/defaults.json", ds.Mountpoint), + jailConfPath) + if err != nil { + fmt.Printf("ERROR creating config.json: %s\n", err.Error()) + return + } + /////////////////////////////////////////////////////////////////////// + // + // ... and update it + // Get conf from config.json + jailConf, err := getJailConfig(jailConfPath) + if err != nil { + log.Println("ERROR reading jail config from %s", jailConfPath) + } + + // 2. Build jail object from config + jailRootPath := fmt.Sprintf("%s/jails/%s/%s", ds.Mountpoint, jname, "root") + j := Jail{ + Name: jailConf.Host_hostuuid, + Config: jailConf, + ConfigPath: jailConfPath, + Datastore: ds.Name, + RootPath: jailRootPath, + Running: false, + } + + j.Config.Release = gCreateArgs.Release + j.Config.Host_hostname = jname + j.Config.Host_hostuuid = jname + + j.WriteConfigToDisk(false) + + /////////////////////////////////////////////////////////////////////// + // + // Create fstab + fstabHandle, err := os.Create(fmt.Sprintf("%s/jails/%s/fstab", ds.Mountpoint, jname)) + if err != nil { + fmt.Printf("ERROR creating fstab: %s", err.Error()) + return + } + defer fstabHandle.Close() + } + + // TODO : Set JailType + } +}