func zpoolTest(t *testing.T, fn func()) { tempfiles := make([]string, 3) for i := range tempfiles { f, _ := ioutil.TempFile("/tmp/", "zfs-") defer f.Close() err := f.Truncate(pow2(30)) ok(t, err) tempfiles[i] = f.Name() defer os.Remove(f.Name()) } pool, err := zfs.CreateZpool("test", nil, tempfiles...) ok(t, err) defer pool.Destroy() ok(t, err) fn() }
func NewProvider(config *ProviderConfig) (volume.Provider, error) { if _, err := exec.LookPath("zfs"); err != nil { return nil, fmt.Errorf("zfs command is not available") } dataset, err := zfs.GetDataset(config.DatasetName) if err != nil { if isDatasetNotExistsError(err) { // if the dataset doesn't exist... if config.Make == nil { // not much we can do without a dataset or pool to contain data return nil, err } // make a zpool backed by a sparse file. it's the most portable thing we can do. if err := os.MkdirAll(filepath.Dir(config.Make.BackingFilename), 0755); err != nil { return nil, err } f, err := os.OpenFile(config.Make.BackingFilename, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600) if err == nil { // if we've created a new file, size it and create a new zpool if err = f.Truncate(config.Make.Size); err != nil { return nil, err } f.Close() if _, err = zfs.CreateZpool( config.DatasetName, nil, "-mnone", // do not mount the root dataset. (we'll mount our own datasets as necessary.) config.Make.BackingFilename, ); err != nil { return nil, err } } else if err.(*os.PathError).Err == syscall.EEXIST { // if the file already exists, check it for existing zpool if err := zpoolImportFile(config.Make.BackingFilename); err != nil { // if 'zpool import' didn't believe it... halt here // we could overwrite but we'd rather stop and avoid potential data loss. return nil, fmt.Errorf("error attempting import of existing zpool file: %s", err) } // note: 'zpool import' recreated *all* the volume datasets in that pool. // currently, even if they're not known to a volume manager, they're not garbage collected. } else { return nil, err } // get the dataset again... `zfs.Zpool` isn't a `zfs.Dataset` dataset, err = zfs.GetDataset(config.DatasetName) if err != nil { return nil, err } } else { // any error more complicated than not_exists, and we're out of our depth return nil, err } } if config.WorkingDir == "" { config.WorkingDir = "/var/lib/flynn/volumes/zfs/" } return &Provider{ config: config, dataset: dataset, volumes: make(map[string]*zfsVolume), }, nil }