package cmd import ( "os" "fmt" //"log" "time" "strings" "github.com/spf13/viper" ) // Internal usage only func updateJail(jail *Jail, doUpdateVersion bool) error { // Create default config as temporary file cfgFile, err := os.CreateTemp("", "gocage-jail-update-") if err != nil { return err } // Folder containing update/upgrade temporary files. Mutualized so we save bandwith when upgrading multiple jails uwd := viper.GetString("updateWorkDir") if len(uwd) == 0 { return fmt.Errorf("updateWorkDir not set in configuration") } _, err = os.Stat(uwd) if os.IsNotExist(err) { if err := os.Mkdir(uwd, 0755); err != nil { return err } } cfgFile.Write([]byte(strings.Replace(fbsdUpdateConfig, "TO-BE-REPLACED-WITH-UPDATEWORKDIR", uwd, 1))) defer cfgFile.Close() defer os.Remove(cfgFile.Name()) cmd := fmt.Sprintf("/usr/sbin/freebsd-update --not-running-from-cron -f %s -b %s --currently-running %s fetch", cfgFile.Name(), jail.RootPath, jail.Config.Release) err = executeCommandWithOutputToStdout(cmd) if err != nil { return err } cmd = fmt.Sprintf("/usr/sbin/freebsd-update --not-running-from-cron -f %s -b %s --currently-running %s install", cfgFile.Name(), jail.RootPath, jail.Config.Release) err = executeCommandWithOutputToStdout(cmd) if err != nil { return err } // Get and write new release into config.json. Don't do that for fake jail (aka release updating) if doUpdateVersion { updateVersion(jail) } return nil } func UpdateJail(args []string) { // Current jail were stopping var cj *Jail var err error // User is updateing a release, fake a jail if len(gUpdateRelease) > 0 { // get datastore mountpoing from datastore name ds, err := getDatastoreFromArray(gUpdateReleaseDS, gDatastores) if err != nil { fmt.Printf("Error getting datastore %s: %v\n", gUpdateReleaseDS, err) return } rp := fmt.Sprintf("%s/releases/%s/root", ds.Mountpoint, gUpdateRelease) fakeJail := Jail{RootPath: rp} v, err := getVersion(&fakeJail) if err != nil { fmt.Printf("Error getting version of release %s: %v\n", gUpdateRelease, err) return } fakeJail.Config.Release = v // Snapshot before updating dt := time.Now() curDate := fmt.Sprintf("%s", dt.Format("2006-01-02_15-04-05")) snapshotName := fmt.Sprintf("gocage_update_%s_%s", v, curDate) err = zfsSnapshot(fmt.Sprintf("%s/releases/%s", ds.ZFSDataset, fakeJail.Config.Release), snapshotName) if err != nil { fmt.Printf("Error snapshoting release %s: %v\n", gUpdateRelease, err) return } err = zfsSnapshot(fmt.Sprintf("%s/releases/%s/root", ds.ZFSDataset, fakeJail.Config.Release), snapshotName) if err != nil { fmt.Printf("Error snapshoting release %s: %v\n", gUpdateRelease, err) } else { fmt.Printf("Release %s was snapshoted with success: %s\n", gUpdateRelease, snapshotName) } if err = updateJail(&fakeJail, false); err != nil { fmt.Printf("Error updating release %s: %v\n", gUpdateRelease, err) } return } for _, a := range args { // Check if jail exist and is distinctly named cj, err = getJailFromArray(a, []string{""}, gJails) if err != nil { fmt.Printf("Error getting jail: %s\n", err) continue } // We cant update basejail as system is readonly if strings.EqualFold(cj.Config.Jailtype, "basejail") { fmt.Printf("%s is a basejail using %s system files. Please update %s!\n", cj.Name, cj.Config.Origin, cj.Config.Origin) continue } fmt.Printf(" > Snapshot jail %s\n", cj.Name) // Set snapshot name dt := time.Now() curDate := fmt.Sprintf("%s", dt.Format("2006-01-02_15-04-05")) gSnapshotName = fmt.Sprintf("gocage_update_%s_%s", cj.Config.Release, curDate) err := createJailSnapshot(*cj) if err != nil { fmt.Printf(" > Snapshot jail %s: ERROR: %s\n", cj.Name, err.Error()) return } fmt.Printf(" > Snapshot jail %s: OK\n", cj.Name) fmt.Printf(" > Update jail %s\n", cj.Name) err = updateJail(cj, true) if err != nil { fmt.Printf("ERROR: %s\n", err.Error()) } else { fmt.Printf(" > Update jail %s: OK\n", cj.Name) } } }