mirror of
https://github.com/zrepl/zrepl.git
synced 2024-11-22 00:13:52 +01:00
zfs.NilBool: document its purpose and move it to its own package 'nodefault'
This commit is contained in:
parent
70bbdfe760
commit
1c937e58f7
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/zrepl/zrepl/config"
|
"github.com/zrepl/zrepl/config"
|
||||||
"github.com/zrepl/zrepl/daemon/filters"
|
"github.com/zrepl/zrepl/daemon/filters"
|
||||||
"github.com/zrepl/zrepl/endpoint"
|
"github.com/zrepl/zrepl/endpoint"
|
||||||
|
"github.com/zrepl/zrepl/util/nodefault"
|
||||||
"github.com/zrepl/zrepl/zfs"
|
"github.com/zrepl/zrepl/zfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ func buildSenderConfig(in SendingJobConfig, jobID endpoint.JobID) (*endpoint.Sen
|
|||||||
|
|
||||||
return &endpoint.SenderConfig{
|
return &endpoint.SenderConfig{
|
||||||
FSF: fsf,
|
FSF: fsf,
|
||||||
Encrypt: &zfs.NilBool{B: in.GetSendOptions().Encrypted},
|
Encrypt: &nodefault.Bool{B: in.GetSendOptions().Encrypted},
|
||||||
JobID: jobID,
|
JobID: jobID,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
|
||||||
"github.com/zrepl/zrepl/daemon/logging/trace"
|
"github.com/zrepl/zrepl/daemon/logging/trace"
|
||||||
|
"github.com/zrepl/zrepl/util/nodefault"
|
||||||
|
|
||||||
"github.com/zrepl/zrepl/config"
|
"github.com/zrepl/zrepl/config"
|
||||||
"github.com/zrepl/zrepl/daemon/filters"
|
"github.com/zrepl/zrepl/daemon/filters"
|
||||||
@ -179,7 +180,7 @@ func (j *SnapJob) doPrune(ctx context.Context) {
|
|||||||
JobID: j.name,
|
JobID: j.name,
|
||||||
FSF: j.fsfilter,
|
FSF: j.fsfilter,
|
||||||
// FIXME encryption setting is irrelevant for SnapJob because the endpoint is only used as pruner.Target
|
// FIXME encryption setting is irrelevant for SnapJob because the endpoint is only used as pruner.Target
|
||||||
Encrypt: &zfs.NilBool{B: true},
|
Encrypt: &nodefault.Bool{B: true},
|
||||||
})
|
})
|
||||||
j.prunerMtx.Lock()
|
j.prunerMtx.Lock()
|
||||||
j.pruner = j.prunerFactory.BuildLocalPruner(ctx, sender, alwaysUpToDateReplicationCursorHistory{sender})
|
j.pruner = j.prunerFactory.BuildLocalPruner(ctx, sender, alwaysUpToDateReplicationCursorHistory{sender})
|
||||||
|
@ -17,19 +17,20 @@ import (
|
|||||||
"github.com/zrepl/zrepl/util/chainedio"
|
"github.com/zrepl/zrepl/util/chainedio"
|
||||||
"github.com/zrepl/zrepl/util/chainlock"
|
"github.com/zrepl/zrepl/util/chainlock"
|
||||||
"github.com/zrepl/zrepl/util/envconst"
|
"github.com/zrepl/zrepl/util/envconst"
|
||||||
|
"github.com/zrepl/zrepl/util/nodefault"
|
||||||
"github.com/zrepl/zrepl/util/semaphore"
|
"github.com/zrepl/zrepl/util/semaphore"
|
||||||
"github.com/zrepl/zrepl/zfs"
|
"github.com/zrepl/zrepl/zfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SenderConfig struct {
|
type SenderConfig struct {
|
||||||
FSF zfs.DatasetFilter
|
FSF zfs.DatasetFilter
|
||||||
Encrypt *zfs.NilBool
|
Encrypt *nodefault.Bool
|
||||||
JobID JobID
|
JobID JobID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SenderConfig) Validate() error {
|
func (c *SenderConfig) Validate() error {
|
||||||
c.JobID.MustValidate()
|
c.JobID.MustValidate()
|
||||||
if err := c.Encrypt.Validate(); err != nil {
|
if err := c.Encrypt.ValidateNoDefault(); err != nil {
|
||||||
return errors.Wrap(err, "`Encrypt` field invalid")
|
return errors.Wrap(err, "`Encrypt` field invalid")
|
||||||
}
|
}
|
||||||
if _, err := StepHoldTag(c.JobID); err != nil {
|
if _, err := StepHoldTag(c.JobID); err != nil {
|
||||||
@ -43,7 +44,7 @@ type Sender struct {
|
|||||||
pdu.UnsafeReplicationServer // prefer compilation errors over default 'method X not implemented' impl
|
pdu.UnsafeReplicationServer // prefer compilation errors over default 'method X not implemented' impl
|
||||||
|
|
||||||
FSFilter zfs.DatasetFilter
|
FSFilter zfs.DatasetFilter
|
||||||
encrypt *zfs.NilBool
|
encrypt *nodefault.Bool
|
||||||
jobId JobID
|
jobId JobID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
|
|
||||||
"github.com/zrepl/zrepl/daemon/logging/trace"
|
"github.com/zrepl/zrepl/daemon/logging/trace"
|
||||||
"github.com/zrepl/zrepl/util/envconst"
|
"github.com/zrepl/zrepl/util/envconst"
|
||||||
|
"github.com/zrepl/zrepl/util/nodefault"
|
||||||
"github.com/zrepl/zrepl/util/semaphore"
|
"github.com/zrepl/zrepl/util/semaphore"
|
||||||
"github.com/zrepl/zrepl/zfs"
|
"github.com/zrepl/zrepl/zfs"
|
||||||
)
|
)
|
||||||
@ -257,7 +258,7 @@ type ListZFSHoldsAndBookmarksQuery struct {
|
|||||||
|
|
||||||
type CreateTXGRangeBound struct {
|
type CreateTXGRangeBound struct {
|
||||||
CreateTXG uint64
|
CreateTXG uint64
|
||||||
Inclusive *zfs.NilBool // must not be nil
|
Inclusive *nodefault.Bool // must not be nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// A non-empty range of CreateTXGs
|
// A non-empty range of CreateTXGs
|
||||||
@ -300,7 +301,7 @@ func (q *ListZFSHoldsAndBookmarksQuery) Validate() error {
|
|||||||
var createTXGRangeBoundAllowCreateTXG0 = envconst.Bool("ZREPL_ENDPOINT_LIST_ABSTRACTIONS_QUERY_CREATETXG_RANGE_BOUND_ALLOW_0", false)
|
var createTXGRangeBoundAllowCreateTXG0 = envconst.Bool("ZREPL_ENDPOINT_LIST_ABSTRACTIONS_QUERY_CREATETXG_RANGE_BOUND_ALLOW_0", false)
|
||||||
|
|
||||||
func (i *CreateTXGRangeBound) Validate() error {
|
func (i *CreateTXGRangeBound) Validate() error {
|
||||||
if err := i.Inclusive.Validate(); err != nil {
|
if err := i.Inclusive.ValidateNoDefault(); err != nil {
|
||||||
return errors.Wrap(err, "Inclusive")
|
return errors.Wrap(err, "Inclusive")
|
||||||
}
|
}
|
||||||
if i.CreateTXG == 0 && !createTXGRangeBoundAllowCreateTXG0 {
|
if i.CreateTXG == 0 && !createTXGRangeBoundAllowCreateTXG0 {
|
||||||
@ -419,7 +420,7 @@ func (r *CreateTXGRange) String() string {
|
|||||||
if r.Since == nil {
|
if r.Since == nil {
|
||||||
fmt.Fprintf(&buf, "~")
|
fmt.Fprintf(&buf, "~")
|
||||||
} else {
|
} else {
|
||||||
if err := r.Since.Inclusive.Validate(); err != nil {
|
if err := r.Since.Inclusive.ValidateNoDefault(); err != nil {
|
||||||
fmt.Fprintf(&buf, "?")
|
fmt.Fprintf(&buf, "?")
|
||||||
} else if r.Since.Inclusive.B {
|
} else if r.Since.Inclusive.B {
|
||||||
fmt.Fprintf(&buf, "[")
|
fmt.Fprintf(&buf, "[")
|
||||||
@ -435,7 +436,7 @@ func (r *CreateTXGRange) String() string {
|
|||||||
fmt.Fprintf(&buf, "~")
|
fmt.Fprintf(&buf, "~")
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(&buf, "%d", r.Until.CreateTXG)
|
fmt.Fprintf(&buf, "%d", r.Until.CreateTXG)
|
||||||
if err := r.Until.Inclusive.Validate(); err != nil {
|
if err := r.Until.Inclusive.ValidateNoDefault(); err != nil {
|
||||||
fmt.Fprintf(&buf, "?")
|
fmt.Fprintf(&buf, "?")
|
||||||
} else if r.Until.Inclusive.B {
|
} else if r.Until.Inclusive.B {
|
||||||
fmt.Fprintf(&buf, "]")
|
fmt.Fprintf(&buf, "]")
|
||||||
@ -829,14 +830,14 @@ func listStaleFiltering(abs []Abstraction, sinceBound *CreateTXGRangeBound) *Sta
|
|||||||
untilBound = &CreateTXGRangeBound{
|
untilBound = &CreateTXGRangeBound{
|
||||||
CreateTXG: (*sfnsc.cursor).GetCreateTXG(),
|
CreateTXG: (*sfnsc.cursor).GetCreateTXG(),
|
||||||
// if we have a cursor, can throw away step hold on both From and To
|
// if we have a cursor, can throw away step hold on both From and To
|
||||||
Inclusive: &zfs.NilBool{B: true},
|
Inclusive: &nodefault.Bool{B: true},
|
||||||
}
|
}
|
||||||
} else if sfnsc.step != nil {
|
} else if sfnsc.step != nil {
|
||||||
untilBound = &CreateTXGRangeBound{
|
untilBound = &CreateTXGRangeBound{
|
||||||
CreateTXG: (*sfnsc.step).GetCreateTXG(),
|
CreateTXG: (*sfnsc.step).GetCreateTXG(),
|
||||||
// if we don't have a cursor, the step most recent step hold is our
|
// if we don't have a cursor, the step most recent step hold is our
|
||||||
// initial replication cursor and it's possibly still live (interrupted initial replication)
|
// initial replication cursor and it's possibly still live (interrupted initial replication)
|
||||||
Inclusive: &zfs.NilBool{B: false},
|
Inclusive: &nodefault.Bool{B: false},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
untilBound = nil // consider everything stale
|
untilBound = nil // consider everything stale
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/zrepl/zrepl/zfs"
|
"github.com/zrepl/zrepl/util/nodefault"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCreateTXGRange(t *testing.T) {
|
func TestCreateTXGRange(t *testing.T) {
|
||||||
@ -47,8 +47,8 @@ func TestCreateTXGRange(t *testing.T) {
|
|||||||
name: "wrong order obvious",
|
name: "wrong order obvious",
|
||||||
expectInvalid: true,
|
expectInvalid: true,
|
||||||
config: &CreateTXGRange{
|
config: &CreateTXGRange{
|
||||||
Since: &CreateTXGRangeBound{23, &zfs.NilBool{B: true}},
|
Since: &CreateTXGRangeBound{23, &nodefault.Bool{B: true}},
|
||||||
Until: &CreateTXGRangeBound{20, &zfs.NilBool{B: true}},
|
Until: &CreateTXGRangeBound{20, &nodefault.Bool{B: true}},
|
||||||
},
|
},
|
||||||
expectString: "[23,20]",
|
expectString: "[23,20]",
|
||||||
},
|
},
|
||||||
@ -56,8 +56,8 @@ func TestCreateTXGRange(t *testing.T) {
|
|||||||
name: "wrong order edge-case could also be empty",
|
name: "wrong order edge-case could also be empty",
|
||||||
expectInvalid: true,
|
expectInvalid: true,
|
||||||
config: &CreateTXGRange{
|
config: &CreateTXGRange{
|
||||||
Since: &CreateTXGRangeBound{23, &zfs.NilBool{B: false}},
|
Since: &CreateTXGRangeBound{23, &nodefault.Bool{B: false}},
|
||||||
Until: &CreateTXGRangeBound{22, &zfs.NilBool{B: true}},
|
Until: &CreateTXGRangeBound{22, &nodefault.Bool{B: true}},
|
||||||
},
|
},
|
||||||
expectString: "(23,22]",
|
expectString: "(23,22]",
|
||||||
},
|
},
|
||||||
@ -65,8 +65,8 @@ func TestCreateTXGRange(t *testing.T) {
|
|||||||
name: "empty",
|
name: "empty",
|
||||||
expectInvalid: true,
|
expectInvalid: true,
|
||||||
config: &CreateTXGRange{
|
config: &CreateTXGRange{
|
||||||
Since: &CreateTXGRangeBound{2, &zfs.NilBool{B: false}},
|
Since: &CreateTXGRangeBound{2, &nodefault.Bool{B: false}},
|
||||||
Until: &CreateTXGRangeBound{2, &zfs.NilBool{B: false}},
|
Until: &CreateTXGRangeBound{2, &nodefault.Bool{B: false}},
|
||||||
},
|
},
|
||||||
expectString: "(2,2)",
|
expectString: "(2,2)",
|
||||||
},
|
},
|
||||||
@ -74,8 +74,8 @@ func TestCreateTXGRange(t *testing.T) {
|
|||||||
name: "inclusive-since-exclusive-until",
|
name: "inclusive-since-exclusive-until",
|
||||||
expectInvalid: false,
|
expectInvalid: false,
|
||||||
config: &CreateTXGRange{
|
config: &CreateTXGRange{
|
||||||
Since: &CreateTXGRangeBound{2, &zfs.NilBool{B: true}},
|
Since: &CreateTXGRangeBound{2, &nodefault.Bool{B: true}},
|
||||||
Until: &CreateTXGRangeBound{5, &zfs.NilBool{B: false}},
|
Until: &CreateTXGRangeBound{5, &nodefault.Bool{B: false}},
|
||||||
},
|
},
|
||||||
expectString: "[2,5)",
|
expectString: "[2,5)",
|
||||||
expect: []testCaseExpectation{
|
expect: []testCaseExpectation{
|
||||||
@ -92,8 +92,8 @@ func TestCreateTXGRange(t *testing.T) {
|
|||||||
name: "exclusive-since-inclusive-until",
|
name: "exclusive-since-inclusive-until",
|
||||||
expectInvalid: false,
|
expectInvalid: false,
|
||||||
config: &CreateTXGRange{
|
config: &CreateTXGRange{
|
||||||
Since: &CreateTXGRangeBound{2, &zfs.NilBool{B: false}},
|
Since: &CreateTXGRangeBound{2, &nodefault.Bool{B: false}},
|
||||||
Until: &CreateTXGRangeBound{5, &zfs.NilBool{B: true}},
|
Until: &CreateTXGRangeBound{5, &nodefault.Bool{B: true}},
|
||||||
},
|
},
|
||||||
expectString: "(2,5]",
|
expectString: "(2,5]",
|
||||||
expect: []testCaseExpectation{
|
expect: []testCaseExpectation{
|
||||||
@ -111,7 +111,7 @@ func TestCreateTXGRange(t *testing.T) {
|
|||||||
expectInvalid: true,
|
expectInvalid: true,
|
||||||
config: &CreateTXGRange{
|
config: &CreateTXGRange{
|
||||||
Since: nil,
|
Since: nil,
|
||||||
Until: &CreateTXGRangeBound{0, &zfs.NilBool{B: true}},
|
Until: &CreateTXGRangeBound{0, &nodefault.Bool{B: true}},
|
||||||
},
|
},
|
||||||
expectString: "~,0]",
|
expectString: "~,0]",
|
||||||
},
|
},
|
||||||
@ -119,7 +119,7 @@ func TestCreateTXGRange(t *testing.T) {
|
|||||||
name: "half-open-no-until",
|
name: "half-open-no-until",
|
||||||
expectInvalid: false,
|
expectInvalid: false,
|
||||||
config: &CreateTXGRange{
|
config: &CreateTXGRange{
|
||||||
Since: &CreateTXGRangeBound{2, &zfs.NilBool{B: false}},
|
Since: &CreateTXGRangeBound{2, &nodefault.Bool{B: false}},
|
||||||
Until: nil,
|
Until: nil,
|
||||||
},
|
},
|
||||||
expectString: "(2,~",
|
expectString: "(2,~",
|
||||||
@ -138,7 +138,7 @@ func TestCreateTXGRange(t *testing.T) {
|
|||||||
expectInvalid: false,
|
expectInvalid: false,
|
||||||
config: &CreateTXGRange{
|
config: &CreateTXGRange{
|
||||||
Since: nil,
|
Since: nil,
|
||||||
Until: &CreateTXGRangeBound{4, &zfs.NilBool{B: true}},
|
Until: &CreateTXGRangeBound{4, &nodefault.Bool{B: true}},
|
||||||
},
|
},
|
||||||
expectString: "~,4]",
|
expectString: "~,4]",
|
||||||
expect: []testCaseExpectation{
|
expect: []testCaseExpectation{
|
||||||
@ -154,7 +154,7 @@ func TestCreateTXGRange(t *testing.T) {
|
|||||||
name: "edgeSince",
|
name: "edgeSince",
|
||||||
expectInvalid: false,
|
expectInvalid: false,
|
||||||
config: &CreateTXGRange{
|
config: &CreateTXGRange{
|
||||||
Since: &CreateTXGRangeBound{math.MaxUint64, &zfs.NilBool{B: true}},
|
Since: &CreateTXGRangeBound{math.MaxUint64, &nodefault.Bool{B: true}},
|
||||||
Until: nil,
|
Until: nil,
|
||||||
},
|
},
|
||||||
expectString: "[18446744073709551615,~",
|
expectString: "[18446744073709551615,~",
|
||||||
@ -169,7 +169,7 @@ func TestCreateTXGRange(t *testing.T) {
|
|||||||
name: "edgeSinceNegative",
|
name: "edgeSinceNegative",
|
||||||
expectInvalid: true,
|
expectInvalid: true,
|
||||||
config: &CreateTXGRange{
|
config: &CreateTXGRange{
|
||||||
Since: &CreateTXGRangeBound{math.MaxUint64, &zfs.NilBool{B: false}},
|
Since: &CreateTXGRangeBound{math.MaxUint64, &nodefault.Bool{B: false}},
|
||||||
Until: nil,
|
Until: nil,
|
||||||
},
|
},
|
||||||
expectString: "(18446744073709551615,~",
|
expectString: "(18446744073709551615,~",
|
||||||
@ -178,7 +178,7 @@ func TestCreateTXGRange(t *testing.T) {
|
|||||||
name: "edgeUntil",
|
name: "edgeUntil",
|
||||||
expectInvalid: false,
|
expectInvalid: false,
|
||||||
config: &CreateTXGRange{
|
config: &CreateTXGRange{
|
||||||
Until: &CreateTXGRangeBound{0, &zfs.NilBool{B: true}},
|
Until: &CreateTXGRangeBound{0, &nodefault.Bool{B: true}},
|
||||||
},
|
},
|
||||||
configAllowZeroCreateTXG: true,
|
configAllowZeroCreateTXG: true,
|
||||||
expectString: "~,0]",
|
expectString: "~,0]",
|
||||||
@ -193,7 +193,7 @@ func TestCreateTXGRange(t *testing.T) {
|
|||||||
expectInvalid: true,
|
expectInvalid: true,
|
||||||
configAllowZeroCreateTXG: true,
|
configAllowZeroCreateTXG: true,
|
||||||
config: &CreateTXGRange{
|
config: &CreateTXGRange{
|
||||||
Until: &CreateTXGRangeBound{0, &zfs.NilBool{B: false}},
|
Until: &CreateTXGRangeBound{0, &nodefault.Bool{B: false}},
|
||||||
},
|
},
|
||||||
expectString: "~,0)",
|
expectString: "~,0)",
|
||||||
},
|
},
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/zrepl/zrepl/platformtest"
|
"github.com/zrepl/zrepl/platformtest"
|
||||||
|
"github.com/zrepl/zrepl/util/nodefault"
|
||||||
"github.com/zrepl/zrepl/zfs"
|
"github.com/zrepl/zrepl/zfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -32,7 +33,7 @@ func ReceiveForceIntoEncryptedErr(ctx *platformtest.Context) {
|
|||||||
|
|
||||||
sendArgs, err := zfs.ZFSSendArgsUnvalidated{
|
sendArgs, err := zfs.ZFSSendArgsUnvalidated{
|
||||||
FS: sfs,
|
FS: sfs,
|
||||||
Encrypted: &zfs.NilBool{B: false},
|
Encrypted: &nodefault.Bool{B: false},
|
||||||
From: nil,
|
From: nil,
|
||||||
To: &sfsSnap1,
|
To: &sfsSnap1,
|
||||||
ResumeToken: "",
|
ResumeToken: "",
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/zrepl/zrepl/platformtest"
|
"github.com/zrepl/zrepl/platformtest"
|
||||||
|
"github.com/zrepl/zrepl/util/nodefault"
|
||||||
"github.com/zrepl/zrepl/zfs"
|
"github.com/zrepl/zrepl/zfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,7 +29,7 @@ func ReceiveForceRollbackWorksUnencrypted(ctx *platformtest.Context) {
|
|||||||
|
|
||||||
sendArgs, err := zfs.ZFSSendArgsUnvalidated{
|
sendArgs, err := zfs.ZFSSendArgsUnvalidated{
|
||||||
FS: sfs,
|
FS: sfs,
|
||||||
Encrypted: &zfs.NilBool{B: false},
|
Encrypted: &nodefault.Bool{B: false},
|
||||||
From: nil,
|
From: nil,
|
||||||
To: &sfsSnap1,
|
To: &sfsSnap1,
|
||||||
ResumeToken: "",
|
ResumeToken: "",
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"github.com/zrepl/zrepl/replication/logic/pdu"
|
"github.com/zrepl/zrepl/replication/logic/pdu"
|
||||||
"github.com/zrepl/zrepl/replication/report"
|
"github.com/zrepl/zrepl/replication/report"
|
||||||
"github.com/zrepl/zrepl/util/limitio"
|
"github.com/zrepl/zrepl/util/limitio"
|
||||||
|
"github.com/zrepl/zrepl/util/nodefault"
|
||||||
"github.com/zrepl/zrepl/zfs"
|
"github.com/zrepl/zrepl/zfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -57,7 +58,7 @@ func (i replicationInvocation) Do(ctx *platformtest.Context) *report.Report {
|
|||||||
}
|
}
|
||||||
sender := i.interceptSender(endpoint.NewSender(endpoint.SenderConfig{
|
sender := i.interceptSender(endpoint.NewSender(endpoint.SenderConfig{
|
||||||
FSF: i.sfilter.AsFilter(),
|
FSF: i.sfilter.AsFilter(),
|
||||||
Encrypt: &zfs.NilBool{B: false},
|
Encrypt: &nodefault.Bool{B: false},
|
||||||
JobID: i.sjid,
|
JobID: i.sjid,
|
||||||
}))
|
}))
|
||||||
receiver := i.interceptReceiver(endpoint.NewReceiver(endpoint.ReceiverConfig{
|
receiver := i.interceptReceiver(endpoint.NewReceiver(endpoint.ReceiverConfig{
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/zrepl/zrepl/platformtest"
|
"github.com/zrepl/zrepl/platformtest"
|
||||||
|
"github.com/zrepl/zrepl/util/nodefault"
|
||||||
"github.com/zrepl/zrepl/zfs"
|
"github.com/zrepl/zrepl/zfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,7 +29,7 @@ func ResumableRecvAndTokenHandling(ctx *platformtest.Context) {
|
|||||||
s := makeResumeSituation(ctx, src, recvFS, zfs.ZFSSendArgsUnvalidated{
|
s := makeResumeSituation(ctx, src, recvFS, zfs.ZFSSendArgsUnvalidated{
|
||||||
FS: sendFS,
|
FS: sendFS,
|
||||||
To: src.snapA,
|
To: src.snapA,
|
||||||
Encrypted: &zfs.NilBool{B: false},
|
Encrypted: &nodefault.Bool{B: false},
|
||||||
ResumeToken: "",
|
ResumeToken: "",
|
||||||
}, zfs.RecvOptions{
|
}, zfs.RecvOptions{
|
||||||
RollbackAndForceRecv: false, // doesnt' exist yet
|
RollbackAndForceRecv: false, // doesnt' exist yet
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/zrepl/zrepl/platformtest"
|
"github.com/zrepl/zrepl/platformtest"
|
||||||
|
"github.com/zrepl/zrepl/util/nodefault"
|
||||||
"github.com/zrepl/zrepl/zfs"
|
"github.com/zrepl/zrepl/zfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -42,7 +43,7 @@ func sendArgsValidationEncryptedSendOfUnencryptedDatasetForbidden_impl(ctx *plat
|
|||||||
RelName: "@a snap",
|
RelName: "@a snap",
|
||||||
GUID: props.Guid,
|
GUID: props.Guid,
|
||||||
},
|
},
|
||||||
Encrypted: &zfs.NilBool{B: true},
|
Encrypted: &nodefault.Bool{B: true},
|
||||||
ResumeToken: "",
|
ResumeToken: "",
|
||||||
}.Validate(ctx)
|
}.Validate(ctx)
|
||||||
|
|
||||||
@ -97,7 +98,7 @@ func SendArgsValidationResumeTokenEncryptionMismatchForbidden(ctx *platformtest.
|
|||||||
unencS := makeResumeSituation(ctx, src, unencRecvFS, zfs.ZFSSendArgsUnvalidated{
|
unencS := makeResumeSituation(ctx, src, unencRecvFS, zfs.ZFSSendArgsUnvalidated{
|
||||||
FS: sendFS,
|
FS: sendFS,
|
||||||
To: src.snapA,
|
To: src.snapA,
|
||||||
Encrypted: &zfs.NilBool{B: false}, // !
|
Encrypted: &nodefault.Bool{B: false}, // !
|
||||||
}, zfs.RecvOptions{
|
}, zfs.RecvOptions{
|
||||||
RollbackAndForceRecv: false,
|
RollbackAndForceRecv: false,
|
||||||
SavePartialRecvState: true,
|
SavePartialRecvState: true,
|
||||||
@ -106,7 +107,7 @@ func SendArgsValidationResumeTokenEncryptionMismatchForbidden(ctx *platformtest.
|
|||||||
encS := makeResumeSituation(ctx, src, encRecvFS, zfs.ZFSSendArgsUnvalidated{
|
encS := makeResumeSituation(ctx, src, encRecvFS, zfs.ZFSSendArgsUnvalidated{
|
||||||
FS: sendFS,
|
FS: sendFS,
|
||||||
To: src.snapA,
|
To: src.snapA,
|
||||||
Encrypted: &zfs.NilBool{B: true}, // !
|
Encrypted: &nodefault.Bool{B: true}, // !
|
||||||
}, zfs.RecvOptions{
|
}, zfs.RecvOptions{
|
||||||
RollbackAndForceRecv: false,
|
RollbackAndForceRecv: false,
|
||||||
SavePartialRecvState: true,
|
SavePartialRecvState: true,
|
||||||
@ -174,7 +175,7 @@ func SendArgsValidationResumeTokenDifferentFilesystemForbidden(ctx *platformtest
|
|||||||
rs := makeResumeSituation(ctx, src1, recvFS, zfs.ZFSSendArgsUnvalidated{
|
rs := makeResumeSituation(ctx, src1, recvFS, zfs.ZFSSendArgsUnvalidated{
|
||||||
FS: sendFS1,
|
FS: sendFS1,
|
||||||
To: src1.snapA,
|
To: src1.snapA,
|
||||||
Encrypted: &zfs.NilBool{B: false},
|
Encrypted: &nodefault.Bool{B: false},
|
||||||
}, zfs.RecvOptions{
|
}, zfs.RecvOptions{
|
||||||
RollbackAndForceRecv: false,
|
RollbackAndForceRecv: false,
|
||||||
SavePartialRecvState: true,
|
SavePartialRecvState: true,
|
||||||
@ -188,7 +189,7 @@ func SendArgsValidationResumeTokenDifferentFilesystemForbidden(ctx *platformtest
|
|||||||
RelName: src2.snapA.RelName,
|
RelName: src2.snapA.RelName,
|
||||||
GUID: src2.snapA.GUID,
|
GUID: src2.snapA.GUID,
|
||||||
},
|
},
|
||||||
Encrypted: &zfs.NilBool{B: false},
|
Encrypted: &nodefault.Bool{B: false},
|
||||||
ResumeToken: rs.recvErrDecoded.ResumeTokenRaw,
|
ResumeToken: rs.recvErrDecoded.ResumeTokenRaw,
|
||||||
}
|
}
|
||||||
_, err = maliciousSend.Validate(ctx)
|
_, err = maliciousSend.Validate(ctx)
|
||||||
|
32
util/nodefault/nodefault.go
Normal file
32
util/nodefault/nodefault.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Package nodefault provides newtypes around builtin Go types
|
||||||
|
// so that if the newtype is used as a field in a struct and that field
|
||||||
|
// is zero-initialized (https://golang.org/ref/spec#The_zero_value),
|
||||||
|
// accessing the field will cause a null pointer deref panic.
|
||||||
|
// Or in other terms: It soft-enforces that the caller sets the field
|
||||||
|
// explicitly when constructing the struct.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// type Config struct {
|
||||||
|
// // This field must be set to a non-nil value,
|
||||||
|
// // forcing the caller to make their mind up
|
||||||
|
// // about this field.
|
||||||
|
// CriticalSetting *nodefault.Bool
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// An function that takes such a Config should _not_ check for nil-ness:
|
||||||
|
// and instead unconditionally dereference:
|
||||||
|
//
|
||||||
|
// func f(c Config) {
|
||||||
|
// if (c.CriticalSetting) { }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// If the caller of f forgot to specify the .CriticalSetting
|
||||||
|
// field, the Go runtime will issue a nil-pointer deref panic
|
||||||
|
// and it'll be clear that the caller did not read the docs of Config.
|
||||||
|
//
|
||||||
|
// f(Config{}) // crashes
|
||||||
|
//
|
||||||
|
// f Config{ CriticalSetting: &nodefault.Bool{B: false}} // doesn't crash
|
||||||
|
//
|
||||||
|
package nodefault
|
19
util/nodefault/nodefault_bool.go
Normal file
19
util/nodefault/nodefault_bool.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package nodefault
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type Bool struct{ B bool }
|
||||||
|
|
||||||
|
func (n *Bool) ValidateNoDefault() error {
|
||||||
|
if n == nil {
|
||||||
|
return fmt.Errorf("must explicitly set `true` or `false`")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Bool) String() string {
|
||||||
|
if n == nil {
|
||||||
|
return "unset"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%v", n.B)
|
||||||
|
}
|
27
zfs/zfs.go
27
zfs/zfs.go
@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"github.com/zrepl/zrepl/util/circlog"
|
"github.com/zrepl/zrepl/util/circlog"
|
||||||
"github.com/zrepl/zrepl/util/envconst"
|
"github.com/zrepl/zrepl/util/envconst"
|
||||||
|
"github.com/zrepl/zrepl/util/nodefault"
|
||||||
"github.com/zrepl/zrepl/zfs/zfscmd"
|
"github.com/zrepl/zrepl/zfs/zfscmd"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -563,27 +564,11 @@ func (v ZFSSendArgVersion) MustBeBookmark() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type NilBool struct{ B bool }
|
|
||||||
|
|
||||||
func (n *NilBool) Validate() error {
|
|
||||||
if n == nil {
|
|
||||||
return fmt.Errorf("must explicitly set `true` or `false`")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *NilBool) String() string {
|
|
||||||
if n == nil {
|
|
||||||
return "unset"
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%v", n.B)
|
|
||||||
}
|
|
||||||
|
|
||||||
// When updating this struct, check Validate and ValidateCorrespondsToResumeToken (POTENTIALLY SECURITY SENSITIVE)
|
// When updating this struct, check Validate and ValidateCorrespondsToResumeToken (POTENTIALLY SECURITY SENSITIVE)
|
||||||
type ZFSSendArgsUnvalidated struct {
|
type ZFSSendArgsUnvalidated struct {
|
||||||
FS string
|
FS string
|
||||||
From, To *ZFSSendArgVersion // From may be nil
|
From, To *ZFSSendArgVersion // From may be nil
|
||||||
Encrypted *NilBool
|
Encrypted *nodefault.Bool
|
||||||
|
|
||||||
// Preferred if not empty
|
// Preferred if not empty
|
||||||
ResumeToken string // if not nil, must match what is specified in From, To (covered by ValidateCorrespondsToResumeToken)
|
ResumeToken string // if not nil, must match what is specified in From, To (covered by ValidateCorrespondsToResumeToken)
|
||||||
@ -596,7 +581,7 @@ type ZFSSendArgsValidated struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type zfsSendArgsValidationContext struct {
|
type zfsSendArgsValidationContext struct {
|
||||||
encEnabled *NilBool
|
encEnabled *nodefault.Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type ZFSSendArgsValidationErrorCode int
|
type ZFSSendArgsValidationErrorCode int
|
||||||
@ -653,7 +638,7 @@ func (a ZFSSendArgsUnvalidated) Validate(ctx context.Context) (v ZFSSendArgsVali
|
|||||||
// fallthrough
|
// fallthrough
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.Encrypted.Validate(); err != nil {
|
if err := a.Encrypted.ValidateNoDefault(); err != nil {
|
||||||
return v, newGenericValidationError(a, errors.Wrap(err, "`Raw` invalid"))
|
return v, newGenericValidationError(a, errors.Wrap(err, "`Raw` invalid"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -663,7 +648,7 @@ func (a ZFSSendArgsUnvalidated) Validate(ctx context.Context) (v ZFSSendArgsVali
|
|||||||
return v, newValidationError(a, ZFSSendArgsFSEncryptionCheckFail,
|
return v, newValidationError(a, ZFSSendArgsFSEncryptionCheckFail,
|
||||||
errors.Wrapf(err, "cannot check whether filesystem %q is encrypted", a.FS))
|
errors.Wrapf(err, "cannot check whether filesystem %q is encrypted", a.FS))
|
||||||
}
|
}
|
||||||
valCtx.encEnabled = &NilBool{fsEncrypted}
|
valCtx.encEnabled = &nodefault.Bool{B: fsEncrypted}
|
||||||
|
|
||||||
if a.Encrypted.B && !fsEncrypted {
|
if a.Encrypted.B && !fsEncrypted {
|
||||||
return v, newValidationError(a, ZFSSendArgsEncryptedSendRequestedButFSUnencrypted,
|
return v, newValidationError(a, ZFSSendArgsEncryptedSendRequestedButFSUnencrypted,
|
||||||
@ -790,7 +775,7 @@ func ZFSSend(ctx context.Context, sendArgs ZFSSendArgsValidated) (*SendStream, e
|
|||||||
|
|
||||||
// pre-validation of sendArgs for plain ErrEncryptedSendNotSupported error
|
// pre-validation of sendArgs for plain ErrEncryptedSendNotSupported error
|
||||||
// TODO go1.13: push this down to sendArgs.Validate
|
// TODO go1.13: push this down to sendArgs.Validate
|
||||||
if encryptedSendValid := sendArgs.Encrypted.Validate(); encryptedSendValid == nil && sendArgs.Encrypted.B {
|
if encryptedSendValid := sendArgs.Encrypted.ValidateNoDefault(); encryptedSendValid == nil && sendArgs.Encrypted.B {
|
||||||
supported, err := EncryptionCLISupported(ctx)
|
supported, err := EncryptionCLISupported(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "cannot determine CLI native encryption support")
|
return nil, errors.Wrap(err, "cannot determine CLI native encryption support")
|
||||||
|
Loading…
Reference in New Issue
Block a user