mirror of
https://github.com/zrepl/zrepl.git
synced 2025-08-14 09:08:24 +02:00
zfs: use exec.CommandContext everywhere
Co-authored-by: InsanePrawn <insane.prawny@gmail.com>
This commit is contained in:
committed by
Christian Schwarz
parent
3187129672
commit
9568e46f05
@ -21,7 +21,7 @@ var encryptionCLISupport struct {
|
||||
func EncryptionCLISupported(ctx context.Context) (bool, error) {
|
||||
encryptionCLISupport.once.Do(func() {
|
||||
// "feature discovery"
|
||||
cmd := exec.Command("zfs", "load-key")
|
||||
cmd := exec.CommandContext(ctx, "zfs", "load-key")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if ee, ok := err.(*exec.ExitError); !ok || ok && !ee.Exited() {
|
||||
encryptionCLISupport.err = errors.Wrap(err, "native encryption cli support feature check failed")
|
||||
@ -50,7 +50,7 @@ func ZFSGetEncryptionEnabled(ctx context.Context, fs string) (enabled bool, err
|
||||
return false, err
|
||||
}
|
||||
|
||||
props, err := zfsGet(fs, []string{"encryption"}, sourceAny)
|
||||
props, err := zfsGet(ctx, fs, []string{"encryption"}, sourceAny)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "cannot get `encryption` property")
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package zfs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
@ -61,10 +62,10 @@ type FilesystemPlaceholderState struct {
|
||||
// is a placeholder. Note that the property source must be `local` for the returned value to be valid.
|
||||
//
|
||||
// For nonexistent FS, err == nil and state.FSExists == false
|
||||
func ZFSGetFilesystemPlaceholderState(p *DatasetPath) (state *FilesystemPlaceholderState, err error) {
|
||||
func ZFSGetFilesystemPlaceholderState(ctx context.Context, p *DatasetPath) (state *FilesystemPlaceholderState, err error) {
|
||||
state = &FilesystemPlaceholderState{FS: p.ToString()}
|
||||
state.FS = p.ToString()
|
||||
props, err := zfsGet(p.ToString(), []string{PlaceholderPropertyName}, sourceLocal)
|
||||
props, err := zfsGet(ctx, p.ToString(), []string{PlaceholderPropertyName}, sourceLocal)
|
||||
var _ error = (*DatasetDoesNotExist)(nil) // weak assertion on zfsGet's interface
|
||||
if _, ok := err.(*DatasetDoesNotExist); ok {
|
||||
return state, nil
|
||||
@ -77,11 +78,11 @@ func ZFSGetFilesystemPlaceholderState(p *DatasetPath) (state *FilesystemPlacehol
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func ZFSCreatePlaceholderFilesystem(p *DatasetPath) (err error) {
|
||||
func ZFSCreatePlaceholderFilesystem(ctx context.Context, p *DatasetPath) (err error) {
|
||||
if p.Length() == 1 {
|
||||
return fmt.Errorf("cannot create %q: pools cannot be created with zfs create", p.ToString())
|
||||
}
|
||||
cmd := exec.Command(ZFS_BINARY, "create",
|
||||
cmd := exec.CommandContext(ctx, ZFS_BINARY, "create",
|
||||
"-o", fmt.Sprintf("%s=%s", PlaceholderPropertyName, placeholderPropertyOn),
|
||||
"-o", "mountpoint=none",
|
||||
p.ToString())
|
||||
@ -103,14 +104,14 @@ func ZFSCreatePlaceholderFilesystem(p *DatasetPath) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func ZFSSetPlaceholder(p *DatasetPath, isPlaceholder bool) error {
|
||||
func ZFSSetPlaceholder(ctx context.Context, p *DatasetPath, isPlaceholder bool) error {
|
||||
props := NewZFSProperties()
|
||||
prop := placeholderPropertyOff
|
||||
if isPlaceholder {
|
||||
prop = placeholderPropertyOn
|
||||
}
|
||||
props.Set(PlaceholderPropertyName, prop)
|
||||
return zfsSet(p.ToString(), props)
|
||||
return zfsSet(ctx, p.ToString(), props)
|
||||
}
|
||||
|
||||
type MigrateHashBasedPlaceholderReport struct {
|
||||
@ -119,8 +120,8 @@ type MigrateHashBasedPlaceholderReport struct {
|
||||
}
|
||||
|
||||
// fs must exist, will panic otherwise
|
||||
func ZFSMigrateHashBasedPlaceholderToCurrent(fs *DatasetPath, dryRun bool) (*MigrateHashBasedPlaceholderReport, error) {
|
||||
st, err := ZFSGetFilesystemPlaceholderState(fs)
|
||||
func ZFSMigrateHashBasedPlaceholderToCurrent(ctx context.Context, fs *DatasetPath, dryRun bool) (*MigrateHashBasedPlaceholderReport, error) {
|
||||
st, err := ZFSGetFilesystemPlaceholderState(ctx, fs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error getting placeholder state: %s", err)
|
||||
}
|
||||
@ -137,7 +138,7 @@ func ZFSMigrateHashBasedPlaceholderToCurrent(fs *DatasetPath, dryRun bool) (*Mig
|
||||
return &report, nil
|
||||
}
|
||||
|
||||
err = ZFSSetPlaceholder(fs, st.IsPlaceholder)
|
||||
err = ZFSSetPlaceholder(ctx, fs, st.IsPlaceholder)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error re-writing placeholder property: %s", err)
|
||||
}
|
||||
|
@ -39,10 +39,10 @@ var resumeSendSupportedCheck struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func ResumeSendSupported() (bool, error) {
|
||||
func ResumeSendSupported(ctx context.Context) (bool, error) {
|
||||
resumeSendSupportedCheck.once.Do(func() {
|
||||
// "feature discovery"
|
||||
cmd := exec.Command("zfs", "send")
|
||||
cmd := exec.CommandContext(ctx, "zfs", "send")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if ee, ok := err.(*exec.ExitError); !ok || ok && !ee.Exited() {
|
||||
resumeSendSupportedCheck.err = errors.Wrap(err, "resumable send cli support feature check failed")
|
||||
@ -155,7 +155,7 @@ func ResumeRecvSupported(ctx context.Context, fs *DatasetPath) (bool, error) {
|
||||
// FIXME: implement nvlist unpacking in Go and read through libzfs_sendrecv.c
|
||||
func ParseResumeToken(ctx context.Context, token string) (*ResumeToken, error) {
|
||||
|
||||
if supported, err := ResumeSendSupported(); err != nil {
|
||||
if supported, err := ResumeSendSupported(ctx); err != nil {
|
||||
return nil, err
|
||||
} else if !supported {
|
||||
return nil, ResumeTokenDecodingNotSupported
|
||||
@ -258,7 +258,7 @@ func ZFSGetReceiveResumeTokenOrEmptyStringIfNotSupported(ctx context.Context, fs
|
||||
return "", nil
|
||||
}
|
||||
const prop_receive_resume_token = "receive_resume_token"
|
||||
props, err := ZFSGet(fs, []string{prop_receive_resume_token})
|
||||
props, err := ZFSGet(ctx, fs, []string{prop_receive_resume_token})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
"github.com/zrepl/zrepl/util/envconst"
|
||||
)
|
||||
|
||||
func ZFSDestroyFilesystemVersion(filesystem *DatasetPath, version *FilesystemVersion) (err error) {
|
||||
func ZFSDestroyFilesystemVersion(ctx context.Context, filesystem *DatasetPath, version *FilesystemVersion) (err error) {
|
||||
|
||||
datasetPath := version.ToAbsPath(filesystem)
|
||||
|
||||
@ -22,7 +22,7 @@ func ZFSDestroyFilesystemVersion(filesystem *DatasetPath, version *FilesystemVer
|
||||
return fmt.Errorf("sanity check failed: no @ or # character found in %q", datasetPath)
|
||||
}
|
||||
|
||||
return ZFSDestroy(datasetPath)
|
||||
return ZFSDestroy(ctx, datasetPath)
|
||||
}
|
||||
|
||||
var destroyerSingleton = destroyerImpl{}
|
||||
@ -48,8 +48,8 @@ func setDestroySnapOpErr(b []*DestroySnapOp, err error) {
|
||||
}
|
||||
|
||||
type destroyer interface {
|
||||
Destroy(args []string) error
|
||||
DestroySnapshotsCommaSyntaxSupported() (bool, error)
|
||||
Destroy(ctx context.Context, args []string) error
|
||||
DestroySnapshotsCommaSyntaxSupported(context.Context) (bool, error)
|
||||
}
|
||||
|
||||
func doDestroy(ctx context.Context, reqs []*DestroySnapOp, e destroyer) {
|
||||
@ -69,7 +69,7 @@ func doDestroy(ctx context.Context, reqs []*DestroySnapOp, e destroyer) {
|
||||
}
|
||||
reqs = validated
|
||||
|
||||
commaSupported, err := e.DestroySnapshotsCommaSyntaxSupported()
|
||||
commaSupported, err := e.DestroySnapshotsCommaSyntaxSupported(ctx)
|
||||
if err != nil {
|
||||
debug("destroy: comma syntax support detection failed: %s", err)
|
||||
setDestroySnapOpErr(reqs, err)
|
||||
@ -85,7 +85,7 @@ func doDestroy(ctx context.Context, reqs []*DestroySnapOp, e destroyer) {
|
||||
|
||||
func doDestroySeq(ctx context.Context, reqs []*DestroySnapOp, e destroyer) {
|
||||
for _, r := range reqs {
|
||||
*r.ErrOut = e.Destroy([]string{fmt.Sprintf("%s@%s", r.Filesystem, r.Name)})
|
||||
*r.ErrOut = e.Destroy(ctx, []string{fmt.Sprintf("%s@%s", r.Filesystem, r.Name)})
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,7 +139,7 @@ func tryBatch(ctx context.Context, batch []*DestroySnapOp, d destroyer) error {
|
||||
}
|
||||
}
|
||||
batchArg := fmt.Sprintf("%s@%s", batchFS, strings.Join(batchNames, ","))
|
||||
return d.Destroy([]string{batchArg})
|
||||
return d.Destroy(ctx, []string{batchArg})
|
||||
}
|
||||
|
||||
// fsbatch must be on same filesystem
|
||||
@ -203,7 +203,7 @@ func doDestroyBatchedRec(ctx context.Context, fsbatch []*DestroySnapOp, d destro
|
||||
|
||||
type destroyerImpl struct{}
|
||||
|
||||
func (d destroyerImpl) Destroy(args []string) error {
|
||||
func (d destroyerImpl) Destroy(ctx context.Context, args []string) error {
|
||||
if len(args) != 1 {
|
||||
// we have no use case for this at the moment, so let's crash (safer than destroying something unexpectedly)
|
||||
panic(fmt.Sprintf("unexpected number of arguments: %v", args))
|
||||
@ -212,7 +212,7 @@ func (d destroyerImpl) Destroy(args []string) error {
|
||||
if !strings.ContainsAny(args[0], "@") {
|
||||
panic(fmt.Sprintf("sanity check: expecting '@' in call to Destroy, got %q", args[0]))
|
||||
}
|
||||
return ZFSDestroy(args[0])
|
||||
return ZFSDestroy(ctx, args[0])
|
||||
}
|
||||
|
||||
var batchDestroyFeatureCheck struct {
|
||||
@ -221,10 +221,10 @@ var batchDestroyFeatureCheck struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (d destroyerImpl) DestroySnapshotsCommaSyntaxSupported() (bool, error) {
|
||||
func (d destroyerImpl) DestroySnapshotsCommaSyntaxSupported(ctx context.Context) (bool, error) {
|
||||
batchDestroyFeatureCheck.once.Do(func() {
|
||||
// "feature discovery"
|
||||
cmd := exec.Command(ZFS_BINARY, "destroy")
|
||||
cmd := exec.CommandContext(ctx, ZFS_BINARY, "destroy")
|
||||
output, err := cmd.CombinedOutput()
|
||||
if _, ok := err.(*exec.ExitError); !ok {
|
||||
debug("destroy feature check failed: %T %s", err, err)
|
||||
|
@ -25,11 +25,11 @@ type mockBatchDestroy struct {
|
||||
e2biglen int
|
||||
}
|
||||
|
||||
func (m *mockBatchDestroy) DestroySnapshotsCommaSyntaxSupported() (bool, error) {
|
||||
func (m *mockBatchDestroy) DestroySnapshotsCommaSyntaxSupported(_ context.Context) (bool, error) {
|
||||
return !m.commaUnsupported, nil
|
||||
}
|
||||
|
||||
func (m *mockBatchDestroy) Destroy(args []string) error {
|
||||
func (m *mockBatchDestroy) Destroy(ctx context.Context, args []string) error {
|
||||
defer m.mtx.Lock().Unlock()
|
||||
if len(args) != 1 {
|
||||
panic("unexpected use of Destroy")
|
||||
|
74
zfs/zfs.go
74
zfs/zfs.go
@ -164,7 +164,7 @@ func (e *ZFSError) Error() string {
|
||||
|
||||
var ZFS_BINARY string = "zfs"
|
||||
|
||||
func ZFSList(properties []string, zfsArgs ...string) (res [][]string, err error) {
|
||||
func ZFSList(ctx context.Context, properties []string, zfsArgs ...string) (res [][]string, err error) {
|
||||
|
||||
args := make([]string, 0, 4+len(zfsArgs))
|
||||
args = append(args,
|
||||
@ -172,7 +172,7 @@ func ZFSList(properties []string, zfsArgs ...string) (res [][]string, err error)
|
||||
"-o", strings.Join(properties, ","))
|
||||
args = append(args, zfsArgs...)
|
||||
|
||||
cmd := exec.Command(ZFS_BINARY, args...)
|
||||
cmd := exec.CommandContext(ctx, ZFS_BINARY, args...)
|
||||
|
||||
var stdout io.Reader
|
||||
stderr := bytes.NewBuffer(make([]byte, 0, 1024))
|
||||
@ -564,7 +564,7 @@ func (a ZFSSendArgVersion) ValidateExistsAndGetCheckedProps(ctx context.Context,
|
||||
return ZFSPropCreateTxgAndGuidProps{}, nil
|
||||
}
|
||||
|
||||
realProps, err := ZFSGetCreateTXGAndGuid(a.FullPath(fs))
|
||||
realProps, err := ZFSGetCreateTXGAndGuid(ctx, a.FullPath(fs))
|
||||
if err != nil {
|
||||
return ZFSPropCreateTxgAndGuidProps{}, err
|
||||
}
|
||||
@ -996,7 +996,7 @@ func ZFSSendDry(ctx context.Context, sendArgs ZFSSendArgs) (_ *DrySendInfo, err
|
||||
}
|
||||
args = append(args, sargs...)
|
||||
|
||||
cmd := exec.Command(ZFS_BINARY, args...)
|
||||
cmd := exec.CommandContext(ctx, ZFS_BINARY, args...)
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return nil, &ZFSError{output, err}
|
||||
@ -1090,11 +1090,11 @@ func ZFSRecv(ctx context.Context, fs string, v *ZFSSendArgVersion, streamCopier
|
||||
rollbackTarget := snaps[0]
|
||||
rollbackTargetAbs := rollbackTarget.ToAbsPath(fsdp)
|
||||
debug("recv: rollback to %q", rollbackTargetAbs)
|
||||
if err := ZFSRollback(fsdp, rollbackTarget, "-r"); err != nil {
|
||||
if err := ZFSRollback(ctx, fsdp, rollbackTarget, "-r"); err != nil {
|
||||
return fmt.Errorf("cannot rollback %s to %s for forced receive: %s", fsdp.ToString(), rollbackTarget, err)
|
||||
}
|
||||
debug("recv: destroy %q", rollbackTargetAbs)
|
||||
if err := ZFSDestroy(rollbackTargetAbs); err != nil {
|
||||
if err := ZFSDestroy(ctx, rollbackTargetAbs); err != nil {
|
||||
return fmt.Errorf("cannot destroy %s for forced receive: %s", rollbackTargetAbs, err)
|
||||
}
|
||||
}
|
||||
@ -1225,12 +1225,12 @@ func (e ClearResumeTokenError) Error() string {
|
||||
}
|
||||
|
||||
// always returns *ClearResumeTokenError
|
||||
func ZFSRecvClearResumeToken(fs string) (err error) {
|
||||
func ZFSRecvClearResumeToken(ctx context.Context, fs string) (err error) {
|
||||
if err := validateZFSFilesystem(fs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd := exec.Command(ZFS_BINARY, "recv", "-A", fs)
|
||||
cmd := exec.CommandContext(ctx, ZFS_BINARY, "recv", "-A", fs)
|
||||
o, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
if bytes.Contains(o, []byte("does not have any resumable receive state to abort")) {
|
||||
@ -1267,11 +1267,11 @@ func (p *ZFSProperties) appendArgs(args *[]string) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func ZFSSet(fs *DatasetPath, props *ZFSProperties) (err error) {
|
||||
return zfsSet(fs.ToString(), props)
|
||||
func ZFSSet(ctx context.Context, fs *DatasetPath, props *ZFSProperties) (err error) {
|
||||
return zfsSet(ctx, fs.ToString(), props)
|
||||
}
|
||||
|
||||
func zfsSet(path string, props *ZFSProperties) (err error) {
|
||||
func zfsSet(ctx context.Context, path string, props *ZFSProperties) (err error) {
|
||||
args := make([]string, 0)
|
||||
args = append(args, "set")
|
||||
err = props.appendArgs(&args)
|
||||
@ -1280,7 +1280,7 @@ func zfsSet(path string, props *ZFSProperties) (err error) {
|
||||
}
|
||||
args = append(args, path)
|
||||
|
||||
cmd := exec.Command(ZFS_BINARY, args...)
|
||||
cmd := exec.CommandContext(ctx, ZFS_BINARY, args...)
|
||||
|
||||
stderr := bytes.NewBuffer(make([]byte, 0, 1024))
|
||||
cmd.Stderr = stderr
|
||||
@ -1299,12 +1299,12 @@ func zfsSet(path string, props *ZFSProperties) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func ZFSGet(fs *DatasetPath, props []string) (*ZFSProperties, error) {
|
||||
return zfsGet(fs.ToString(), props, sourceAny)
|
||||
func ZFSGet(ctx context.Context, fs *DatasetPath, props []string) (*ZFSProperties, error) {
|
||||
return zfsGet(ctx, fs.ToString(), props, sourceAny)
|
||||
}
|
||||
|
||||
// The returned error includes requested filesystem and version as quoted strings in its error message
|
||||
func ZFSGetGUID(fs string, version string) (g uint64, err error) {
|
||||
func ZFSGetGUID(ctx context.Context, fs string, version string) (g uint64, err error) {
|
||||
defer func(e *error) {
|
||||
if *e != nil {
|
||||
*e = fmt.Errorf("zfs get guid fs=%q version=%q: %s", fs, version, *e)
|
||||
@ -1320,7 +1320,7 @@ func ZFSGetGUID(fs string, version string) (g uint64, err error) {
|
||||
return 0, errors.New("version does not start with @ or #")
|
||||
}
|
||||
path := fmt.Sprintf("%s%s", fs, version)
|
||||
props, err := zfsGet(path, []string{"guid"}, sourceAny) // always local
|
||||
props, err := zfsGet(ctx, path, []string{"guid"}, sourceAny) // always local
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@ -1332,11 +1332,11 @@ type GetMountpointOutput struct {
|
||||
Mountpoint string
|
||||
}
|
||||
|
||||
func ZFSGetMountpoint(fs string) (*GetMountpointOutput, error) {
|
||||
func ZFSGetMountpoint(ctx context.Context, fs string) (*GetMountpointOutput, error) {
|
||||
if err := EntityNamecheck(fs, EntityTypeFilesystem); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
props, err := zfsGet(fs, []string{"mountpoint", "mounted"}, sourceAny)
|
||||
props, err := zfsGet(ctx, fs, []string{"mountpoint", "mounted"}, sourceAny)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1352,8 +1352,8 @@ func ZFSGetMountpoint(fs string) (*GetMountpointOutput, error) {
|
||||
return o, nil
|
||||
}
|
||||
|
||||
func ZFSGetRawAnySource(path string, props []string) (*ZFSProperties, error) {
|
||||
return zfsGet(path, props, sourceAny)
|
||||
func ZFSGetRawAnySource(ctx context.Context, path string, props []string) (*ZFSProperties, error) {
|
||||
return zfsGet(ctx, path, props, sourceAny)
|
||||
}
|
||||
|
||||
var zfsGetDatasetDoesNotExistRegexp = regexp.MustCompile(`^cannot open '([^)]+)': (dataset does not exist|no such pool or dataset)`) // verified in platformtest
|
||||
@ -1412,9 +1412,9 @@ func (s zfsPropertySource) zfsGetSourceFieldPrefixes() []string {
|
||||
return prefixes
|
||||
}
|
||||
|
||||
func zfsGet(path string, props []string, allowedSources zfsPropertySource) (*ZFSProperties, error) {
|
||||
func zfsGet(ctx context.Context, path string, props []string, allowedSources zfsPropertySource) (*ZFSProperties, error) {
|
||||
args := []string{"get", "-Hp", "-o", "property,value,source", strings.Join(props, ","), path}
|
||||
cmd := exec.Command(ZFS_BINARY, args...)
|
||||
cmd := exec.CommandContext(ctx, ZFS_BINARY, args...)
|
||||
stdout, err := cmd.Output()
|
||||
if err != nil {
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
@ -1462,8 +1462,8 @@ type ZFSPropCreateTxgAndGuidProps struct {
|
||||
CreateTXG, Guid uint64
|
||||
}
|
||||
|
||||
func ZFSGetCreateTXGAndGuid(ds string) (ZFSPropCreateTxgAndGuidProps, error) {
|
||||
props, err := zfsGetNumberProps(ds, []string{"createtxg", "guid"}, sourceAny)
|
||||
func ZFSGetCreateTXGAndGuid(ctx context.Context, ds string) (ZFSPropCreateTxgAndGuidProps, error) {
|
||||
props, err := zfsGetNumberProps(ctx, ds, []string{"createtxg", "guid"}, sourceAny)
|
||||
if err != nil {
|
||||
return ZFSPropCreateTxgAndGuidProps{}, err
|
||||
}
|
||||
@ -1474,8 +1474,8 @@ func ZFSGetCreateTXGAndGuid(ds string) (ZFSPropCreateTxgAndGuidProps, error) {
|
||||
}
|
||||
|
||||
// returns *DatasetDoesNotExist if the dataset does not exist
|
||||
func zfsGetNumberProps(ds string, props []string, src zfsPropertySource) (map[string]uint64, error) {
|
||||
sps, err := zfsGet(ds, props, sourceAny)
|
||||
func zfsGetNumberProps(ctx context.Context, ds string, props []string, src zfsPropertySource) (map[string]uint64, error) {
|
||||
sps, err := zfsGet(ctx, ds, props, sourceAny)
|
||||
if err != nil {
|
||||
if _, ok := err.(*DatasetDoesNotExist); ok {
|
||||
return nil, err // pass through as is
|
||||
@ -1557,7 +1557,7 @@ func tryParseDestroySnapshotsError(arg string, stderr []byte) *DestroySnapshotsE
|
||||
}
|
||||
}
|
||||
|
||||
func ZFSDestroy(arg string) (err error) {
|
||||
func ZFSDestroy(ctx context.Context, arg string) (err error) {
|
||||
|
||||
var dstype, filesystem string
|
||||
idx := strings.IndexAny(arg, "@#")
|
||||
@ -1576,7 +1576,7 @@ func ZFSDestroy(arg string) (err error) {
|
||||
|
||||
defer prometheus.NewTimer(prom.ZFSDestroyDuration.WithLabelValues(dstype, filesystem))
|
||||
|
||||
cmd := exec.Command(ZFS_BINARY, "destroy", arg)
|
||||
cmd := exec.CommandContext(ctx, ZFS_BINARY, "destroy", arg)
|
||||
|
||||
var stderr bytes.Buffer
|
||||
cmd.Stderr = &stderr
|
||||
@ -1607,15 +1607,15 @@ func ZFSDestroy(arg string) (err error) {
|
||||
|
||||
}
|
||||
|
||||
func ZFSDestroyIdempotent(path string) error {
|
||||
err := ZFSDestroy(path)
|
||||
func ZFSDestroyIdempotent(ctx context.Context, path string) error {
|
||||
err := ZFSDestroy(ctx, path)
|
||||
if _, ok := err.(*DatasetDoesNotExist); ok {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func ZFSSnapshot(fs *DatasetPath, name string, recursive bool) (err error) {
|
||||
func ZFSSnapshot(ctx context.Context, fs *DatasetPath, name string, recursive bool) (err error) {
|
||||
|
||||
promTimer := prometheus.NewTimer(prom.ZFSSnapshotDuration.WithLabelValues(fs.ToString()))
|
||||
defer promTimer.ObserveDuration()
|
||||
@ -1624,7 +1624,7 @@ func ZFSSnapshot(fs *DatasetPath, name string, recursive bool) (err error) {
|
||||
if err := EntityNamecheck(snapname, EntityTypeSnapshot); err != nil {
|
||||
return errors.Wrap(err, "zfs snapshot")
|
||||
}
|
||||
cmd := exec.Command(ZFS_BINARY, "snapshot", snapname)
|
||||
cmd := exec.CommandContext(ctx, ZFS_BINARY, "snapshot", snapname)
|
||||
|
||||
stderr := bytes.NewBuffer(make([]byte, 0, 1024))
|
||||
cmd.Stderr = stderr
|
||||
@ -1667,7 +1667,7 @@ var ErrBookmarkCloningNotSupported = fmt.Errorf("bookmark cloning feature is not
|
||||
//
|
||||
// does not destroy an existing bookmark, returns
|
||||
//
|
||||
func ZFSBookmark(fs string, v ZFSSendArgVersion, bookmark string) (err error) {
|
||||
func ZFSBookmark(ctx context.Context, fs string, v ZFSSendArgVersion, bookmark string) (err error) {
|
||||
|
||||
promTimer := prometheus.NewTimer(prom.ZFSBookmarkDuration.WithLabelValues(fs))
|
||||
defer promTimer.ObserveDuration()
|
||||
@ -1687,7 +1687,7 @@ func ZFSBookmark(fs string, v ZFSSendArgVersion, bookmark string) (err error) {
|
||||
|
||||
debug("bookmark: %q %q", snapname, bookmarkname)
|
||||
|
||||
cmd := exec.Command(ZFS_BINARY, "bookmark", snapname, bookmarkname)
|
||||
cmd := exec.CommandContext(ctx, ZFS_BINARY, "bookmark", snapname, bookmarkname)
|
||||
|
||||
stderr := bytes.NewBuffer(make([]byte, 0, 1024))
|
||||
cmd.Stderr = stderr
|
||||
@ -1703,7 +1703,7 @@ func ZFSBookmark(fs string, v ZFSSendArgVersion, bookmark string) (err error) {
|
||||
} else if zfsBookmarkExistsRegex.Match(stderr.Bytes()) {
|
||||
|
||||
// check if this was idempotent
|
||||
bookGuid, err := ZFSGetGUID(fs, "#"+bookmark)
|
||||
bookGuid, err := ZFSGetGUID(ctx, fs, "#"+bookmark)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "bookmark idempotency check") // guid error expressive enough
|
||||
}
|
||||
@ -1731,7 +1731,7 @@ func ZFSBookmark(fs string, v ZFSSendArgVersion, bookmark string) (err error) {
|
||||
|
||||
}
|
||||
|
||||
func ZFSRollback(fs *DatasetPath, snapshot FilesystemVersion, rollbackArgs ...string) (err error) {
|
||||
func ZFSRollback(ctx context.Context, fs *DatasetPath, snapshot FilesystemVersion, rollbackArgs ...string) (err error) {
|
||||
|
||||
snapabs := snapshot.ToAbsPath(fs)
|
||||
if snapshot.Type != Snapshot {
|
||||
@ -1742,7 +1742,7 @@ func ZFSRollback(fs *DatasetPath, snapshot FilesystemVersion, rollbackArgs ...st
|
||||
args = append(args, rollbackArgs...)
|
||||
args = append(args, snapabs)
|
||||
|
||||
cmd := exec.Command(ZFS_BINARY, args...)
|
||||
cmd := exec.CommandContext(ctx, ZFS_BINARY, args...)
|
||||
|
||||
stderr := bytes.NewBuffer(make([]byte, 0, 1024))
|
||||
cmd.Stderr = stderr
|
||||
|
@ -1,6 +1,7 @@
|
||||
package zfs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -11,9 +12,11 @@ func TestZFSListHandlesProducesZFSErrorOnNonZeroExit(t *testing.T) {
|
||||
|
||||
var err error
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
ZFS_BINARY = "./test_helpers/zfs_failer.sh"
|
||||
|
||||
_, err = ZFSList([]string{"fictionalprop"}, "nonexistent/dataset")
|
||||
_, err = ZFSList(ctx, []string{"fictionalprop"}, "nonexistent/dataset")
|
||||
|
||||
assert.Error(t, err)
|
||||
zfsError, ok := err.(*ZFSError)
|
||||
|
Reference in New Issue
Block a user