5 Commits

Author SHA1 Message Date
yo
07eccffbd1 Add Devfs_ruleset property to reflect generated RS 2022-10-15 16:33:29 +02:00
yo
7809107ea4 Update readme 2022-10-15 15:24:24 +02:00
yo
5ab0a59db4 Update readme 2022-10-15 15:23:58 +02:00
yo
1b27753718 Add service file 2022-10-15 15:16:26 +02:00
yo
c97f5317dd Add start and stop all jails for boot/shutdown, add debug mode 2022-10-15 14:53:43 +02:00
8 changed files with 167 additions and 32 deletions

View File

@ -143,7 +143,7 @@ gocage datastore list
+------------+-------------+------------+-----------+----------+------------+ +------------+-------------+------------+-----------+----------+------------+
</pre></code> </pre></code>
#### Filter datastores ### Filter datastores
As with jails and snapshots, you can filter by name: As with jails and snapshots, you can filter by name:
<pre><code> <pre><code>
gocage datastore list iocage gocage datastore list iocage
@ -154,7 +154,7 @@ gocage datastore list iocage
+------------+-------------+------------+-----------+----------+------------+ +------------+-------------+------------+-----------+----------+------------+
</pre></code> </pre></code>
#### Sort datastores ### Sort datastores
You can sort datastores: You can sort datastores:
<pre><code> <pre><code>
gocage datastore list -s -Available gocage datastore list -s -Available
@ -175,6 +175,11 @@ With multi datastore comes the need to migrate a jail between datastores.
Migration can be done with a minimal downtime, using zfs differential send/receive. Migration can be done with a minimal downtime, using zfs differential send/receive.
Source jail datasets are sent to the destination datastore, jail is stopped and a last differential sync is done before starting jail on new datastore. Source jail datasets are sent to the destination datastore, jail is stopped and a last differential sync is done before starting jail on new datastore.
### Warning
Be aware the moment you migrate a jail to another datastore than /iocage default, you lose compatibility with iocage.
Then you need to disable iocage service, and enable gocage so the jails will start automatically at boot.
Also make sure, if you don't destroy source jail, that it won't have the "boot" property set or you will have the 2 jails up at boot.
<pre><code> <pre><code>
gocage migrate -d fastiocage srv-random gocage migrate -d fastiocage srv-random
Snapshot data/iocage/jails/srv-random: Done Snapshot data/iocage/jails/srv-random: Done
@ -182,3 +187,4 @@ Snapshot data/iocage/jails/srv-random/root: Done
Migrate jail config dataset to fastdata/iocage/jails/srv-random: Done Migrate jail config dataset to fastdata/iocage/jails/srv-random: Done
Migrate jail filesystem dataset to fastdata/iocage/jails/srv-random/root: Done Migrate jail filesystem dataset to fastdata/iocage/jails/srv-random/root: Done
</pre></code> </pre></code>

View File

@ -273,6 +273,7 @@ func listJailsFromDirectory(dir string, dsname string) ([]Jail, error) {
j.JID = rj.Jid j.JID = rj.Jid
j.Running = true j.Running = true
j.InternalName = rj.Name j.InternalName = rj.Name
j.Devfs_ruleset = rj.Devfs_ruleset
break break
} }
} }

View File

