github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/metadata_v2.go (about) 1 /* 2 * Copyright 2022 VMware, Inc. All rights reserved. Licensed under the Apache v2 License. 3 */ 4 5 package govcd 6 7 import ( 8 "fmt" 9 "github.com/vmware/go-vcloud-director/v2/types/v56" 10 "github.com/vmware/go-vcloud-director/v2/util" 11 "net/http" 12 "regexp" 13 "strings" 14 ) 15 16 // NOTE: This "v2" is not v2 in terms of API versioning, it's just a way to separate the functions that handle 17 // metadata in a complete way (v2, this file) and the deprecated functions that were incomplete (v1, they lacked 18 // "visibility" and "domain" handling). 19 // 20 // The idea is that once a new major version of go-vcloud-director is released, one can just remove "v1" file and perform 21 // a minor refactoring of the code here (probably renaming functions). Also, the code in "v2" is organized differently, 22 // as this is classified using "CRUD blocks" (meaning that all Create functions are together, same for Read... etc), 23 // which makes the code more readable. 24 25 // ------------------------------------------------------------------------------------------------ 26 // GET metadata by key 27 // ------------------------------------------------------------------------------------------------ 28 29 // GetMetadataByKeyAndHref returns metadata from the given resource reference, corresponding to the given key and domain. 30 func (vcdClient *VCDClient) GetMetadataByKeyAndHref(href, key string, isSystem bool) (*types.MetadataValue, error) { 31 return getMetadataByKey(&vcdClient.Client, href, "", key, isSystem) 32 } 33 34 // GetMetadataByKey returns VM metadata corresponding to the given key and domain. 35 func (vm *VM) GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) { 36 return getMetadataByKey(vm.client, vm.VM.HREF, vm.VM.Name, key, isSystem) 37 } 38 39 // GetMetadataByKey returns VDC metadata corresponding to the given key and domain. 40 func (vdc *Vdc) GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) { 41 return getMetadataByKey(vdc.client, vdc.Vdc.HREF, vdc.Vdc.Name, key, isSystem) 42 } 43 44 // GetMetadataByKey returns AdminVdc metadata corresponding to the given key and domain. 45 func (adminVdc *AdminVdc) GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) { 46 return getMetadataByKey(adminVdc.client, adminVdc.AdminVdc.HREF, adminVdc.AdminVdc.Name, key, isSystem) 47 } 48 49 // GetMetadataByKey returns ProviderVdc metadata corresponding to the given key and domain. 50 // Note: Requires system administrator privileges. 51 func (providerVdc *ProviderVdc) GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) { 52 return getMetadataByKey(providerVdc.client, providerVdc.ProviderVdc.HREF, providerVdc.ProviderVdc.Name, key, isSystem) 53 } 54 55 // GetMetadataByKey returns VApp metadata corresponding to the given key and domain. 56 func (vapp *VApp) GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) { 57 return getMetadataByKey(vapp.client, vapp.VApp.HREF, vapp.VApp.Name, key, isSystem) 58 } 59 60 // GetMetadataByKey returns VAppTemplate metadata corresponding to the given key and domain. 61 func (vAppTemplate *VAppTemplate) GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) { 62 return getMetadataByKey(vAppTemplate.client, vAppTemplate.VAppTemplate.HREF, vAppTemplate.VAppTemplate.Name, key, isSystem) 63 } 64 65 // GetMetadataByKey returns MediaRecord metadata corresponding to the given key and domain. 66 func (mediaRecord *MediaRecord) GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) { 67 return getMetadataByKey(mediaRecord.client, mediaRecord.MediaRecord.HREF, mediaRecord.MediaRecord.Name, key, isSystem) 68 } 69 70 // GetMetadataByKey returns Media metadata corresponding to the given key and domain. 71 func (media *Media) GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) { 72 return getMetadataByKey(media.client, media.Media.HREF, media.Media.Name, key, isSystem) 73 } 74 75 // GetMetadataByKey returns Catalog metadata corresponding to the given key and domain. 76 func (catalog *Catalog) GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) { 77 return getMetadataByKey(catalog.client, catalog.Catalog.HREF, catalog.Catalog.Name, key, isSystem) 78 } 79 80 // GetMetadataByKey returns AdminCatalog metadata corresponding to the given key and domain. 81 func (adminCatalog *AdminCatalog) GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) { 82 return getMetadataByKey(adminCatalog.client, adminCatalog.AdminCatalog.HREF, adminCatalog.AdminCatalog.Name, key, isSystem) 83 } 84 85 // GetMetadataByKey returns the Org metadata corresponding to the given key and domain. 86 func (org *Org) GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) { 87 return getMetadataByKey(org.client, org.Org.HREF, org.Org.Name, key, isSystem) 88 } 89 90 // GetMetadataByKey returns the AdminOrg metadata corresponding to the given key and domain. 91 // Note: Requires system administrator privileges. 92 func (adminOrg *AdminOrg) GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) { 93 return getMetadataByKey(adminOrg.client, adminOrg.AdminOrg.HREF, adminOrg.AdminOrg.Name, key, isSystem) 94 } 95 96 // GetMetadataByKey returns the metadata corresponding to the given key and domain. 97 func (disk *Disk) GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) { 98 return getMetadataByKey(disk.client, disk.Disk.HREF, disk.Disk.Name, key, isSystem) 99 } 100 101 // GetMetadataByKey returns OrgVDCNetwork metadata corresponding to the given key and domain. 102 func (orgVdcNetwork *OrgVDCNetwork) GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) { 103 return getMetadataByKey(orgVdcNetwork.client, orgVdcNetwork.OrgVDCNetwork.HREF, orgVdcNetwork.OrgVDCNetwork.Name, key, isSystem) 104 } 105 106 // GetMetadataByKey returns CatalogItem metadata corresponding to the given key and domain. 107 func (catalogItem *CatalogItem) GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) { 108 return getMetadataByKey(catalogItem.client, catalogItem.CatalogItem.HREF, catalogItem.CatalogItem.Name, key, isSystem) 109 } 110 111 // GetMetadataByKey returns OpenApiOrgVdcNetwork metadata corresponding to the given key and domain. 112 // NOTE: This function cannot retrieve metadata if the network belongs to a VDC Group. 113 // TODO: This function is currently using XML API underneath as OpenAPI metadata is still not supported. 114 func (openApiOrgVdcNetwork *OpenApiOrgVdcNetwork) GetMetadataByKey(key string, isSystem bool) (*types.MetadataValue, error) { 115 href := fmt.Sprintf("%s/network/%s", openApiOrgVdcNetwork.client.VCDHREF.String(), extractUuid(openApiOrgVdcNetwork.OpenApiOrgVdcNetwork.ID)) 116 return getMetadataByKey(openApiOrgVdcNetwork.client, href, openApiOrgVdcNetwork.OpenApiOrgVdcNetwork.Name, key, isSystem) 117 } 118 119 // ------------------------------------------------------------------------------------------------ 120 // GET all metadata 121 // ------------------------------------------------------------------------------------------------ 122 123 // GetMetadataByHref returns metadata from the given resource reference. 124 func (vcdClient *VCDClient) GetMetadataByHref(href string) (*types.Metadata, error) { 125 return getMetadata(&vcdClient.Client, href, "") 126 } 127 128 // GetMetadata returns VM metadata. 129 func (vm *VM) GetMetadata() (*types.Metadata, error) { 130 return getMetadata(vm.client, vm.VM.HREF, vm.VM.Name) 131 } 132 133 // GetMetadata returns VDC metadata. 134 func (vdc *Vdc) GetMetadata() (*types.Metadata, error) { 135 return getMetadata(vdc.client, vdc.Vdc.HREF, vdc.Vdc.Name) 136 } 137 138 // GetMetadata returns AdminVdc metadata. 139 func (adminVdc *AdminVdc) GetMetadata() (*types.Metadata, error) { 140 return getMetadata(adminVdc.client, adminVdc.AdminVdc.HREF, adminVdc.AdminVdc.Name) 141 } 142 143 // GetMetadata returns ProviderVdc metadata. 144 // Note: Requires system administrator privileges. 145 func (providerVdc *ProviderVdc) GetMetadata() (*types.Metadata, error) { 146 return getMetadata(providerVdc.client, providerVdc.ProviderVdc.HREF, providerVdc.ProviderVdc.Name) 147 } 148 149 // GetMetadata returns VApp metadata. 150 func (vapp *VApp) GetMetadata() (*types.Metadata, error) { 151 return getMetadata(vapp.client, vapp.VApp.HREF, vapp.VApp.Name) 152 } 153 154 // GetMetadata returns VAppTemplate metadata. 155 func (vAppTemplate *VAppTemplate) GetMetadata() (*types.Metadata, error) { 156 return getMetadata(vAppTemplate.client, vAppTemplate.VAppTemplate.HREF, vAppTemplate.VAppTemplate.Name) 157 } 158 159 // GetMetadata returns MediaRecord metadata. 160 func (mediaRecord *MediaRecord) GetMetadata() (*types.Metadata, error) { 161 return getMetadata(mediaRecord.client, mediaRecord.MediaRecord.HREF, mediaRecord.MediaRecord.Name) 162 } 163 164 // GetMetadata returns Media metadata. 165 func (media *Media) GetMetadata() (*types.Metadata, error) { 166 return getMetadata(media.client, media.Media.HREF, media.Media.Name) 167 } 168 169 // GetMetadata returns Catalog metadata. 170 func (catalog *Catalog) GetMetadata() (*types.Metadata, error) { 171 return getMetadata(catalog.client, catalog.Catalog.HREF, catalog.Catalog.Name) 172 } 173 174 // GetMetadata returns AdminCatalog metadata. 175 func (adminCatalog *AdminCatalog) GetMetadata() (*types.Metadata, error) { 176 return getMetadata(adminCatalog.client, adminCatalog.AdminCatalog.HREF, adminCatalog.AdminCatalog.Name) 177 } 178 179 // GetMetadata returns the Org metadata of the corresponding organization seen as administrator 180 func (org *Org) GetMetadata() (*types.Metadata, error) { 181 return getMetadata(org.client, org.Org.HREF, org.Org.Name) 182 } 183 184 // GetMetadata returns the AdminOrg metadata of the corresponding organization seen as administrator 185 func (adminOrg *AdminOrg) GetMetadata() (*types.Metadata, error) { 186 return getMetadata(adminOrg.client, adminOrg.AdminOrg.HREF, adminOrg.AdminOrg.Name) 187 } 188 189 // GetMetadata returns the metadata of the corresponding independent disk 190 func (disk *Disk) GetMetadata() (*types.Metadata, error) { 191 return getMetadata(disk.client, disk.Disk.HREF, disk.Disk.Name) 192 } 193 194 // GetMetadata returns OrgVDCNetwork metadata. 195 func (orgVdcNetwork *OrgVDCNetwork) GetMetadata() (*types.Metadata, error) { 196 return getMetadata(orgVdcNetwork.client, orgVdcNetwork.OrgVDCNetwork.HREF, orgVdcNetwork.OrgVDCNetwork.Name) 197 } 198 199 // GetMetadata returns CatalogItem metadata. 200 func (catalogItem *CatalogItem) GetMetadata() (*types.Metadata, error) { 201 return getMetadata(catalogItem.client, catalogItem.CatalogItem.HREF, catalogItem.CatalogItem.Name) 202 } 203 204 // GetMetadata returns OpenApiOrgVdcNetwork metadata. 205 // NOTE: This function cannot retrieve metadata if the network belongs to a VDC Group. 206 // TODO: This function is currently using XML API underneath as OpenAPI metadata is still not supported. 207 func (openApiOrgVdcNetwork *OpenApiOrgVdcNetwork) GetMetadata() (*types.Metadata, error) { 208 href := fmt.Sprintf("%s/network/%s", openApiOrgVdcNetwork.client.VCDHREF.String(), extractUuid(openApiOrgVdcNetwork.OpenApiOrgVdcNetwork.ID)) 209 return getMetadata(openApiOrgVdcNetwork.client, href, openApiOrgVdcNetwork.OpenApiOrgVdcNetwork.Name) 210 } 211 212 // ------------------------------------------------------------------------------------------------ 213 // ADD metadata async 214 // ------------------------------------------------------------------------------------------------ 215 216 // AddMetadataEntryWithVisibilityByHrefAsync adds metadata to the given resource reference with the given key, value, type and visibility 217 // and returns the task. 218 func (vcdClient *VCDClient) AddMetadataEntryWithVisibilityByHrefAsync(href, key, value, typedValue, visibility string, isSystem bool) (Task, error) { 219 return addMetadata(&vcdClient.Client, href, "", key, value, typedValue, visibility, isSystem) 220 } 221 222 // AddMetadataEntryWithVisibilityAsync adds metadata to the given VM with the given key, value, type and visibility 223 // // and returns the task. 224 func (vm *VM) AddMetadataEntryWithVisibilityAsync(key, value, typedValue, visibility string, isSystem bool) (Task, error) { 225 return addMetadata(vm.client, vm.VM.HREF, vm.VM.Name, key, value, typedValue, visibility, isSystem) 226 } 227 228 // AddMetadataEntryWithVisibilityAsync adds metadata to the given AdminVdc with the given key, value, type and visibility 229 // and returns the task. 230 func (adminVdc *AdminVdc) AddMetadataEntryWithVisibilityAsync(key, value, typedValue, visibility string, isSystem bool) (Task, error) { 231 return addMetadata(adminVdc.client, adminVdc.AdminVdc.HREF, adminVdc.AdminVdc.Name, key, value, typedValue, visibility, isSystem) 232 } 233 234 // AddMetadataEntryWithVisibilityAsync adds metadata to the given ProviderVdc with the given key, value, type and visibility 235 // and returns the task. 236 // Note: Requires system administrator privileges. 237 func (providerVdc *ProviderVdc) AddMetadataEntryWithVisibilityAsync(key, value, typedValue, visibility string, isSystem bool) (Task, error) { 238 return addMetadata(providerVdc.client, providerVdc.ProviderVdc.HREF, providerVdc.ProviderVdc.Name, key, value, typedValue, visibility, isSystem) 239 } 240 241 // AddMetadataEntryWithVisibilityAsync adds metadata to the given VApp with the given key, value, type and visibility 242 // and returns the task. 243 func (vapp *VApp) AddMetadataEntryWithVisibilityAsync(key, value, typedValue, visibility string, isSystem bool) (Task, error) { 244 return addMetadata(vapp.client, vapp.VApp.HREF, vapp.VApp.Name, key, value, typedValue, visibility, isSystem) 245 } 246 247 // AddMetadataEntryWithVisibilityAsync adds metadata to the given VAppTemplate with the given key, value, type and visibility 248 // and returns the task. 249 func (vAppTemplate *VAppTemplate) AddMetadataEntryWithVisibilityAsync(key, value, typedValue, visibility string, isSystem bool) (Task, error) { 250 return addMetadata(vAppTemplate.client, vAppTemplate.VAppTemplate.HREF, vAppTemplate.VAppTemplate.Name, key, value, typedValue, visibility, isSystem) 251 } 252 253 // AddMetadataEntryWithVisibilityAsync adds metadata to the given MediaRecord with the given key, value, type and visibility 254 // and returns the task. 255 func (mediaRecord *MediaRecord) AddMetadataEntryWithVisibilityAsync(key, value, typedValue, visibility string, isSystem bool) (Task, error) { 256 return addMetadata(mediaRecord.client, mediaRecord.MediaRecord.HREF, mediaRecord.MediaRecord.Name, key, value, typedValue, visibility, isSystem) 257 } 258 259 // AddMetadataEntryWithVisibilityAsync adds metadata to the given Media with the given key, value, type and visibility 260 // and returns the task. 261 func (media *Media) AddMetadataEntryWithVisibilityAsync(key, value, typedValue, visibility string, isSystem bool) (Task, error) { 262 return addMetadata(media.client, media.Media.HREF, media.Media.Name, key, value, typedValue, visibility, isSystem) 263 } 264 265 // AddMetadataEntryWithVisibilityAsync adds metadata to the given AdminCatalog with the given key, value, type and visibility 266 // and returns the task. 267 func (adminCatalog *AdminCatalog) AddMetadataEntryWithVisibilityAsync(key, value, typedValue, visibility string, isSystem bool) (Task, error) { 268 return addMetadata(adminCatalog.client, adminCatalog.AdminCatalog.HREF, adminCatalog.AdminCatalog.Name, key, value, typedValue, visibility, isSystem) 269 } 270 271 // AddMetadataEntryWithVisibilityAsync adds metadata to the given AdminOrg with the given key, value, type and visibility 272 // and returns the task. 273 func (adminOrg *AdminOrg) AddMetadataEntryWithVisibilityAsync(key, value, typedValue, visibility string, isSystem bool) (Task, error) { 274 return addMetadata(adminOrg.client, adminOrg.AdminOrg.HREF, adminOrg.AdminOrg.Name, key, value, typedValue, visibility, isSystem) 275 } 276 277 // AddMetadataEntryWithVisibilityAsync adds metadata to the given Disk with the given key, value, type and visibility 278 // and returns the task. 279 func (disk *Disk) AddMetadataEntryWithVisibilityAsync(key, value, typedValue, visibility string, isSystem bool) (Task, error) { 280 return addMetadata(disk.client, disk.Disk.HREF, disk.Disk.Name, key, value, typedValue, visibility, isSystem) 281 } 282 283 // AddMetadataEntryWithVisibilityAsync adds metadata to the given OrgVDCNetwork with the given key, value, type and visibility 284 // and returns the task. 285 // Note: Requires system administrator privileges. 286 func (orgVdcNetwork *OrgVDCNetwork) AddMetadataEntryWithVisibilityAsync(key, value, typedValue, visibility string, isSystem bool) (Task, error) { 287 return addMetadata(orgVdcNetwork.client, getAdminURL(orgVdcNetwork.OrgVDCNetwork.HREF), orgVdcNetwork.OrgVDCNetwork.Name, key, value, typedValue, visibility, isSystem) 288 } 289 290 // AddMetadataEntryWithVisibilityAsync adds metadata to the given Catalog Item with the given key, value, type and visibility 291 // and returns the task. 292 func (catalogItem *CatalogItem) AddMetadataEntryWithVisibilityAsync(key, value, typedValue, visibility string, isSystem bool) (Task, error) { 293 return addMetadata(catalogItem.client, catalogItem.CatalogItem.HREF, catalogItem.CatalogItem.Name, key, value, typedValue, visibility, isSystem) 294 } 295 296 // ------------------------------------------------------------------------------------------------ 297 // ADD metadata 298 // ------------------------------------------------------------------------------------------------ 299 300 // AddMetadataEntryWithVisibilityByHref adds metadata to the given resource reference with the given key, value, type and visibility 301 // and waits for completion. 302 func (vcdClient *VCDClient) AddMetadataEntryWithVisibilityByHref(href, key, value, typedValue, visibility string, isSystem bool) error { 303 task, err := vcdClient.AddMetadataEntryWithVisibilityByHrefAsync(href, key, value, typedValue, visibility, isSystem) 304 if err != nil { 305 return err 306 } 307 return task.WaitTaskCompletion() 308 } 309 310 // AddMetadataEntryWithVisibility adds metadata to the receiver VM and waits for the task to finish. 311 func (vm *VM) AddMetadataEntryWithVisibility(key, value, typedValue, visibility string, isSystem bool) error { 312 return addMetadataAndWait(vm.client, vm.VM.HREF, vm.VM.Name, key, value, typedValue, visibility, isSystem) 313 } 314 315 // AddMetadataEntryWithVisibility adds metadata to the receiver AdminVdc and waits for the task to finish. 316 func (adminVdc *AdminVdc) AddMetadataEntryWithVisibility(key, value, typedValue, visibility string, isSystem bool) error { 317 return addMetadataAndWait(adminVdc.client, adminVdc.AdminVdc.HREF, adminVdc.AdminVdc.Name, key, value, typedValue, visibility, isSystem) 318 } 319 320 // AddMetadataEntryWithVisibility adds metadata to the receiver ProviderVdc and waits for the task to finish. 321 // Note: Requires system administrator privileges. 322 func (providerVdc *ProviderVdc) AddMetadataEntryWithVisibility(key, value, typedValue, visibility string, isSystem bool) error { 323 return addMetadataAndWait(providerVdc.client, providerVdc.ProviderVdc.HREF, providerVdc.ProviderVdc.Name, key, value, typedValue, visibility, isSystem) 324 } 325 326 // AddMetadataEntryWithVisibility adds metadata to the receiver VApp and waits for the task to finish. 327 func (vapp *VApp) AddMetadataEntryWithVisibility(key, value, typedValue, visibility string, isSystem bool) error { 328 return addMetadataAndWait(vapp.client, vapp.VApp.HREF, vapp.VApp.Name, key, value, typedValue, visibility, isSystem) 329 } 330 331 // AddMetadataEntryWithVisibility adds metadata to the receiver VAppTemplate and waits for the task to finish. 332 func (vAppTemplate *VAppTemplate) AddMetadataEntryWithVisibility(key, value, typedValue, visibility string, isSystem bool) error { 333 return addMetadataAndWait(vAppTemplate.client, vAppTemplate.VAppTemplate.HREF, vAppTemplate.VAppTemplate.Name, key, value, typedValue, visibility, isSystem) 334 } 335 336 // AddMetadataEntryWithVisibility adds metadata to the receiver MediaRecord and waits for the task to finish. 337 func (mediaRecord *MediaRecord) AddMetadataEntryWithVisibility(key, value, typedValue, visibility string, isSystem bool) error { 338 return addMetadataAndWait(mediaRecord.client, mediaRecord.MediaRecord.HREF, mediaRecord.MediaRecord.Name, key, value, typedValue, visibility, isSystem) 339 } 340 341 // AddMetadataEntryWithVisibility adds metadata to the receiver Media and waits for the task to finish. 342 func (media *Media) AddMetadataEntryWithVisibility(key, value, typedValue, visibility string, isSystem bool) error { 343 return addMetadataAndWait(media.client, media.Media.HREF, media.Media.Name, key, value, typedValue, visibility, isSystem) 344 } 345 346 // AddMetadataEntryWithVisibility adds metadata to the receiver AdminCatalog and waits for the task to finish. 347 func (adminCatalog *AdminCatalog) AddMetadataEntryWithVisibility(key, value, typedValue, visibility string, isSystem bool) error { 348 return addMetadataAndWait(adminCatalog.client, adminCatalog.AdminCatalog.HREF, adminCatalog.AdminCatalog.Name, key, value, typedValue, visibility, isSystem) 349 } 350 351 // AddMetadataEntryWithVisibility adds metadata to the receiver AdminOrg and waits for the task to finish. 352 func (adminOrg *AdminOrg) AddMetadataEntryWithVisibility(key, value, typedValue, visibility string, isSystem bool) error { 353 return addMetadataAndWait(adminOrg.client, adminOrg.AdminOrg.HREF, adminOrg.AdminOrg.Name, key, value, typedValue, visibility, isSystem) 354 } 355 356 // AddMetadataEntryWithVisibility adds metadata to the receiver Disk and waits for the task to finish. 357 func (disk *Disk) AddMetadataEntryWithVisibility(key, value, typedValue, visibility string, isSystem bool) error { 358 return addMetadataAndWait(disk.client, disk.Disk.HREF, disk.Disk.Name, key, value, typedValue, visibility, isSystem) 359 } 360 361 // AddMetadataEntryWithVisibility adds metadata to the receiver OrgVDCNetwork and waits for the task to finish. 362 // Note: Requires system administrator privileges. 363 func (orgVdcNetwork *OrgVDCNetwork) AddMetadataEntryWithVisibility(key, value, typedValue, visibility string, isSystem bool) error { 364 return addMetadataAndWait(orgVdcNetwork.client, getAdminURL(orgVdcNetwork.OrgVDCNetwork.HREF), orgVdcNetwork.OrgVDCNetwork.Name, key, value, typedValue, visibility, isSystem) 365 } 366 367 // AddMetadataEntryWithVisibility adds metadata to the receiver CatalogItem and waits for the task to finish. 368 func (catalogItem *CatalogItem) AddMetadataEntryWithVisibility(key, value, typedValue, visibility string, isSystem bool) error { 369 return addMetadataAndWait(catalogItem.client, catalogItem.CatalogItem.HREF, catalogItem.CatalogItem.Name, key, value, typedValue, visibility, isSystem) 370 } 371 372 // AddMetadataEntryWithVisibility adds metadata to the receiver OpenApiOrgVdcNetwork and waits for the task to finish. 373 // Note: It doesn't add metadata to networks that belong to a VDC Group. 374 // TODO: This function is currently using XML API underneath as OpenAPI metadata is still not supported. 375 func (openApiOrgVdcNetwork *OpenApiOrgVdcNetwork) AddMetadataEntryWithVisibility(key, value, typedValue, visibility string, isSystem bool) error { 376 href := fmt.Sprintf("%s/admin/network/%s", openApiOrgVdcNetwork.client.VCDHREF.String(), extractUuid(openApiOrgVdcNetwork.OpenApiOrgVdcNetwork.ID)) 377 task, err := addMetadata(openApiOrgVdcNetwork.client, href, openApiOrgVdcNetwork.OpenApiOrgVdcNetwork.Name, key, value, typedValue, visibility, isSystem) 378 if err != nil { 379 return err 380 } 381 return task.WaitTaskCompletion() 382 } 383 384 // ------------------------------------------------------------------------------------------------ 385 // MERGE metadata async 386 // ------------------------------------------------------------------------------------------------ 387 388 // MergeMetadataWithVisibilityByHrefAsync updates the metadata entries present in the referenced entity and creates the ones not present, then 389 // returns the task. 390 func (vcdClient *VCDClient) MergeMetadataWithVisibilityByHrefAsync(href string, metadata map[string]types.MetadataValue) (Task, error) { 391 return mergeAllMetadata(&vcdClient.Client, href, "", metadata) 392 } 393 394 // MergeMetadataWithMetadataValuesAsync merges VM metadata provided as a key-value map of type `typedValue` with the already present in VCD, 395 // then returns the task. 396 func (vm *VM) MergeMetadataWithMetadataValuesAsync(metadata map[string]types.MetadataValue) (Task, error) { 397 return mergeAllMetadata(vm.client, vm.VM.HREF, vm.VM.Name, metadata) 398 } 399 400 // MergeMetadataWithMetadataValuesAsync merges AdminVdc metadata provided as a key-value map of type `typedValue` with the already present in VCD, 401 // then waits for the task to complete. 402 func (adminVdc *AdminVdc) MergeMetadataWithMetadataValuesAsync(metadata map[string]types.MetadataValue) (Task, error) { 403 return mergeAllMetadata(adminVdc.client, adminVdc.AdminVdc.HREF, adminVdc.AdminVdc.Name, metadata) 404 } 405 406 // MergeMetadataWithMetadataValuesAsync merges Provider VDC metadata provided as a key-value map of type `typedValue` with the already present in VCD, 407 // then waits for the task to complete. 408 // Note: Requires system administrator privileges. 409 func (providerVdc *ProviderVdc) MergeMetadataWithMetadataValuesAsync(metadata map[string]types.MetadataValue) (Task, error) { 410 return mergeAllMetadata(providerVdc.client, providerVdc.ProviderVdc.HREF, providerVdc.ProviderVdc.Name, metadata) 411 } 412 413 // MergeMetadataWithMetadataValuesAsync merges VApp metadata provided as a key-value map of type `typedValue` with the already present in VCD, 414 // then waits for the task to complete. 415 func (vapp *VApp) MergeMetadataWithMetadataValuesAsync(metadata map[string]types.MetadataValue) (Task, error) { 416 return mergeAllMetadata(vapp.client, vapp.VApp.HREF, vapp.VApp.Name, metadata) 417 } 418 419 // MergeMetadataWithMetadataValuesAsync merges VAppTemplate metadata provided as a key-value map of type `typedValue` with the already present in VCD, 420 // then waits for the task to complete. 421 func (vAppTemplate *VAppTemplate) MergeMetadataWithMetadataValuesAsync(metadata map[string]types.MetadataValue) (Task, error) { 422 return mergeAllMetadata(vAppTemplate.client, vAppTemplate.VAppTemplate.HREF, vAppTemplate.VAppTemplate.Name, metadata) 423 } 424 425 // MergeMetadataWithMetadataValuesAsync merges MediaRecord metadata provided as a key-value map of type `typedValue` with the already present in VCD, 426 // then waits for the task to complete. 427 func (mediaRecord *MediaRecord) MergeMetadataWithMetadataValuesAsync(metadata map[string]types.MetadataValue) (Task, error) { 428 return mergeAllMetadata(mediaRecord.client, mediaRecord.MediaRecord.HREF, mediaRecord.MediaRecord.Name, metadata) 429 } 430 431 // MergeMetadataWithMetadataValuesAsync merges Media metadata provided as a key-value map of type `typedValue` with the already present in VCD, 432 // then waits for the task to complete. 433 func (media *Media) MergeMetadataWithMetadataValuesAsync(metadata map[string]types.MetadataValue) (Task, error) { 434 return mergeAllMetadata(media.client, media.Media.HREF, media.Media.Name, metadata) 435 } 436 437 // MergeMetadataWithMetadataValuesAsync merges AdminCatalog metadata provided as a key-value map of type `typedValue` with the already present in VCD, 438 // then waits for the task to complete. 439 func (adminCatalog *AdminCatalog) MergeMetadataWithMetadataValuesAsync(metadata map[string]types.MetadataValue) (Task, error) { 440 return mergeAllMetadata(adminCatalog.client, adminCatalog.AdminCatalog.HREF, adminCatalog.AdminCatalog.Name, metadata) 441 } 442 443 // MergeMetadataWithMetadataValuesAsync merges AdminOrg metadata provided as a key-value map of type `typedValue` with the already present in VCD, 444 // then waits for the task to complete. 445 func (adminOrg *AdminOrg) MergeMetadataWithMetadataValuesAsync(metadata map[string]types.MetadataValue) (Task, error) { 446 return mergeAllMetadata(adminOrg.client, adminOrg.AdminOrg.HREF, adminOrg.AdminOrg.Name, metadata) 447 } 448 449 // MergeMetadataWithMetadataValuesAsync merges Disk metadata provided as a key-value map of type `typedValue` with the already present in VCD, 450 // then waits for the task to complete. 451 func (disk *Disk) MergeMetadataWithMetadataValuesAsync(metadata map[string]types.MetadataValue) (Task, error) { 452 return mergeAllMetadata(disk.client, disk.Disk.HREF, disk.Disk.Name, metadata) 453 } 454 455 // MergeMetadataWithMetadataValuesAsync merges OrgVDCNetwork metadata provided as a key-value map of type `typedValue` with the already present in VCD, 456 // then waits for the task to complete. 457 // Note: Requires system administrator privileges. 458 func (orgVdcNetwork *OrgVDCNetwork) MergeMetadataWithMetadataValuesAsync(metadata map[string]types.MetadataValue) (Task, error) { 459 return mergeAllMetadata(orgVdcNetwork.client, getAdminURL(orgVdcNetwork.OrgVDCNetwork.HREF), orgVdcNetwork.OrgVDCNetwork.Name, metadata) 460 } 461 462 // MergeMetadataWithMetadataValuesAsync merges CatalogItem metadata provided as a key-value map of type `typedValue` with the already present in VCD, 463 // then waits for the task to complete. 464 func (catalogItem *CatalogItem) MergeMetadataWithMetadataValuesAsync(metadata map[string]types.MetadataValue) (Task, error) { 465 return mergeAllMetadata(catalogItem.client, catalogItem.CatalogItem.HREF, catalogItem.CatalogItem.Name, metadata) 466 } 467 468 // ------------------------------------------------------------------------------------------------ 469 // MERGE metadata 470 // ------------------------------------------------------------------------------------------------ 471 472 // MergeMetadataWithMetadataValues updates the metadata values that are already present in the receiver VM and creates the ones not present. 473 // The input metadata map has a "metadata key"->"metadata value" relation. 474 // This function waits until merge finishes. 475 func (vm *VM) MergeMetadataWithMetadataValues(metadata map[string]types.MetadataValue) error { 476 return mergeMetadataAndWait(vm.client, vm.VM.HREF, vm.VM.Name, metadata) 477 } 478 479 // MergeMetadataWithMetadataValues updates the metadata values that are already present in the receiver AdminVdc and creates the ones not present. 480 // The input metadata map has a "metadata key"->"metadata value" relation. 481 // This function waits until merge finishes. 482 func (adminVdc *AdminVdc) MergeMetadataWithMetadataValues(metadata map[string]types.MetadataValue) error { 483 return mergeMetadataAndWait(adminVdc.client, adminVdc.AdminVdc.HREF, adminVdc.AdminVdc.Name, metadata) 484 } 485 486 // MergeMetadataWithMetadataValues updates the metadata values that are already present in the receiver ProviderVdc and creates the ones not present. 487 // The input metadata map has a "metadata key"->"metadata value" relation. 488 // This function waits until merge finishes. 489 // Note: Requires system administrator privileges. 490 func (providerVdc *ProviderVdc) MergeMetadataWithMetadataValues(metadata map[string]types.MetadataValue) error { 491 return mergeMetadataAndWait(providerVdc.client, providerVdc.ProviderVdc.HREF, providerVdc.ProviderVdc.Name, metadata) 492 } 493 494 // MergeMetadataWithMetadataValues updates the metadata values that are already present in the receiver VApp and creates the ones not present. 495 // The input metadata map has a "metadata key"->"metadata value" relation. 496 // This function waits until merge finishes. 497 func (vApp *VApp) MergeMetadataWithMetadataValues(metadata map[string]types.MetadataValue) error { 498 return mergeMetadataAndWait(vApp.client, vApp.VApp.HREF, vApp.VApp.Name, metadata) 499 } 500 501 // MergeMetadataWithMetadataValues updates the metadata values that are already present in the receiver VAppTemplate and creates the ones not present. 502 // The input metadata map has a "metadata key"->"metadata value" relation. 503 // This function waits until merge finishes. 504 func (vAppTemplate *VAppTemplate) MergeMetadataWithMetadataValues(metadata map[string]types.MetadataValue) error { 505 return mergeMetadataAndWait(vAppTemplate.client, vAppTemplate.VAppTemplate.HREF, vAppTemplate.VAppTemplate.Name, metadata) 506 } 507 508 // MergeMetadataWithMetadataValues updates the metadata values that are already present in the receiver MediaRecord and creates the ones not present. 509 // The input metadata map has a "metadata key"->"metadata value" relation. 510 // This function waits until merge finishes. 511 func (mediaRecord *MediaRecord) MergeMetadataWithMetadataValues(metadata map[string]types.MetadataValue) error { 512 return mergeMetadataAndWait(mediaRecord.client, mediaRecord.MediaRecord.HREF, mediaRecord.MediaRecord.Name, metadata) 513 } 514 515 // MergeMetadataWithMetadataValues updates the metadata values that are already present in the receiver Media and creates the ones not present. 516 // The input metadata map has a "metadata key"->"metadata value" relation. 517 // This function waits until merge finishes. 518 func (media *Media) MergeMetadataWithMetadataValues(metadata map[string]types.MetadataValue) error { 519 return mergeMetadataAndWait(media.client, media.Media.HREF, media.Media.Name, metadata) 520 } 521 522 // MergeMetadataWithMetadataValues updates the metadata values that are already present in the receiver AdminCatalog and creates the ones not present. 523 // The input metadata map has a "metadata key"->"metadata value" relation. 524 // This function waits until merge finishes. 525 func (adminCatalog *AdminCatalog) MergeMetadataWithMetadataValues(metadata map[string]types.MetadataValue) error { 526 return mergeMetadataAndWait(adminCatalog.client, adminCatalog.AdminCatalog.HREF, adminCatalog.AdminCatalog.Name, metadata) 527 } 528 529 // MergeMetadataWithMetadataValues updates the metadata values that are already present in the receiver AdminOrg and creates the ones not present. 530 // The input metadata map has a "metadata key"->"metadata value" relation. 531 // This function waits until merge finishes. 532 func (adminOrg *AdminOrg) MergeMetadataWithMetadataValues(metadata map[string]types.MetadataValue) error { 533 return mergeMetadataAndWait(adminOrg.client, adminOrg.AdminOrg.HREF, adminOrg.AdminOrg.Name, metadata) 534 } 535 536 // MergeMetadataWithMetadataValues updates the metadata values that are already present in the receiver Disk and creates the ones not present. 537 // The input metadata map has a "metadata key"->"metadata value" relation. 538 // This function waits until merge finishes. 539 func (disk *Disk) MergeMetadataWithMetadataValues(metadata map[string]types.MetadataValue) error { 540 return mergeMetadataAndWait(disk.client, disk.Disk.HREF, disk.Disk.Name, metadata) 541 } 542 543 // MergeMetadataWithMetadataValues updates the metadata values that are already present in the receiver OrgVDCNetwork and creates the ones not present. 544 // The input metadata map has a "metadata key"->"metadata value" relation. 545 // This function waits until merge finishes. 546 // Note: Requires system administrator privileges. 547 func (orgVdcNetwork *OrgVDCNetwork) MergeMetadataWithMetadataValues(metadata map[string]types.MetadataValue) error { 548 return mergeMetadataAndWait(orgVdcNetwork.client, getAdminURL(orgVdcNetwork.OrgVDCNetwork.HREF), orgVdcNetwork.OrgVDCNetwork.Name, metadata) 549 } 550 551 // MergeMetadataWithMetadataValues updates the metadata values that are already present in the receiver CatalogItem and creates the ones not present. 552 // The input metadata map has a "metadata key"->"metadata value" relation. 553 // This function waits until merge finishes. 554 func (catalogItem *CatalogItem) MergeMetadataWithMetadataValues(metadata map[string]types.MetadataValue) error { 555 return mergeMetadataAndWait(catalogItem.client, catalogItem.CatalogItem.HREF, catalogItem.CatalogItem.Name, metadata) 556 } 557 558 // MergeMetadataWithMetadataValues updates the metadata values that are already present in the receiver OpenApiOrgVdcNetwork and creates the ones not present. 559 // The input metadata map has a "metadata key"->"metadata value" relation. 560 // This function waits until merge finishes. 561 // Note: It doesn't merge metadata to networks that belong to a VDC Group. 562 // TODO: This function is currently using XML API underneath as OpenAPI metadata is still not supported. 563 func (openApiOrgVdcNetwork *OpenApiOrgVdcNetwork) MergeMetadataWithMetadataValues(metadata map[string]types.MetadataValue) error { 564 href := fmt.Sprintf("%s/admin/network/%s", openApiOrgVdcNetwork.client.VCDHREF.String(), extractUuid(openApiOrgVdcNetwork.OpenApiOrgVdcNetwork.ID)) 565 task, err := mergeAllMetadata(openApiOrgVdcNetwork.client, href, openApiOrgVdcNetwork.OpenApiOrgVdcNetwork.Name, metadata) 566 if err != nil { 567 return err 568 } 569 return task.WaitTaskCompletion() 570 } 571 572 // ------------------------------------------------------------------------------------------------ 573 // DELETE metadata async 574 // ------------------------------------------------------------------------------------------------ 575 576 // DeleteMetadataEntryWithDomainByHrefAsync deletes metadata from the given resource reference, depending on key provided as input 577 // and returns a task. 578 func (vcdClient *VCDClient) DeleteMetadataEntryWithDomainByHrefAsync(href, key string, isSystem bool) (Task, error) { 579 return deleteMetadata(&vcdClient.Client, href, "", key, isSystem) 580 } 581 582 // DeleteMetadataEntryWithDomainAsync deletes VM metadata associated to the input key and returns the task. 583 func (vm *VM) DeleteMetadataEntryWithDomainAsync(key string, isSystem bool) (Task, error) { 584 return deleteMetadata(vm.client, vm.VM.HREF, vm.VM.Name, key, isSystem) 585 } 586 587 // DeleteMetadataEntryWithDomainAsync deletes AdminVdc metadata associated to the input key and returns the task. 588 func (adminVdc *AdminVdc) DeleteMetadataEntryWithDomainAsync(key string, isSystem bool) (Task, error) { 589 return deleteMetadata(adminVdc.client, adminVdc.AdminVdc.HREF, adminVdc.AdminVdc.Name, key, isSystem) 590 } 591 592 // DeleteMetadataEntryWithDomainAsync deletes ProviderVdc metadata associated to the input key and returns the task. 593 // Note: Requires system administrator privileges. 594 func (providerVdc *ProviderVdc) DeleteMetadataEntryWithDomainAsync(key string, isSystem bool) (Task, error) { 595 return deleteMetadata(providerVdc.client, providerVdc.ProviderVdc.HREF, providerVdc.ProviderVdc.Name, key, isSystem) 596 } 597 598 // DeleteMetadataEntryWithDomainAsync deletes VApp metadata associated to the input key and returns the task. 599 func (vapp *VApp) DeleteMetadataEntryWithDomainAsync(key string, isSystem bool) (Task, error) { 600 return deleteMetadata(vapp.client, vapp.VApp.HREF, vapp.VApp.Name, key, isSystem) 601 } 602 603 // DeleteMetadataEntryWithDomainAsync deletes VAppTemplate metadata associated to the input key and returns the task. 604 func (vAppTemplate *VAppTemplate) DeleteMetadataEntryWithDomainAsync(key string, isSystem bool) (Task, error) { 605 return deleteMetadata(vAppTemplate.client, vAppTemplate.VAppTemplate.HREF, vAppTemplate.VAppTemplate.Name, key, isSystem) 606 } 607 608 // DeleteMetadataEntryWithDomainAsync deletes MediaRecord metadata associated to the input key and returns the task. 609 func (mediaRecord *MediaRecord) DeleteMetadataEntryWithDomainAsync(key string, isSystem bool) (Task, error) { 610 return deleteMetadata(mediaRecord.client, mediaRecord.MediaRecord.HREF, mediaRecord.MediaRecord.Name, key, isSystem) 611 } 612 613 // DeleteMetadataEntryWithDomainAsync deletes Media metadata associated to the input key and returns the task. 614 func (media *Media) DeleteMetadataEntryWithDomainAsync(key string, isSystem bool) (Task, error) { 615 return deleteMetadata(media.client, media.Media.HREF, media.Media.Name, key, isSystem) 616 } 617 618 // DeleteMetadataEntryWithDomainAsync deletes AdminCatalog metadata associated to the input key and returns the task. 619 func (adminCatalog *AdminCatalog) DeleteMetadataEntryWithDomainAsync(key string, isSystem bool) (Task, error) { 620 return deleteMetadata(adminCatalog.client, adminCatalog.AdminCatalog.HREF, adminCatalog.AdminCatalog.Name, key, isSystem) 621 } 622 623 // DeleteMetadataEntryWithDomainAsync deletes AdminOrg metadata associated to the input key and returns the task. 624 func (adminOrg *AdminOrg) DeleteMetadataEntryWithDomainAsync(key string, isSystem bool) (Task, error) { 625 return deleteMetadata(adminOrg.client, adminOrg.AdminOrg.HREF, adminOrg.AdminOrg.Name, key, isSystem) 626 } 627 628 // DeleteMetadataEntryWithDomainAsync deletes Disk metadata associated to the input key and returns the task. 629 func (disk *Disk) DeleteMetadataEntryWithDomainAsync(key string, isSystem bool) (Task, error) { 630 return deleteMetadata(disk.client, disk.Disk.HREF, disk.Disk.Name, key, isSystem) 631 } 632 633 // DeleteMetadataEntryWithDomainAsync deletes OrgVDCNetwork metadata associated to the input key and returns the task. 634 // Note: Requires system administrator privileges. 635 func (orgVdcNetwork *OrgVDCNetwork) DeleteMetadataEntryWithDomainAsync(key string, isSystem bool) (Task, error) { 636 return deleteMetadata(orgVdcNetwork.client, getAdminURL(orgVdcNetwork.OrgVDCNetwork.HREF), orgVdcNetwork.OrgVDCNetwork.Name, key, isSystem) 637 } 638 639 // DeleteMetadataEntryWithDomainAsync deletes CatalogItem metadata associated to the input key and returns the task. 640 func (catalogItem *CatalogItem) DeleteMetadataEntryWithDomainAsync(key string, isSystem bool) (Task, error) { 641 return deleteMetadata(catalogItem.client, catalogItem.CatalogItem.HREF, catalogItem.CatalogItem.Name, key, isSystem) 642 } 643 644 // ------------------------------------------------------------------------------------------------ 645 // DELETE metadata 646 // ------------------------------------------------------------------------------------------------ 647 648 // DeleteMetadataEntryWithDomainByHref deletes metadata from the given resource reference, depending on key provided as input 649 // and waits for the task to finish. 650 func (vcdClient *VCDClient) DeleteMetadataEntryWithDomainByHref(href, key string, isSystem bool) error { 651 task, err := vcdClient.DeleteMetadataEntryWithDomainByHrefAsync(href, key, isSystem) 652 if err != nil { 653 return err 654 } 655 return task.WaitTaskCompletion() 656 } 657 658 // DeleteMetadataEntryWithDomain deletes VM metadata associated to the input key and waits for the task to finish. 659 func (vm *VM) DeleteMetadataEntryWithDomain(key string, isSystem bool) error { 660 return deleteMetadataAndWait(vm.client, vm.VM.HREF, vm.VM.Name, key, isSystem) 661 } 662 663 // DeleteMetadataEntryWithDomain deletes AdminVdc metadata associated to the input key and waits for the task to finish. 664 // Note: Requires system administrator privileges. 665 func (adminVdc *AdminVdc) DeleteMetadataEntryWithDomain(key string, isSystem bool) error { 666 return deleteMetadataAndWait(adminVdc.client, getAdminURL(adminVdc.AdminVdc.HREF), adminVdc.AdminVdc.Name, key, isSystem) 667 } 668 669 // DeleteMetadataEntryWithDomain deletes ProviderVdc metadata associated to the input key and waits for the task to finish. 670 // Note: Requires system administrator privileges. 671 func (providerVdc *ProviderVdc) DeleteMetadataEntryWithDomain(key string, isSystem bool) error { 672 return deleteMetadataAndWait(providerVdc.client, providerVdc.ProviderVdc.HREF, providerVdc.ProviderVdc.Name, key, isSystem) 673 } 674 675 // DeleteMetadataEntryWithDomain deletes VApp metadata associated to the input key and waits for the task to finish. 676 func (vApp *VApp) DeleteMetadataEntryWithDomain(key string, isSystem bool) error { 677 return deleteMetadataAndWait(vApp.client, vApp.VApp.HREF, vApp.VApp.Name, key, isSystem) 678 } 679 680 // DeleteMetadataEntryWithDomain deletes VAppTemplate metadata associated to the input key and waits for the task to finish. 681 func (vAppTemplate *VAppTemplate) DeleteMetadataEntryWithDomain(key string, isSystem bool) error { 682 return deleteMetadataAndWait(vAppTemplate.client, vAppTemplate.VAppTemplate.HREF, vAppTemplate.VAppTemplate.Name, key, isSystem) 683 } 684 685 // DeleteMetadataEntryWithDomain deletes MediaRecord metadata associated to the input key and waits for the task to finish. 686 func (mediaRecord *MediaRecord) DeleteMetadataEntryWithDomain(key string, isSystem bool) error { 687 return deleteMetadataAndWait(mediaRecord.client, mediaRecord.MediaRecord.HREF, mediaRecord.MediaRecord.Name, key, isSystem) 688 } 689 690 // DeleteMetadataEntryWithDomain deletes Media metadata associated to the input key and waits for the task to finish. 691 func (media *Media) DeleteMetadataEntryWithDomain(key string, isSystem bool) error { 692 return deleteMetadataAndWait(media.client, media.Media.HREF, media.Media.Name, key, isSystem) 693 } 694 695 // DeleteMetadataEntryWithDomain deletes AdminCatalog metadata associated to the input key and waits for the task to finish. 696 func (adminCatalog *AdminCatalog) DeleteMetadataEntryWithDomain(key string, isSystem bool) error { 697 return deleteMetadataAndWait(adminCatalog.client, adminCatalog.AdminCatalog.HREF, adminCatalog.AdminCatalog.Name, key, isSystem) 698 } 699 700 // DeleteMetadataEntryWithDomain deletes AdminOrg metadata associated to the input key and waits for the task to finish. 701 func (adminOrg *AdminOrg) DeleteMetadataEntryWithDomain(key string, isSystem bool) error { 702 return deleteMetadataAndWait(adminOrg.client, adminOrg.AdminOrg.HREF, adminOrg.AdminOrg.Name, key, isSystem) 703 } 704 705 // DeleteMetadataEntryWithDomain deletes Disk metadata associated to the input key and waits for the task to finish. 706 func (disk *Disk) DeleteMetadataEntryWithDomain(key string, isSystem bool) error { 707 return deleteMetadataAndWait(disk.client, disk.Disk.HREF, disk.Disk.Name, key, isSystem) 708 } 709 710 // DeleteMetadataEntryWithDomain deletes OrgVDCNetwork metadata associated to the input key and waits for the task to finish. 711 // Note: Requires system administrator privileges. 712 func (orgVdcNetwork *OrgVDCNetwork) DeleteMetadataEntryWithDomain(key string, isSystem bool) error { 713 return deleteMetadataAndWait(orgVdcNetwork.client, getAdminURL(orgVdcNetwork.OrgVDCNetwork.HREF), orgVdcNetwork.OrgVDCNetwork.Name, key, isSystem) 714 } 715 716 // DeleteMetadataEntryWithDomain deletes CatalogItem metadata associated to the input key and waits for the task to finish. 717 func (catalogItem *CatalogItem) DeleteMetadataEntryWithDomain(key string, isSystem bool) error { 718 return deleteMetadataAndWait(catalogItem.client, catalogItem.CatalogItem.HREF, catalogItem.CatalogItem.Name, key, isSystem) 719 } 720 721 // DeleteMetadataEntryWithDomain deletes OpenApiOrgVdcNetwork metadata associated to the input key and waits for the task to finish. 722 // Note: It doesn't delete metadata from networks that belong to a VDC Group. 723 // TODO: This function is currently using XML API underneath as OpenAPI metadata is still not supported. 724 func (openApiOrgVdcNetwork *OpenApiOrgVdcNetwork) DeleteMetadataEntryWithDomain(key string, isSystem bool) error { 725 href := fmt.Sprintf("%s/admin/network/%s", openApiOrgVdcNetwork.client.VCDHREF.String(), extractUuid(openApiOrgVdcNetwork.OpenApiOrgVdcNetwork.ID)) 726 task, err := deleteMetadata(openApiOrgVdcNetwork.client, href, openApiOrgVdcNetwork.OpenApiOrgVdcNetwork.Name, key, isSystem) 727 if err != nil { 728 return err 729 } 730 return task.WaitTaskCompletion() 731 } 732 733 // ------------------------------------------------------------------------------------------------ 734 // Ignored metadata set/unset 735 // ------------------------------------------------------------------------------------------------ 736 737 // SetMetadataToIgnore allows to update the metadata to be ignored in all metadata API calls with 738 // the given input. It returns the old IgnoredMetadata configuration from the client 739 func (vcdClient *VCDClient) SetMetadataToIgnore(ignoredMetadata []IgnoredMetadata) []IgnoredMetadata { 740 result := vcdClient.Client.IgnoredMetadata 741 vcdClient.Client.IgnoredMetadata = ignoredMetadata 742 return result 743 } 744 745 // ------------------------------------------------------------------------------------------------ 746 // Generic private functions 747 // ------------------------------------------------------------------------------------------------ 748 749 // getMetadata is a generic function to retrieve metadata from VCD 750 func getMetadataByKey(client *Client, requestUri, name, key string, isSystem bool) (*types.MetadataValue, error) { 751 metadata := &types.MetadataValue{} 752 href := requestUri + "/metadata/" 753 754 if isSystem { 755 href += "SYSTEM/" 756 } 757 758 _, err := client.ExecuteRequest(href+key, http.MethodGet, types.MimeMetaData, "error retrieving metadata by key "+key+": %s", nil, metadata) 759 if err != nil { 760 return nil, err 761 } 762 return filterSingleXmlMetadataEntry(key, requestUri, name, metadata, client.IgnoredMetadata) 763 } 764 765 // getMetadata is a generic function to retrieve metadata from VCD 766 func getMetadata(client *Client, requestUri, name string) (*types.Metadata, error) { 767 metadata := &types.Metadata{} 768 769 _, err := client.ExecuteRequest(requestUri+"/metadata/", http.MethodGet, types.MimeMetaData, "error retrieving metadata: %s", nil, metadata) 770 if err != nil { 771 return nil, err 772 } 773 return filterXmlMetadata(metadata, requestUri, name, client.IgnoredMetadata) 774 } 775 776 // addMetadata adds metadata to an entity. 777 // If the metadata entry is of the SYSTEM domain (isSystem=true), one can set different types of Visibility: 778 // types.MetadataReadOnlyVisibility, types.MetadataHiddenVisibility but NOT types.MetadataReadWriteVisibility. 779 // If the metadata entry is of the GENERAL domain (isSystem=false), visibility is always types.MetadataReadWriteVisibility. 780 // In terms of typedValues, that must be one of: 781 // types.MetadataStringValue, types.MetadataNumberValue, types.MetadataDateTimeValue and types.MetadataBooleanValue. 782 func addMetadata(client *Client, requestUri, name, key, value, typedValue, visibility string, isSystem bool) (Task, error) { 783 apiEndpoint := urlParseRequestURI(requestUri) 784 newMetadata := &types.MetadataValue{ 785 Xmlns: types.XMLNamespaceVCloud, 786 Xsi: types.XMLNamespaceXSI, 787 TypedValue: &types.MetadataTypedValue{ 788 XsiType: typedValue, 789 Value: value, 790 }, 791 Domain: &types.MetadataDomainTag{ 792 Visibility: visibility, 793 Domain: "SYSTEM", 794 }, 795 } 796 797 if isSystem { 798 apiEndpoint.Path += "/metadata/SYSTEM/" + key 799 } else { 800 apiEndpoint.Path += "/metadata/" + key 801 newMetadata.Domain.Domain = "GENERAL" 802 if visibility != types.MetadataReadWriteVisibility { 803 newMetadata.Domain.Visibility = types.MetadataReadWriteVisibility 804 } 805 } 806 807 _, err := filterSingleXmlMetadataEntry(key, requestUri, name, newMetadata, client.IgnoredMetadata) 808 if err != nil { 809 return Task{}, err 810 } 811 812 domain := newMetadata.Domain.Visibility 813 task, err := client.ExecuteTaskRequest(apiEndpoint.String(), http.MethodPut, types.MimeMetaDataValue, "error adding metadata: %s", newMetadata) 814 815 // Workaround for ugly error returned by VCD: "API Error: 500: [ <uuid> ] visibility" 816 if err != nil && strings.HasSuffix(err.Error(), "visibility") { 817 err = fmt.Errorf("error adding metadata with key %s: visibility cannot be %s when domain is %s: %s", key, visibility, domain, err) 818 } 819 return task, err 820 } 821 822 // addMetadataAndWait adds metadata to an entity and waits for the task completion. 823 // The function supports passing a value that requires a typed value that must be one of: 824 // types.MetadataStringValue, types.MetadataNumberValue, types.MetadataDateTimeValue and types.MetadataBooleanValue. 825 // Visibility also needs to be one of: types.MetadataReadOnlyVisibility, types.MetadataHiddenVisibility or types.MetadataReadWriteVisibility 826 func addMetadataAndWait(client *Client, requestUri, name, key, value, typedValue, visibility string, isSystem bool) error { 827 task, err := addMetadata(client, requestUri, name, key, value, typedValue, visibility, isSystem) 828 if err != nil { 829 return err 830 } 831 832 return task.WaitTaskCompletion() 833 } 834 835 // mergeAllMetadata updates the metadata values that are already present in VCD and creates the ones not present. 836 // The input metadata map has a "metadata key"->"metadata value" relation. 837 // If the operation is successful, it returns the created task. 838 func mergeAllMetadata(client *Client, requestUri, name string, metadata map[string]types.MetadataValue) (Task, error) { 839 var metadataToMerge []*types.MetadataEntry 840 for key, value := range metadata { 841 metadataToMerge = append(metadataToMerge, &types.MetadataEntry{ 842 Xmlns: types.XMLNamespaceVCloud, 843 Xsi: types.XMLNamespaceXSI, 844 Key: key, 845 TypedValue: value.TypedValue, 846 Domain: value.Domain, 847 }) 848 } 849 850 newMetadata := &types.Metadata{ 851 Xmlns: types.XMLNamespaceVCloud, 852 Xsi: types.XMLNamespaceXSI, 853 MetadataEntry: metadataToMerge, 854 } 855 856 apiEndpoint := urlParseRequestURI(requestUri) 857 apiEndpoint.Path += "/metadata" 858 859 filteredMetadata, err := filterXmlMetadata(newMetadata, requestUri, name, client.IgnoredMetadata) 860 if err != nil { 861 return Task{}, err 862 } 863 if len(filteredMetadata.MetadataEntry) == 0 { 864 return Task{}, fmt.Errorf("after filtering metadata, there is no metadata to merge") 865 } 866 867 return client.ExecuteTaskRequest(apiEndpoint.String(), http.MethodPost, types.MimeMetaData, "error merging metadata: %s", filteredMetadata) 868 } 869 870 // mergeAllMetadata updates the metadata values that are already present in VCD and creates the ones not present. 871 // The input metadata map has a "metadata key"->"metadata value" relation. 872 // This function waits until merge finishes. 873 func mergeMetadataAndWait(client *Client, requestUri, name string, metadata map[string]types.MetadataValue) error { 874 task, err := mergeAllMetadata(client, requestUri, name, metadata) 875 if err != nil { 876 return err 877 } 878 879 return task.WaitTaskCompletion() 880 } 881 882 // deleteMetadata deletes metadata associated to the input key from an entity referenced by its URI, then returns the 883 // task. 884 func deleteMetadata(client *Client, requestUri, name, key string, isSystem bool) (Task, error) { 885 apiEndpoint := urlParseRequestURI(requestUri) 886 if isSystem { 887 apiEndpoint.Path += "/metadata/SYSTEM/" + key 888 } else { 889 apiEndpoint.Path += "/metadata/" + key 890 } 891 892 err := filterMetadataToDelete(client, key, requestUri, name, isSystem, client.IgnoredMetadata) 893 if err != nil { 894 return Task{}, err 895 } 896 897 return client.ExecuteTaskRequest(apiEndpoint.String(), http.MethodDelete, "", "error deleting metadata: %s", nil) 898 } 899 900 // deleteMetadata deletes metadata associated to the input key from an entity referenced by its URI. 901 func deleteMetadataAndWait(client *Client, requestUri, name, key string, isSystem bool) error { 902 task, err := deleteMetadata(client, requestUri, name, key, isSystem) 903 if err != nil { 904 return err 905 } 906 907 return task.WaitTaskCompletion() 908 } 909 910 // IgnoredMetadata is a structure that defines the metadata entries that should be ignored by the VCD Client. 911 // The filtering works in such a way that all the non-nil pointers in an instance of this struct are evaluated with 912 // a logical AND. 913 // For example, ignoredMetadata.ObjectType = "org", ignoredMetadata.ObjectName = "foo" will ignore all metadata from 914 // Organizations whose name is "foo", with any key and any value. 915 // Note: This struct is only used by metadata_v2.go methods. 916 // Note 2: Filtering by ObjectName is not possible in the "ByHref" methods from VCDClient. 917 type IgnoredMetadata struct { 918 ObjectType *string // Type of the object that has the metadata as defined in the API documentation https://developer.vmware.com/apis/1601/vmware-cloud-director, for example "catalog", "disk", "org"... 919 ObjectName *string // Name of the object 920 KeyRegex *regexp.Regexp // A regular expression to filter out metadata keys 921 ValueRegex *regexp.Regexp // A regular expression to filter out metadata values 922 } 923 924 func (im IgnoredMetadata) String() string { 925 objectType := "<nil>" 926 if im.ObjectType != nil { 927 objectType = *im.ObjectType 928 } 929 930 objectName := "<nil>" 931 if im.ObjectName != nil { 932 objectName = *im.ObjectName 933 } 934 935 return fmt.Sprintf("IgnoredMetadata(ObjectType=%v, ObjectName=%v, KeyRegex=%v, ValueRegex=%v)", objectType, objectName, im.KeyRegex, im.ValueRegex) 936 } 937 938 // normalisedMetadata is an auxiliary type that allows to transform XML and OpenAPI metadata into a common structure 939 // for operations that are executed the same way in both flavors. 940 type normalisedMetadata struct { 941 ObjectType string 942 ObjectName string 943 Key string 944 Value string 945 } 946 947 // normaliseXmlMetadata transforms XML metadata into a normalised structure 948 func normaliseXmlMetadata(key, href, objectName string, metadataEntry *types.MetadataValue) (*normalisedMetadata, error) { 949 objectType, err := getMetadataObjectTypeFromHref(href) 950 if err != nil { 951 return nil, err 952 } 953 954 return &normalisedMetadata{ 955 ObjectType: objectType, 956 ObjectName: objectName, 957 Key: key, 958 Value: metadataEntry.TypedValue.Value, 959 }, nil 960 } 961 962 // filterXmlMetadata filters all metadata entries, given a slice of metadata that needs to be ignored. It doesn't 963 // alter the input metadata, but returns a copy of the filtered metadata. 964 func filterXmlMetadata(allMetadata *types.Metadata, href, objectName string, metadataToIgnore []IgnoredMetadata) (*types.Metadata, error) { 965 if len(metadataToIgnore) == 0 { 966 return allMetadata, nil 967 } 968 969 result := &types.Metadata{ 970 XMLName: allMetadata.XMLName, 971 Xmlns: allMetadata.Xmlns, 972 HREF: allMetadata.HREF, 973 Type: allMetadata.Type, 974 Xsi: allMetadata.Xsi, 975 Link: allMetadata.Link, 976 MetadataEntry: nil, 977 } 978 979 var filteredMetadata []*types.MetadataEntry 980 for _, originalEntry := range allMetadata.MetadataEntry { 981 _, err := filterSingleXmlMetadataEntry(originalEntry.Key, href, objectName, &types.MetadataValue{Domain: originalEntry.Domain, TypedValue: originalEntry.TypedValue}, metadataToIgnore) 982 if err != nil { 983 if strings.Contains(err.Error(), "ignored") { 984 continue 985 } 986 return nil, err 987 } 988 filteredMetadata = append(filteredMetadata, originalEntry) 989 } 990 result.MetadataEntry = filteredMetadata 991 return result, nil 992 } 993 994 func filterSingleXmlMetadataEntry(key, href, objectName string, metadataEntry *types.MetadataValue, metadataToIgnore []IgnoredMetadata) (*types.MetadataValue, error) { 995 normalisedEntry, err := normaliseXmlMetadata(key, href, objectName, metadataEntry) 996 if err != nil { 997 return nil, err 998 } 999 isFiltered := filterSingleGenericMetadataEntry(normalisedEntry, metadataToIgnore) 1000 if isFiltered { 1001 return nil, fmt.Errorf("the metadata entry with key '%s' and value '%v' is being ignored", key, metadataEntry.TypedValue.Value) 1002 } 1003 return metadataEntry, nil 1004 } 1005 1006 // filterSingleGenericMetadataEntry filters a single metadata entry given a slice of metadata that needs to be ignored. It doesn't 1007 // alter the input metadata, but returns a bool that indicates whether the entry should be ignored or not. 1008 func filterSingleGenericMetadataEntry(normalisedMetadataEntry *normalisedMetadata, metadataToIgnore []IgnoredMetadata) bool { 1009 if len(metadataToIgnore) == 0 { 1010 return false 1011 } 1012 1013 for _, entryToIgnore := range metadataToIgnore { 1014 if entryToIgnore.ObjectType == nil && entryToIgnore.ObjectName == nil && entryToIgnore.KeyRegex == nil && entryToIgnore.ValueRegex == nil { 1015 continue 1016 } 1017 util.Logger.Printf("[DEBUG] Comparing metadata with key '%s' with ignored metadata filter '%s'", normalisedMetadataEntry.Key, entryToIgnore) 1018 // We apply an optimistic approach here to simplify the conditions, so the metadata entry will always be ignored unless the filters 1019 // tell otherwise, that is, if they are nil (not all of them as per the condition above), if they're empty or if they don't match. 1020 // All the filtering options (type, name, keyRegex and valueRegex) must compute to true for the metadata to be ignored. 1021 if (entryToIgnore.ObjectType == nil || strings.TrimSpace(*entryToIgnore.ObjectType) == "" || *entryToIgnore.ObjectType == normalisedMetadataEntry.ObjectType) && 1022 (entryToIgnore.ObjectName == nil || strings.TrimSpace(*entryToIgnore.ObjectName) == "" || strings.TrimSpace(normalisedMetadataEntry.ObjectName) == "" || *entryToIgnore.ObjectName == normalisedMetadataEntry.ObjectName) && 1023 (entryToIgnore.KeyRegex == nil || entryToIgnore.KeyRegex.MatchString(normalisedMetadataEntry.Key)) && 1024 (entryToIgnore.ValueRegex == nil || entryToIgnore.ValueRegex.MatchString(normalisedMetadataEntry.Value)) { 1025 util.Logger.Printf("[DEBUG] the metadata entry with key '%s' and value '%v' is being ignored", normalisedMetadataEntry.ObjectType, normalisedMetadataEntry.Value) 1026 return true 1027 } 1028 } 1029 return false 1030 } 1031 1032 // filterMetadataToDelete filters a metadata entry that is going to be deleted, given a slice of metadata that needs to be ignored. 1033 func filterMetadataToDelete(client *Client, key, href, objectName string, isSystem bool, metadataToIgnore []IgnoredMetadata) error { 1034 if len(metadataToIgnore) == 0 { 1035 return nil 1036 } 1037 1038 objectType, err := getMetadataObjectTypeFromHref(href) 1039 if err != nil { 1040 return err 1041 } 1042 for _, entryToIgnore := range metadataToIgnore { 1043 if entryToIgnore.ObjectType == nil && entryToIgnore.ObjectName == nil && entryToIgnore.KeyRegex == nil && entryToIgnore.ValueRegex == nil { 1044 continue 1045 } 1046 1047 if (entryToIgnore.ObjectType == nil || strings.TrimSpace(*entryToIgnore.ObjectType) == "" || *entryToIgnore.ObjectType == objectType) && 1048 (entryToIgnore.ObjectName == nil || strings.TrimSpace(*entryToIgnore.ObjectName) == "" || strings.TrimSpace(objectName) == "" || *entryToIgnore.ObjectName == objectName) && 1049 (entryToIgnore.KeyRegex == nil || entryToIgnore.KeyRegex.MatchString(key)) { 1050 1051 // Entering here means that it is a good candidate to be ignored, but we need to know the metadata value 1052 // as we may be filtering by value 1053 ignore := true 1054 if entryToIgnore.ValueRegex != nil { 1055 metadataEntry, err := getMetadataByKey(client, href, objectName, key, isSystem) 1056 if err != nil { 1057 return err 1058 } 1059 if !entryToIgnore.ValueRegex.MatchString(metadataEntry.TypedValue.Value) { 1060 ignore = false 1061 } 1062 } 1063 1064 if ignore { 1065 util.Logger.Printf("[DEBUG] can't delete metadata entry %s as it is ignored", key) 1066 return fmt.Errorf("can't delete metadata entry %s as it is ignored", key) 1067 } 1068 return nil 1069 } 1070 } 1071 return nil 1072 1073 } 1074 1075 // getMetadataObjectTypeFromHref returns the type of the object referenced by the input HREF. 1076 // For example, "https://atl1-vcd-static-130-117.eng.vmware.com/api/admin/org/11582a00-16bb-4916-a42f-2d5e453ccf36" 1077 // will return "org". 1078 func getMetadataObjectTypeFromHref(href string) (string, error) { 1079 splitHref := strings.Split(href, "/") 1080 if len(splitHref) < 2 { 1081 return "", fmt.Errorf("could not find any object type in the provided HREF '%s'", href) 1082 } 1083 return splitHref[len(splitHref)-2], nil 1084 }