Add snapshot walk implementations
Temporarily remove zfs and aufs until interface update Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
		
							
								
								
									
										201
									
								
								vendor/github.com/mistifyio/go-zfs/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										201
									
								
								vendor/github.com/mistifyio/go-zfs/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,201 +0,0 @@ | ||||
| Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
|  | ||||
|    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
|  | ||||
|    1. Definitions. | ||||
|  | ||||
|       "License" shall mean the terms and conditions for use, reproduction, | ||||
|       and distribution as defined by Sections 1 through 9 of this document. | ||||
|  | ||||
|       "Licensor" shall mean the copyright owner or entity authorized by | ||||
|       the copyright owner that is granting the License. | ||||
|  | ||||
|       "Legal Entity" shall mean the union of the acting entity and all | ||||
|       other entities that control, are controlled by, or are under common | ||||
|       control with that entity. For the purposes of this definition, | ||||
|       "control" means (i) the power, direct or indirect, to cause the | ||||
|       direction or management of such entity, whether by contract or | ||||
|       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
|       outstanding shares, or (iii) beneficial ownership of such entity. | ||||
|  | ||||
|       "You" (or "Your") shall mean an individual or Legal Entity | ||||
|       exercising permissions granted by this License. | ||||
|  | ||||
|       "Source" form shall mean the preferred form for making modifications, | ||||
|       including but not limited to software source code, documentation | ||||
|       source, and configuration files. | ||||
|  | ||||
|       "Object" form shall mean any form resulting from mechanical | ||||
|       transformation or translation of a Source form, including but | ||||
|       not limited to compiled object code, generated documentation, | ||||
|       and conversions to other media types. | ||||
|  | ||||
|       "Work" shall mean the work of authorship, whether in Source or | ||||
|       Object form, made available under the License, as indicated by a | ||||
|       copyright notice that is included in or attached to the work | ||||
|       (an example is provided in the Appendix below). | ||||
|  | ||||
|       "Derivative Works" shall mean any work, whether in Source or Object | ||||
|       form, that is based on (or derived from) the Work and for which the | ||||
|       editorial revisions, annotations, elaborations, or other modifications | ||||
|       represent, as a whole, an original work of authorship. For the purposes | ||||
|       of this License, Derivative Works shall not include works that remain | ||||
|       separable from, or merely link (or bind by name) to the interfaces of, | ||||
|       the Work and Derivative Works thereof. | ||||
|  | ||||
|       "Contribution" shall mean any work of authorship, including | ||||
|       the original version of the Work and any modifications or additions | ||||
|       to that Work or Derivative Works thereof, that is intentionally | ||||
|       submitted to Licensor for inclusion in the Work by the copyright owner | ||||
|       or by an individual or Legal Entity authorized to submit on behalf of | ||||
|       the copyright owner. For the purposes of this definition, "submitted" | ||||
|       means any form of electronic, verbal, or written communication sent | ||||
|       to the Licensor or its representatives, including but not limited to | ||||
|       communication on electronic mailing lists, source code control systems, | ||||
|       and issue tracking systems that are managed by, or on behalf of, the | ||||
|       Licensor for the purpose of discussing and improving the Work, but | ||||
|       excluding communication that is conspicuously marked or otherwise | ||||
|       designated in writing by the copyright owner as "Not a Contribution." | ||||
|  | ||||
|       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||
|       on behalf of whom a Contribution has been received by Licensor and | ||||
|       subsequently incorporated within the Work. | ||||
|  | ||||
|    2. Grant of Copyright License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       copyright license to reproduce, prepare Derivative Works of, | ||||
|       publicly display, publicly perform, sublicense, and distribute the | ||||
|       Work and such Derivative Works in Source or Object form. | ||||
|  | ||||
|    3. Grant of Patent License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       (except as stated in this section) patent license to make, have made, | ||||
|       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||
|       where such license applies only to those patent claims licensable | ||||
|       by such Contributor that are necessarily infringed by their | ||||
|       Contribution(s) alone or by combination of their Contribution(s) | ||||
|       with the Work to which such Contribution(s) was submitted. If You | ||||
|       institute patent litigation against any entity (including a | ||||
|       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||
|       or a Contribution incorporated within the Work constitutes direct | ||||
|       or contributory patent infringement, then any patent licenses | ||||
|       granted to You under this License for that Work shall terminate | ||||
|       as of the date such litigation is filed. | ||||
|  | ||||
|    4. Redistribution. You may reproduce and distribute copies of the | ||||
|       Work or Derivative Works thereof in any medium, with or without | ||||
|       modifications, and in Source or Object form, provided that You | ||||
|       meet the following conditions: | ||||
|  | ||||
|       (a) You must give any other recipients of the Work or | ||||
|           Derivative Works a copy of this License; and | ||||
|  | ||||
|       (b) You must cause any modified files to carry prominent notices | ||||
|           stating that You changed the files; and | ||||
|  | ||||
|       (c) You must retain, in the Source form of any Derivative Works | ||||
|           that You distribute, all copyright, patent, trademark, and | ||||
|           attribution notices from the Source form of the Work, | ||||
|           excluding those notices that do not pertain to any part of | ||||
|           the Derivative Works; and | ||||
|  | ||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ||||
|           distribution, then any Derivative Works that You distribute must | ||||
|           include a readable copy of the attribution notices contained | ||||
|           within such NOTICE file, excluding those notices that do not | ||||
|           pertain to any part of the Derivative Works, in at least one | ||||
|           of the following places: within a NOTICE text file distributed | ||||
|           as part of the Derivative Works; within the Source form or | ||||
|           documentation, if provided along with the Derivative Works; or, | ||||
|           within a display generated by the Derivative Works, if and | ||||
|           wherever such third-party notices normally appear. The contents | ||||
|           of the NOTICE file are for informational purposes only and | ||||
|           do not modify the License. You may add Your own attribution | ||||
|           notices within Derivative Works that You distribute, alongside | ||||
|           or as an addendum to the NOTICE text from the Work, provided | ||||
|           that such additional attribution notices cannot be construed | ||||
|           as modifying the License. | ||||
|  | ||||
|       You may add Your own copyright statement to Your modifications and | ||||
|       may provide additional or different license terms and conditions | ||||
|       for use, reproduction, or distribution of Your modifications, or | ||||
|       for any such Derivative Works as a whole, provided Your use, | ||||
|       reproduction, and distribution of the Work otherwise complies with | ||||
|       the conditions stated in this License. | ||||
|  | ||||
|    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||
|       any Contribution intentionally submitted for inclusion in the Work | ||||
|       by You to the Licensor shall be under the terms and conditions of | ||||
|       this License, without any additional terms or conditions. | ||||
|       Notwithstanding the above, nothing herein shall supersede or modify | ||||
|       the terms of any separate license agreement you may have executed | ||||
|       with Licensor regarding such Contributions. | ||||
|  | ||||
|    6. Trademarks. This License does not grant permission to use the trade | ||||
|       names, trademarks, service marks, or product names of the Licensor, | ||||
|       except as required for reasonable and customary use in describing the | ||||
|       origin of the Work and reproducing the content of the NOTICE file. | ||||
|  | ||||
|    7. Disclaimer of Warranty. Unless required by applicable law or | ||||
|       agreed to in writing, Licensor provides the Work (and each | ||||
|       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
|       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
|       implied, including, without limitation, any warranties or conditions | ||||
|       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||
|       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||
|       appropriateness of using or redistributing the Work and assume any | ||||
|       risks associated with Your exercise of permissions under this License. | ||||
|  | ||||
|    8. Limitation of Liability. In no event and under no legal theory, | ||||
|       whether in tort (including negligence), contract, or otherwise, | ||||
|       unless required by applicable law (such as deliberate and grossly | ||||
|       negligent acts) or agreed to in writing, shall any Contributor be | ||||
|       liable to You for damages, including any direct, indirect, special, | ||||
|       incidental, or consequential damages of any character arising as a | ||||
|       result of this License or out of the use or inability to use the | ||||
|       Work (including but not limited to damages for loss of goodwill, | ||||
|       work stoppage, computer failure or malfunction, or any and all | ||||
|       other commercial damages or losses), even if such Contributor | ||||
|       has been advised of the possibility of such damages. | ||||
|  | ||||
|    9. Accepting Warranty or Additional Liability. While redistributing | ||||
|       the Work or Derivative Works thereof, You may choose to offer, | ||||
|       and charge a fee for, acceptance of support, warranty, indemnity, | ||||
|       or other liability obligations and/or rights consistent with this | ||||
|       License. However, in accepting such obligations, You may act only | ||||
|       on Your own behalf and on Your sole responsibility, not on behalf | ||||
|       of any other Contributor, and only if You agree to indemnify, | ||||
|       defend, and hold each Contributor harmless for any liability | ||||
|       incurred by, or claims asserted against, such Contributor by reason | ||||
|       of your accepting any such warranty or additional liability. | ||||
|  | ||||
|    END OF TERMS AND CONDITIONS | ||||
|  | ||||
|    APPENDIX: How to apply the Apache License to your work. | ||||
|  | ||||
|       To apply the Apache License to your work, attach the following | ||||
|       boilerplate notice, with the fields enclosed by brackets "{}" | ||||
|       replaced with your own identifying information. (Don't include | ||||
|       the brackets!)  The text should be enclosed in the appropriate | ||||
|       comment syntax for the file format. We also recommend that a | ||||
|       file or class name and description of purpose be included on the | ||||
|       same "printed page" as the copyright notice for easier | ||||
|       identification within third-party archives. | ||||
|  | ||||
|    Copyright (c) 2014, OmniTI Computer Consulting, Inc. | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
							
								
								
									
										54
									
								
								vendor/github.com/mistifyio/go-zfs/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/mistifyio/go-zfs/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,54 +0,0 @@ | ||||
| # Go Wrapper for ZFS # | ||||
|  | ||||
| Simple wrappers for ZFS command line tools. | ||||
|  | ||||
| [](https://godoc.org/github.com/mistifyio/go-zfs) | ||||
|  | ||||
| ## Requirements ## | ||||
|  | ||||
| You need a working ZFS setup.  To use on Ubuntu 14.04, setup ZFS: | ||||
|  | ||||
|     sudo apt-get install python-software-properties | ||||
|     sudo apt-add-repository ppa:zfs-native/stable | ||||
|     sudo apt-get update | ||||
|     sudo apt-get install ubuntu-zfs libzfs-dev | ||||
|  | ||||
| Developed using Go 1.3, but currently there isn't anything 1.3 specific. Don't use Ubuntu packages for Go, use http://golang.org/doc/install | ||||
|  | ||||
| Generally you need root privileges to use anything zfs related. | ||||
|  | ||||
| ## Status ## | ||||
|  | ||||
| This has been only been tested on Ubuntu 14.04 | ||||
|  | ||||
| In the future, we hope to work directly with libzfs. | ||||
|  | ||||
| # Hacking # | ||||
|  | ||||
| The tests have decent examples for most functions. | ||||
|  | ||||
| ```go | ||||
| //assuming a zpool named test | ||||
| //error handling omitted | ||||
|  | ||||
|  | ||||
| f, err := zfs.CreateFilesystem("test/snapshot-test", nil) | ||||
| ok(t, err) | ||||
|  | ||||
| s, err := f.Snapshot("test", nil) | ||||
| ok(t, err) | ||||
|  | ||||
| // snapshot is named "test/snapshot-test@test" | ||||
|  | ||||
| c, err := s.Clone("test/clone-test", nil) | ||||
|  | ||||
| err := c.Destroy() | ||||
| err := s.Destroy() | ||||
| err := f.Destroy() | ||||
|  | ||||
| ``` | ||||
|  | ||||
| # Contributing # | ||||
|  | ||||
| See the [contributing guidelines](./CONTRIBUTING.md) | ||||
|  | ||||
							
								
								
									
										18
									
								
								vendor/github.com/mistifyio/go-zfs/error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/mistifyio/go-zfs/error.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,18 +0,0 @@ | ||||
| package zfs | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| ) | ||||
|  | ||||
| // Error is an error which is returned when the `zfs` or `zpool` shell | ||||
| // commands return with a non-zero exit code. | ||||
| type Error struct { | ||||
| 	Err    error | ||||
| 	Debug  string | ||||
| 	Stderr string | ||||
| } | ||||
|  | ||||
| // Error returns the string representation of an Error. | ||||
| func (e Error) Error() string { | ||||
| 	return fmt.Sprintf("%s: %q => %s", e.Err, e.Debug, e.Stderr) | ||||
| } | ||||
							
								
								
									
										360
									
								
								vendor/github.com/mistifyio/go-zfs/utils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										360
									
								
								vendor/github.com/mistifyio/go-zfs/utils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,360 +0,0 @@ | ||||
| package zfs | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"os/exec" | ||||
| 	"regexp" | ||||
| 	"runtime" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/google/uuid" | ||||
| ) | ||||
|  | ||||
| type command struct { | ||||
| 	Command string | ||||
| 	Stdin   io.Reader | ||||
| 	Stdout  io.Writer | ||||
| } | ||||
|  | ||||
| func (c *command) Run(arg ...string) ([][]string, error) { | ||||
|  | ||||
| 	cmd := exec.Command(c.Command, arg...) | ||||
|  | ||||
| 	var stdout, stderr bytes.Buffer | ||||
|  | ||||
| 	if c.Stdout == nil { | ||||
| 		cmd.Stdout = &stdout | ||||
| 	} else { | ||||
| 		cmd.Stdout = c.Stdout | ||||
| 	} | ||||
|  | ||||
| 	if c.Stdin != nil { | ||||
| 		cmd.Stdin = c.Stdin | ||||
|  | ||||
| 	} | ||||
| 	cmd.Stderr = &stderr | ||||
|  | ||||
| 	id := uuid.New().String() | ||||
| 	joinedArgs := strings.Join(cmd.Args, " ") | ||||
|  | ||||
| 	logger.Log([]string{"ID:" + id, "START", joinedArgs}) | ||||
| 	err := cmd.Run() | ||||
| 	logger.Log([]string{"ID:" + id, "FINISH"}) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return nil, &Error{ | ||||
| 			Err:    err, | ||||
| 			Debug:  strings.Join([]string{cmd.Path, joinedArgs[1:]}, " "), | ||||
| 			Stderr: stderr.String(), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// assume if you passed in something for stdout, that you know what to do with it | ||||
| 	if c.Stdout != nil { | ||||
| 		return nil, nil | ||||
| 	} | ||||
|  | ||||
| 	lines := strings.Split(stdout.String(), "\n") | ||||
|  | ||||
| 	//last line is always blank | ||||
| 	lines = lines[0 : len(lines)-1] | ||||
| 	output := make([][]string, len(lines)) | ||||
|  | ||||
| 	for i, l := range lines { | ||||
| 		output[i] = strings.Fields(l) | ||||
| 	} | ||||
|  | ||||
| 	return output, nil | ||||
| } | ||||
|  | ||||
| func setString(field *string, value string) { | ||||
| 	v := "" | ||||
| 	if value != "-" { | ||||
| 		v = value | ||||
| 	} | ||||
| 	*field = v | ||||
| } | ||||
|  | ||||
| func setUint(field *uint64, value string) error { | ||||
| 	var v uint64 | ||||
| 	if value != "-" { | ||||
| 		var err error | ||||
| 		v, err = strconv.ParseUint(value, 10, 64) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
| 	*field = v | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (ds *Dataset) parseLine(line []string) error { | ||||
| 	var err error | ||||
|  | ||||
| 	if len(line) != len(dsPropList) { | ||||
| 		return errors.New("Output does not match what is expected on this platform") | ||||
| 	} | ||||
| 	setString(&ds.Name, line[0]) | ||||
| 	setString(&ds.Origin, line[1]) | ||||
|  | ||||
| 	if err = setUint(&ds.Used, line[2]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err = setUint(&ds.Avail, line[3]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	setString(&ds.Mountpoint, line[4]) | ||||
| 	setString(&ds.Compression, line[5]) | ||||
| 	setString(&ds.Type, line[6]) | ||||
|  | ||||
| 	if err = setUint(&ds.Volsize, line[7]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err = setUint(&ds.Quota, line[8]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err = setUint(&ds.Referenced, line[9]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if runtime.GOOS == "solaris" { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	if err = setUint(&ds.Written, line[10]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err = setUint(&ds.Logicalused, line[11]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if err = setUint(&ds.Usedbydataset, line[12]); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * from zfs diff`s escape function: | ||||
|  * | ||||
|  * Prints a file name out a character at a time.  If the character is | ||||
|  * not in the range of what we consider "printable" ASCII, display it | ||||
|  * as an escaped 3-digit octal value.  ASCII values less than a space | ||||
|  * are all control characters and we declare the upper end as the | ||||
|  * DELete character.  This also is the last 7-bit ASCII character. | ||||
|  * We choose to treat all 8-bit ASCII as not printable for this | ||||
|  * application. | ||||
|  */ | ||||
| func unescapeFilepath(path string) (string, error) { | ||||
| 	buf := make([]byte, 0, len(path)) | ||||
| 	llen := len(path) | ||||
| 	for i := 0; i < llen; { | ||||
| 		if path[i] == '\\' { | ||||
| 			if llen < i+4 { | ||||
| 				return "", fmt.Errorf("Invalid octal code: too short") | ||||
| 			} | ||||
| 			octalCode := path[(i + 1):(i + 4)] | ||||
| 			val, err := strconv.ParseUint(octalCode, 8, 8) | ||||
| 			if err != nil { | ||||
| 				return "", fmt.Errorf("Invalid octal code: %v", err) | ||||
| 			} | ||||
| 			buf = append(buf, byte(val)) | ||||
| 			i += 4 | ||||
| 		} else { | ||||
| 			buf = append(buf, path[i]) | ||||
| 			i++ | ||||
| 		} | ||||
| 	} | ||||
| 	return string(buf), nil | ||||
| } | ||||
|  | ||||
| var changeTypeMap = map[string]ChangeType{ | ||||
| 	"-": Removed, | ||||
| 	"+": Created, | ||||
| 	"M": Modified, | ||||
| 	"R": Renamed, | ||||
| } | ||||
| var inodeTypeMap = map[string]InodeType{ | ||||
| 	"B": BlockDevice, | ||||
| 	"C": CharacterDevice, | ||||
| 	"/": Directory, | ||||
| 	">": Door, | ||||
| 	"|": NamedPipe, | ||||
| 	"@": SymbolicLink, | ||||
| 	"P": EventPort, | ||||
| 	"=": Socket, | ||||
| 	"F": File, | ||||
| } | ||||
|  | ||||
| // matches (+1) or (-1) | ||||
| var referenceCountRegex = regexp.MustCompile("\\(([+-]\\d+?)\\)") | ||||
|  | ||||
| func parseReferenceCount(field string) (int, error) { | ||||
| 	matches := referenceCountRegex.FindStringSubmatch(field) | ||||
| 	if matches == nil { | ||||
| 		return 0, fmt.Errorf("Regexp does not match") | ||||
| 	} | ||||
| 	return strconv.Atoi(matches[1]) | ||||
| } | ||||
|  | ||||
| func parseInodeChange(line []string) (*InodeChange, error) { | ||||
| 	llen := len(line) | ||||
| 	if llen < 1 { | ||||
| 		return nil, fmt.Errorf("Empty line passed") | ||||
| 	} | ||||
|  | ||||
| 	changeType := changeTypeMap[line[0]] | ||||
| 	if changeType == 0 { | ||||
| 		return nil, fmt.Errorf("Unknown change type '%s'", line[0]) | ||||
| 	} | ||||
|  | ||||
| 	switch changeType { | ||||
| 	case Renamed: | ||||
| 		if llen != 4 { | ||||
| 			return nil, fmt.Errorf("Mismatching number of fields: expect 4, got: %d", llen) | ||||
| 		} | ||||
| 	case Modified: | ||||
| 		if llen != 4 && llen != 3 { | ||||
| 			return nil, fmt.Errorf("Mismatching number of fields: expect 3..4, got: %d", llen) | ||||
| 		} | ||||
| 	default: | ||||
| 		if llen != 3 { | ||||
| 			return nil, fmt.Errorf("Mismatching number of fields: expect 3, got: %d", llen) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	inodeType := inodeTypeMap[line[1]] | ||||
| 	if inodeType == 0 { | ||||
| 		return nil, fmt.Errorf("Unknown inode type '%s'", line[1]) | ||||
| 	} | ||||
|  | ||||
| 	path, err := unescapeFilepath(line[2]) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("Failed to parse filename: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	var newPath string | ||||
| 	var referenceCount int | ||||
| 	switch changeType { | ||||
| 	case Renamed: | ||||
| 		newPath, err = unescapeFilepath(line[3]) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("Failed to parse filename: %v", err) | ||||
| 		} | ||||
| 	case Modified: | ||||
| 		if llen == 4 { | ||||
| 			referenceCount, err = parseReferenceCount(line[3]) | ||||
| 			if err != nil { | ||||
| 				return nil, fmt.Errorf("Failed to parse reference count: %v", err) | ||||
| 			} | ||||
| 		} | ||||
| 	default: | ||||
| 		newPath = "" | ||||
| 	} | ||||
|  | ||||
| 	return &InodeChange{ | ||||
| 		Change:               changeType, | ||||
| 		Type:                 inodeType, | ||||
| 		Path:                 path, | ||||
| 		NewPath:              newPath, | ||||
| 		ReferenceCountChange: referenceCount, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // example input | ||||
| //M       /       /testpool/bar/ | ||||
| //+       F       /testpool/bar/hello.txt | ||||
| //M       /       /testpool/bar/hello.txt (+1) | ||||
| //M       /       /testpool/bar/hello-hardlink | ||||
| func parseInodeChanges(lines [][]string) ([]*InodeChange, error) { | ||||
| 	changes := make([]*InodeChange, len(lines)) | ||||
|  | ||||
| 	for i, line := range lines { | ||||
| 		c, err := parseInodeChange(line) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("Failed to parse line %d of zfs diff: %v, got: '%s'", i, err, line) | ||||
| 		} | ||||
| 		changes[i] = c | ||||
| 	} | ||||
| 	return changes, nil | ||||
| } | ||||
|  | ||||
| func listByType(t, filter string) ([]*Dataset, error) { | ||||
| 	args := []string{"list", "-rHp", "-t", t, "-o", dsPropListOptions} | ||||
|  | ||||
| 	if filter != "" { | ||||
| 		args = append(args, filter) | ||||
| 	} | ||||
| 	out, err := zfs(args...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var datasets []*Dataset | ||||
|  | ||||
| 	name := "" | ||||
| 	var ds *Dataset | ||||
| 	for _, line := range out { | ||||
| 		if name != line[0] { | ||||
| 			name = line[0] | ||||
| 			ds = &Dataset{Name: name} | ||||
| 			datasets = append(datasets, ds) | ||||
| 		} | ||||
| 		if err := ds.parseLine(line); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return datasets, nil | ||||
| } | ||||
|  | ||||
| func propsSlice(properties map[string]string) []string { | ||||
| 	args := make([]string, 0, len(properties)*3) | ||||
| 	for k, v := range properties { | ||||
| 		args = append(args, "-o") | ||||
| 		args = append(args, fmt.Sprintf("%s=%s", k, v)) | ||||
| 	} | ||||
| 	return args | ||||
| } | ||||
|  | ||||
| func (z *Zpool) parseLine(line []string) error { | ||||
| 	prop := line[1] | ||||
| 	val := line[2] | ||||
|  | ||||
| 	var err error | ||||
|  | ||||
| 	switch prop { | ||||
| 	case "name": | ||||
| 		setString(&z.Name, val) | ||||
| 	case "health": | ||||
| 		setString(&z.Health, val) | ||||
| 	case "allocated": | ||||
| 		err = setUint(&z.Allocated, val) | ||||
| 	case "size": | ||||
| 		err = setUint(&z.Size, val) | ||||
| 	case "free": | ||||
| 		err = setUint(&z.Free, val) | ||||
| 	case "fragmentation": | ||||
| 		// Trim trailing "%" before parsing uint | ||||
| 		i := strings.Index(val, "%") | ||||
| 		if i < 0 { | ||||
| 			i = len(val) | ||||
| 		} | ||||
| 		err = setUint(&z.Fragmentation, val[:i]) | ||||
| 	case "readonly": | ||||
| 		z.ReadOnly = val == "on" | ||||
| 	case "freeing": | ||||
| 		err = setUint(&z.Freeing, val) | ||||
| 	case "leaked": | ||||
| 		err = setUint(&z.Leaked, val) | ||||
| 	case "dedupratio": | ||||
| 		// Trim trailing "x" before parsing float64 | ||||
| 		z.DedupRatio, err = strconv.ParseFloat(val[:len(val)-1], 64) | ||||
| 	} | ||||
| 	return err | ||||
| } | ||||
							
								
								
									
										17
									
								
								vendor/github.com/mistifyio/go-zfs/utils_notsolaris.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/mistifyio/go-zfs/utils_notsolaris.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,17 +0,0 @@ | ||||
| // +build !solaris | ||||
|  | ||||
| package zfs | ||||
|  | ||||
| import ( | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // List of ZFS properties to retrieve from zfs list command on a non-Solaris platform | ||||
| var dsPropList = []string{"name", "origin", "used", "available", "mountpoint", "compression", "type", "volsize", "quota", "referenced", "written", "logicalused", "usedbydataset"} | ||||
|  | ||||
| var dsPropListOptions = strings.Join(dsPropList, ",") | ||||
|  | ||||
| // List of Zpool properties to retrieve from zpool list command on a non-Solaris platform | ||||
| var zpoolPropList = []string{"name", "health", "allocated", "size", "free", "readonly", "dedupratio", "fragmentation", "freeing", "leaked"} | ||||
| var zpoolPropListOptions = strings.Join(zpoolPropList, ",") | ||||
| var zpoolArgs = []string{"get", "-p", zpoolPropListOptions} | ||||
							
								
								
									
										17
									
								
								vendor/github.com/mistifyio/go-zfs/utils_solaris.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/mistifyio/go-zfs/utils_solaris.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,17 +0,0 @@ | ||||
| // +build solaris | ||||
|  | ||||
| package zfs | ||||
|  | ||||
| import ( | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // List of ZFS properties to retrieve from zfs list command on a Solaris platform | ||||
| var dsPropList = []string{"name", "origin", "used", "available", "mountpoint", "compression", "type", "volsize", "quota", "referenced"} | ||||
|  | ||||
| var dsPropListOptions = strings.Join(dsPropList, ",") | ||||
|  | ||||
| // List of Zpool properties to retrieve from zpool list command on a non-Solaris platform | ||||
| var zpoolPropList = []string{"name", "health", "allocated", "size", "free", "readonly", "dedupratio"} | ||||
| var zpoolPropListOptions = strings.Join(zpoolPropList, ",") | ||||
| var zpoolArgs = []string{"get", "-p", zpoolPropListOptions} | ||||
							
								
								
									
										452
									
								
								vendor/github.com/mistifyio/go-zfs/zfs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										452
									
								
								vendor/github.com/mistifyio/go-zfs/zfs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,452 +0,0 @@ | ||||
| // Package zfs provides wrappers around the ZFS command line tools. | ||||
| package zfs | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // ZFS dataset types, which can indicate if a dataset is a filesystem, | ||||
| // snapshot, or volume. | ||||
| const ( | ||||
| 	DatasetFilesystem = "filesystem" | ||||
| 	DatasetSnapshot   = "snapshot" | ||||
| 	DatasetVolume     = "volume" | ||||
| ) | ||||
|  | ||||
| // Dataset is a ZFS dataset.  A dataset could be a clone, filesystem, snapshot, | ||||
| // or volume.  The Type struct member can be used to determine a dataset's type. | ||||
| // | ||||
| // The field definitions can be found in the ZFS manual: | ||||
| // http://www.freebsd.org/cgi/man.cgi?zfs(8). | ||||
| type Dataset struct { | ||||
| 	Name          string | ||||
| 	Origin        string | ||||
| 	Used          uint64 | ||||
| 	Avail         uint64 | ||||
| 	Mountpoint    string | ||||
| 	Compression   string | ||||
| 	Type          string | ||||
| 	Written       uint64 | ||||
| 	Volsize       uint64 | ||||
| 	Logicalused   uint64 | ||||
| 	Usedbydataset uint64 | ||||
| 	Quota         uint64 | ||||
| 	Referenced    uint64 | ||||
| } | ||||
|  | ||||
| // InodeType is the type of inode as reported by Diff | ||||
| type InodeType int | ||||
|  | ||||
| // Types of Inodes | ||||
| const ( | ||||
| 	_                     = iota // 0 == unknown type | ||||
| 	BlockDevice InodeType = iota | ||||
| 	CharacterDevice | ||||
| 	Directory | ||||
| 	Door | ||||
| 	NamedPipe | ||||
| 	SymbolicLink | ||||
| 	EventPort | ||||
| 	Socket | ||||
| 	File | ||||
| ) | ||||
|  | ||||
| // ChangeType is the type of inode change as reported by Diff | ||||
| type ChangeType int | ||||
|  | ||||
| // Types of Changes | ||||
| const ( | ||||
| 	_                  = iota // 0 == unknown type | ||||
| 	Removed ChangeType = iota | ||||
| 	Created | ||||
| 	Modified | ||||
| 	Renamed | ||||
| ) | ||||
|  | ||||
| // DestroyFlag is the options flag passed to Destroy | ||||
| type DestroyFlag int | ||||
|  | ||||
| // Valid destroy options | ||||
| const ( | ||||
| 	DestroyDefault         DestroyFlag = 1 << iota | ||||
| 	DestroyRecursive                   = 1 << iota | ||||
| 	DestroyRecursiveClones             = 1 << iota | ||||
| 	DestroyDeferDeletion               = 1 << iota | ||||
| 	DestroyForceUmount                 = 1 << iota | ||||
| ) | ||||
|  | ||||
| // InodeChange represents a change as reported by Diff | ||||
| type InodeChange struct { | ||||
| 	Change               ChangeType | ||||
| 	Type                 InodeType | ||||
| 	Path                 string | ||||
| 	NewPath              string | ||||
| 	ReferenceCountChange int | ||||
| } | ||||
|  | ||||
| // Logger can be used to log commands/actions | ||||
| type Logger interface { | ||||
| 	Log(cmd []string) | ||||
| } | ||||
|  | ||||
| type defaultLogger struct{} | ||||
|  | ||||
| func (*defaultLogger) Log(cmd []string) { | ||||
| 	return | ||||
| } | ||||
|  | ||||
| var logger Logger = &defaultLogger{} | ||||
|  | ||||
| // SetLogger set a log handler to log all commands including arguments before | ||||
| // they are executed | ||||
| func SetLogger(l Logger) { | ||||
| 	if l != nil { | ||||
| 		logger = l | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // zfs is a helper function to wrap typical calls to zfs. | ||||
| func zfs(arg ...string) ([][]string, error) { | ||||
| 	c := command{Command: "zfs"} | ||||
| 	return c.Run(arg...) | ||||
| } | ||||
|  | ||||
| // Datasets returns a slice of ZFS datasets, regardless of type. | ||||
| // A filter argument may be passed to select a dataset with the matching name, | ||||
| // or empty string ("") may be used to select all datasets. | ||||
| func Datasets(filter string) ([]*Dataset, error) { | ||||
| 	return listByType("all", filter) | ||||
| } | ||||
|  | ||||
| // 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(filter string) ([]*Dataset, error) { | ||||
| 	return listByType(DatasetSnapshot, filter) | ||||
| } | ||||
|  | ||||
| // Filesystems returns a slice of ZFS filesystems. | ||||
| // A filter argument may be passed to select a filesystem with the matching name, | ||||
| // or empty string ("") may be used to select all filesystems. | ||||
| func Filesystems(filter string) ([]*Dataset, error) { | ||||
| 	return listByType(DatasetFilesystem, filter) | ||||
| } | ||||
|  | ||||
| // Volumes returns a slice of ZFS volumes. | ||||
| // A filter argument may be passed to select a volume with the matching name, | ||||
| // or empty string ("") may be used to select all volumes. | ||||
| func Volumes(filter string) ([]*Dataset, error) { | ||||
| 	return listByType(DatasetVolume, filter) | ||||
| } | ||||
|  | ||||
| // GetDataset retrieves a single ZFS dataset by name.  This dataset could be | ||||
| // any valid ZFS dataset type, such as a clone, filesystem, snapshot, or volume. | ||||
| func GetDataset(name string) (*Dataset, error) { | ||||
| 	out, err := zfs("list", "-Hp", "-o", dsPropListOptions, name) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	ds := &Dataset{Name: name} | ||||
| 	for _, line := range out { | ||||
| 		if err := ds.parseLine(line); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return ds, nil | ||||
| } | ||||
|  | ||||
| // Clone clones a ZFS snapshot and returns a clone dataset. | ||||
| // An error will be returned if the input dataset is not of snapshot type. | ||||
| func (d *Dataset) Clone(dest string, properties map[string]string) (*Dataset, error) { | ||||
| 	if d.Type != DatasetSnapshot { | ||||
| 		return nil, errors.New("can only clone snapshots") | ||||
| 	} | ||||
| 	args := make([]string, 2, 4) | ||||
| 	args[0] = "clone" | ||||
| 	args[1] = "-p" | ||||
| 	if properties != nil { | ||||
| 		args = append(args, propsSlice(properties)...) | ||||
| 	} | ||||
| 	args = append(args, []string{d.Name, dest}...) | ||||
| 	_, err := zfs(args...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return GetDataset(dest) | ||||
| } | ||||
|  | ||||
| // Unmount unmounts currently mounted ZFS file systems. | ||||
| func (d *Dataset) Unmount(force bool) (*Dataset, error) { | ||||
| 	if d.Type == DatasetSnapshot { | ||||
| 		return nil, errors.New("cannot unmount snapshots") | ||||
| 	} | ||||
| 	args := make([]string, 1, 3) | ||||
| 	args[0] = "umount" | ||||
| 	if force { | ||||
| 		args = append(args, "-f") | ||||
| 	} | ||||
| 	args = append(args, d.Name) | ||||
| 	_, err := zfs(args...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return GetDataset(d.Name) | ||||
| } | ||||
|  | ||||
| // Mount mounts ZFS file systems. | ||||
| func (d *Dataset) Mount(overlay bool, options []string) (*Dataset, error) { | ||||
| 	if d.Type == DatasetSnapshot { | ||||
| 		return nil, errors.New("cannot mount snapshots") | ||||
| 	} | ||||
| 	args := make([]string, 1, 5) | ||||
| 	args[0] = "mount" | ||||
| 	if overlay { | ||||
| 		args = append(args, "-O") | ||||
| 	} | ||||
| 	if options != nil { | ||||
| 		args = append(args, "-o") | ||||
| 		args = append(args, strings.Join(options, ",")) | ||||
| 	} | ||||
| 	args = append(args, d.Name) | ||||
| 	_, err := zfs(args...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return GetDataset(d.Name) | ||||
| } | ||||
|  | ||||
| // 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(input io.Reader, name string) (*Dataset, error) { | ||||
| 	c := command{Command: "zfs", Stdin: input} | ||||
| 	_, err := c.Run("receive", name) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return GetDataset(name) | ||||
| } | ||||
|  | ||||
| // SendSnapshot 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 *Dataset) SendSnapshot(output io.Writer) error { | ||||
| 	if d.Type != DatasetSnapshot { | ||||
| 		return errors.New("can only send snapshots") | ||||
| 	} | ||||
|  | ||||
| 	c := command{Command: "zfs", Stdout: output} | ||||
| 	_, err := c.Run("send", d.Name) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // CreateVolume creates a new ZFS volume with the specified name, size, and | ||||
| // properties. | ||||
| // A full list of available ZFS properties may be found here: | ||||
| // https://www.freebsd.org/cgi/man.cgi?zfs(8). | ||||
| func CreateVolume(name string, size uint64, properties map[string]string) (*Dataset, error) { | ||||
| 	args := make([]string, 4, 5) | ||||
| 	args[0] = "create" | ||||
| 	args[1] = "-p" | ||||
| 	args[2] = "-V" | ||||
| 	args[3] = strconv.FormatUint(size, 10) | ||||
| 	if properties != nil { | ||||
| 		args = append(args, propsSlice(properties)...) | ||||
| 	} | ||||
| 	args = append(args, name) | ||||
| 	_, err := zfs(args...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return GetDataset(name) | ||||
| } | ||||
|  | ||||
| // 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 *Dataset) Destroy(flags DestroyFlag) error { | ||||
| 	args := make([]string, 1, 3) | ||||
| 	args[0] = "destroy" | ||||
| 	if flags&DestroyRecursive != 0 { | ||||
| 		args = append(args, "-r") | ||||
| 	} | ||||
|  | ||||
| 	if flags&DestroyRecursiveClones != 0 { | ||||
| 		args = append(args, "-R") | ||||
| 	} | ||||
|  | ||||
| 	if flags&DestroyDeferDeletion != 0 { | ||||
| 		args = append(args, "-d") | ||||
| 	} | ||||
|  | ||||
| 	if flags&DestroyForceUmount != 0 { | ||||
| 		args = append(args, "-f") | ||||
| 	} | ||||
|  | ||||
| 	args = append(args, d.Name) | ||||
| 	_, err := zfs(args...) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // 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 *Dataset) SetProperty(key, val string) error { | ||||
| 	prop := strings.Join([]string{key, val}, "=") | ||||
| 	_, err := zfs("set", prop, d.Name) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // 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 *Dataset) GetProperty(key string) (string, error) { | ||||
| 	out, err := zfs("get", "-H", key, d.Name) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	return out[0][2], nil | ||||
| } | ||||
|  | ||||
| // Rename renames a dataset. | ||||
| func (d *Dataset) Rename(name string, createParent bool, recursiveRenameSnapshots bool) (*Dataset, error) { | ||||
| 	args := make([]string, 3, 5) | ||||
| 	args[0] = "rename" | ||||
| 	args[1] = d.Name | ||||
| 	args[2] = name | ||||
| 	if createParent { | ||||
| 		args = append(args, "-p") | ||||
| 	} | ||||
| 	if recursiveRenameSnapshots { | ||||
| 		args = append(args, "-r") | ||||
| 	} | ||||
| 	_, err := zfs(args...) | ||||
| 	if err != nil { | ||||
| 		return d, err | ||||
| 	} | ||||
|  | ||||
| 	return GetDataset(name) | ||||
| } | ||||
|  | ||||
| // Snapshots returns a slice of all ZFS snapshots of a given dataset. | ||||
| func (d *Dataset) Snapshots() ([]*Dataset, error) { | ||||
| 	return Snapshots(d.Name) | ||||
| } | ||||
|  | ||||
| // CreateFilesystem creates a new ZFS filesystem with the specified name and | ||||
| // properties. | ||||
| // A full list of available ZFS properties may be found here: | ||||
| // https://www.freebsd.org/cgi/man.cgi?zfs(8). | ||||
| func CreateFilesystem(name string, properties map[string]string) (*Dataset, error) { | ||||
| 	args := make([]string, 1, 4) | ||||
| 	args[0] = "create" | ||||
|  | ||||
| 	if properties != nil { | ||||
| 		args = append(args, propsSlice(properties)...) | ||||
| 	} | ||||
|  | ||||
| 	args = append(args, name) | ||||
| 	_, err := zfs(args...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return GetDataset(name) | ||||
| } | ||||
|  | ||||
| // Snapshot creates a new ZFS snapshot of the receiving dataset, using the | ||||
| // specified name.  Optionally, the snapshot can be taken recursively, creating | ||||
| // snapshots of all descendent filesystems in a single, atomic operation. | ||||
| func (d *Dataset) Snapshot(name string, recursive bool) (*Dataset, error) { | ||||
| 	args := make([]string, 1, 4) | ||||
| 	args[0] = "snapshot" | ||||
| 	if recursive { | ||||
| 		args = append(args, "-r") | ||||
| 	} | ||||
| 	snapName := fmt.Sprintf("%s@%s", d.Name, name) | ||||
| 	args = append(args, snapName) | ||||
| 	_, err := zfs(args...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return GetDataset(snapName) | ||||
| } | ||||
|  | ||||
| // Rollback rolls back the receiving ZFS dataset to a previous snapshot. | ||||
| // Optionally, intermediate snapshots can be destroyed.  A ZFS snapshot | ||||
| // rollback cannot be completed without this option, if more recent | ||||
| // snapshots exist. | ||||
| // An error will be returned if the input dataset is not of snapshot type. | ||||
| func (d *Dataset) Rollback(destroyMoreRecent bool) error { | ||||
| 	if d.Type != DatasetSnapshot { | ||||
| 		return errors.New("can only rollback snapshots") | ||||
| 	} | ||||
|  | ||||
| 	args := make([]string, 1, 3) | ||||
| 	args[0] = "rollback" | ||||
| 	if destroyMoreRecent { | ||||
| 		args = append(args, "-r") | ||||
| 	} | ||||
| 	args = append(args, d.Name) | ||||
|  | ||||
| 	_, err := zfs(args...) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // Children returns a slice of children of the receiving ZFS dataset. | ||||
| // A recursion depth may be specified, or a depth of 0 allows unlimited | ||||
| // recursion. | ||||
| func (d *Dataset) Children(depth uint64) ([]*Dataset, error) { | ||||
| 	args := []string{"list"} | ||||
| 	if depth > 0 { | ||||
| 		args = append(args, "-d") | ||||
| 		args = append(args, strconv.FormatUint(depth, 10)) | ||||
| 	} else { | ||||
| 		args = append(args, "-r") | ||||
| 	} | ||||
| 	args = append(args, "-t", "all", "-Hp", "-o", dsPropListOptions) | ||||
| 	args = append(args, d.Name) | ||||
|  | ||||
| 	out, err := zfs(args...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var datasets []*Dataset | ||||
| 	name := "" | ||||
| 	var ds *Dataset | ||||
| 	for _, line := range out { | ||||
| 		if name != line[0] { | ||||
| 			name = line[0] | ||||
| 			ds = &Dataset{Name: name} | ||||
| 			datasets = append(datasets, ds) | ||||
| 		} | ||||
| 		if err := ds.parseLine(line); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	return datasets[1:], nil | ||||
| } | ||||
|  | ||||
| // Diff returns changes between a snapshot and the given ZFS dataset. | ||||
| // The snapshot name must include the filesystem part as it is possible to | ||||
| // compare clones with their origin snapshots. | ||||
| func (d *Dataset) Diff(snapshot string) ([]*InodeChange, error) { | ||||
| 	args := []string{"diff", "-FH", snapshot, d.Name}[:] | ||||
| 	out, err := zfs(args...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	inodeChanges, err := parseInodeChanges(out) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return inodeChanges, nil | ||||
| } | ||||
							
								
								
									
										112
									
								
								vendor/github.com/mistifyio/go-zfs/zpool.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										112
									
								
								vendor/github.com/mistifyio/go-zfs/zpool.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,112 +0,0 @@ | ||||
| package zfs | ||||
|  | ||||
| // ZFS zpool states, which can indicate if a pool is online, offline, | ||||
| // degraded, etc.  More information regarding zpool states can be found here: | ||||
| // https://docs.oracle.com/cd/E19253-01/819-5461/gamno/index.html. | ||||
| const ( | ||||
| 	ZpoolOnline   = "ONLINE" | ||||
| 	ZpoolDegraded = "DEGRADED" | ||||
| 	ZpoolFaulted  = "FAULTED" | ||||
| 	ZpoolOffline  = "OFFLINE" | ||||
| 	ZpoolUnavail  = "UNAVAIL" | ||||
| 	ZpoolRemoved  = "REMOVED" | ||||
| ) | ||||
|  | ||||
| // Zpool is a ZFS zpool.  A pool is a top-level structure in ZFS, and can | ||||
| // contain many descendent datasets. | ||||
| type Zpool struct { | ||||
| 	Name          string | ||||
| 	Health        string | ||||
| 	Allocated     uint64 | ||||
| 	Size          uint64 | ||||
| 	Free          uint64 | ||||
| 	Fragmentation uint64 | ||||
| 	ReadOnly      bool | ||||
| 	Freeing       uint64 | ||||
| 	Leaked        uint64 | ||||
| 	DedupRatio    float64 | ||||
| } | ||||
|  | ||||
| // zpool is a helper function to wrap typical calls to zpool. | ||||
| func zpool(arg ...string) ([][]string, error) { | ||||
| 	c := command{Command: "zpool"} | ||||
| 	return c.Run(arg...) | ||||
| } | ||||
|  | ||||
| // GetZpool retrieves a single ZFS zpool by name. | ||||
| func GetZpool(name string) (*Zpool, error) { | ||||
| 	args := zpoolArgs | ||||
| 	args = append(args, name) | ||||
| 	out, err := zpool(args...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// there is no -H | ||||
| 	out = out[1:] | ||||
|  | ||||
| 	z := &Zpool{Name: name} | ||||
| 	for _, line := range out { | ||||
| 		if err := z.parseLine(line); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return z, nil | ||||
| } | ||||
|  | ||||
| // Datasets returns a slice of all ZFS datasets in a zpool. | ||||
| func (z *Zpool) Datasets() ([]*Dataset, error) { | ||||
| 	return Datasets(z.Name) | ||||
| } | ||||
|  | ||||
| // Snapshots returns a slice of all ZFS snapshots in a zpool. | ||||
| func (z *Zpool) Snapshots() ([]*Dataset, error) { | ||||
| 	return Snapshots(z.Name) | ||||
| } | ||||
|  | ||||
| // CreateZpool creates a new ZFS zpool with the specified name, properties, | ||||
| // and optional arguments. | ||||
| // A full list of available ZFS properties and command-line arguments may be | ||||
| // found here: https://www.freebsd.org/cgi/man.cgi?zfs(8). | ||||
| func CreateZpool(name string, properties map[string]string, args ...string) (*Zpool, error) { | ||||
| 	cli := make([]string, 1, 4) | ||||
| 	cli[0] = "create" | ||||
| 	if properties != nil { | ||||
| 		cli = append(cli, propsSlice(properties)...) | ||||
| 	} | ||||
| 	cli = append(cli, name) | ||||
| 	cli = append(cli, args...) | ||||
| 	_, err := zpool(cli...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return &Zpool{Name: name}, nil | ||||
| } | ||||
|  | ||||
| // Destroy destroys a ZFS zpool by name. | ||||
| func (z *Zpool) Destroy() error { | ||||
| 	_, err := zpool("destroy", z.Name) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // ListZpools list all ZFS zpools accessible on the current system. | ||||
| func ListZpools() ([]*Zpool, error) { | ||||
| 	args := []string{"list", "-Ho", "name"} | ||||
| 	out, err := zpool(args...) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var pools []*Zpool | ||||
|  | ||||
| 	for _, line := range out { | ||||
| 		z, err := GetZpool(line[0]) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		pools = append(pools, z) | ||||
| 	} | ||||
| 	return pools, nil | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Derek McGowan
					Derek McGowan