Skip to content

Commit b74b010

Browse files
committed
Implement bindings for CNS Unregister Volume
Created new method called CnsUnregisterVolume Created CnsUnregisterVolume, CnsUnregisterVolumeRequestType and CnsUnregisterVolumeResponse types Created UnregisterVolume method on CNS Client Created TestUnregisterVolume function to test the changes Signed-off-by: Satyanarayana Kolluri <[email protected]>
1 parent f12361c commit b74b010

File tree

5 files changed

+217
-0
lines changed

5 files changed

+217
-0
lines changed

cns/client.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,3 +320,17 @@ func (c *Client) SyncVolume(ctx context.Context, syncSpecs []cnstypes.CnsSyncVol
320320
}
321321
return object.NewTask(c.vim25Client, res.Returnval), nil
322322
}
323+
324+
// UnregisterVolume calls the CNS UnregisterVolume API
325+
func (c *Client) UnregisterVolume(ctx context.Context, spec []cnstypes.CnsUnregisterVolumeSpec) (*object.Task, error) {
326+
req := cnstypes.CnsUnregisterVolume{
327+
This: CnsVolumeManagerInstance,
328+
UnregisterSpec: spec,
329+
}
330+
331+
res, err := methods.CnsUnregisterVolume(ctx, c, &req)
332+
if err != nil {
333+
return nil, err
334+
}
335+
return object.NewTask(c.vim25Client, res.Returnval), nil
336+
}

cns/client_test.go

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,6 +1794,148 @@ func TestClient(t *testing.T) {
17941794

17951795
}
17961796

