func TestVolumeAttach(t *testing.T) { tf := func(config gofig.Config, client types.Client, t *testing.T) { nextDevice, err := client.Executor().NextDevice( context.Background().WithValue(context.ServiceKey, vfs.Name), utils.NewStore()) assert.NoError(t, err) if err != nil { t.FailNow() } request := &types.VolumeAttachRequest{ NextDeviceName: &nextDevice, } reply, attTokn, err := client.API().VolumeAttach( nil, vfs.Name, "vfs-002", request) assert.NoError(t, err) if reply == nil { t.FailNow() } assert.Equal(t, "/dev/xvdc", attTokn) assert.Equal(t, "vfs-002", reply.ID) assert.Equal(t, "/dev/xvdc", reply.Attachments[0].DeviceName) } apitests.Run(t, vfs.Name, newTestConfig(t), tf) }
func (d *driver) VolumeAttach( ctx types.Context, volumeID string, opts *types.VolumeAttachOpts) (*types.Volume, string, error) { if d.isController() { return nil, "", utils.NewUnsupportedForClientTypeError( d.clientType, "VolumeAttach") } ctx = d.requireCtx(ctx) serviceName, ok := context.ServiceName(ctx) if !ok { return nil, "", goof.New("missing service name") } nextDevice, err := d.NextDevice(ctx, utils.NewStore()) if err != nil { return nil, "", err } var nextDevicePtr *string if nextDevice != "" { nextDevicePtr = &nextDevice } req := &types.VolumeAttachRequest{ NextDeviceName: nextDevicePtr, Force: opts.Force, Opts: opts.Opts.Map(), } return d.client.VolumeAttach(ctx, serviceName, volumeID, req) }
// Test volume attachment by volume ID func volumeAttach( t *testing.T, client types.Client, volumeID string) *types.Volume { log.WithField("volumeID", volumeID).Info("attaching volume") // Get next device name from executor nextDevice, err := client.Executor().NextDevice(context.Background().WithValue(context.ServiceKey, ebs.Name), utils.NewStore()) assert.NoError(t, err) if err != nil { t.Error("error getting next device name from executor") t.FailNow() } reply, token, err := client.API().VolumeAttach( nil, ebs.Name, volumeID, &types.VolumeAttachRequest{ NextDeviceName: &nextDevice, }) assert.NoError(t, err) if err != nil { t.Error("failed volumeAttach") t.FailNow() } apitests.LogAsJSON(reply, t) assert.NotEqual(t, token, "") return reply }
// Test is the APITestFunc for the NextDeviceTest. func (tt *NextDeviceTest) Test( config gofig.Config, client types.Client, t *testing.T) { ctx := context.Background().WithValue(context.ServiceKey, tt.Driver) val, err := client.Executor().NextDevice(ctx, utils.NewStore()) assert.NoError(t, err) assert.Equal(t, tt.Expected, val) }
func (c *client) dial(ctx types.Context) error { ctx.WithField("path", lsxMutex).Info("lsx lock file path") svcInfos, err := c.Services(ctx) if err != nil { return err } // controller clients do not have any additional dialer logic if c.isController() { return nil } store := utils.NewStore() c.ctx = c.ctx.WithValue(context.ServerKey, c.ServerName()) if !c.config.GetBool(types.ConfigExecutorNoDownload) { ctx.Info("initializing executors cache") if _, err := c.Executors(ctx); err != nil { return err } if err := c.updateExecutor(ctx); err != nil { return err } } for service, _ := range svcInfos { ctx := c.ctx.WithValue(context.ServiceKey, service) ctx.Info("initializing supported cache") supported, err := c.Supported(ctx, store) if err != nil { return goof.WithError("error initializing supported cache", err) } if !supported { ctx.Warn("executor not supported") continue } ctx.Info("initializing instance ID cache") if _, err := c.InstanceID(ctx, store); err != nil { if err == types.ErrNotImplemented { ctx.WithError(err).Warn("cannot get instance ID") continue } return goof.WithError("error initializing instance ID cache", err) } } return nil }
func TestClient(t *testing.T) { apitests.Run(t, vfs.Name, newTestConfig(t), func(config gofig.Config, client types.Client, t *testing.T) { ctx := context.Background() iid, err := client.Executor().InstanceID( ctx.WithValue(context.ServiceKey, vfs.Name), utils.NewStore()) assert.NoError(t, err) assert.NotNil(t, iid) }) }
func TestStorageDriverVolumes(t *testing.T) { apitests.Run(t, vfs.Name, newTestConfig(t), func(config gofig.Config, client types.Client, t *testing.T) { vols, err := client.Storage().Volumes( context.Background().WithValue( context.ServiceKey, vfs.Name), &types.VolumesOpts{ Attachments: types.VolAttReqTrue, Opts: utils.NewStore()}) assert.NoError(t, err) assert.Len(t, vols, 2) }) }
func TestVolumeAttachWithControllerClient(t *testing.T) { tf := func(config gofig.Config, client types.Client, t *testing.T) { _, err := client.Executor().NextDevice( context.Background().WithValue(context.ServiceKey, vfs.Name), utils.NewStore()) assert.Error(t, err) assert.Equal(t, "unsupported op for client type", err.Error()) _, _, err = client.API().VolumeAttach( nil, vfs.Name, "vfs-002", &types.VolumeAttachRequest{}) assert.Error(t, err) assert.Equal(t, "unsupported op for client type", err.Error()) } apitests.RunWithClientType( t, types.ControllerClient, vfs.Name, newTestConfig(t), tf) }
// Test is the APITestFunc for the InstanceTest. func (tt *InstanceTest) Test( config gofig.Config, client types.Client, t *testing.T) { expectedBuf, err := json.Marshal(tt.Expected) assert.NoError(t, err) expectedJSON := string(expectedBuf) ctx := context.Background().WithValue(context.ServiceKey, tt.Driver) iid, err := client.Storage().InstanceInspect(ctx, utils.NewStore()) assert.NoError(t, err) iidBuf, err := json.Marshal(iid) assert.NoError(t, err) iidJSON := string(iidBuf) assert.Equal(t, expectedJSON, iidJSON) }
// Check if InstanceID metadata is properly returned by executor // and InstanceID.ID is filled out by InstanceInspect func TestInstanceID(t *testing.T) { if skipTests() { t.SkipNow() } // create storage driver sd, err := registry.NewStorageDriver(ebs.Name) if err != nil { t.Fatal(err) } // initialize storage driver ctx := context.Background() if err := sd.Init(ctx, registry.NewConfig()); err != nil { t.Fatal(err) } // Get Instance ID metadata from executor iid, err := ebsUtils.InstanceID(ctx) assert.NoError(t, err) if err != nil { t.Fatal(err) } // Fill in Instance ID's ID field with InstanceInspect ctx = ctx.WithValue(context.InstanceIDKey, iid) i, err := sd.InstanceInspect(ctx, utils.NewStore()) if err != nil { t.Fatal(err) } iid = i.InstanceID // test resulting InstanceID apitests.Run( t, ebs.Name, nil, (&apitests.InstanceIDTest{ Driver: ebs.Name, Expected: iid, }).Test) }
func TestInstanceID(t *testing.T) { //PASSES lowercase hidden for testing other stuff if skipTests() { t.SkipNow() } sd, err := registry.NewStorageDriver(rackspace.Name) if err != nil { t.Fatal(err) } ctx := context.Background() configR := registry.NewConfig() if err := configR.ReadConfig(bytes.NewReader(configYAML)); err != nil { panic(err) } if err := sd.Init(ctx, configR); err != nil { t.Fatal(err) } iid, err := rackspacex.InstanceID(configR) if err != nil { t.Fatal(err) } ctx = ctx.WithValue(context.InstanceIDKey, iid) i, err := sd.InstanceInspect(ctx, utils.NewStore()) if err != nil { t.Fatal(err) } iid = i.InstanceID apitests.Run( t, rackspace.Name, configYAML, (&apitests.InstanceIDTest{ Driver: rackspace.Name, Expected: iid, }).Test) }
func TestInstanceID(t *testing.T) { if skipTests() { t.SkipNow() } sd, err := registry.NewStorageDriver(efs.Name) if err != nil { t.Fatal(err) } ctx := context.Background() if err := sd.Init(ctx, registry.NewConfig()); err != nil { t.Fatal(err) } iid, err := efsx.InstanceID() assert.NoError(t, err) if err != nil { t.Error("failed TestInstanceID") t.FailNow() } assert.NotEqual(t, iid, "") ctx = ctx.WithValue(context.InstanceIDKey, iid) i, err := sd.InstanceInspect(ctx, utils.NewStore()) if err != nil { t.Fatal(err) } iid = i.InstanceID apitests.Run( t, efs.Name, configYAML, (&apitests.InstanceIDTest{ Driver: efs.Name, Expected: iid, }).Test) }
// Test is the APITestFunc for the LocalDevicesTest. func (tt *LocalDevicesTest) Test( config gofig.Config, client types.Client, t *testing.T) { expectedBuf, err := tt.Expected.MarshalText() assert.NoError(t, err) expectedText := string(expectedBuf) ctx := context.Background().WithValue(context.ServiceKey, tt.Driver) val, err := client.Executor().LocalDevices(ctx, &types.LocalDevicesOpts{ ScanType: types.DeviceScanQuick, Opts: utils.NewStore(), }) assert.NoError(t, err) buf, err := val.MarshalText() assert.NoError(t, err) actualText := string(buf) assert.Equal(t, expectedText, actualText) }
// Mount will return a mount point path when specifying either a volumeName // or volumeID. If a overwriteFs boolean is specified it will overwrite // the FS based on newFsType if it is detected that there is no FS present. func (d *driver) Mount( ctx types.Context, volumeID, volumeName string, opts *types.VolumeMountOpts) (string, *types.Volume, error) { ctx.WithFields(log.Fields{ "volumeName": volumeName, "volumeID": volumeID, "opts": opts}).Info("mounting volume") vol, err := d.volumeInspectByIDOrName( ctx, volumeID, volumeName, types.VolAttReqWithDevMapOnlyVolsAttachedToInstanceOrUnattachedVols, opts.Opts) if isErrNotFound(err) && d.volumeCreateImplicit() { var err error if vol, err = d.Create(ctx, volumeName, &types.VolumeCreateOpts{ Opts: utils.NewStore(), }); err != nil { return "", nil, goof.WithError( "problem creating volume implicitly", err) } } else if err != nil { return "", nil, err } if vol == nil { return "", nil, goof.New("no volume returned or created") } client := context.MustClient(ctx) if len(vol.Attachments) == 0 || opts.Preempt { mp, err := d.getVolumeMountPath(vol.Name) if err != nil { return "", nil, err } ctx.Debug("performing precautionary unmount") _ = client.OS().Unmount(ctx, mp, opts.Opts) var token string vol, token, err = client.Storage().VolumeAttach( ctx, vol.ID, &types.VolumeAttachOpts{ Force: opts.Preempt, Opts: utils.NewStore(), }) if err != nil { return "", nil, err } if token != "" { opts := &types.WaitForDeviceOpts{ LocalDevicesOpts: types.LocalDevicesOpts{ ScanType: apiconfig.DeviceScanType(d.config), Opts: opts.Opts, }, Token: token, Timeout: apiconfig.DeviceAttachTimeout(d.config), } _, _, err = client.Executor().WaitForDevice(ctx, opts) if err != nil { return "", nil, goof.WithError( "problem with device discovery", err) } } vol, err = d.volumeInspectByIDOrName( ctx, vol.ID, "", types.VolAttReqTrue, opts.Opts) if err != nil { return "", nil, err } } if len(vol.Attachments) == 0 { return "", nil, goof.New("volume did not attach") } 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 local attachment found") } if ma.DeviceName == "" { return "", nil, goof.New("no device name returned") } mounts, err := client.OS().Mounts( ctx, ma.DeviceName, "", opts.Opts) if err != nil { return "", nil, err } if len(mounts) > 0 { return d.volumeMountPath(mounts[0].MountPoint), vol, nil } if opts.NewFSType == "" { opts.NewFSType = d.fsType() } if err := client.OS().Format( ctx, ma.DeviceName, &types.DeviceFormatOpts{ NewFSType: opts.NewFSType, OverwriteFS: opts.OverwriteFS, }); err != nil { return "", nil, err } mountPath, err := d.getVolumeMountPath(vol.Name) if err != nil { return "", nil, err } if err := os.MkdirAll(mountPath, 0755); err != nil { return "", nil, err } if err := client.OS().Mount( ctx, ma.DeviceName, mountPath, &types.DeviceMountOpts{}); err != nil { return "", nil, err } mntPath := d.volumeMountPath(mountPath) fields := log.Fields{ "vol": vol, "mntPath": mntPath, } ctx.WithFields(fields).Info("volume mounted") return mntPath, vol, nil }
func store() apitypes.Store { return apiutils.NewStore() }
func (m *mod) buildMux() *http.ServeMux { mux := http.NewServeMux() // m.ctx.WithServiceName(m.ctx.ServiceName()) mux.HandleFunc("/Plugin.Activate", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1.2+json") fmt.Fprintln(w, `{"Implements": ["VolumeDriver"]}`) m.ctx.Debug("/Plugin.Activate") }) mux.HandleFunc("/VolumeDriver.Create", func(w http.ResponseWriter, r *http.Request) { var pr pluginRequest if err := json.NewDecoder(r.Body).Decode(&pr); err != nil { http.Error(w, fmt.Sprintf("{\"Error\":\"%s\"}", err.Error()), 500) m.ctx.WithError(err).Error("/VolumeDriver.Create: error decoding json") return } m.ctx.WithField("pluginResponse", pr).Debug("/VolumeDriver.Create") store := apiutils.NewStoreWithVars(pr.Opts) vtype := store.GetStringPtr("type") if vtype == nil { vtype = store.GetStringPtr("volumetype") } _, err := m.lsc.Integration().Create( m.ctx, pr.Name, &apitypes.VolumeCreateOpts{ AvailabilityZone: store.GetStringPtr("availabilityZone"), IOPS: store.GetInt64Ptr("iops"), Size: store.GetInt64Ptr("size"), Type: vtype, Opts: store, }) if err != nil { http.Error(w, fmt.Sprintf("{\"Error\":\"%s\"}", err.Error()), 500) m.ctx.WithError(err).Error("/VolumeDriver.Create: error creating volume") return } w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1.2+json") fmt.Fprintln(w, `{}`) }) mux.HandleFunc("/VolumeDriver.Remove", func(w http.ResponseWriter, r *http.Request) { var pr pluginRequest if err := json.NewDecoder(r.Body).Decode(&pr); err != nil { http.Error(w, fmt.Sprintf("{\"Error\":\"%s\"}", err.Error()), 500) m.ctx.WithError(err).Error("/VolumeDriver.Remove: error decoding json") return } m.ctx.WithField("pluginResponse", pr).Debug("/VolumeDriver.Remove") // TODO We need the service name err := m.lsc.Integration().Remove(m.ctx, pr.Name, apiutils.NewStore()) if err != nil { http.Error(w, fmt.Sprintf("{\"Error\":\"%s\"}", err.Error()), 500) m.ctx.WithError(err).Error("/VolumeDriver.Remove: error removing volume") return } w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1.2+json") fmt.Fprintln(w, `{}`) }) mux.HandleFunc("/VolumeDriver.Path", func(w http.ResponseWriter, r *http.Request) { var pr pluginRequest if err := json.NewDecoder(r.Body).Decode(&pr); err != nil { http.Error(w, fmt.Sprintf("{\"Error\":\"%s\"}", err.Error()), 500) m.ctx.WithError(err).Error("/VolumeDriver.Path: error decoding json") return } m.ctx.WithField("pluginResponse", pr).Debug("/VolumeDriver.Path") mountPath, err := m.lsc.Integration().Path( m.ctx, "", pr.Name, apiutils.NewStore()) if err != nil { http.Error(w, fmt.Sprintf("{\"Error\":\"%s\"}", err.Error()), 500) m.ctx.WithError(err).Error("/VolumeDriver.Path: error returning path") return } w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1.2+json") fmt.Fprintln(w, fmt.Sprintf("{\"Mountpoint\": \"%s\"}", mountPath)) }) mux.HandleFunc("/VolumeDriver.Mount", func(w http.ResponseWriter, r *http.Request) { var pr pluginRequest if err := json.NewDecoder(r.Body).Decode(&pr); err != nil { http.Error(w, fmt.Sprintf("{\"Error\":\"%s\"}", err.Error()), 500) m.ctx.WithError(err).Error("/VolumeDriver.Mount: error decoding json") return } m.ctx.WithField("pluginResponse", pr).Debug("/VolumeDriver.Mount") mountPath, _, err := m.lsc.Integration().Mount( m.ctx, "", pr.Name, &apitypes.VolumeMountOpts{}) if err != nil { http.Error(w, fmt.Sprintf("{\"Error\":\"%s\"}", err.Error()), 500) m.ctx.WithError(err).Error("/VolumeDriver.Mount: error mounting volume") return } w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1.2+json") fmt.Fprintln(w, fmt.Sprintf("{\"Mountpoint\": \"%s\"}", mountPath)) }) mux.HandleFunc("/VolumeDriver.Unmount", func(w http.ResponseWriter, r *http.Request) { var pr pluginRequest if err := json.NewDecoder(r.Body).Decode(&pr); err != nil { http.Error(w, fmt.Sprintf("{\"Error\":\"%s\"}", err.Error()), 500) m.ctx.WithError(err).Error("/VolumeDriver.Unmount: error decoding json") return } m.ctx.WithField("pluginResponse", pr).Debug("/VolumeDriver.Unmount") _, err := m.lsc.Integration().Unmount( m.ctx, "", pr.Name, apiutils.NewStore()) if err != nil { http.Error(w, fmt.Sprintf("{\"Error\":\"%s\"}", err.Error()), 500) m.ctx.WithError(err).Error("/VolumeDriver.Unmount: error unmounting volume") return } w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1.2+json") fmt.Fprintln(w, `{}`) }) mux.HandleFunc("/VolumeDriver.Get", func(w http.ResponseWriter, r *http.Request) { var pr pluginRequest if err := json.NewDecoder(r.Body).Decode(&pr); err != nil { http.Error(w, fmt.Sprintf("{\"Error\":\"%s\"}", err.Error()), 500) m.ctx.WithError(err).Error("/VolumeDriver.Get: error decoding json") return } m.ctx.WithField("pluginResponse", pr).Debug("/VolumeDriver.Get") volMapping, err := m.lsc.Integration().Inspect( m.ctx, pr.Name, apiutils.NewStore()) if err != nil { http.Error(w, fmt.Sprintf("{\"Error\":\"%s\"}", err.Error()), 500) m.ctx.WithError(err).Error("/VolumeDriver.Get: error getting volume") return } w.Header().Set( "Content-Type", "application/vnd.docker.plugins.v1.2+json") json.NewEncoder(w).Encode(map[string]apitypes.VolumeMapping{ "Volume": volMapping, }) }) mux.HandleFunc("/VolumeDriver.List", func(w http.ResponseWriter, r *http.Request) { var pr pluginRequest if err := json.NewDecoder(r.Body).Decode(&pr); err != nil { http.Error(w, fmt.Sprintf("{\"Error\":\"%s\"}", err.Error()), 500) m.ctx.WithError(err).Error("/VolumeDriver.List: error decoding json") return } m.ctx.WithField("pluginResponse", pr).Debug("/VolumeDriver.List") volMappings, err := m.lsc.Integration().List(m.ctx, apiutils.NewStore()) if err != nil { http.Error(w, fmt.Sprintf("{\"Error\":\"%s\"}", err.Error()), 500) m.ctx.WithError(err).Error("/VolumeDriver.List: error listing volumes") return } w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1.2+json") json.NewEncoder(w).Encode( map[string][]apitypes.VolumeMapping{"Volumes": volMappings}) }) mux.HandleFunc("/VolumeDriver.Capabilities", func(w http.ResponseWriter, r *http.Request) { var pr pluginRequest if err := json.NewDecoder(r.Body).Decode(&pr); err != nil { http.Error(w, fmt.Sprintf("{\"Error\":\"%s\"}", err.Error()), 500) m.ctx.WithError(err).Error("/VolumeDriver.Capabilities: error decoding json") return } m.ctx.WithField("pluginResponse", pr).Debug("/VolumeDriver.Capabilities") w.Header().Set("Content-Type", "application/vnd.docker.plugins.v1.2+json") fmt.Fprintln(w, `{"Capabilities": { "Scope": "global" }}`) }) return mux }
// 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 }
// Run runs the executor CLI. func Run() { args := os.Args if len(args) < 3 { printUsageAndExit() } d, err := registry.NewStorageExecutor(args[1]) if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } driverName := strings.ToLower(d.Name()) config, err := apiconfig.NewConfig() if err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } apiconfig.UpdateLogLevel(config) ctx := context.Background() if err := d.Init(ctx, config); err != nil { fmt.Fprintf(os.Stderr, "error: %v\n", err) os.Exit(1) } cmd := cmdRx.FindString(args[2]) if cmd == "" { printUsageAndExit() } store := utils.NewStore() var ( result interface{} op string exitCode int ) if strings.EqualFold(cmd, apitypes.LSXCmdSupported) { op = "supported" if dws, ok := d.(apitypes.StorageExecutorWithSupported); ok { opResult, opErr := dws.Supported(ctx, store) if opErr != nil { err = opErr } else { result = opResult } } else { err = apitypes.ErrNotImplemented } } else if strings.EqualFold(cmd, apitypes.LSXCmdInstanceID) { op = "instance ID" opResult, opErr := d.InstanceID(ctx, store) if opErr != nil { err = opErr } else { opResult.Driver = driverName result = opResult } } else if strings.EqualFold(cmd, apitypes.LSXCmdNextDevice) { op = "next device" opResult, opErr := d.NextDevice(ctx, store) if opErr != nil && opErr != apitypes.ErrNotImplemented { err = opErr } else { result = opResult } } else if strings.EqualFold(cmd, apitypes.LSXCmdLocalDevices) { if len(args) < 4 { printUsageAndExit() } op = "local devices" opResult, opErr := d.LocalDevices(ctx, &apitypes.LocalDevicesOpts{ ScanType: apitypes.ParseDeviceScanType(args[3]), Opts: store, }) opResult.Driver = driverName if opErr != nil { err = opErr } else { result = opResult } } else if strings.EqualFold(cmd, apitypes.LSXCmdWaitForDevice) { if len(args) < 5 { printUsageAndExit() } op = "wait" opts := &apitypes.WaitForDeviceOpts{ LocalDevicesOpts: apitypes.LocalDevicesOpts{ ScanType: apitypes.ParseDeviceScanType(args[3]), Opts: store, }, Token: strings.ToLower(args[4]), Timeout: utils.DeviceAttachTimeout(args[5]), } ldl := func() (bool, *apitypes.LocalDevices, error) { ldm, err := d.LocalDevices(ctx, &opts.LocalDevicesOpts) if err != nil { return false, nil, err } for k := range ldm.DeviceMap { if strings.ToLower(k) == opts.Token { return true, ldm, nil } } return false, ldm, nil } var ( found bool opErr error opResult *apitypes.LocalDevices timeoutC = time.After(opts.Timeout) tick = time.Tick(500 * time.Millisecond) ) TimeoutLoop: for { select { case <-timeoutC: exitCode = apitypes.LSXExitCodeTimedOut break TimeoutLoop case <-tick: if found, opResult, opErr = ldl(); found || opErr != nil { break TimeoutLoop } } } if opErr != nil { err = opErr } else { opResult.Driver = driverName result = opResult } } if err != nil { // if the function is not implemented then exit with // apitypes.LSXExitCodeNotImplemented to let callers // know that the function is unsupported on this system exitCode = 1 if strings.EqualFold(err.Error(), apitypes.ErrNotImplemented.Error()) { exitCode = apitypes.LSXExitCodeNotImplemented } fmt.Fprintf(os.Stderr, "error: error getting %s: %v\n", op, err) os.Exit(exitCode) } switch tr := result.(type) { case bool: fmt.Fprintf(os.Stdout, "%v", result) case string: fmt.Fprintln(os.Stdout, result) case encoding.TextMarshaler: buf, err := tr.MarshalText() if err != nil { fmt.Fprintf(os.Stderr, "error: error encoding %s: %v\n", op, err) os.Exit(1) } os.Stdout.Write(buf) default: buf, err := json.Marshal(result) if err != nil { fmt.Fprintf(os.Stderr, "error: error encoding %s: %v\n", op, err) os.Exit(1) } if isNullBuf(buf) { os.Stdout.Write(emptyJSONBuff) } else { os.Stdout.Write(buf) } } os.Exit(exitCode) }
func (d *driver) Init(ctx types.Context, config gofig.Config) error { logFields := log.Fields{} addr := config.GetString(types.ConfigHost) d.ctx = ctx.WithValue(context.HostKey, addr) d.ctx.Debug("got configured host address") proto, lAddr, err := gotil.ParseAddress(addr) if err != nil { return err } tlsConfig, err := utils.ParseTLSConfig( config, logFields, "libstorage.client") if err != nil { return err } host := getHost(proto, lAddr, tlsConfig) lsxPath := config.GetString(types.ConfigExecutorPath) cliType := types.ParseClientType(config.GetString(types.ConfigClientType)) disableKeepAlive := config.GetBool(types.ConfigHTTPDisableKeepAlive) logFields["host"] = host logFields["lsxPath"] = lsxPath logFields["clientType"] = cliType logFields["disableKeepAlive"] = disableKeepAlive httpTransport := &http.Transport{ Dial: func(string, string) (net.Conn, error) { if tlsConfig == nil { return net.Dial(proto, lAddr) } return tls.Dial(proto, lAddr, tlsConfig) }, DisableKeepAlives: disableKeepAlive, } apiClient := apiclient.New(host, httpTransport) logReq := config.GetBool(types.ConfigLogHTTPRequests) logRes := config.GetBool(types.ConfigLogHTTPResponses) apiClient.LogRequests(logReq) apiClient.LogResponses(logRes) logFields["enableInstanceIDHeaders"] = EnableInstanceIDHeaders logFields["enableLocalDevicesHeaders"] = EnableLocalDevicesHeaders logFields["logRequests"] = logReq logFields["logResponses"] = logRes d.client = client{ APIClient: apiClient, ctx: ctx, config: config, clientType: cliType, serviceCache: &lss{Store: utils.NewStore()}, } if d.clientType == types.IntegrationClient { newIIDCache := utils.NewStore dur, err := time.ParseDuration( config.GetString(types.ConfigClientCacheInstanceID)) if err != nil { logFields["iidCacheDuration"] = dur.String() newIIDCache = func() types.Store { return utils.NewTTLStore(dur, true) } } d.lsxCache = &lss{Store: utils.NewStore()} d.supportedCache = utils.NewStore() d.instanceIDCache = &lss{Store: newIIDCache()} } d.ctx.WithFields(logFields).Info("created libStorage client") if err := d.dial(ctx); err != nil { return err } d.ctx.Info("successefully dialed libStorage server") return nil }