func (s *storageService) initStorageDriver(ctx types.Context) error { driverName := s.config.GetString("driver") if driverName == "" { driverName = s.config.GetString("libstorage.driver") if driverName == "" { driverName = s.config.GetString("libstorage.storage.driver") if driverName == "" { return goof.WithField( "service", s.name, "error getting driver name") } } } ctx.WithField("driverName", driverName).Debug("got driver name") driver, err := registry.NewStorageDriver(driverName) if err != nil { return err } ctx = ctx.WithValue(context.DriverKey, driver) if err := driver.Init(ctx, s.config); err != nil { return err } s.driver = driver return nil }
func waitUntilLibStorageStopped(ctx apitypes.Context, errs <-chan error) { ctx.Debug("waiting until libStorage is stopped") // if there is no err channel then do not wait until libStorage is stopped // as the absence of the err channel means libStorage was not started in // embedded mode if errs == nil { ctx.Debug("done waiting on err chan; err chan is nil") return } // in a goroutine, range over the apiserver.Close channel until it's closed for range apiserver.Close() { } ctx.Debug("done sending close signals to libStorage") // block until the err channel is closed for err := range errs { if err == nil { continue } ctx.WithError(err).Error("error on closing libStorage server") } ctx.Debug("done waiting on err chan") }
// // VolumeDetach detaches a volume. func (d *driver) VolumeDetach( ctx types.Context, volumeID string, opts *types.VolumeDetachOpts) (*types.Volume, error) { fields := eff(map[string]interface{}{ "moduleName": ctx, "volumeId": volumeID, }) if volumeID == "" { return nil, goof.WithFields(fields, "volumeId is required for VolumeDetach") } vols, err := d.getVolume(ctx, volumeID, "", types.VolAttReqTrue) if err != nil { return nil, err } resp := volumeattach.Delete( d.client, vols[0].Attachments[0].InstanceID.ID, volumeID) if resp.Err != nil { return nil, goof.WithFieldsE(fields, "error detaching volume", resp.Err) } ctx.WithFields(fields).Debug("waiting for volume to detach") volume, err := d.waitVolumeAttachStatus(ctx, volumeID, false) if err == nil { return volume, nil } log.WithFields(fields).Debug("volume detached") return nil, nil }
func (d *idm) Mount( ctx types.Context, volumeID, volumeName string, opts *types.VolumeMountOpts) (string, *types.Volume, error) { opts.Preempt = d.preempt() fields := log.Fields{ "volumeName": volumeName, "volumeID": volumeID, "opts": opts} ctx.WithFields(fields).Debug("mounting volume") mp, vol, err := d.IntegrationDriver.Mount( ctx.Join(d.ctx), volumeID, volumeName, opts) if err != nil { return "", nil, err } // if the volume has attachments assign the new mount point to the // MountPoint field of the first attachment element if len(vol.Attachments) > 0 { vol.Attachments[0].MountPoint = mp } d.incCount(volumeName) return mp, vol, err }
// Validate validates the provided data (d) against the provided schema (s). func Validate(ctx types.Context, s, d []byte) error { if ctx == nil { log.StandardLogger().WithFields(log.Fields{ "schema": string(s), "body": string(d), }).Debug("validating schema") } else { ctx.WithFields(log.Fields{ "schema": string(s), "body": string(d), }).Debug("validating schema") } validator, err := getSchemaValidator(s) if err != nil { return err } if len(d) == 0 { d = []byte("{}") } data, err := ucl.Parse(bytes.NewReader(d)) if err != nil { return err } return validator.Validate(data) }
func (c *client) NextDevice( ctx types.Context, opts types.Store) (string, error) { if c.isController() { return "", utils.NewUnsupportedForClientTypeError( c.clientType, "NextDevice") } if supported, _ := c.Supported(ctx, opts); !supported { return "", errExecutorNotSupported } ctx = context.RequireTX(ctx.Join(c.ctx)) serviceName, ok := context.ServiceName(ctx) if !ok { return "", goof.New("missing service name") } si, err := c.getServiceInfo(serviceName) if err != nil { return "", err } driverName := si.Driver.Name out, err := c.runExecutor(ctx, driverName, types.LSXCmdNextDevice) if err != nil { return "", err } ctx.Debug("xli nextdevice success") return gotil.Trim(string(out)), nil }
func (d *odm) IsMounted( ctx types.Context, mountPoint string, opts types.Store) (bool, error) { return d.OSDriver.IsMounted(ctx.Join(d.Context), mountPoint, opts) }
func (d *driver) Init(ctx types.Context, config gofig.Config) error { d.ctx = ctx d.config = config d.volPath = vfs.VolumesDirPath(config) d.snapPath = vfs.SnapshotsDirPath(config) ctx.WithField("vfs.root.path", vfs.RootDir(config)).Info("vfs.root") os.MkdirAll(d.volPath, 0755) os.MkdirAll(d.snapPath, 0755) d.volJSONGlobPatt = fmt.Sprintf("%s/*.json", d.volPath) d.snapJSONGlobPatt = fmt.Sprintf("%s/*.json", d.snapPath) volJSONPaths, err := d.getVolJSONs() if err != nil { return nil } d.volCount = int64(len(volJSONPaths)) - 1 snapJSONPaths, err := d.getSnapJSONs() if err != nil { return nil } d.snapCount = int64(len(snapJSONPaths)) - 1 return nil }
func (d *driver) VolumeRemove( ctx types.Context, volumeID string, opts types.Store) error { ctx.WithFields(log.Fields{ "volumeID": volumeID, }).Debug("mockDriver.VolumeRemove") var xToRemove int var volume *types.Volume for x, v := range d.volumes { if strings.ToLower(v.ID) == strings.ToLower(volumeID) { volume = v xToRemove = x break } } if volume == nil { return utils.NewNotFoundError(volumeID) } d.volumes = append(d.volumes[:xToRemove], d.volumes[xToRemove+1:]...) return nil }
func (c *client) downloadExecutor(ctx types.Context) error { if c.isController() { return utils.NewUnsupportedForClientTypeError( c.clientType, "downloadExecutor") } ctx.Debug("downloading executor") f, err := os.OpenFile( types.LSX.String(), os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0755) if err != nil { return err } defer f.Close() rdr, err := c.APIClient.ExecutorGet(ctx, types.LSX.Name()) n, err := io.Copy(f, rdr) if err != nil { return err } if err := f.Sync(); err != nil { return err } ctx.WithField("bytes", n).Debug("downloaded executor") return nil }
func (d *idm) initPathCache(ctx types.Context) { if !d.pathCacheEnabled() { ctx.Info("path cache initializion disabled") return } if name, ok := context.ServiceName(ctx); !ok || name == "" { ctx.Info("path cache initializion disabled; no service name in ctx") return } f := func(async bool) { ctx.WithField("async", async).Info("initializing the path cache") _, err := d.List(ctx, apiutils.NewStoreWithData(initPathCacheMap)) if err != nil { ctx.WithField("async", async).WithError(err).Error( "error initializing the path cache") } else { ctx.WithField("async", async).Debug("initialized the path cache") } } if d.pathCacheAsync() { go f(true) } else { f(false) } }
// Init initializes the driver. func (d *driver) Init(ctx types.Context, config gofig.Config) error { d.config = config fields := map[string]interface{}{ "provider": vbox.Name, "moduleName": vbox.Name, "endpoint": d.endpoint(), "userName": d.username(), "tls": d.tls(), "volumePath": d.volumePath(), "controllerName": d.controllerName(), "machineNameOrId": d.machineNameID(""), } ctx.Info("initializing driver: ", fields) d.vbox = vboxc.New(d.username(), d.password(), d.endpoint(), d.tls(), d.controllerName()) if err := d.vbox.Logon(); err != nil { return goof.WithFieldsE(fields, "error logging in", err) } ctx.WithFields(fields).Info("storage driver initialized") return nil }
func (c *client) getExecutorChecksum(ctx types.Context) (string, error) { if c.isController() { return "", utils.NewUnsupportedForClientTypeError( c.clientType, "getExecutorChecksum") } ctx.Debug("getting executor checksum") f, err := os.Open(types.LSX.String()) if err != nil { return "", err } defer f.Close() h := md5.New() buf := make([]byte, 1024) for { n, err := f.Read(buf) if err == io.EOF { break } if err != nil { return "", err } if _, err := h.Write(buf[:n]); err != nil { return "", err } } sum := fmt.Sprintf("%x", h.Sum(nil)) ctx.WithField("localChecksum", sum).Debug("got local executor checksum") return sum, nil }
func (d *driver) findMachineByNameOrID( ctx types.Context, nameOrID string) (*vboxc.Machine, error) { ctx.WithField("nameOrID", nameOrID).Debug("finding local machine") m, err := d.vbox.FindMachine(nameOrID) if err != nil { return nil, err } if m == nil { return nil, goof.New("could not find machine") } if id, err := m.GetID(); err == nil { m.ID = id } else { return nil, err } if name, err := m.GetName(); err == nil { m.Name = name } else { return nil, err } return m, nil }
func (d *idm) List( ctx types.Context, opts types.Store) ([]types.VolumeMapping, error) { fields := log.Fields{ "opts": opts} ctx.WithFields(fields).Debug("listing volumes") volMaps, err := d.IntegrationDriver.List(ctx.Join(d.ctx), opts) if err != nil { return nil, err } volMapsWithNames := []types.VolumeMapping{} for _, vm := range volMaps { if vm.VolumeName() != "" { volMapsWithNames = append(volMapsWithNames, vm) } } if !d.pathCacheEnabled() { return volMapsWithNames, nil } for _, vm := range volMapsWithNames { vmn := vm.VolumeName() if !d.isCounted(vmn) && vm.MountPoint() != "" { d.initCount(vmn) } } return volMapsWithNames, nil }
func (d *odm) Unmount( ctx types.Context, mountPoint string, opts types.Store) error { return d.OSDriver.Unmount(ctx.Join(d.Context), mountPoint, opts) }
// Handle is the type's Handler function. func (h *postArgsHandler) Handle( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { reqObj := ctx.Value("reqObj") if reqObj == nil { return fmt.Errorf("missing request object") } v := reflect.ValueOf(reqObj).Elem() t := v.Type() for i := 0; i < v.NumField(); i++ { ft := t.Field(i) fv := v.Field(i).Interface() switch tfv := fv.(type) { case nil: // do nothing case map[string]interface{}: store.Set(getFieldName(ft), utils.NewStoreWithData(tfv)) default: // add it to the store store.Set(getFieldName(ft), fv) } } return h.handler(ctx, w, req, store) }
func (d *driver) SnapshotRemove( ctx types.Context, snapshotID string, opts types.Store) error { ctx.WithFields(log.Fields{ "snapshotID": snapshotID, }).Debug("mockDriver.SnapshotRemove") var xToRemove int var snapshot *types.Snapshot for x, s := range d.snapshots { if strings.ToLower(s.ID) == strings.ToLower(snapshotID) { snapshot = s xToRemove = x break } } if snapshot == nil { return utils.NewNotFoundError(snapshotID) } d.snapshots = append(d.snapshots[:xToRemove], d.snapshots[xToRemove+1:]...) return nil }
// Inspect returns a specific volume as identified by the provided // volume name. func (d *driver) Inspect( ctx types.Context, volumeName string, opts types.Store) (types.VolumeMapping, error) { fields := log.Fields{ "volumeName": volumeName, "opts": opts} ctx.WithFields(fields).Info("inspecting volume") objs, err := d.List(ctx, opts) if err != nil { return nil, err } var obj types.VolumeMapping for _, o := range objs { if strings.ToLower(volumeName) == strings.ToLower(o.VolumeName()) { obj = o break } } if obj == nil { return nil, utils.NewNotFoundError(volumeName) } fields = log.Fields{ "volumeName": volumeName, "volume": obj} ctx.WithFields(fields).Info("volume inspected") return obj, nil }
// Handle is the type's Handler function. func (h *queryParamsHandler) Handle( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { for k, v := range req.URL.Query() { ctx.WithFields(log.Fields{ "key": k, "value": v, "len(value)": len(v), }).Debug("query param") switch len(v) { case 0: store.Set(k, true) case 1: if len(v[0]) == 0 { store.Set(k, true) } else { if i, err := strconv.ParseInt(v[0], 10, 64); err == nil { store.Set(k, i) } else if b, err := strconv.ParseBool(v[0]); err == nil { store.Set(k, b) } else { store.Set(k, v[0]) } } default: store.Set(k, v) } } return h.handler(ctx, w, req, store) }
// Create will create a new volume with the volumeName and opts. func (d *driver) Create( ctx types.Context, volumeName string, opts *types.VolumeCreateOpts) (*types.Volume, error) { if volumeName == "" { return nil, goof.New("missing volume name or ID") } optsNew := &types.VolumeCreateOpts{} az := d.availabilityZone() optsNew.AvailabilityZone = &az i, _ := strconv.Atoi(d.size()) size := int64(i) optsNew.Size = &size volumeType := d.volumeType() optsNew.Type = &volumeType io, _ := strconv.Atoi(d.iops()) IOPS := int64(io) optsNew.IOPS = &IOPS if opts.Opts.IsSet("availabilityZone") { az = opts.Opts.GetString("availabilityZone") } if opts.Opts.IsSet("size") { size = opts.Opts.GetInt64("size") } if opts.Opts.IsSet("volumeType") { volumeType = opts.Opts.GetString("volumeType") } if opts.Opts.IsSet("type") { volumeType = opts.Opts.GetString("type") } if opts.Opts.IsSet("iops") { IOPS = opts.Opts.GetInt64("iops") } optsNew.Opts = opts.Opts ctx.WithFields(log.Fields{ "volumeName": volumeName, "availabilityZone": az, "size": size, "volumeType": volumeType, "IOPS": IOPS, "opts": opts}).Info("creating volume") client := context.MustClient(ctx) vol, err := client.Storage().VolumeCreate(ctx, volumeName, optsNew) if err != nil { return nil, err } ctx.WithFields(log.Fields{ "volumeName": volumeName, "vol": vol}).Info("volume created") return vol, nil }
func (d *driver) Login(ctx types.Context) (interface{}, error) { sess := &session{} if iid, ok := context.InstanceID(ctx); ok { sess.id = iid.String() } ctx.Debugf("vfs login=%s", sess.id) return sess, nil }
func (d *odm) Mounts( ctx types.Context, deviceName, mountPoint string, opts types.Store) ([]*types.MountInfo, error) { ctx = ctx.Join(d.Context) return d.OSDriver.Mounts(ctx.Join(d.Context), deviceName, mountPoint, opts) }
func (d *odm) Mount( ctx types.Context, deviceName, mountPoint string, opts *types.DeviceMountOpts) error { ctx = ctx.Join(d.Context) return d.OSDriver.Mount(ctx.Join(d.Context), deviceName, mountPoint, opts) }
func (c *client) requireCtx(ctx types.Context) types.Context { if ctx == nil { ctx = c.ctx } else { ctx = ctx.Join(c.ctx) } return context.RequireTX(ctx) }
// VolumeDetach detaches a volume. func (d *driver) VolumeDetach( ctx types.Context, volumeID string, opts *types.VolumeDetachOpts) (*types.Volume, error) { // review volume with attachments to any host ec2vols, err := d.getVolume(ctx, volumeID, "") if err != nil { return nil, goof.WithError("error getting volume", err) } volumes, convErr := d.toTypesVolume( ctx, ec2vols, types.VolAttReqTrue) if convErr != nil { return nil, goof.WithError("error converting to types.Volume", convErr) } // no volumes to detach if len(volumes) == 0 { return nil, errNoVolReturned } // volume has no attachments if len(volumes[0].Attachments) == 0 { return nil, errVolAlreadyDetached } dvInput := &awsec2.DetachVolumeInput{ VolumeId: &volumeID, Force: &opts.Force, } // Detach volume using EC2 API call if _, err = mustSession(ctx).DetachVolume(dvInput); err != nil { return nil, goof.WithFieldsE( log.Fields{ "provider": d.Name(), "volumeID": volumeID}, "error detaching volume", err) } if err = d.waitVolumeComplete(ctx, volumeID, waitVolumeDetach); err != nil { return nil, goof.WithError("error waiting for volume detach", err) } ctx.Info("detached volume", volumeID) // check if successful detach detachedVol, err := d.VolumeInspect( ctx, volumeID, &types.VolumeInspectOpts{ Attachments: types.VolAttReqTrue, Opts: opts.Opts, }) if err != nil { return nil, goof.WithError("error getting volume", err) } return detachedVol, nil }
func (c *client) InstanceInspect( ctx types.Context, service string) (*types.Instance, error) { si, err := c.ServiceInspect( ctx.WithValue(ctxInstanceForSvc, &ctxInstanceForSvcT{}), service) if err != nil { return nil, err } return si.Instance, nil }
func (d *driver) createVolume( ctx types.Context, name string, size int64) (*vboxc.Medium, error) { if name == "" { return nil, goof.New("name is empty") } path := filepath.Join(d.volumePath(), name) ctx.WithField("path", path).Debug("creating vmdk") return d.vbox.CreateMedium("vmdk", path, size) }
// VolumeAttach attaches a volume and provides a token clients can use // to validate that device has appeared locally. func (d *driver) VolumeAttach( ctx types.Context, volumeID string, opts *types.VolumeAttachOpts) (*types.Volume, string, error) { svc := mustSession(ctx) vol, err := d.VolumeInspect(ctx, volumeID, &types.VolumeInspectOpts{Attachments: types.VolAttReqTrue}) if err != nil { return nil, "", err } iid := context.MustInstanceID(ctx) var ma *types.VolumeAttachment for _, att := range vol.Attachments { if att.InstanceID.ID == iid.ID { ma = att break } } // No mount targets were found if ma == nil { secGrpIDs := d.secGroups if v, ok := iid.Fields[efs.InstanceIDFieldSecurityGroups]; ok { iSecGrpIDs := strings.Split(v, ";") ctx.WithField("secGrpIDs", iSecGrpIDs).Debug( "using instance security group IDs") secGrpIDs = iSecGrpIDs } if len(secGrpIDs) == 0 { return nil, "", errInvalidSecGroups } request := &awsefs.CreateMountTargetInput{ FileSystemId: aws.String(vol.ID), SubnetId: aws.String(iid.ID), SecurityGroups: aws.StringSlice(secGrpIDs), } // TODO(mhrabovcin): Should we block here until MountTarget is in // "available" LifeCycleState? Otherwise mount could fail until creation // is completed. _, err = svc.CreateMountTarget(request) // Failed to create mount target if err != nil { return nil, "", err } } return vol, "", err }
// Volumes returns all volumes or a filtered list of volumes. func (d *driver) Volumes( ctx types.Context, opts *types.VolumesOpts) ([]*types.Volume, error) { svc := mustSession(ctx) fileSystems, err := d.getAllFileSystems(svc) if err != nil { return nil, err } var volumesSD []*types.Volume for _, fileSystem := range fileSystems { // Make sure that name is popullated if fileSystem.Name == nil { ctx.WithFields(log.Fields{ "filesystemid": *fileSystem.FileSystemId, }).Warn("missing EFS filesystem name") continue } // Only volumes with partition prefix if !strings.HasPrefix(*fileSystem.Name, d.tag+tagDelimiter) { continue } // Only volumes in "available" state if *fileSystem.LifeCycleState != awsefs.LifeCycleStateAvailable { continue } volumeSD := &types.Volume{ Name: d.getPrintableName(*fileSystem.Name), ID: *fileSystem.FileSystemId, Size: *fileSystem.SizeInBytes.Value, Attachments: nil, } var atts []*types.VolumeAttachment if opts.Attachments.Requested() { atts, err = d.getVolumeAttachments( ctx, *fileSystem.FileSystemId, opts.Attachments) if err != nil { return nil, err } } if len(atts) > 0 { volumeSD.Attachments = atts } volumesSD = append(volumesSD, volumeSD) } return volumesSD, nil }