1797+
func TestUnregisterVolume(t *testing.T) {
1798+
ctx := context.Background()
1799+
// Setup: create a CNS client and a volume to unregister
1800+
url := os.Getenv("CNS_VC_URL")
1801+
if url == "" {
1802+
t.Skip("CNS_VC_URL is not set")
1803+
}
1804+
datacenter := os.Getenv("CNS_DATACENTER")
1805+
datastore := os.Getenv("CNS_DATASTORE")
1806+
u, err := soap.ParseURL(url)
1807+
if err != nil {
1808+
t.Fatal(err)
1809+
}
1810+
c, err := govmomi.NewClient(ctx, u, true)
1811+
if err != nil {
1812+
t.Fatal(err)
1813+
}
1814+
1815+
if !isvSphereVersion91orAbove(context.Background(), c.ServiceContent.About) {
1816+
t.Skip("This test requires vSphere 9.1 or above")
1817+
}
1818+
1819+
cnsClient, err := NewClient(ctx, c.Client)
1820+
if err != nil {
1821+
t.Fatal(err)
1822+
}
1823+
finder := find.NewFinder(cnsClient.vim25Client, false)
1824+
dc, err := finder.Datacenter(ctx, datacenter)
1825+
if err != nil {
1826+
t.Fatal(err)
1827+
}
1828+
finder.SetDatacenter(dc)
1829+
ds, err := finder.Datastore(ctx, datastore)
1830+
if err != nil {
1831+
t.Fatal(err)
1832+
}
1833+
1834+
props := []string{"info", "summary"}
1835+
pc := property.DefaultCollector(c.Client)
1836+
var dsSummaries []mo.Datastore
1837+
err = pc.Retrieve(ctx, []vim25types.ManagedObjectReference{ds.Reference()}, props, &dsSummaries)
1838+
if err != nil {
1839+
t.Fatal(err)
1840+
}
1841+
1842+
var dsList []vim25types.ManagedObjectReference
1843+
dsList = append(dsList, ds.Reference())
1844+
1845+
var containerClusterArray []cnstypes.CnsContainerCluster
1846+
containerCluster := cnstypes.CnsContainerCluster{
1847+
ClusterType: string(cnstypes.CnsClusterTypeKubernetes),
1848+
ClusterId: "demo-cluster-id",
1849+
VSphereUser: "[email protected]",
1850+
ClusterFlavor: string(cnstypes.CnsClusterFlavorVanilla),
1851+
ClusterDistribution: "OpenShift",
1852+
}
1853+
containerClusterArray = append(containerClusterArray, containerCluster)
1854+
1855+
// Test CreateVolume API
1856+
volumeName := "pvc-" + uuid.New().String()
1857+
var cnsVolumeCreateSpecList []cnstypes.CnsVolumeCreateSpec
1858+
cnsVolumeCreateSpec := cnstypes.CnsVolumeCreateSpec{
1859+
Name: volumeName,
1860+
VolumeType: string(cnstypes.CnsVolumeTypeBlock),
1861+
Metadata: cnstypes.CnsVolumeMetadata{
1862+
ContainerCluster: containerCluster,
1863+
},
1864+
BackingObjectDetails: &cnstypes.CnsBlockBackingDetails{
1865+
CnsBackingObjectDetails: cnstypes.CnsBackingObjectDetails{
1866+
CapacityInMb: 5120,
1867+
},
1868+
},
1869+
Datastores: dsList,
1870+
}
1871+
1872+
cnsVolumeCreateSpecList = append(cnsVolumeCreateSpecList, cnsVolumeCreateSpec)
1873+
1874+
createTask, err := cnsClient.CreateVolume(ctx, cnsVolumeCreateSpecList)
1875+
if err != nil {
1876+
t.Errorf("Failed to create volume. Error: %+v \n", err)
1877+
t.Fatal(err)
1878+
}
1879+
createTaskInfo, err := GetTaskInfo(ctx, createTask)
1880+
if err != nil {
1881+
t.Errorf("Failed to create volume. Error: %+v \n", err)
1882+
t.Fatal(err)
1883+
}
1884+
createTaskResult, err := GetTaskResult(ctx, createTaskInfo)
1885+
if err != nil {
1886+
t.Errorf("Failed to create volume. Error: %+v \n", err)
1887+
t.Fatal(err)
1888+
}
1889+
if createTaskResult == nil {
1890+
t.Fatalf("Empty create task results")
1891+
t.FailNow()
1892+
}
1893+
createVolumeOperationRes := createTaskResult.GetCnsVolumeOperationResult()
1894+
if createVolumeOperationRes.Fault != nil {
1895+
if cnsFault, ok := createVolumeOperationRes.Fault.Fault.(*cnstypes.CnsFault); ok {
1896+
if cause := cnsFault.FaultCause; cause != nil {
1897+
if inner, ok := cause.Fault.(*vim25types.NotSupported); ok {
1898+
t.Logf("Caught NotSupported fault: %q", cause.LocalizedMessage)
1899+
} else {
1900+
t.Logf("Inner fault type: %T", inner)
1901+
}
1902+
}
1903+
}
1904+
t.Fatalf("Failed to create volume: fault=%+v", createVolumeOperationRes.Fault)
1905+
}
1906+
volumeId := createVolumeOperationRes.VolumeId.Id
1907+
volumeCreateResult := (createTaskResult).(*cnstypes.CnsVolumeCreateResult)
1908+
t.Logf("volumeCreateResult %+v", volumeCreateResult)
1909+
t.Logf("Volume created successfully. volumeId: %s", volumeId)
1910+
1911+
spec := []cnstypes.CnsUnregisterVolumeSpec{
1912+
{
1913+
VolumeId: cnstypes.CnsVolumeId{Id: volumeId},
1914+
TargetVolumeType: string(cnstypes.CnsUnregisterTargetVolumeTypeFCD),
1915+
},
1916+
}
1917+
task, err := cnsClient.UnregisterVolume(ctx, spec)
1918+
if err != nil {
1919+
t.Fatalf("UnregisterVolume failed: %+v", err)
1920+
}
1921+
taskInfo, err := GetTaskInfo(ctx, task)
1922+
if err != nil {
1923+
t.Fatalf("GetTaskInfo failed: %+v", err)
1924+
}
1925+
taskResult, err := GetTaskResult(ctx, taskInfo)
1926+
if err != nil {
1927+
t.Fatalf("GetTaskResult failed: %+v", err)
1928+
}
1929+
if taskResult == nil {
1930+
t.Fatalf("Empty unregister task results")
1931+
}
1932+
operationRes := taskResult.GetCnsVolumeOperationResult()
1933+
if operationRes.Fault != nil {
1934+
t.Fatalf("Failed to unregister volume: fault=%+v", operationRes.Fault)
1935+
}
1936+
t.Logf("Volume unregistered successfully: %s", volumeId)
1937+
}
1938+
17971939
// isvSphereVersion70U3orAbove checks if specified version is 7.0 Update 3 or higher
17981940
// The method takes aboutInfo{} as input which contains details about
17991941
// VC version, build number and so on.

