Description
NB: This issue is relevant to the implementation of data sources/imports in terraform-provider-vcd.
Problem
Currently we have several methods with the format
func (parent *ParentEntity) GetEntityByName(name string) (Entity, error) {}
func (parent *ParentEntity) FindEntityByName(name string) (Entity, error) {}
We have three problems with these methods:
- Non standard names. They should all be called
Find...
or allGet...
- Some return an
Entity
structure, some a pointer to the entity - Some return an error when the entity is not found, some return nil and an empty structure when the entity was not found.
- Not really a problem, but a limitation: we only search by name, while we will soon need to search for ID too.
Problem n.2 and n.3 contribute to complicate usage of such methods. Currently we do something like:
entity, err := parent.FindEntityByName(name)
if err != nil {
return err
}
if entity == Entity{} {
return err
}
// OR something like
if entity.Child.HREF == "" {
return err
}
The point is that we don't know for sure what the error means, and we don't know what to expect from the return value.
Proposal
To alleviate the problems above, we need to
- User standard names
- Make it simpler to detect when the search failed
- Assign meaning to the errors
Solution 1: remove the error and use pointers
func (parent *ParentEntity) GetEntityByName(name string) *Entity {}
If we want the users to inspect the returned object to determine whether the search was successful, we don't need the error. We just return a pointer to the structure and the receiver function can simply say if entity != nil
and that's it.
Solution 2: Give meaning to the error and return pointers
var ErrorEntityNotFound = fmt.Errorf("entity was not found")
// ...
func (parent *ParentEntity) GetEntityByName(name string) (*Entity, error) {
if weDidNotFindTheEntity {
return nil, ErrorEntityNotFound
}
}
Using this method, the receiving function will do:
entity, err := parent.FindEntityByName(name)
if err != nil { // meaning we did not find, or there was some other error
return someError
}
// OR
if entity == nil { // also this means that we did not find
return someError
}
// OR
if err == ErrorEntityNotFound { // also this means that we did not find
return someError
}
Standardization
Whichever solution we choose, we should do six things:
- Deprecate the existing methods, but leave them in place, as they need to still work in Terraform
- Create new methods to replace the deprecated ones, with a standard name, such as
FetchEntityByNameOrId
- make the method find the entity using either name or ID
- the method must return a pointer to the entity structure
- in case of not found, it will return a nil pointer and if solution n.2 is chosen, a standardized error.
- For every data source that we implement, we start using the new methods and change usage of the old methods with the new ones for the corresponding resource. When we replace everything, we can safely bump up the version and remove the deprecated things.
I vote for Solution n. 2
CC: @lvirbalas @vbauzysvmware @Didainius