// 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) SnapshotCopy( ctx types.Context, snapshotID, snapshotName, destinationID string, opts types.Store) (*types.Snapshot, error) { context.MustSession(ctx) ogSnap, err := d.getSnapshotByID(snapshotID) if err != nil { return nil, err } newSnap := &types.Snapshot{ ID: d.newSnapshotID(ogSnap.VolumeID), VolumeID: ogSnap.VolumeID, VolumeSize: ogSnap.VolumeSize, Name: snapshotName, Status: "online", StartTime: time.Now().Unix(), Fields: ogSnap.Fields, } if customFields := opts.GetStore("opts"); customFields != nil { for _, k := range customFields.Keys() { newSnap.Fields[k] = customFields.GetString(k) } } if err := d.writeSnapshot(newSnap); err != nil { return nil, err } return newSnap, nil }
func (r *router) snapshotRemove( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { service := context.MustService(ctx) run := func( ctx types.Context, svc types.StorageService) (interface{}, error) { return nil, svc.Driver().SnapshotRemove( ctx, store.GetString("snapshotID"), store) } return httputils.WriteTask( ctx, r.config, w, store, service.TaskExecute(ctx, run, nil), http.StatusResetContent) }
// WriteTask writes a task to a ResponseWriter. func WriteTask( ctx types.Context, config gofig.Config, w http.ResponseWriter, store types.Store, task *types.Task, okStatus int) error { if store.GetBool("async") { WriteJSON(w, http.StatusAccepted, task) return nil } exeTimeoutDur, err := time.ParseDuration( config.GetString(types.ConfigServerTasksExeTimeout)) if err != nil { exeTimeoutDur = time.Duration(time.Second * 60) } exeTimeout := time.NewTimer(exeTimeoutDur) select { case <-services.TaskWaitC(ctx, task.ID): if task.Error != nil { return task.Error } WriteJSON(w, okStatus, task.Result) case <-exeTimeout.C: WriteJSON(w, http.StatusRequestTimeout, task) } return nil }
func (r *router) volumeSnapshot( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { service := context.MustService(ctx) run := func( ctx types.Context, svc types.StorageService) (interface{}, error) { return svc.Driver().VolumeSnapshot( ctx, store.GetString("volumeID"), store.GetString("snapshotName"), store) } return httputils.WriteTask( ctx, r.config, w, store, service.TaskExecute(ctx, run, schema.SnapshotSchema), http.StatusCreated) }
func (d *driver) VolumeSnapshot( ctx types.Context, volumeID, snapshotName string, opts types.Store) (*types.Snapshot, error) { context.MustSession(ctx) v, err := d.getVolumeByID(volumeID) if err != nil { return nil, err } s := &types.Snapshot{ ID: d.newSnapshotID(v.ID), VolumeID: v.ID, VolumeSize: v.Size, Name: snapshotName, Status: "online", StartTime: time.Now().Unix(), Fields: v.Fields, } if customFields := opts.GetStore("opts"); customFields != nil { for _, k := range customFields.Keys() { s.Fields[k] = customFields.GetString(k) } } if err := d.writeSnapshot(s); err != nil { return nil, err } return s, nil }
func (d *driver) VolumeCopy( ctx types.Context, volumeID, volumeName string, opts types.Store) (*types.Volume, error) { context.MustSession(ctx) ogVol, err := d.getVolumeByID(volumeID) if err != nil { return nil, err } newVol := &types.Volume{ ID: d.newVolumeID(), Name: volumeName, AvailabilityZone: ogVol.AvailabilityZone, IOPS: ogVol.IOPS, Size: ogVol.Size, Type: ogVol.Type, Fields: ogVol.Fields, } if customFields := opts.GetStore("opts"); customFields != nil { for _, k := range customFields.Keys() { newVol.Fields[k] = customFields.GetString(k) } } if err := d.writeVolume(newVol); err != nil { return nil, err } return newVol, nil }
func (r *router) volumeDetach( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { service := context.MustService(ctx) if _, ok := context.InstanceID(ctx); !ok { return utils.NewMissingInstanceIDError(service.Name()) } run := func( ctx types.Context, svc types.StorageService) (interface{}, error) { v, err := svc.Driver().VolumeDetach( ctx, store.GetString("volumeID"), &types.VolumeDetachOpts{ Force: store.GetBool("force"), Opts: store, }) if err != nil { return nil, err } if v == nil { return nil, nil } if OnVolume != nil { ok, err := OnVolume(ctx, req, store, v) if err != nil { return nil, err } if !ok { return nil, utils.NewNotFoundError(v.ID) } } if v.AttachmentState == 0 { v.AttachmentState = types.VolumeAvailable } return v, nil } return httputils.WriteTask( ctx, r.config, w, store, service.TaskExecute(ctx, run, nil), http.StatusResetContent) }
func parseFilter(store types.Store) (*types.Filter, error) { if !store.IsSet("filter") { return nil, nil } fsz := store.GetString("filter") filter, err := filters.CompileFilter(fsz) if err != nil { return nil, utils.NewBadFilterErr(fsz, err) } return filter, nil }
func (r *router) executorHead( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { ei, err := executors.ExecutorInfoInspect(store.GetString("executor"), false) if err != nil { return err } return writeFile(w, ei) }
func (r *router) volumeCreate( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { service := context.MustService(ctx) run := func( ctx types.Context, svc types.StorageService) (interface{}, error) { v, err := svc.Driver().VolumeCreateFromSnapshot( ctx, store.GetString("snapshotID"), store.GetString("name"), &types.VolumeCreateOpts{ AvailabilityZone: store.GetStringPtr("availabilityZone"), IOPS: store.GetInt64Ptr("iops"), Size: store.GetInt64Ptr("size"), Type: store.GetStringPtr("type"), Opts: store, }) if err != nil { return nil, err } if volume.OnVolume != nil { ok, err := volume.OnVolume(ctx, req, store, v) if err != nil { return nil, err } if !ok { return nil, utils.NewNotFoundError(v.ID) } } return v, nil } return httputils.WriteTask( ctx, r.config, w, store, service.TaskExecute(ctx, run, schema.VolumeSchema), http.StatusCreated) }
func (r *router) volumeCopy( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { service := context.MustService(ctx) run := func( ctx types.Context, svc types.StorageService) (interface{}, error) { v, err := svc.Driver().VolumeCopy( ctx, store.GetString("volumeID"), store.GetString("volumeName"), store) if err != nil { return nil, err } if OnVolume != nil { ok, err := OnVolume(ctx, req, store, v) if err != nil { return nil, err } if !ok { return nil, utils.NewNotFoundError(v.ID) } } if v.AttachmentState == 0 { v.AttachmentState = types.VolumeAvailable } return v, nil } return httputils.WriteTask( ctx, r.config, w, store, service.TaskExecute(ctx, run, schema.VolumeSchema), http.StatusCreated) }
func (d *driver) VolumeSnapshot( ctx types.Context, volumeID, snapshotName string, opts types.Store) (*types.Snapshot, error) { ctx = d.requireCtx(ctx) serviceName, ok := context.ServiceName(ctx) if !ok { return nil, goof.New("missing service name") } req := &types.VolumeSnapshotRequest{ SnapshotName: snapshotName, Opts: opts.Map(), } return d.client.VolumeSnapshot(ctx, serviceName, volumeID, req) }
// Handle is the type's Handler function. func (h *serviceValidator) Handle( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { if !store.IsSet("service") { return utils.NewStoreKeyErr("service") } serviceName := store.GetString("service") service := services.GetStorageService(ctx, serviceName) if service == nil { return utils.NewNotFoundError(serviceName) } ctx = context.WithStorageService(ctx, service) return h.handler(ctx, w, req, store) }
func (d *driver) SnapshotCopy( ctx types.Context, snapshotID, snapshotName, destinationID string, opts types.Store) (*types.Snapshot, error) { ctx = d.requireCtx(ctx) serviceName, ok := context.ServiceName(ctx) if !ok { return nil, goof.New("missing service name") } req := &types.SnapshotCopyRequest{ SnapshotName: snapshotName, DestinationID: destinationID, Opts: opts.Map(), } return d.client.SnapshotCopy(ctx, serviceName, snapshotID, req) }
// List returns all available volume mappings. func (d *driver) List( ctx types.Context, opts types.Store) ([]types.VolumeMapping, error) { client := context.MustClient(ctx) vols, err := client.Storage().Volumes( ctx, &types.VolumesOpts{ Attachments: opts.GetAttachments(), Opts: opts, }, ) if err != nil { return nil, err } serviceName, serviceNameOK := context.ServiceName(ctx) if !serviceNameOK { return nil, goof.New("service name is missing") } volMaps := []types.VolumeMapping{} for _, v := range vols { vs := make(map[string]interface{}) vs["name"] = v.Name vs["size"] = v.Size vs["iops"] = v.IOPS vs["type"] = v.Type vs["availabilityZone"] = v.AvailabilityZone vs["fields"] = v.Fields vs["service"] = serviceName vs["server"] = serviceName volMaps = append(volMaps, &volumeMapping{ Name: v.Name, VolumeMountPoint: v.MountPoint(), VolumeStatus: vs, }) } return volMaps, nil }
func toServiceInfo( ctx types.Context, service types.StorageService, store types.Store) (*types.ServiceInfo, error) { d := service.Driver() var instance *types.Instance if store.GetBool("instance") { if _, ok := context.InstanceID(ctx); !ok { return nil, utils.NewMissingInstanceIDError(service.Name()) } var err error instance, err = d.InstanceInspect(ctx, store) if err != nil { return nil, err } } st, err := d.Type(ctx) if err != nil { return nil, err } nd, err := d.NextDeviceInfo(ctx) if err != nil { return nil, err } return &types.ServiceInfo{ Name: service.Name(), Instance: instance, Driver: &types.DriverInfo{ Name: d.Name(), Type: st, NextDevice: nd, }, }, nil }
func (r *router) volumeAttach( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { service := context.MustService(ctx) if _, ok := context.InstanceID(ctx); !ok { return utils.NewMissingInstanceIDError(service.Name()) } run := func( ctx types.Context, svc types.StorageService) (interface{}, error) { v, attTokn, err := svc.Driver().VolumeAttach( ctx, store.GetString("volumeID"), &types.VolumeAttachOpts{ NextDevice: store.GetStringPtr("nextDeviceName"), Force: store.GetBool("force"), Opts: store, }) if err != nil { return nil, err } if OnVolume != nil { ok, err := OnVolume(ctx, req, store, v) if err != nil { return nil, err } if !ok { return nil, utils.NewNotFoundError(v.ID) } } if v.AttachmentState == 0 { v.AttachmentState = types.VolumeAttached } return &types.VolumeAttachResponse{ Volume: v, AttachToken: attTokn, }, nil } return httputils.WriteTask( ctx, r.config, w, store, service.TaskExecute(ctx, run, schema.VolumeAttachResponseSchema), http.StatusOK) }
func (r *router) volumesForService( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { filter, err := parseFilter(store) if err != nil { return err } if filter != nil { store.Set("filter", filter) } service := context.MustService(ctx) opts := &types.VolumesOpts{ Attachments: store.GetAttachments(), Opts: store, } run := func( ctx types.Context, svc types.StorageService) (interface{}, error) { return getFilteredVolumes(ctx, req, store, svc, opts, filter) } return httputils.WriteTask( ctx, r.config, w, store, service.TaskExecute(ctx, run, schema.VolumeMapSchema), http.StatusOK) }
// 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) }
func (r *router) volumeInspect( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { attachments := store.GetAttachments() service := context.MustService(ctx) iid, iidOK := context.InstanceID(ctx) if !iidOK && attachments.RequiresInstanceID() { return utils.NewMissingInstanceIDError(service.Name()) } opts := &types.VolumeInspectOpts{ Attachments: attachments, Opts: store, } var run types.StorageTaskRunFunc if store.IsSet("byName") { run = func( ctx types.Context, svc types.StorageService) (interface{}, error) { vols, err := svc.Driver().Volumes( ctx, &types.VolumesOpts{ Attachments: attachments, Opts: store, }) if err != nil { return nil, err } volID := store.GetString("volumeID") for _, v := range vols { if strings.EqualFold(v.Name, volID) { if !handleVolAttachments(ctx, nil, iid, v, attachments) { return nil, utils.NewNotFoundError(volID) } if OnVolume != nil { ok, err := OnVolume(ctx, req, store, v) if err != nil { return nil, err } if !ok { return nil, utils.NewNotFoundError(volID) } } return v, nil } } return nil, utils.NewNotFoundError(volID) } } else { run = func( ctx types.Context, svc types.StorageService) (interface{}, error) { v, err := svc.Driver().VolumeInspect( ctx, store.GetString("volumeID"), opts) if err != nil { return nil, err } if !handleVolAttachments(ctx, nil, iid, v, attachments) { return nil, utils.NewNotFoundError(v.ID) } if OnVolume != nil { ok, err := OnVolume(ctx, req, store, v) if err != nil { return nil, err } if !ok { return nil, utils.NewNotFoundError(v.ID) } } return v, nil } } return httputils.WriteTask( ctx, r.config, w, store, service.TaskExecute(ctx, run, schema.VolumeSchema), http.StatusOK) }
// Unmount will unmount the specified volume by volumeName or volumeID. func (d *driver) Unmount( ctx types.Context, volumeID, volumeName string, opts types.Store) (*types.Volume, error) { ctx.WithFields(log.Fields{ "volumeName": volumeName, "volumeID": volumeID, "opts": opts}).Info("unmounting volume") if volumeName == "" && volumeID == "" { return nil, goof.New("missing volume name or ID") } vol, err := d.volumeInspectByIDOrName( ctx, volumeID, volumeName, types.VolAttReqWithDevMapOnlyVolsAttachedToInstance, opts) if err != nil { return nil, err } if len(vol.Attachments) == 0 { return nil, nil } client := context.MustClient(ctx) inst, err := client.Storage().InstanceInspect(ctx, utils.NewStore()) if err != nil { return nil, goof.New("problem getting instance ID") } var ma *types.VolumeAttachment for _, att := range vol.Attachments { if att.InstanceID.ID == inst.InstanceID.ID { ma = att break } } if ma == nil { return nil, goof.New("no attachment found for instance") } if ma.DeviceName == "" { return nil, goof.New("no device name found for attachment") } mounts, err := client.OS().Mounts( ctx, ma.DeviceName, "", opts) if err != nil { return nil, err } for _, mount := range mounts { ctx.WithField("mount", mount).Debug("retrieved mount") } if len(mounts) > 0 { for _, mount := range mounts { ctx.WithField("mount", mount).Debug("unmounting mount point") err = client.OS().Unmount(ctx, mount.MountPoint, opts) if err != nil { return nil, err } } } vol, err = client.Storage().VolumeDetach(ctx, vol.ID, &types.VolumeDetachOpts{ Force: opts.GetBool("force"), Opts: utils.NewStore(), }) if err != nil { return nil, err } ctx.WithFields(log.Fields{ "vol": vol}).Info("unmounted and detached volume") return vol, nil }
func (r *router) volumeDetachAll( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { var ( taskIDs []int tasks = map[string]*types.Task{} opts = &types.VolumesOpts{Opts: store} reply types.ServiceVolumeMap = map[string]types.VolumeMap{} replyRWL = &sync.Mutex{} ) for service := range services.StorageServices(ctx) { run := func( ctx types.Context, svc types.StorageService) (interface{}, error) { ctx = context.WithStorageService(ctx, svc) if _, ok := context.InstanceID(ctx); !ok { return nil, utils.NewMissingInstanceIDError(service.Name()) } var err error if ctx, err = context.WithStorageSession(ctx); err != nil { return nil, err } driver := svc.Driver() volumes, err := driver.Volumes(ctx, opts) if err != nil { return nil, err } // check here var volumeMap types.VolumeMap = map[string]*types.Volume{} defer func() { if len(volumeMap) > 0 { replyRWL.Lock() defer replyRWL.Unlock() reply[service.Name()] = volumeMap } }() for _, volume := range volumes { v, err := driver.VolumeDetach( ctx, volume.ID, &types.VolumeDetachOpts{ Force: store.GetBool("force"), Opts: store, }) if err != nil { return nil, err } if err != nil { return nil, err } if v == nil { continue } if OnVolume != nil { ok, err := OnVolume(ctx, req, store, v) if err != nil { return nil, err } if !ok { return nil, utils.NewNotFoundError(v.ID) } } if v.AttachmentState == 0 { v.AttachmentState = types.VolumeAvailable } volumeMap[v.ID] = v } return nil, nil } task := service.TaskExecute(ctx, run, nil) taskIDs = append(taskIDs, task.ID) tasks[service.Name()] = task } run := func(ctx types.Context) (interface{}, error) { services.TaskWaitAll(ctx, taskIDs...) for _, v := range tasks { if v.Error != nil { return nil, utils.NewBatchProcessErr(reply, v.Error) } } return reply, nil } return httputils.WriteTask( ctx, r.config, w, store, services.TaskExecute(ctx, run, schema.ServiceVolumeMapSchema), http.StatusResetContent) }
func (r *router) volumeDetachAllForService( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { service := context.MustService(ctx) if _, ok := context.InstanceID(ctx); !ok { return utils.NewMissingInstanceIDError(service.Name()) } var reply types.VolumeMap = map[string]*types.Volume{} run := func( ctx types.Context, svc types.StorageService) (interface{}, error) { driver := svc.Driver() volumes, err := driver.Volumes(ctx, &types.VolumesOpts{Opts: store}) if err != nil { return nil, err } for _, volume := range volumes { v, err := driver.VolumeDetach( ctx, volume.ID, &types.VolumeDetachOpts{ Force: store.GetBool("force"), Opts: store, }) if err != nil { return nil, utils.NewBatchProcessErr(reply, err) } if err != nil { return nil, err } if v == nil { continue } if OnVolume != nil { ok, err := OnVolume(ctx, req, store, v) if err != nil { return nil, err } if !ok { return nil, utils.NewNotFoundError(v.ID) } } if v.AttachmentState == 0 { v.AttachmentState = types.VolumeAvailable } reply[v.ID] = v } return reply, nil } return httputils.WriteTask( ctx, r.config, w, store, service.TaskExecute(ctx, run, schema.VolumeMapSchema), http.StatusResetContent) }
func (r *router) volumes( ctx types.Context, w http.ResponseWriter, req *http.Request, store types.Store) error { filter, err := parseFilter(store) if err != nil { return err } if filter != nil { store.Set("filter", filter) } var ( tasks = map[string]*types.Task{} taskIDs []int opts = &types.VolumesOpts{ Attachments: store.GetAttachments(), Opts: store, } reply = types.ServiceVolumeMap{} ) for service := range services.StorageServices(ctx) { run := func( ctx types.Context, svc types.StorageService) (interface{}, error) { ctx = context.WithStorageService(ctx, svc) var err error if ctx, err = context.WithStorageSession(ctx); err != nil { return nil, err } return getFilteredVolumes(ctx, req, store, svc, opts, filter) } task := service.TaskExecute(ctx, run, schema.VolumeMapSchema) taskIDs = append(taskIDs, task.ID) tasks[service.Name()] = task } run := func(ctx types.Context) (interface{}, error) { services.TaskWaitAll(ctx, taskIDs...) for k, v := range tasks { if v.Error != nil { return nil, utils.NewBatchProcessErr(reply, v.Error) } objMap, ok := v.Result.(types.VolumeMap) if !ok { return nil, utils.NewBatchProcessErr( reply, goof.New("error casting to types.VolumeMap")) } reply[k] = objMap } return reply, nil } return httputils.WriteTask( ctx, r.config, w, store, services.TaskExecute(ctx, run, schema.ServiceVolumeMapSchema), http.StatusOK) }