From 314859538eb01fd2f96931764994e3ed6d75e2b8 Mon Sep 17 00:00:00 2001 From: Vladimir Vivien Date: Wed, 9 Aug 2017 14:55:29 -0400 Subject: [PATCH] ScaleIO - Specify SDC GUID value via node label The commit allow ScaleIO volume plugin to read SDC GUID value as a node label. If binary drv_cfg is not installed, the plugin will still work properly. If node label not found, it defaults to drv_cfg if installed. --- pkg/volume/scaleio/sio_client.go | 34 +++++++++++++++++++------- pkg/volume/scaleio/sio_mgr.go | 16 +----------- pkg/volume/scaleio/sio_util.go | 35 ++++++++++++++++++++++++--- pkg/volume/scaleio/sio_volume.go | 17 +++++++++++++ pkg/volume/scaleio/sio_volume_test.go | 18 +++++++++++++- 5 files changed, 92 insertions(+), 28 deletions(-) diff --git a/pkg/volume/scaleio/sio_client.go b/pkg/volume/scaleio/sio_client.go index ac26868d324..50d7bd11d8b 100644 --- a/pkg/volume/scaleio/sio_client.go +++ b/pkg/volume/scaleio/sio_client.go @@ -74,6 +74,7 @@ type sioClient struct { spClient *sio.StoragePool provisionMode string sdcPath string + sdcGuid string instanceID string inited bool diskRegex *regexp.Regexp @@ -292,28 +293,43 @@ func (c *sioClient) DeleteVolume(id sioVolumeID) error { return nil } +// IID returns the scaleio instance id for node func (c *sioClient) IID() (string, error) { if err := c.init(); err != nil { return "", err } + // if instanceID not set, retrieve it if c.instanceID == "" { + guid, err := c.getGuid() + if err != nil { + return "", err + } + sdc, err := c.sysClient.FindSdc("SdcGuid", guid) + if err != nil { + glog.Error(log("failed to retrieve sdc info %s", err)) + return "", err + } + c.instanceID = sdc.Sdc.ID + glog.V(4).Info(log("retrieved instanceID %s", c.instanceID)) + } + return c.instanceID, nil +} + +// getGuid returns instance GUID, if not set using resource labels +// it attemps to fallback to using drv_cfg binary +func (c *sioClient) getGuid() (string, error) { + if c.sdcGuid == "" { + glog.V(4).Info(log("sdc guid label not set, falling back to using drv_cfg")) cmd := c.getSdcCmd() output, err := c.exec.Run(cmd, "--query_guid") if err != nil { glog.Error(log("drv_cfg --query_guid failed: %v", err)) return "", err } - guid := strings.TrimSpace(string(output)) - sdc, err := c.sysClient.FindSdc("SdcGuid", guid) - if err != nil { - glog.Error(log("failed to get sdc info %s", err)) - return "", err - } - c.instanceID = sdc.Sdc.ID - glog.V(4).Info(log("got instanceID %s", c.instanceID)) + c.sdcGuid = strings.TrimSpace(string(output)) } - return c.instanceID, nil + return c.sdcGuid, nil } // getSioDiskPaths traverse local disk devices to retrieve device path diff --git a/pkg/volume/scaleio/sio_mgr.go b/pkg/volume/scaleio/sio_mgr.go index ecde665a1ac..711fa7fce5d 100644 --- a/pkg/volume/scaleio/sio_mgr.go +++ b/pkg/volume/scaleio/sio_mgr.go @@ -81,6 +81,7 @@ func (m *sioMgr) getClient() (sioInterface, error) { client.spName = configs[confKey.storagePool] client.sdcPath = configs[confKey.sdcRootPath] client.provisionMode = configs[confKey.storageMode] + client.sdcGuid = configs[confKey.sdcGuid] m.client = client @@ -215,23 +216,12 @@ func (m *sioMgr) DeleteVolume(volName string) error { if err != nil { return err } - iid, err := client.IID() - if err != nil { - glog.Error(log("failed to get instanceID: %v", err)) - return err - } vol, err := client.FindVolume(volName) if err != nil { return err } - // if still attached, stop - if m.isSdcMappedToVol(iid, vol) { - glog.Error(log("volume %s still attached, unable to delete", volName)) - return errors.New("volume still attached") - } - if err := client.DeleteVolume(sioVolumeID(vol.ID)); err != nil { glog.Error(log("failed to delete volume %s: %v", volName, err)) return err @@ -242,10 +232,6 @@ func (m *sioMgr) DeleteVolume(volName string) error { } -//***************************************************************** -// Helpers -//***************************************************************** - // isSdcMappedToVol returns true if the sdc is mapped to the volume func (m *sioMgr) isSdcMappedToVol(sdcID string, vol *siotypes.Volume) bool { if len(vol.MappedSdcInfo) == 0 { diff --git a/pkg/volume/scaleio/sio_util.go b/pkg/volume/scaleio/sio_util.go index 194d49e0e80..3c2f13a3405 100644 --- a/pkg/volume/scaleio/sio_util.go +++ b/pkg/volume/scaleio/sio_util.go @@ -47,7 +47,8 @@ var ( readOnly, username, password, - namespace string + namespace, + sdcGuid string }{ gateway: "gateway", sslEnabled: "sslEnabled", @@ -64,9 +65,10 @@ var ( username: "username", password: "password", namespace: "namespace", + sdcGuid: "sdcGuid", } - nsSep = "%" - sdcRootPath = "/opt/emc/scaleio/sdc/bin" + sdcGuidLabelName = "scaleio.sdcGuid" + sdcRootPath = "/opt/emc/scaleio/sdc/bin" secretNotFoundErr = errors.New("secret not found") configMapNotFoundErr = errors.New("configMap not found") @@ -215,6 +217,33 @@ func attachSecret(plug *sioPlugin, namespace string, configData map[string]strin return nil } +// attachSdcGuid injects the sdc guid node label value into config +func attachSdcGuid(plug *sioPlugin, conf map[string]string) error { + guid, err := getSdcGuidLabel(plug) + if err != nil { + return err + } + conf[confKey.sdcGuid] = guid + return nil +} + +// getSdcGuidLabel fetches the scaleio.sdcGuid node label +// associated with the node executing this code. +func getSdcGuidLabel(plug *sioPlugin) (string, error) { + nodeLabels, err := plug.host.GetNodeLabels() + if err != nil { + return "", err + } + label, ok := nodeLabels[sdcGuidLabelName] + if !ok { + glog.V(4).Info(log("node label %s not found", sdcGuidLabelName)) + return "", nil + } + + glog.V(4).Info(log("found node label %s=%s", sdcGuidLabelName, label)) + return label, nil +} + // getVolumeSourceFromSpec safely extracts ScaleIOVolumeSource from spec func getVolumeSourceFromSpec(spec *volume.Spec) (*api.ScaleIOVolumeSource, error) { if spec.Volume != nil && spec.Volume.ScaleIO != nil { diff --git a/pkg/volume/scaleio/sio_volume.go b/pkg/volume/scaleio/sio_volume.go index 079df8f67f9..85e7fb0b43f 100644 --- a/pkg/volume/scaleio/sio_volume.go +++ b/pkg/volume/scaleio/sio_volume.go @@ -386,7 +386,13 @@ func (v *sioVolume) setSioMgr() error { return err } + // merge in Sdc Guid label value + if err := attachSdcGuid(v.plugin, configData); err != nil { + glog.Error(log("failed to retrieve sdc guid: %v", err)) + return err + } mgr, err := newSioMgr(configData, v.plugin.host.GetExec(v.plugin.GetPluginName())) + if err != nil { glog.Error(log("failed to reset sio manager: %v", err)) return err @@ -418,7 +424,14 @@ func (v *sioVolume) resetSioMgr() error { return err } + // merge in Sdc Guid label value + if err := attachSdcGuid(v.plugin, configData); err != nil { + glog.Error(log("failed to retrieve sdc guid: %v", err)) + return err + } + mgr, err := newSioMgr(configData, v.plugin.host.GetExec(v.plugin.GetPluginName())) + if err != nil { glog.Error(log("failed to reset scaleio mgr: %v", err)) return err @@ -453,6 +466,7 @@ func (v *sioVolume) setSioMgrFromConfig() error { } mgr, err := newSioMgr(data, v.plugin.host.GetExec(v.plugin.GetPluginName())) + if err != nil { glog.Error(log("failed while setting scaleio mgr from config: %v", err)) return err @@ -462,6 +476,8 @@ func (v *sioVolume) setSioMgrFromConfig() error { return nil } +// setSioMgrFromSpec sets the scaleio manager from a spec object. +// The spec may be complete or incomplete depending on lifecycle phase. func (v *sioVolume) setSioMgrFromSpec() error { glog.V(4).Info(log("setting sio manager from spec")) if v.sioMgr == nil { @@ -482,6 +498,7 @@ func (v *sioVolume) setSioMgrFromSpec() error { } mgr, err := newSioMgr(configData, v.plugin.host.GetExec(v.plugin.GetPluginName())) + if err != nil { glog.Error(log("failed to reset sio manager: %v", err)) return err diff --git a/pkg/volume/scaleio/sio_volume_test.go b/pkg/volume/scaleio/sio_volume_test.go index b83be41828e..ad2f75475b8 100644 --- a/pkg/volume/scaleio/sio_volume_test.go +++ b/pkg/volume/scaleio/sio_volume_test.go @@ -60,8 +60,14 @@ func newPluginMgr(t *testing.T) (*volume.VolumePluginMgr, string) { "password": []byte("password"), }, } + fakeClient := fakeclient.NewSimpleClientset(config) - host := volumetest.NewFakeVolumeHost(tmpDir, fakeClient, nil) + host := volumetest.NewFakeVolumeHostWithNodeLabels( + tmpDir, + fakeClient, + nil, + map[string]string{sdcGuidLabelName: "abc-123"}, + ) plugMgr := &volume.VolumePluginMgr{} plugMgr.InitPlugins(ProbeVolumePlugins(), nil /* prober */, host) @@ -195,6 +201,11 @@ func TestVolumeMounterUnmounter(t *testing.T) { t.Errorf("SetUp() - expecting multiple volume disabled by default") } + // did we read sdcGuid label + if _, ok := sioVol.sioMgr.configData[confKey.sdcGuid]; !ok { + t.Errorf("Expected to find node label scaleio.sdcGuid, but did not find it") + } + // rebuild spec builtSpec, err := sioPlug.ConstructVolumeSpec(volume.NewSpecFromVolume(vol).Name(), path) if err != nil { @@ -322,6 +333,11 @@ func TestVolumeProvisioner(t *testing.T) { t.Fatalf("Expected success, got: %v", err) } + // did we read sdcGuid label + if _, ok := sioVol.sioMgr.configData[confKey.sdcGuid]; !ok { + t.Errorf("Expected to find node label scaleio.sdcGuid, but did not find it") + } + // isMultiMap applied if !sio.isMultiMap { t.Errorf("SetUp() expecting attached volume with multi-mapping")