github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/vm_groups.go (about) 1 package govcd 2 3 import ( 4 "fmt" 5 "github.com/vmware/go-vcloud-director/v2/types/v56" 6 "net/url" 7 "strings" 8 ) 9 10 // LogicalVmGroup is used to create VM Placement Policies. 11 type LogicalVmGroup struct { 12 LogicalVmGroup *types.LogicalVmGroup 13 client *Client 14 } 15 16 // VmGroup is used to create VM Placement Policies. 17 type VmGroup struct { 18 VmGroup *types.QueryResultVmGroupsRecordType 19 client *Client 20 } 21 22 // This constant is useful when managing Logical VM Groups by referencing VM Groups, as these are 23 // XML based and don't deal with IDs with full URNs, while Logical VM Groups are OpenAPI based and they do. 24 const vmGroupUrnPrefix = "urn:vcloud:namedVmGroup" 25 26 // GetVmGroupById finds a VM Group by its ID. 27 // On success, returns a pointer to the VmGroup structure and a nil error 28 // On failure, returns a nil pointer and an error 29 func (vcdClient *VCDClient) GetVmGroupById(id string) (*VmGroup, error) { 30 return getVmGroupWithFilter(vcdClient, "vmGroupId=="+url.QueryEscape(extractUuid(id))) 31 } 32 33 // GetVmGroupByNamedVmGroupIdAndProviderVdcUrn finds a VM Group by its Named VM Group ID and Provider VDC URN. 34 // On success, returns a pointer to the VmGroup structure and a nil error 35 // On failure, returns a nil pointer and an error 36 func (vcdClient *VCDClient) GetVmGroupByNamedVmGroupIdAndProviderVdcUrn(namedVmGroupId, pvdcUrn string) (*VmGroup, error) { 37 id := extractUuid(namedVmGroupId) 38 resourcePools, err := getResourcePools(vcdClient, pvdcUrn) 39 if err != nil { 40 return nil, fmt.Errorf("could not get VM Group with namedVmGroupId=%s: %s", id, err) 41 } 42 filter, err := buildFilterForVmGroups(resourcePools, "namedVmGroupId", id) 43 if err != nil { 44 return nil, fmt.Errorf("could not get VM Group with namedVmGroupId=%s: %s", id, err) 45 } 46 return getVmGroupWithFilter(vcdClient, filter) 47 } 48 49 // GetVmGroupByNameAndProviderVdcUrn finds a VM Group by its name and associated Provider VDC URN. 50 // On success, returns a pointer to the VmGroup structure and a nil error 51 // On failure, returns a nil pointer and an error 52 func (vcdClient *VCDClient) GetVmGroupByNameAndProviderVdcUrn(name, pvdcUrn string) (*VmGroup, error) { 53 resourcePools, err := getResourcePools(vcdClient, pvdcUrn) 54 if err != nil { 55 return nil, fmt.Errorf("could not get VM Group with vmGroupName=%s: %s", name, err) 56 } 57 filter, err := buildFilterForVmGroups(resourcePools, "vmGroupName", name) 58 if err != nil { 59 return nil, fmt.Errorf("could not get VM Group with vmGroupName=%s: %s", name, err) 60 } 61 return getVmGroupWithFilter(vcdClient, filter) 62 } 63 64 // buildFilterForVmGroups builds a filter to search for VM Groups based on the given resource pools and the desired 65 // identifier key and value. 66 func buildFilterForVmGroups(resourcePools []*types.QueryResultResourcePoolRecordType, idKey, idValue string) (string, error) { 67 if strings.TrimSpace(idKey) == "" || strings.TrimSpace(idValue) == "" { 68 return "", fmt.Errorf("identifier must have a key and value to be able to search") 69 } 70 clusterMorefs := "" 71 vCenters := "" 72 for _, resourcePool := range resourcePools { 73 if resourcePool.ClusterMoref != "" { 74 clusterMorefs += fmt.Sprintf("clusterMoref==%s,", url.QueryEscape(resourcePool.ClusterMoref)) 75 } 76 if resourcePool.VcenterHREF != "" { 77 vCenters += fmt.Sprintf("vcId==%s,", url.QueryEscape(extractUuid(resourcePool.VcenterHREF))) 78 } 79 } 80 81 if len(clusterMorefs) == 0 || len(vCenters) == 0 { 82 return "", fmt.Errorf("could not retrieve Resource pools information to retrieve VM Group with %s=%s", idKey, idValue) 83 } 84 // Removes trailing "," 85 clusterMorefs = clusterMorefs[:len(clusterMorefs)-1] 86 vCenters = vCenters[:len(vCenters)-1] 87 88 return fmt.Sprintf("(%s==%s;(%s);(%s))", url.QueryEscape(idKey), url.QueryEscape(idValue), clusterMorefs, vCenters), nil 89 } 90 91 // GetLogicalVmGroupById finds a Logical VM Group by its URN. 92 // On success, returns a pointer to the LogicalVmGroup structure and a nil error 93 // On failure, returns a nil pointer and an error 94 func (vcdClient *VCDClient) GetLogicalVmGroupById(logicalVmGroupId string) (*LogicalVmGroup, error) { 95 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointLogicalVmGroups 96 97 apiVersion, err := vcdClient.Client.getOpenApiHighestElevatedVersion(endpoint) 98 if err != nil { 99 return nil, err 100 } 101 102 if logicalVmGroupId == "" { 103 return nil, fmt.Errorf("empty Logical VM Group id") 104 } 105 106 urlRef, err := vcdClient.Client.OpenApiBuildEndpoint(endpoint, logicalVmGroupId) 107 if err != nil { 108 return nil, err 109 } 110 111 result := &LogicalVmGroup{ 112 LogicalVmGroup: &types.LogicalVmGroup{}, 113 client: &vcdClient.Client, 114 } 115 116 err = vcdClient.Client.OpenApiGetItem(apiVersion, urlRef, nil, result.LogicalVmGroup, nil) 117 if err != nil { 118 return nil, fmt.Errorf("error getting Logical VM Group: %s", err) 119 } 120 121 return result, nil 122 } 123 124 // CreateLogicalVmGroup creates a new Logical VM Group in VCD 125 func (vcdClient *VCDClient) CreateLogicalVmGroup(logicalVmGroup types.LogicalVmGroup) (*LogicalVmGroup, error) { 126 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointLogicalVmGroups 127 128 apiVersion, err := vcdClient.Client.getOpenApiHighestElevatedVersion(endpoint) 129 if err != nil { 130 return nil, err 131 } 132 133 urlRef, err := vcdClient.Client.OpenApiBuildEndpoint(endpoint) 134 if err != nil { 135 return nil, err 136 } 137 138 result := &LogicalVmGroup{ 139 LogicalVmGroup: &types.LogicalVmGroup{}, 140 client: &vcdClient.Client, 141 } 142 143 err = vcdClient.Client.OpenApiPostItem(apiVersion, urlRef, nil, logicalVmGroup, result.LogicalVmGroup, nil) 144 if err != nil { 145 return nil, fmt.Errorf("error creating the Logical VM Group: %s", err) 146 } 147 148 return result, nil 149 } 150 151 // Delete deletes the receiver Logical VM Group 152 func (logicalVmGroup *LogicalVmGroup) Delete() error { 153 if logicalVmGroup.LogicalVmGroup.ID == "" { 154 return fmt.Errorf("cannot delete Logical VM Group without id") 155 } 156 157 endpoint := types.OpenApiPathVersion1_0_0 + types.OpenApiEndpointLogicalVmGroups 158 159 apiVersion, err := logicalVmGroup.client.getOpenApiHighestElevatedVersion(endpoint) 160 if err != nil { 161 return err 162 } 163 164 urlRef, err := logicalVmGroup.client.OpenApiBuildEndpoint(endpoint, logicalVmGroup.LogicalVmGroup.ID) 165 if err != nil { 166 return err 167 } 168 169 err = logicalVmGroup.client.OpenApiDeleteItem(apiVersion, urlRef, nil, nil) 170 if err != nil { 171 return fmt.Errorf("error deleting the Logical VM Group: %s", err) 172 } 173 return nil 174 } 175 176 // getVmGroupWithFilter finds a VM Group by specifying a filter=(filterKey==filterValue). 177 // On success, returns a pointer to the VmGroup structure and a nil error 178 // On failure, returns a nil pointer and an error 179 func getVmGroupWithFilter(vcdClient *VCDClient, filter string) (*VmGroup, error) { 180 foundVmGroups, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ 181 "type": "vmGroups", 182 "filter": filter, 183 "filterEncoded": "true", 184 }) 185 if err != nil { 186 return nil, err 187 } 188 if len(foundVmGroups.Results.VmGroupsRecord) == 0 { 189 return nil, ErrorEntityNotFound 190 } 191 if len(foundVmGroups.Results.VmGroupsRecord) > 1 { 192 return nil, fmt.Errorf("more than one VM Group found with the filter: %v", filter) 193 } 194 vmGroup := &VmGroup{ 195 VmGroup: foundVmGroups.Results.VmGroupsRecord[0], 196 client: &vcdClient.Client, 197 } 198 return vmGroup, nil 199 } 200 201 // getResourcePools returns the Resource Pool that can unequivocally identify a VM Group 202 func getResourcePools(vcdClient *VCDClient, pvdcUrn string) ([]*types.QueryResultResourcePoolRecordType, error) { 203 foundResourcePools, err := vcdClient.QueryWithNotEncodedParams(nil, map[string]string{ 204 "type": "resourcePool", 205 "filter": fmt.Sprintf("providerVdc==%s", url.QueryEscape(pvdcUrn)), 206 "filterEncoded": "true", 207 }) 208 if err != nil { 209 return nil, fmt.Errorf("could not get the Resource pool: %s", err) 210 } 211 if len(foundResourcePools.Results.ResourcePoolRecord) == 0 { 212 return nil, ErrorEntityNotFound 213 } 214 return foundResourcePools.Results.ResourcePoolRecord, nil 215 }