forked from mistifyio/go-zfs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
snapshot.go
155 lines (135 loc) · 4.61 KB
/
snapshot.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Package zfs provides wrappers around the ZFS command line tools.
package zfs
import (
"context"
"io"
"math"
)
const datasetSnapshot = "snapshot"
// CloneOptions stores options passed to Clone method
type CloneOptions struct {
Properties map[string]string
}
// SendOptions is the set of options available for Send command
type SendOptions struct {
Raw bool
Properties bool
IncrementFrom *Snapshot
}
// Snapshots returns a slice of ZFS snapshots.
// A filter argument may be passed to select a snapshot with the matching name,
// or empty string ("") may be used to select all snapshots.
func Snapshots(ctx context.Context) ([]*Snapshot, error) {
return snapshots(ctx, "", math.MaxUint16)
}
func snapshots(ctx context.Context, filter string, depth uint16) ([]*Snapshot, error) {
infos, err := info(ctx, datasetSnapshot, filter, depth)
if err != nil {
return nil, err
}
snapshots := []*Snapshot{}
for _, info := range infos {
snapshots = append(snapshots, &Snapshot{Info: info})
}
return snapshots, nil
}
// GetSnapshot retrieves a single ZFS snapshot by name
func GetSnapshot(ctx context.Context, name string) (*Snapshot, error) {
info, err := info(ctx, datasetSnapshot, name, 0)
if err != nil {
return nil, err
}
return &Snapshot{Info: info[0]}, nil
}
// ReceiveSnapshot receives a ZFS stream from the input io.Reader, creates a
// new snapshot with the specified name, and streams the input data into the
// newly-created snapshot.
func ReceiveSnapshot(ctx context.Context, input io.ReadCloser, name string) (*Snapshot, error) {
defer input.Close()
if _, err := zfsStdin(ctx, input, "receive", name); err != nil {
return nil, err
}
return GetSnapshot(ctx, name)
}
// Snapshot is a ZFS snapshot
type Snapshot struct {
Info Info
}
// Clone clones a ZFS snapshot and returns the cloned filesystem.
// An error will be returned if the input dataset is not of snapshot type.
func (d *Snapshot) Clone(ctx context.Context, dest string, options CloneOptions) (*Filesystem, error) {
args := []string{"clone"}
if len(options.Properties) > 0 {
args = append(args, propsSlice(options.Properties)...)
}
args = append(args, d.Info.Name, dest)
if _, err := zfs(ctx, args...); err != nil {
return nil, err
}
return GetFilesystem(ctx, dest)
}
// Holds returns holds on snapshot
func (d *Snapshot) Holds(ctx context.Context) ([]string, error) {
holds, err := zfs(ctx, "holds", "-H", d.Info.Name)
if err != nil {
return nil, err
}
out := make([]string, 0, len(holds))
for _, h := range holds {
out = append(out, h[1])
}
return out, nil
}
// Hold holds the snapshot
func (d *Snapshot) Hold(ctx context.Context, tag string) error {
_, err := zfs(ctx, "hold", tag, d.Info.Name)
return err
}
// Release releases the snapshot
func (d *Snapshot) Release(ctx context.Context, tag string) error {
_, err := zfs(ctx, "release", tag, d.Info.Name)
return err
}
// Send sends a ZFS stream of a snapshot to the input io.Writer.
// An error will be returned if the input dataset is not of snapshot type.
func (d *Snapshot) Send(ctx context.Context, options SendOptions, output io.WriteCloser) error {
defer output.Close()
args := []string{"send"}
if options.Raw {
args = append(args, "--raw")
}
if options.Properties {
args = append(args, "--props")
}
if options.IncrementFrom != nil {
args = append(args, "-i", options.IncrementFrom.Info.Name)
}
args = append(args, d.Info.Name)
return zfsStdout(ctx, output, args...)
}
// Destroy destroys a ZFS dataset. If the destroy bit flag is set, any
// descendents of the dataset will be recursively destroyed, including snapshots.
// If the deferred bit flag is set, the snapshot is marked for deferred
// deletion.
func (d *Snapshot) Destroy(ctx context.Context, flags DestroyFlag) error {
return destroy(ctx, d.Info.Name, flags)
}
// SetProperty sets a ZFS property on the receiving dataset.
// A full list of available ZFS properties may be found here:
// https://www.freebsd.org/cgi/man.cgi?zfs(8).
func (d *Snapshot) SetProperty(ctx context.Context, key, val string) error {
return setProperty(ctx, d.Info.Name, key, val)
}
// GetProperty returns the current value of a ZFS property from the
// receiving dataset.
// A full list of available ZFS properties may be found here:
// https://www.freebsd.org/cgi/man.cgi?zfs(8).
func (d *Snapshot) GetProperty(ctx context.Context, key string) (string, bool, error) {
return getProperty(ctx, d.Info.Name, key)
}
// Rollback rolls back the receiving ZFS filesystem to a previous snapshot.
// Intermediate snapshots can be destroyed.
func (d *Snapshot) Rollback(ctx context.Context) error {
_, err := zfs(ctx, "rollback", "-r", d.Info.Name)
return err
}