-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add resource and data source for MAAS zones #258
base: master
Are you sure you want to change the base?
Conversation
Everyone contributing to this PR have now signed the CLA. Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @peterctl
Awesome work. Thank you for your first (I am looking forward to more) contribution to the provider. I tried to be exhaustive with comments to help you tackle the issues faster. Apart from 1-2 things that we can debate, rest of the suggested changes are needed.
Please take a look and let me know to re-review.
PS. Please include examples for data-source, resource and import and run make generate_docs
to produce Markdown for the new resources. When you are done, please include the files to your PR too. Naming of directories and files is important for the tool to pick up the examples.
Reference:
- https://github.com/canonical/terraform-provider-maas/blob/master/examples/data-sources/maas_resource_pool/data-source.tf
- https://github.com/canonical/terraform-provider-maas/blob/master/examples/resources/maas_resource_pool/resource.tf
- https://github.com/canonical/terraform-provider-maas/blob/master/examples/resources/maas_resource_pool/import.sh
🍻
if err != nil { | ||
return diag.FromErr(err) | ||
} | ||
d.SetId(zone.Name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about setting as terraform ID the database ID of the zone instead of the name? In addition, line 41 "id": fmt.Sprintf("%v", zone.ID),
is not needed
d.SetId(zone.Name) | |
d.SetId(fmt.Sprintf("%v", zone.ID)) |
maas/resource_maas_zone.go
Outdated
client := meta.(*client.Client) | ||
|
||
params := getZoneParams(d) | ||
zone, err := findZone(client, params.Name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trying to find if zone already exists in MAAS here costs an extra API call to MAAS. It is accepted to blindly try create the zone as the intention is that Terraform is managing it. If it already exists, MAAS will throw an error and this will be propagated to gomaasclient, then from the client to terraform provider and finally being presented to user as part of diagnostic errors. Then the user can import the zone to Terraform and continue its management with Terraform.
Let's simplify the function. Resource pool is again a good example as the implementation is more or less identical.
return diag.FromErr(err) | ||
} | ||
} | ||
d.SetId(zone.Name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As said earlier, let's save the database ID as a Terraform resource ID
func resourceZoneDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { | ||
client := meta.(*client.Client) | ||
|
||
if err := client.Zone.Delete(d.Id()); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be simplified to
if err := client.Zone.Delete(d.Id()); err != nil { | |
return client.Zone.Delete(id)) |
given that id is calculated like the previous suggestion
} | ||
|
||
conn := testutils.TestAccProvider.Meta().(*client.Client) | ||
gotZone, err := conn.Zone.Get(rs.Primary.ID) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is also needed if we are to save the database ID as the Terraform resource ID
id, err := strconv.Atoi(rs.Primary.ID)
if err != nil {
return err
}
// Retrieve our maas_zone by referencing it's state ID for API lookup | ||
response, err := conn.Zone.Get(rs.Primary.ID) | ||
if err == nil { | ||
if response != nil && response.Name == rs.Primary.ID { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if response != nil && response.Name == rs.Primary.ID { | |
if response != nil && response.ID == rs.Primary.ID { |
Hi @skatsaounis, Thank you for the thorough review! It's my first time working directly with Terraform providers so the feedback is very useful to me. I have applied most of the requested changes already, but I have an issue with setting the database ID as the Terraform ID instead of the name. The reason for this is that the gomaasclient will only accept names as arguments to // client_tests.go
package main
import (
"fmt"
"os"
"terraform-provider-maas/maas"
)
func playground() error {
config := maas.Config{
APIURL: os.Getenv("MAAS_API_URL"),
APIKey: os.Getenv("MAAS_API_KEY"),
ApiVersion: "2.0",
}
client, err := config.Client()
if err != nil {
return err
}
zoneByName, errByName := client.Zone.Get("az1")
zoneByID, errByID := client.Zone.Get("3")
fmt.Printf("zoneByName: %+v\n", zoneByName)
fmt.Printf("errByName: %+v\n", errByName)
fmt.Printf("zoneByID: %+v\n", zoneByID)
fmt.Printf("errByID: %+v\n", errByID)
return nil
}
func main() {
err := playground()
fmt.Println(err)
} $ go run client_playground.go
zoneByName: &{Name:az1 Description: ResourceURI:/MAAS/api/2.0/zones/az1/ ID:3}
errByName: <nil>
zoneByID: &{Name: Description: ResourceURI: ID:0}
errByID: ServerError: 404 Not Found (No Zone matches the given query.) For clarity, the ID and name do match as can be seen in If we want to use the database ID as the Terraform ID, I think we would need to rely on params := getZoneParams(d)
zone, err := getZone(d.Id())
if err != nil {
return diag.FromErr(err)
}
zone, err = client.Zone.Update(zone.Name, params)
if err != nil {
return diag.FromErr(err)
} Please advise on how to proceed with name vs ID. Is there a better approach? |
Hi @peterctl , The fact that MAAS API v2 is using the zone name instead of the database ID is problematic by itself. Since we cannot change the contract, it is what it is. With the v3 MAAS API we aim to solve this issue among others, but it is not there yet. As you spotted, the findZone is what you need here. We may add an extra API call, but it is a cheap one since zones response is small and we should expect something in the magnitude of tens or hundreds. What is the benefit though? Imagine that someone outside terraform, updated the zone name but there are already existing machines assigned to that zone. What you would expect from Terraform is to identify that change and try to update the same zone, instead of creating a new record. One of the weird behaviors of the API v2 is that you can use Please proceed with the database ID as the Terraform resource ID. In addition, we have to add a field of machines, like we do with tags so that we can assign the zone to machines with Terraform. I forgot to tell you in the first review. An alternative would be a new resource |
Managing MAAS availability zones through Terraform is a missing feature that I needed for a project.
Acceptance test output for the zone resource and datasource can be seen here: