func Init(id int32, cfg *module.ModuleConfig) (module.Module, error) { osdm, osdmErr := osm.NewOSDriverManager(cfg.Config) if osdmErr != nil { return nil, osdmErr } if len(osdm.Drivers) == 0 { return nil, errors.New("no os drivers initialized") } sdm, sdmErr := storage.NewStorageDriverManager(cfg.Config) if sdmErr != nil { return nil, sdmErr } if len(sdm.Drivers) == 0 { return nil, errors.New("no storage drivers initialized") } vdm, vdmErr := volume.NewVolumeDriverManager(cfg.Config, osdm, sdm) if vdmErr != nil { return nil, vdmErr } if len(vdm.Drivers) == 0 { return nil, errors.New("no volume drivers initialized") } return &Module{ id: id, vdm: vdm, name: MOD_NAME, desc: MOD_DESC, addr: cfg.Address, }, nil }
// NetworkName will return relevant information about how a volume can be discovered on an OS func (driver *Driver) NetworkName(volumeName, instanceID string) (string, error) { log.WithFields(log.Fields{ "volumeName": volumeName, "instanceID": instanceID, "driverName": driver.Name()}).Info("returning network name") volumes, err := driver.sdm.GetVolume("", volumeName) if err != nil { return "", err } switch { case len(volumes) == 0: return "", errors.New("No volumes returned by name") case len(volumes) > 1: return "", errors.New("Multiple volumes returned by name") } volumeAttachment, err := driver.sdm.GetVolumeAttach( volumes[0].VolumeID, instanceID) if err != nil { return "", err } if len(volumeAttachment) == 0 { return "", errors.New("Volume not attached") } volumes, err = driver.sdm.GetVolume("", volumeName) if err != nil { return "", err } return volumes[0].NetworkName, nil }
// Path returns the mounted path of the volume func (driver *Driver) Path(volumeName, volumeID string) (string, error) { log.WithFields(log.Fields{ "volumeName": volumeName, "volumeID": volumeID, "driverName": driver.Name()}).Info("getting path to volume") if volumeName == "" && volumeID == "" { return "", errors.New("Missing volume name or ID") } instances, err := driver.sdm.GetInstance() if err != nil { return "", err } switch { case len(instances) == 0: return "", errors.New("No instances") case len(instances) > 1: return "", errors.New("Too many instances returned, limit the storagedrivers") } volumes, err := driver.sdm.GetVolume(volumeID, volumeName) if err != nil { return "", err } switch { case len(volumes) == 0: return "", errors.New("No volumes returned by name") case len(volumes) > 1: return "", errors.New("Multiple volumes returned by name") } volumeAttachment, err := driver.sdm.GetVolumeAttach(volumes[0].VolumeID, instances[0].InstanceID) if err != nil { return "", err } if len(volumeAttachment) == 0 { return "", nil } mounts, err := driver.osdm.GetMounts(volumeAttachment[0].DeviceName, "") if err != nil { return "", err } if len(mounts) == 0 { return "", nil } return mounts[0].Mountpoint, nil }
func (driver *Driver) getLunMaps(initiatorName, volumeID string) (xtio.Refs, error) { if initiatorName == "" { return nil, errors.New("Missing initiatorName") } initiatorGroup, err := driver.Client.GetInitiatorGroup("", initiatorName) if err != nil { return nil, err } lunMaps, err := driver.Client.GetLunMaps() if err != nil { return nil, err } var refs xtio.Refs for _, ref := range lunMaps { idents := strings.Split(ref.Name, "_") if len(idents) < 3 { continue } else if strconv.Itoa(initiatorGroup.Index) == idents[1] && volumeID == idents[0] { refs = append(refs, ref) } } return refs, nil }
func getVolumeMountPath(name string) (string, error) { if name == "" { return "", errors.New("Missing volume name") } return fmt.Sprintf("%s/%s", mountDirectoryPath, name), nil }
// Remove will remove a remote volume func (driver *Driver) Remove(volumeName string) error { log.WithFields(log.Fields{ "volumeName": volumeName, "driverName": driver.Name()}).Info("removing volume") if volumeName == "" { return errors.New("Missing volume name") } instances, err := driver.sdm.GetInstance() if err != nil { return err } switch { case len(instances) == 0: return errors.New("No instances") case len(instances) > 1: return errors.New("Too many instances returned, limit the storagedrivers") } volumes, err := driver.sdm.GetVolume("", volumeName) if err != nil { return err } switch { case len(volumes) == 0: return errors.New("No volumes returned by name") case len(volumes) > 1: return errors.New("Multiple volumes returned by name") } err = driver.Unmount("", volumes[0].VolumeID) if err != nil { return err } err = driver.sdm.RemoveVolume(volumes[0].VolumeID) if err != nil { return err } return nil }
func (osdm *OSDriverManager) Unmount(mountPoint string) error { for _, driver := range osdm.Drivers { log.WithFields(log.Fields{ "mountPoint": mountPoint, "driverName": driver.Name()}).Info("unmounting filesystem") return driver.Unmount(mountPoint) } return errors.New("No OS detected") }
func (osdm *OSDriverManager) Mounted(mountPoint string) (bool, error) { for _, driver := range osdm.Drivers { log.WithFields(log.Fields{ "mountPoint": mountPoint, "driverName": driver.Name()}).Info("checking filesystem mount") return driver.Mounted(mountPoint) } return false, errors.New("No OS detected") }
func (osdm *OSDriverManager) Format(deviceName, fsType string, overwriteFs bool) error { for _, driver := range osdm.Drivers { log.WithFields(log.Fields{ "deviceName": deviceName, "fsType": fsType, "overwriteFs": overwriteFs, "driverName": driver.Name()}).Info("formatting if blank or overwriteFs specified") return driver.Format(deviceName, fsType, overwriteFs) } return errors.New("No OS detected") }
func (osdm *OSDriverManager) Mount(device, target, mountOptions, mountLabel string) error { for _, driver := range osdm.Drivers { log.WithFields(log.Fields{ "device": device, "target": target, "mountOptions": mountOptions, "mountLabel": mountLabel, "driverName": driver.Name()}).Info("mounting filesystem") return driver.Mount(device, target, mountOptions, mountLabel) } return errors.New("No OS detected") }
func (osdm *OSDriverManager) GetMounts(deviceName, mountPoint string) ([]*mount.Info, error) { for _, driver := range osdm.Drivers { mounts, err := driver.GetMounts(deviceName, mountPoint) if err != nil { return nil, err } return mounts, nil } return nil, errors.New("No OS detected") }
func NewOSDriverManager(conf *config.Config) (*OSDriverManager, error) { drivers, err := getDrivers(conf) if err != nil { return nil, err } if len(drivers) == 0 { return nil, errors.New("no os drivers initialized") } return &OSDriverManager{drivers, conf}, nil }
func (osdm *OSDriverManager) GetMounts(deviceName, mountPoint string) ([]*mount.Info, error) { for _, driver := range osdm.Drivers { log.WithFields(log.Fields{ "deviceName": deviceName, "mountPoint": mountPoint, "driverName": driver.Name()}).Info("getting mounts") mounts, err := driver.GetMounts(deviceName, mountPoint) if err != nil { return nil, err } return mounts, nil } return nil, errors.New("No OS detected") }
func NewStorageDriverManager(conf *config.Config) (*StorageDriverManager, error) { sd, sdErr := getDrivers(conf) if sdErr != nil { return nil, sdErr } if len(sd) == 0 { return nil, errors.New("no storage drivers initialized") } return &StorageDriverManager{ Drivers: sd, Config: conf, }, nil }
func getIQN() (string, error) { data, err := ioutil.ReadFile("/etc/iscsi/initiatorname.iscsi") if err != nil { return "", err } result := string(data) lines := strings.Split(result, "\n") for _, line := range lines { split := strings.Split(line, "=") if split[0] == "InitiatorName" { return split[1], nil } } return "", errors.New("IQN not found") }
func NewVolumeDriverManager( conf *config.Config, osDriverManager *osm.OSDriverManager, storageDriverManager *storage.StorageDriverManager) (*VolumeDriverManager, error) { vd, vdErr := getDrivers(conf, osDriverManager, storageDriverManager) if vdErr != nil { return nil, vdErr } if len(vd) == 0 { return nil, errors.New("no volume drivers initialized") } return &VolumeDriverManager{ Drivers: vd, }, nil }
func getLocalDevices() (deviceNames []string, err error) { file := "/proc/partitions" contentBytes, err := ioutil.ReadFile(file) if err != nil { return []string{}, errors.New(fmt.Sprintf("Couldn't read %s: %v", file, err)) } content := string(contentBytes) lines := strings.Split(content, "\n") for _, line := range lines[2:] { fields := strings.Fields(line) if len(fields) == 4 { deviceNames = append(deviceNames, fields[3]) } } return deviceNames, nil }
func (driver *Driver) GetDeviceNextAvailable() (string, error) { letters := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p"} blockDeviceNames := make(map[string]bool) blockDeviceMapping, err := driver.GetVolumeMapping() if err != nil { return "", err } for _, blockDevice := range blockDeviceMapping { re, _ := regexp.Compile(`^/dev/xvd([a-z])`) res := re.FindStringSubmatch(blockDevice.DeviceName) if len(res) > 0 { blockDeviceNames[res[1]] = true } } localDevices, err := getLocalDevices() if err != nil { return "", err } for _, localDevice := range localDevices { re, _ := regexp.Compile(`^xvd([a-z])`) res := re.FindStringSubmatch(localDevice) if len(res) > 0 { blockDeviceNames[res[1]] = true } } for _, letter := range letters { if !blockDeviceNames[letter] { nextDeviceName := "/dev/xvd" + letter log.Println("Got next device name: " + nextDeviceName) return nextDeviceName, nil } } return "", errors.New("No available device") }
func (driver *Driver) CopySnapshot(runAsync bool, volumeID, snapshotID, snapshotName, destinationSnapshotName, destinationRegion string) (*storage.Snapshot, error) { return nil, errors.New("This driver does not implement CopySnapshot") }
func (driver *Driver) CopySnapshot(runAsync bool, volumeID, snapshotID, snapshotName, destinationSnapshotName, destinationRegion string) (*storage.Snapshot, error) { if volumeID == "" && snapshotID == "" && snapshotName == "" { return nil, errors.New("Missing volumeID, snapshotID, or snapshotName") } snapshots, err := driver.getSnapshot(volumeID, snapshotID, snapshotName) if err != nil { return nil, err } if len(snapshots) > 1 { return nil, ErrMultipleVolumesReturned } else if len(snapshots) == 0 { return nil, ErrNoVolumesReturned } snapshotID = snapshots[0].Id options := &ec2.CopySnapshot{ SourceRegion: driver.EC2Instance.Region.Name, DestinationRegion: destinationRegion, SourceSnapshotId: snapshotID, Description: fmt.Sprintf("[Copied %s from %s]", snapshotID, driver.EC2Instance.Region.Name), } resp := &ec2.CopySnapshotResp{} auth := aws.Auth{ AccessKey: driver.Config.AwsAccessKey, SecretKey: driver.Config.AwsSecretKey} destEC2Instance := ec2.New( auth, aws.Regions[destinationRegion], ) origEC2Instance := driver.EC2Instance driver.EC2Instance = destEC2Instance defer func() { driver.EC2Instance = origEC2Instance }() resp, err = driver.EC2Instance.CopySnapshot(options) if err != nil { return nil, err } if destinationSnapshotName != "" { _, err := driver.EC2Instance.CreateTags([]string{resp.SnapshotId}, []ec2.Tag{{"Name", destinationSnapshotName}}) if err != nil { return nil, err } } if !runAsync { log.Println("Waiting for snapshot copy to complete") err = driver.waitSnapshotComplete(resp.SnapshotId) if err != nil { return nil, err } } snapshot, err := driver.GetSnapshot("", resp.SnapshotId, "") if err != nil { return nil, err } return snapshot[0], nil }
return nil, errors.New("no volume drivers initialized") } return &Module{ id: id, vdm: vdm, name: MOD_NAME, desc: MOD_DESC, addr: cfg.Address, }, nil } const driverName = "dockervolumedriver" var ( ErrMissingHost = errors.New("Missing host parameter") ErrBadHostSpecified = errors.New("Bad host specified, ie. unix:///run/docker/plugins/rexray.sock or tcp://127.0.0.1:8080") ErrBadProtocol = errors.New("Bad protocol specified with host, ie. unix:// or tcp://") ) type pluginRequest struct { Name string `json:"Name,omitempty"` Opts volume.VolumeOpts `json:"Opts,omitempty"` } func (mod *Module) Start() error { proto, addr, parseAddrErr := util.ParseAddress(mod.Address()) if parseAddrErr != nil { return parseAddrErr }
func (mod *Module) Start() error { proto, addr, parseAddrErr := util.ParseAddress(mod.Address()) if parseAddrErr != nil { return parseAddrErr } const validProtoPatt = "(?i)^unix|tcp$" isProtoValid, matchProtoErr := regexp.MatchString(validProtoPatt, proto) if matchProtoErr != nil { return errors.New(fmt.Sprintf( "Error matching protocol %s with pattern '%s' ERR: %v", proto, validProtoPatt, matchProtoErr)) } if !isProtoValid { return errors.New(fmt.Sprintf("Invalid protocol %s", proto)) } if err := os.MkdirAll("/etc/docker/plugins", 0755); err != nil { return err } var specPath string var startFunc func() error mux := mod.buildMux() if proto == "unix" { sockFile := addr sockFileDir := filepath.Dir(sockFile) mkSockFileDirErr := os.MkdirAll(sockFileDir, 0755) if mkSockFileDirErr != nil { return mkSockFileDirErr } _ = os.RemoveAll(sockFile) specPath = mod.Address() startFunc = func() error { l, lErr := net.Listen("unix", sockFile) if lErr != nil { return lErr } defer l.Close() defer os.Remove(sockFile) return http.Serve(l, mux) } } else { specPath = addr startFunc = func() error { s := &http.Server{ Addr: addr, Handler: mux, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, MaxHeaderBytes: 1 << 20, } return s.ListenAndServe() } } go func() { sErr := startFunc() if sErr != nil { panic(sErr) } }() writeSpecErr := ioutil.WriteFile( "/etc/docker/plugins/rexray.spec", []byte(specPath), 0644) if writeSpecErr != nil { return writeSpecErr } return nil }
const ProviderName = "XtremIO" type Driver struct { Client *xtio.Client Initiator xtio.Initiator VolumesSig string LunMapsSig string VolumesByNAA map[string]xtio.Volume UseDeviceMapper bool UseMultipath bool Config *config.Config } var ( ErrMissingVolumeID = errors.New("Missing VolumeID") ErrMultipleVolumesReturned = errors.New("Multiple Volumes returned") ErrNoVolumesReturned = errors.New("No Volumes returned") ErrLocalVolumeMaps = errors.New("Getting local volume mounts") ) func ef() errors.Fields { return errors.Fields{ "provider": ProviderName, } } func eff(fields errors.Fields) map[string]interface{} { errFields := map[string]interface{}{ "provider": ProviderName, }
func (vdm *VolumeDriverManager) Unmount(volumeName, volumeID string) error { for _, driver := range vdm.Drivers { return driver.Unmount(volumeName, volumeID) } return errors.New("no volume manager specified") }
func (vdm *VolumeDriverManager) Mount(volumeName, volumeID string, overwriteFs bool, newFsType string) (string, error) { for _, driver := range vdm.Drivers { return driver.Mount(volumeName, volumeID, overwriteFs, newFsType) } return "", errors.New("no volume manager specified") }
func (vdm *VolumeDriverManager) NetworkName(volumeName, instanceID string) (string, error) { for _, driver := range vdm.Drivers { return driver.NetworkName(volumeName, instanceID) } return "", errors.New("no volume manager specified") }
func (vdm *VolumeDriverManager) Detach(volumeName, instanceID string) error { for _, driver := range vdm.Drivers { return driver.Detach(volumeName, instanceID) } return errors.New("no volume manager specified") }
func (vdm *VolumeDriverManager) Remove(volumeName string) error { for _, driver := range vdm.Drivers { return driver.Remove(volumeName) } return errors.New("no volume manager specified") }
func (vdm *VolumeDriverManager) Path(volumeName, volumeID string) (string, error) { for _, driver := range vdm.Drivers { return driver.Path(volumeName, volumeID) } return "", errors.New("no volume manager specified") }
func (driver *Driver) GetDeviceNextAvailable() (string, error) { return "", errors.New("This driver does not implment, since it cannot determine device name when attaching") }