getJailFromArray filtering by type, add fileCopy, isFirstNetDhcp

This commit is contained in:
yo 2023-08-05 19:49:55 +02:00
parent 45e1c57ce4
commit 6a8b022165

View File

@ -24,6 +24,141 @@ const (
ifconfigipv4re = `inet[[:space:]](` + ipv4re + `)`
// Maximum thread qty for start/stop
gMaxThreads = 4
gDefaultsJson = ` {
"CONFIG_VERSION": "27",
"allow_chflags": 0,
"allow_mlock": 0,
"allow_mount": 0,
"allow_mount_devfs": 0,
"allow_mount_fusefs": 0,
"allow_mount_nullfs": 0,
"allow_mount_procfs": 0,
"allow_mount_tmpfs": 0,
"allow_mount_zfs": 0,
"allow_quotas": 0,
"allow_raw_sockets": 0,
"allow_set_hostname": 1,
"allow_socket_af": 0,
"allow_sysvipc": 0,
"allow_tun": 0,
"allow_vmm": 0,
"assign_localhost": 0,
"available": "readonly",
"basejail": 0,
"boot": 0,
"bpf": 0,
"children_max": "0",
"comment": "none",
"compression": "lz4",
"compressratio": "readonly",
"coredumpsize": "off",
"count": "1",
"cpuset": "off",
"cputime": "off",
"datasize": "off",
"dedup": "off",
"defaultrouter": "auto",
"defaultrouter6": "auto",
"depends": "none",
"devfs_ruleset": "4",
"dhcp": 0,
"enforce_statfs": "2",
"exec_clean": 1,
"exec_created": "/usr/bin/true",
"exec_fib": "0",
"exec_jail_user": "root",
"exec_poststart": "/usr/bin/true",
"exec_poststop": "/usr/bin/true",
"exec_prestart": "/usr/bin/true",
"exec_prestop": "/usr/bin/true",
"exec_start": "/bin/sh /etc/rc",
"exec_stop": "/bin/sh /etc/rc.shutdown",
"exec_system_jail_user": "0",
"exec_system_user": "root",
"exec_timeout": "60",
"host_domainname": "none",
"host_time": 1,
"hostid": "36353536-3135-5a43-4a34-313130315a56",
"hostid_strict_check": 0,
"interfaces": "vnet0:bridge0",
"ip4": "new",
"ip4_addr": "none",
"ip4_saddrsel": 1,
"ip6": "new",
"ip6_addr": "none",
"ip6_saddrsel": 1,
"ip_hostname": 0,
"jail_zfs": 0,
"jail_zfs_mountpoint": "none",
"last_started": "none",
"localhost_ip": "none",
"login_flags": "-f root",
"mac_prefix": "2c44fd",
"maxproc": "off",
"memorylocked": "off",
"memoryuse": "off",
"min_dyn_devfs_ruleset": "1000",
"mount_devfs": 1,
"mount_fdescfs": 1,
"mount_linprocfs": 0,
"mount_procfs": 0,
"mountpoint": "readonly",
"msgqqueued": "off",
"msgqsize": "off",
"nat": 0,
"nat_backend": "ipfw",
"nat_forwards": "none",
"nat_interface": "none",
"nat_prefix": "172.16",
"nmsgq": "off",
"notes": "none",
"nsem": "off",
"nsemop": "off",
"nshm": "off",
"nthr": "off",
"openfiles": "off",
"origin": "readonly",
"owner": "root",
"pcpu": "off",
"plugin_name": "none",
"plugin_repository": "none",
"priority": "99",
"pseudoterminals": "off",
"quota": "none",
"readbps": "off",
"readiops": "off",
"reservation": "none",
"resolver": "/etc/resolv.conf",
"rlimits": "off",
"rtsold": 0,
"securelevel": "2",
"shmsize": "off",
"stacksize": "off",
"stop_timeout": "30",
"swapuse": "off",
"sync_state": "none",
"sync_target": "none",
"sync_tgt_zpool": "none",
"sysvmsg": "new",
"sysvsem": "new",
"sysvshm": "new",
"template": 0,
"type": "jail",
"used": "readonly",
"vmemoryuse": "off",
"vnet": 0,
"vnet0_mac": "none",
"vnet1_mac": "none",
"vnet2_mac": "none",
"vnet3_mac": "none",
"vnet_default_interface": "auto",
"vnet_interfaces": "none",
"wallclock": "off",
"writebps": "off",
"writeiops": "off"
}
`
)
/*****************************************************************************
@ -218,6 +353,8 @@ func executeCommand(cmdline string) (string, error) {
// else
word = word + string(c)
}
log.Debugf("executeCommand: %s\n", strings.Join(cmd, " "))
if len(cmd) > 1 {
out, err = exec.Command(cmd[0], cmd[1:]...).CombinedOutput()
@ -545,8 +682,11 @@ func zfsSnapshot(dataset string, snapname string) error {
return nil
}
// Copy snapshot to a new dataset
// TODO : Intercept death of sending process, then kill receiving
func zfsCopy(src string, dest string) error {
// First, declare sending process & pipe
log.Debugf("Execute: zfs send %s\n", src)
cmd_send := exec.Command("zfs", "send", src)
stdout_send, err := cmd_send.StdoutPipe()
if err != nil {
@ -555,6 +695,7 @@ func zfsCopy(src string, dest string) error {
}
// then declare receiving process & pipe
log.Debugf("Execute: zfs receive %s\n", dest)
cmd_recv := exec.Command("zfs", "receive", dest)
stdin_recv, err := cmd_recv.StdinPipe()
if err != nil {
@ -568,16 +709,19 @@ func zfsCopy(src string, dest string) error {
// then start processes and wait for finish
if err := cmd_recv.Start(); err != nil {
//fmt.Printf("Error: %v\n", err)
log.Debugf("zfs receive %s started: %v", dest, err)
return errors.New(fmt.Sprintf("Error starting receive process: %v\n", err))
}
//fmt.Printf("DEBUG: Start \"zfs send %s\"\n", dsconf)
if err := cmd_send.Start(); err != nil {
//fmt.Printf("Error: %v\n", err)
log.Debugf("zfs send %s started: %v", src, err)
return errors.New(fmt.Sprintf("Error starting send process: %v\n", err))
}
//fmt.Printf("DEBUG: Wait for zfs send to finish\n")
if err := cmd_send.Wait(); err != nil {
log.Debugf("zfs send %s stopped with %v", err)
//fmt.Printf("Error: zfs send halted with %v\n", err)
return errors.New(fmt.Sprintf("send halted with: %v\n", err))
}
@ -668,6 +812,7 @@ func zfsGetDatasetByMountpoint(mountpoint string) (string, error) {
// Delete a ZFS Dataset by name
func zfsDestroy(dataset string) error {
log.Debugf("execute \"zfs destroy -r %s\"\n", dataset)
cmd := fmt.Sprintf("zfs destroy -r %s", dataset)
out, err := executeCommand(cmd)
if err != nil {
@ -676,6 +821,30 @@ func zfsDestroy(dataset string) error {
return nil
}
/* Copy file */
func copyFile(src, dst string) error {
srcfinfo, err := os.Stat(src)
if err != nil {
return fmt.Errorf("Cannot find source file: %s", err.Error())
}
if !srcfinfo.Mode().IsRegular() {
return fmt.Errorf("%s is not a regular file", src)
}
srcHandle, err := os.Open(src)
if err != nil {
return fmt.Errorf("Cannot open source file: %s", err.Error())
}
defer srcHandle.Close()
dstHandle, err := os.Create(dst)
if err != nil {
return fmt.Errorf("Cannot create destination file: %s", err.Error())
}
defer dstHandle.Close()
_, err = io.Copy(dstHandle, srcHandle)
return err
}
/*****************************************************************************
*
* rc.conf management
@ -818,7 +987,7 @@ func getValueFromRunningConfig(jname string, param string) (string, error) {
if err != nil {
return "", err
}
for _, line := range strings.Split(string(content), "\n") {
if strings.Contains(line, fmt.Sprintf("%s = ", param)) {
split := strings.Split(line, "=")
@ -833,7 +1002,7 @@ func getValueFromRunningConfig(jname string, param string) (string, error) {
}
}
}
return "", fmt.Errorf("Parameter not found: %s", param)
}
@ -852,14 +1021,29 @@ func isStringInArray(strarr []string, searched string) bool {
return false
}
func (j Jail) isFirstNetDhcp() bool {
for _, n := range strings.Split(j.Config.Ip4_addr, ",") {
splitd := strings.Split(n, "|")
if len(splitd) > 1 && strings.EqualFold(splitd[1], "dhcp") {
return true
}
}
return false
}
/********************************************************************************
* Get a specific jail reference, to update properties after a range loop
* Name can be short or long form ("myjail" vs "mystore/myjail")
* An empty jailtype means "all types"
*******************************************************************************/
func getJailFromArray(name string, jarray []Jail) (*Jail, error) {
func getJailFromArray(name string, jailtypes []string, jarray []Jail) (*Jail, error) {
var ds, jail string
var jails []Jail
if (len(jailtypes) == 1 && len(jailtypes[0]) == 0) || len(jailtypes) == 0 {
jailtypes = []string{"jail", "basetpl"}
}
if strings.Contains(name, "/") {
split := strings.Split(name, "/")
if len(split) != 2 {
@ -872,16 +1056,17 @@ func getJailFromArray(name string, jarray []Jail) (*Jail, error) {
}
for i, j := range jarray {
//if jail == j.Name {
if strings.HasPrefix(j.Name, jail) {
if len(ds) > 0 {
if strings.EqualFold(ds, j.Datastore) {
return &jarray[i], nil
if isStringInArray(jailtypes, j.Config.Jailtype) {
if len(ds) > 0 {
if strings.EqualFold(ds, j.Datastore) {
return &jarray[i], nil
} else {
continue
}
} else {
continue
jails = append(jails, j)
}
} else {
jails = append(jails, j)
}
}
}
@ -913,7 +1098,7 @@ func setJailConfigUpdated(jail *Jail) error {
return errors.New(fmt.Sprintf("No config path for jail %s", jail.Name))
}
j, err := getJailFromArray(jail.Name, gJails)
j, err := getJailFromArray(jail.Name, []string{""}, gJails)
if err != nil {
return err
}
@ -987,6 +1172,47 @@ func writeConfigToDisk(j *Jail, changeauto bool) {
}
}
func (j Jail) WriteConfigToDisk(changeauto bool) {
// we will manipulate properties so get a copy
jc := j.Config
if changeauto == false {
// Overwrite "auto" properties
ondiskjc, err := getJailConfig(j.ConfigPath)
if err != nil {
panic(err)
}
// TODO : List all fields, then call getStructFieldValue to compare value with "auto"
// If "auto" then keep it that way before writing ondiskjc to disk
var properties []string
properties = getStructFieldNames(ondiskjc, properties, "")
for _, p := range properties {
v, _, err := getStructFieldValue(ondiskjc, p)
if err != nil {
panic(err)
}
if v.String() == "auto" {
err = setStructFieldValue(&jc, p, "auto")
if err != nil {
fmt.Printf("ERROR sanitizing config: %s\n", err.Error())
os.Exit(1)
}
}
}
}
marshaled, err := json.MarshalIndent(jc, "", " ")
if err != nil {
fmt.Printf("ERROR marshaling config: %s\n", err.Error())
}
if os.WriteFile(j.ConfigPath, []byte(marshaled), 0644); err != nil {
fmt.Printf("Error writing config file %s: %v\n", j.ConfigPath, err)
os.Exit(1)
}
}
/******************************************************************************
* Return the quantity of jails with the name passed as parameter
*****************************************************************************/
@ -1002,7 +1228,7 @@ func countOfJailsWithThisName(name string) int {
func isNameDistinctive(name string, jails []Jail) bool {
_, err := getJailFromArray(name, jails)
_, err := getJailFromArray(name, []string{""}, jails)
if err != nil {
return false
} else {