@ -10,11 +10,11 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
// TODO : Use log // TODO : Use log
//log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
const ( const (
gVersion = "0.29g" gVersion = "0.31"
// TODO : Get from $jail_zpool/defaults.json // TODO : Get from $jail_zpool/defaults.json
MIN_DYN_DEVFS_RULESET = 1000 MIN_DYN_DEVFS_RULESET = 1000
@ -27,6 +27,7 @@ var (
gUseSudo bool gUseSudo bool
gForce bool gForce bool
gDebug bool
gConfigFile string gConfigFile string
gDisplayJColumns string gDisplayJColumns string
@ -109,7 +110,11 @@ ex: gocage list srv-db srv-web`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
// Load inventory // Load inventory
ListJails(args, false) ListJails(args, false)
StopJail(args) if len(args) == 0 {
StopAllRunningJails()
} else {
StopJail(args)
}
}, },
} }
@ -119,11 +124,17 @@ ex: gocage list srv-db srv-web`,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
// Load inventory // Load inventory
ListJails(args, false) ListJails(args, false)
StartJail(args) if len(args) == 0 {
StartJailsAtBoot()
} else {
StartJail(args)
}
WriteConfigToDisk(false) WriteConfigToDisk(false)
}, },
} }
restartCmd = &cobra.Command{ restartCmd = &cobra.Command{
Use: "restart", Use: "restart",
Short: "restart jail", Short: "restart jail",
@ -293,6 +304,7 @@ func init() {
rootCmd.PersistentFlags().StringVarP(&gConfigFile, "config", "c", "/usr/local/etc/gocage.conf.yml", "GoCage configuration file") rootCmd.PersistentFlags().StringVarP(&gConfigFile, "config", "c", "/usr/local/etc/gocage.conf.yml", "GoCage configuration file")
rootCmd.PersistentFlags().BoolVarP(&gUseSudo, "sudo", "u", false, "Use sudo to run commands") rootCmd.PersistentFlags().BoolVarP(&gUseSudo, "sudo", "u", false, "Use sudo to run commands")
rootCmd.PersistentFlags().StringVarP(&gTimeZone, "timezone", "t", "", "Specify timezone. Will get from /var/db/zoneinfo if not set.") rootCmd.PersistentFlags().StringVarP(&gTimeZone, "timezone", "t", "", "Specify timezone. Will get from /var/db/zoneinfo if not set.")
rootCmd.PersistentFlags().BoolVarP(&gDebug, "debug", "d", false, "Debug mode")
// Command dependant switches // Command dependant switches
@ -414,6 +426,12 @@ func initConfig() {
fmt.Printf("More than 3 sort criteria is not supported!\n") fmt.Printf("More than 3 sort criteria is not supported!\n")
os.Exit(1) os.Exit(1)
} }
if gDebug {
log.SetLevel(log.DebugLevel)
log.Debugf("Debug mode enabled\n")
}
} }
/******************************************************************************** /********************************************************************************

View File

@ -1049,6 +1049,34 @@ func cleanAfterStartCrash() {
} }
// Start all jails with boot=true, in priority order
func StartJailsAtBoot() {
var startList []Jail
// Get boot enabled jails
for _, j := range gJails {
if j.Config.Boot > 0 {
startList = append(startList, j)
}
}
// Order by priority
js := initJailSortStruct()
fct, _, err := getStructFieldValue(js, "Config.PriorityInc")
if err != nil {
log.Errorf("ERROR getting JailSort struct field \"Config.PriorityInc\"\n")
return
}
JailsOrderedBy(fct.Interface().(jailLessFunc)).Sort(startList)
for _, j := range startList {
jFullName := fmt.Sprintf("%s/%s", j.Datastore, j.Name)
log.Debugf("Starting %s with priority %s\n", jFullName, j.Config.Priority)
StartJail([]string{jFullName})
}
}
/* /*
Start jail: Start jail:
Check jail fstab? Check jail fstab?
@ -1088,7 +1116,7 @@ func StartJail(args []string) {
} }
if cj.Running == true { if cj.Running == true {
fmt.Printf("Jail %s is already running!\n", cj.Name) fmt.Printf("Jail %s/%s is already running!\n", cj.Datastore, cj.Name)
continue continue
} }
@ -1303,8 +1331,9 @@ func StartJail(args []string) {
fmt.Printf(" > Start jail: OK\n") fmt.Printf(" > Start jail: OK\n")
fmt.Printf(" > With devfs ruleset %d\n", dynrs) fmt.Printf(" > With devfs ruleset %d\n", dynrs)
// Update running state and JID // Update running state, JID and Devfs_ruleset
cj.Running = true cj.Running = true
cj.Devfs_ruleset = dynrs
rjails, err := jail.GetJails() rjails, err := jail.GetJails()
if err != nil { if err != nil {
fmt.Printf("Error: Unable to list running jails\n") fmt.Printf("Error: Unable to list running jails\n")

View File

@ -10,6 +10,8 @@ import (
//"reflect" //"reflect"
"strconv" "strconv"
"strings" "strings"
log "github.com/sirupsen/logrus"
) )
// TODO : Use SYS_RCTL_GET_RACCT syscall // TODO : Use SYS_RCTL_GET_RACCT syscall
@ -166,6 +168,33 @@ func stopJail(jail *Jail) error {
return nil return nil
} }
// Stop all running jails by reverse priority
func StopAllRunningJails() {
var stopList []Jail
// Get boot enabled jails
for _, j := range gJails {
if j.Running == true {
stopList = append(stopList, j)
}
}
// Order by priority
js := initJailSortStruct()
fct, _, err := getStructFieldValue(js, "Config.PriorityDec")
if err != nil {
log.Errorf("ERROR getting JailSort struct field \"Config.PriorityDec\"\n")
return
}
JailsOrderedBy(fct.Interface().(jailLessFunc)).Sort(stopList)
for _, j := range stopList {
jFullName := fmt.Sprintf("%s/%s", j.Datastore, j.Name)
log.Debugf("Stopping %s with priority %s\n", jFullName, j.Config.Priority)
StopJail([]string{jFullName})
}
}
/* /*
Stop jail: Stop jail:
Remove rctl rules Remove rctl rules
@ -257,20 +286,13 @@ func StopJail(args []string) {
fmt.Printf(" > Destroy VNet interfaces: OK\n") fmt.Printf(" > Destroy VNet interfaces: OK\n")
} }
} }
// Get currently used ruleset from /var/run/jail.$internal_name.conf fmt.Printf(" > Remove devfs ruleset %d: \n", cj.Devfs_ruleset)
ruleset, err := getValueFromRunningConfig(cj.InternalName, "devfs_ruleset") err = deleteDevfsRuleset(cj.Devfs_ruleset)
if err != nil {
fmt.Printf("ERROR getting current devfs ruleset: %s\n", err.Error())
return
}
rsi, _ := strconv.Atoi(ruleset)
fmt.Printf(" > Remove devfs ruleset %d: \n", rsi)
err = deleteDevfsRuleset(rsi)
if err != nil { if err != nil {
fmt.Printf("ERROR: %s\n", err.Error()) fmt.Printf("ERROR: %s\n", err.Error())
} else { } else {
fmt.Printf(" > Remove devfsruleset %d: OK\n", rsi) fmt.Printf(" > Remove devfsruleset %d: OK\n", cj.Devfs_ruleset)
} }
fmt.Printf(" > Stop jail %s:\n", cj.Name) fmt.Printf(" > Stop jail %s:\n", cj.Name)
@ -372,6 +394,9 @@ func StopJail(args []string) {
if err = setStructFieldValue(&gJails[i], "InternalName", ""); err != nil { if err = setStructFieldValue(&gJails[i], "InternalName", ""); err != nil {
fmt.Printf("ERROR: clearing InternalName property: %s\n", err.Error()) fmt.Printf("ERROR: clearing InternalName property: %s\n", err.Error())
} }
if err = setStructFieldValue(&gJails[i], "Devfs_ruleset", "0"); err != nil {
fmt.Printf("ERROR: setting Devfs_ruleset property to 0: %s\n", err.Error())
}
} }
} }
} }

View File

@ -27,6 +27,7 @@ type Jail struct {
Running bool Running bool
// No need, Config.Release always represent what is running (plus it know release for non-running jails) // No need, Config.Release always represent what is running (plus it know release for non-running jails)
//Release string //Release string
Devfs_ruleset int // The effective devfs ruleset generated at runtime
Zpool string Zpool string
Datastore string Datastore string
} }
@ -247,6 +248,8 @@ type JailSort struct {
DatastoreDec jailLessFunc DatastoreDec jailLessFunc
ZpoolInc jailLessFunc ZpoolInc jailLessFunc
ZpoolDec jailLessFunc ZpoolDec jailLessFunc
Devfs_rulesetInc jailLessFunc
Devfs_rulesetDec jailLessFunc
Config JailConfigSort Config JailConfigSort
} }

View File

@ -14,16 +14,17 @@ package jail
*/ */
import "C" import "C"
import ( import (
"strconv" "strconv"
// "syscall" // "syscall"
"unsafe" "unsafe"
) )
type Jail struct { type Jail struct {
Name string Name string
Jid int Jid int
Path string Path string
Devfs_ruleset int
} }
@ -33,8 +34,8 @@ func GetJails() ([]Jail, error) {
var jl Jail var jl Jail
var err error var err error
// Make "params" a list of 4 jails parameters // Make "params" a list of 5 jails parameters
params := make([]C.struct_jailparam, 4) params := make([]C.struct_jailparam, 5)
// initialize parameter names // initialize parameter names
csname := C.CString("name") csname := C.CString("name")
@ -43,27 +44,31 @@ func GetJails() ([]Jail, error) {
defer C.free(unsafe.Pointer(csjid)) defer C.free(unsafe.Pointer(csjid))
cspath := C.CString("path") cspath := C.CString("path")
defer C.free(unsafe.Pointer(cspath)) defer C.free(unsafe.Pointer(cspath))
csdevfsrs := C.CString("devfs_ruleset")
defer C.free(unsafe.Pointer(csdevfsrs))
cslastjid := C.CString("lastjid") cslastjid := C.CString("lastjid")
defer C.free(unsafe.Pointer(cslastjid)) defer C.free(unsafe.Pointer(cslastjid))
// initialize params struct with parameter names // initialize params struct with parameter names
C.jailparam_init(&params[0], csname) C.jailparam_init(&params[0], csname)
C.jailparam_init(&params[1], csjid) C.jailparam_init(&params[1], csjid)
C.jailparam_init(&params[2], cspath) C.jailparam_init(&params[2], cspath)
C.jailparam_init(&params[3], csdevfsrs)
// The key to retrieve jail. lastjid = 0 returns first jail and its jid as jailparam_get return value // The key to retrieve jail. lastjid = 0 returns first jail and its jid as jailparam_get return value
C.jailparam_init(&params[3], cslastjid) C.jailparam_init(&params[4], cslastjid)
lastjailid := 0 lastjailid := 0
cslastjidval := C.CString(strconv.Itoa(lastjailid)) cslastjidval := C.CString(strconv.Itoa(lastjailid))
defer C.free(unsafe.Pointer(cslastjidval)) defer C.free(unsafe.Pointer(cslastjidval))
C.jailparam_import(&params[3], cslastjidval) C.jailparam_import(&params[4], cslastjidval)
// loop on existing jails // loop on existing jails
for lastjailid >= 0 { for lastjailid >= 0 {
// get parameter values // get parameter values
lastjailid = int(C.jailparam_get(&params[0], 4, 0)) lastjailid = int(C.jailparam_get(&params[0], 5, 0))
if lastjailid > 0 { if lastjailid > 0 {
nametmp := C.jailparam_export(&params[0]) nametmp := C.jailparam_export(&params[0])
jl.Name = C.GoString(nametmp) jl.Name = C.GoString(nametmp)
@ -75,23 +80,28 @@ func GetJails() ([]Jail, error) {
// Memory mgmt : Non gere par Go // Memory mgmt : Non gere par Go
C.free(unsafe.Pointer(jidtmp)) C.free(unsafe.Pointer(jidtmp))
pathtmp := C.jailparam_export(&params[2]) pathtmp := C.jailparam_export(&params[2])
jl.Path = C.GoString(pathtmp) jl.Path = C.GoString(pathtmp)
// Memory mgmt : Non gere par Go // Memory mgmt : Non gere par Go
C.free(unsafe.Pointer(pathtmp)) C.free(unsafe.Pointer(pathtmp))
drstmp := C.jailparam_export(&params[3])
jl.Devfs_ruleset, _ = strconv.Atoi(C.GoString(drstmp))
// Memory mgmt : Non gere par Go
C.free(unsafe.Pointer(drstmp))
jls = append(jls, jl) jls = append(jls, jl)
//log.Debug("Got jid " + strconv.Itoa(jl.jid) + " with name " + jl.name) //log.Debug("Got jid " + strconv.Itoa(jl.jid) + " with name " + jl.name)
// Prepare next loop iteration // Prepare next loop iteration
cslastjidval := C.CString(strconv.Itoa(lastjailid)) cslastjidval := C.CString(strconv.Itoa(lastjailid))
defer C.free(unsafe.Pointer(cslastjidval)) defer C.free(unsafe.Pointer(cslastjidval))
C.jailparam_import(&params[3], cslastjidval) C.jailparam_import(&params[4], cslastjidval)
} }
} }
// Free 4 items of params list // Free 5 items of params list
C.jailparam_free(&params[0], 4) C.jailparam_free(&params[0], 5)
return jls, err return jls, err
} }

43
service/gocage Executable file
View File

@ -0,0 +1,43 @@
#!/bin/sh
#
# $FreeBSD$
#
# PROVIDE: gocage
# REQUIRE: LOGIN cleanvar
# KEYWORD: shutdown
# Add the following lines to /etc/rc.conf to enable :
#
# gocage_enable="YES"
#
# gocage_conf="/usr/local/etc/gocage.conf.yml"
#
. /etc/rc.subr
name="gocage"
rcvar=gocage_enable
# read configuration and set defaults
load_rc_config "$name"
: ${gocage_enable:="NO"}
: ${gocage_conf="/usr/local/etc/gocage.conf.yml"}
start_cmd=${name}_start
stop_cmd=${name}_stop
gocage_start()
{
echo "Gocage starting jails... "
/usr/local/bin/gocage -c ${gocage_conf} start
}
gocage_stop()
{
echo "Gocage stopping jails... "
/usr/local/bin/gocage -c ${gocage_conf} stop
}
run_rc_command "$1"