cns/methods/methods.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,3 +375,23 @@ func CnsSyncVolume(ctx context.Context, r soap.RoundTripper, req *types.CnsSyncV
375375

376376
return resBody.Res, nil
377377
}
378+
379+
type CnsUnregisterVolumeBody struct {
380+
Req *types.CnsUnregisterVolume `xml:"urn:vsan CnsUnregisterVolume,omitempty"`
381+
Res *types.CnsUnregisterVolumeResponse `xml:"urn:vsan CnsUnregisterVolumeResponse,omitempty"`
382+
Fault_ *soap.Fault `xml:"http://schemas.xmlsoap.org/soap/envelope/ Fault,omitempty"`
383+
}
384+
385+
func (b *CnsUnregisterVolumeBody) Fault() *soap.Fault { return b.Fault_ }
386+
387+
func CnsUnregisterVolume(ctx context.Context, r soap.RoundTripper, req *types.CnsUnregisterVolume) (*types.CnsUnregisterVolumeResponse, error) {
388+
var reqBody, resBody CnsUnregisterVolumeBody
389+
390+
reqBody.Req = req
391+
392+
if err := r.RoundTrip(ctx, &reqBody, &resBody); err != nil {
393+
return nil, err
394+
}
395+
396+
return resBody.Res, nil
397+
}

cns/types/enum.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,14 @@ const (
9595
func init() {
9696
types.Add("vsan:CnsSyncVolumeMode", reflect.TypeOf((*CnsSyncVolumeMode)(nil)).Elem())
9797
}
98+
99+
type CnsUnregisterTargetVolumeType string
100+
101+
const (
102+
CnsUnregisterTargetVolumeTypeFCD = CnsUnregisterTargetVolumeType("FCD")
103+
CnsUnregisterTargetVolumeTypeLEGACY_DISK = CnsUnregisterTargetVolumeType("LEGACY_DISK")
104+
)
105+
106+
func init() {
107+
types.Add("vsan:CnsUnregisterTargetVolumeType", reflect.TypeOf((*CnsUnregisterTargetVolumeType)(nil)).Elem())
108+
}

cns/types/types.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -987,3 +987,33 @@ type CnsSyncVolumeSpec struct {
987987
func init() {
988988
types.Add("vsan:CnsSyncVolumeSpec", reflect.TypeOf((*CnsSyncVolumeSpec)(nil)).Elem())
989989
}
990+
991+
type CnsUnregisterVolume CnsUnregisterVolumeRequestType
992+
993+
func init() {
994+
types.Add("vsan:CnsUnregisterVolume", reflect.TypeOf((*CnsUnregisterVolume)(nil)).Elem())
995+
}
996+
997+
type CnsUnregisterVolumeRequestType struct {
998+
This types.ManagedObjectReference `xml:"_this" json:"-"`
999+
UnregisterSpec []CnsUnregisterVolumeSpec `xml:"unregisterSpec,omitempty" json:"UnregisterSpec,omitempty"`
1000+
}
1001+
1002+
func init() {
1003+
types.Add("vsan:CnsUnregisterVolumeRequestType", reflect.TypeOf((*CnsUnregisterVolumeRequestType)(nil)).Elem())
1004+
}
1005+
1006+
type CnsUnregisterVolumeResponse struct {
1007+
Returnval types.ManagedObjectReference `xml:"returnval" json:"returnval"`
1008+
}
1009+
1010+
type CnsUnregisterVolumeSpec struct {
1011+
types.DynamicData
1012+
1013+
VolumeId CnsVolumeId `xml:"volumeId" json:"volumeId"`
1014+
TargetVolumeType string `xml:"targetVolumeType" json:"targetVolumeType"`
1015+
}
1016+
1017+
func init() {
1018+
types.Add("vsan:CnsUnregisterVolumeSpec", reflect.TypeOf((*CnsUnregisterVolumeSpec)(nil)).Elem())
1019+
}

0 commit comments

Comments
 (0)