zfs send/recv: Support raw sends (-w/-Lce) and property handling (-p, -b, -o, -x)

Signed-off-by: InsanePrawn <insane.prawny@gmail.com>
This commit is contained in:
InsanePrawn
2020-08-30 18:16:31 +02:00
parent 8e1937fe75
commit 893d686eef
8 changed files with 448 additions and 25 deletions
+35 -4
View File
@@ -12,6 +12,8 @@ import (
"github.com/pkg/errors"
"github.com/zrepl/yaml-config"
zfsprop "github.com/zrepl/zrepl/zfs/property"
)
type Config struct {
@@ -76,8 +78,15 @@ type SnapJob struct {
}
type SendOptions struct {
Encrypted bool `yaml:"encrypted"`
StepHolds SendOptionsStepHolds `yaml:"step_holds,optional"`
Encrypted bool `yaml:"encrypted,optional"`
Raw bool `yaml:"raw,optional"`
SendProperties bool `yaml:"send_properties,optional"`
BackupProperties bool `yaml:"backup_properties,optional"`
LargeBlocks bool `yaml:"large_blocks,optional"`
Compressed bool `yaml:"compressed,optional"`
EmbeddedData bool `yaml:"embbeded_data,optional"`
}
type SendOptionsStepHolds struct {
@@ -87,21 +96,43 @@ type SendOptionsStepHolds struct {
var _ yaml.Defaulter = (*SendOptions)(nil)
func (l *SendOptions) SetDefault() {
*l = SendOptions{Encrypted: false}
*l = SendOptions{
Encrypted: false,
Raw: false,
SendProperties: false,
BackupProperties: false,
LargeBlocks: false,
Compressed: false,
EmbeddedData: false,
}
}
type RecvOptions struct {
// Note: we cannot enforce encrypted recv as the ZFS cli doesn't provide a mechanism for it
// Encrypted bool `yaml:"may_encrypted"`
// Future:
// Reencrypt bool `yaml:"reencrypt"`
Properties *PropertyRecvOptions `yaml:"properties,fromdefaults"`
}
var _ yaml.Defaulter = (*RecvOptions)(nil)
func (l *RecvOptions) SetDefault() {
*l = RecvOptions{}
*l = RecvOptions{Properties: &PropertyRecvOptions{}}
}
type PropertyRecvOptions struct {
Inherit []zfsprop.Property `yaml:"inherit,optional"`
Override map[zfsprop.Property]string `yaml:"override,optional"`
}
var _ yaml.Defaulter = (*PropertyRecvOptions)(nil)
func (l *PropertyRecvOptions) SetDefault() {
//*l = PropertyRecvOptions{}
//TODO: is below necessary?
*l = PropertyRecvOptions{Inherit: make([]zfsprop.Property, 0), Override: make(map[zfsprop.Property]string)}
}
type PushJob struct {
+132
View File
@@ -0,0 +1,132 @@
package config
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func TestRecvOptions(t *testing.T) {
tmpl := `
jobs:
- name: foo
type: pull
connect:
type: local
listener_name: foo
client_identity: bar
root_fs: "zreplplatformtest"
%s
interval: manual
pruning:
keep_sender:
- type: last_n
count: 10
keep_receiver:
- type: last_n
count: 10
`
recv_properties_empty := `
recv:
properties:
`
recv_inherit_empty := `
recv:
properties:
inherit:
`
recv_inherit := `
recv:
properties:
inherit:
- testprop
`
recv_override_empty := `
recv:
properties:
override:
`
recv_override := `
recv:
properties:
override:
testprop2: "test123"
`
recv_override_and_inherit := `
recv:
properties:
inherit:
- testprop
override:
testprop2: "test123"
`
recv_empty := `
recv: {}
`
recv_not_specified := `
`
fill := func(s string) string { return fmt.Sprintf(tmpl, s) }
var c *Config
t.Run("recv_inherit_empty", func(t *testing.T) {
c, err := testConfig(t, fill(recv_inherit_empty))
assert.NoError(t, err)
assert.NotNil(t, c)
})
t.Run("recv_inherit", func(t *testing.T) {
c = testValidConfig(t, fill(recv_inherit))
inherit := c.Jobs[0].Ret.(*PullJob).Recv.Properties.Inherit
assert.NotEmpty(t, inherit)
})
t.Run("recv_override_empty", func(t *testing.T) {
c, err := testConfig(t, fill(recv_override_empty))
assert.NoError(t, err)
assert.NotNil(t, c)
})
t.Run("recv_override", func(t *testing.T) {
c = testValidConfig(t, fill(recv_override))
override := c.Jobs[0].Ret.(*PullJob).Recv.Properties.Override
assert.NotEmpty(t, override)
})
t.Run("recv_override_and_inherit", func(t *testing.T) {
c = testValidConfig(t, fill(recv_override_and_inherit))
inherit := c.Jobs[0].Ret.(*PullJob).Recv.Properties.Inherit
override := c.Jobs[0].Ret.(*PullJob).Recv.Properties.Override
assert.NotEmpty(t, inherit)
assert.NotEmpty(t, override)
})
t.Run("recv_properties_empty", func(t *testing.T) {
c, err := testConfig(t, fill(recv_properties_empty))
assert.NoError(t, err)
assert.NotNil(t, c)
})
t.Run("recv_empty", func(t *testing.T) {
c, err := testConfig(t, fill(recv_empty))
assert.NoError(t, err)
assert.NotNil(t, c)
})
t.Run("send_not_specified", func(t *testing.T) {
c, err := testConfig(t, fill(recv_not_specified))
assert.NoError(t, err)
assert.NotNil(t, c)
})
}
+79 -5
View File
@@ -38,7 +38,41 @@ jobs:
encrypted: true
`
encrypted_unspecified := `
raw_true := `
send:
raw: true
`
raw_false := `
send:
raw: false
`
raw_and_encrypted := `
send:
encrypted: true
raw: true
`
properties_and_encrypted := `
send:
encrypted: true
send_properties: true
`
properties_true := `
send:
send_properties: true
`
properties_false := `
send:
send_properties: false
`
send_empty := `
send: {}
`
@@ -59,10 +93,50 @@ jobs:
assert.Equal(t, true, encrypted)
})
t.Run("encrypted_unspecified", func(t *testing.T) {
c, err := testConfig(t, fill(encrypted_unspecified))
assert.Error(t, err)
assert.Nil(t, c)
t.Run("send_empty", func(t *testing.T) {
c := testValidConfig(t, fill(send_empty))
encrypted := c.Jobs[0].Ret.(*PushJob).Send.Encrypted
assert.Equal(t, false, encrypted)
})
t.Run("properties_and_encrypted", func(t *testing.T) {
c := testValidConfig(t, fill(properties_and_encrypted))
encrypted := c.Jobs[0].Ret.(*PushJob).Send.Encrypted
properties := c.Jobs[0].Ret.(*PushJob).Send.SendProperties
assert.Equal(t, true, encrypted)
assert.Equal(t, true, properties)
})
t.Run("properties_false", func(t *testing.T) {
c := testValidConfig(t, fill(properties_false))
properties := c.Jobs[0].Ret.(*PushJob).Send.SendProperties
assert.Equal(t, false, properties)
})
t.Run("properties_true", func(t *testing.T) {
c := testValidConfig(t, fill(properties_true))
properties := c.Jobs[0].Ret.(*PushJob).Send.SendProperties
assert.Equal(t, true, properties)
})
t.Run("raw_true", func(t *testing.T) {
c := testValidConfig(t, fill(raw_true))
raw := c.Jobs[0].Ret.(*PushJob).Send.Raw
assert.Equal(t, true, raw)
})
t.Run("raw_false", func(t *testing.T) {
c := testValidConfig(t, fill(raw_false))
raw := c.Jobs[0].Ret.(*PushJob).Send.Raw
assert.Equal(t, false, raw)
})
t.Run("raw_and_encrypted", func(t *testing.T) {
c := testValidConfig(t, fill(raw_and_encrypted))
raw := c.Jobs[0].Ret.(*PushJob).Send.Raw
encrypted := c.Jobs[0].Ret.(*PushJob).Send.Encrypted
assert.Equal(t, true, raw)
assert.Equal(t, true, encrypted)
})
t.Run("send_not_specified", func(t *testing.T) {