Closed sk4zuzu closed 7 months ago
To clarify -> if you add the missing vm_template
this does not change the outcome.. :point_up: :relieved:
Hi,
Thanks for reporting this, I'll try to give a lot of informations as a starting point to work on this problem, feel free to discuss if you have some better ideas or if I made a mistake somewhere :)
A bit of context: Until now I didn't worked on service and service templates resources because these resources were added in goca and then in the terraform provider by OpenNebula team members, and these resources don't work like the other ones (other resources are fully manage via XML-RPC protocol, there's no REST API). I may be the reviewer of the PR when this was submitted but overall I didn't know enough about oneflow and there was no bugs submitted by users until now.
Some more details on what's happening in the create and read step of the provider for the service_template
resource:
I'm able to reproduce the problem of this issue applying this:
resource "opennebula_service_template" "service_template" {
name = "test-svc"
permissions = "760"
template = <<EOF
{
"TEMPLATE": {
"BODY": {
"name": "test-svc",
"deployment": "straight",
"description": "",
"roles": [
{
"name": "vnf",
"cardinality": 1,
"min_vms": 1,
"vm_template_contents": "...",
"cooldown": 120,
"elasticity_policies": [],
"scheduled_policies": []
}
]
}
}
}
EOF
}
The diffs appears at the next plan.
In the provider the content of the template
field is unmarshalled in this Goca structure:
https://github.com/OpenNebula/one/blob/master/src/oca/go/src/goca/schemas/service_template/service_template.go#L30
Then the service is created from this structure: https://github.com/OpenNebula/terraform-provider-opennebula/blob/master/opennebula/resource_opennebula_service_template.go#L130
As a side note, I don't get why this code is here: https://github.com/OpenNebula/one/blob/master/src/oca/go/src/goca/service_template.go#L117 nil is returned just after, sounds like dead code
Now let's look at the Goca Create method for the service template resource: https://github.com/OpenNebula/one/blob/master/src/oca/go/src/goca/service_template.go#L97
It's splitted across Goca and the provider but the json content is unmarshalled, then marshalled and again unmarshalled.
Doing this suit of marshall/unmarshal allow to check the json, remove empty fields (via omitempty
annotation on structs in goca) etc.
Then I added a line here to get some additional logs from the provider (I did the changes on my computer only): https://github.com/OpenNebula/one/blob/master/src/oca/go/src/goca/service_template.go#L106
Here the log I got:
map[string]interface {}{
"name": "test-svc",
"deployment": "straight",
"roles": []interface {}{
map[string]interface {}{
"min_vms": float64(1),
"cooldown": float64(120),
"name": "vnf",
"cardinality": float64(1),
"vm_template": float64(0),
"vm_template_contents": "...",
},
},
}
Now we need let's look at the reading step so I added a logging line here in the provider https://github.com/OpenNebula/terraform-provider-opennebula/blob/master/opennebula/resource_opennebula_service_template.go#L265
Again it the code there's some marhal/unmarshaling. Here is the resulting log line:
{"BODY":{"name":"test-svc","deployment":"straight","roles":[{"name":"vnf","cardinality":1,"vm_template":0,"vm_template_contents":"...","min_vms":1,"cooldown":120}]}}
All the diffs shown by terraform seems to be on absent fields, or fields with their "empty" value (0 for an integer etc.)
Let's consider the description
field: this sounds like terraform see it described in the string inside of the template
field, but when reading from OpenNebula the template part, the empty description is not described.
It's expected, the Goca structure have some omitempty
, so when marshalling all empty values are removed.
For vm_template
it's different because this field has no omitempty
field, so even when 0 is
Not sure on how we should fix this, some quick ideas to test:
ValidateFunc
and DiffSuppressFunc
functions, to the template
field of the service_template
resource.omitempty
is not enough fined grained (it remove an int if it's value is 0). For instance, we could replace an int
field by an *int
field to distinguish when a field has it's "empty" value and when it's just not presentBut if possible, from terraform point of view it may be better to do some refactoring (in the provider and probably in Goca) to work with service_template
and service
resources in the same way that other resources.
This would allow to share a bunch of code between service
and service_template
resources in the TF provider like it's already done between template
and virtual_machine
resources. This would add a lot of new fields to the service_template
resource and this would allow to replace the template
text field.
Would this last solution be possible ? (I'm asking because in https://marketplace.opennebula.io/appliance/7c82d610-73f1-47d1-a85a-d799e00c631e I already see the json to pass in template
)
Description
:warning: I believe this is debatable if this "bug" is to be handled in the provider, but please bear with me... :hugs:
Let's consider this exact OneFlow template -> https://marketplace.opennebula.io/appliance/7c82d610-73f1-47d1-a85a-d799e00c631e
Running
terraform apply
twice causes:Terraform and Provider version
Affected resources and data sources
opennebula_service_template
Terraform configuration
Expected behavior
The second
terraform apply
run should be idempotent and the resource should not be recreated (it should be at least in-place modified).Actual behavior
The second
terraform apply
run recreates the resource despite there is no actual difference in the config.Steps to Reproduce
Debug output
N/A
Panic output
N/A
Important factoids
https://pls.watch/#v=https://i.imgur.com/LXzo2h8.mp4&t=5s;8s :thinking:
References
https://docs.opennebula.io/6.6/integration_and_development/system_interfaces/appflow_api.html#service-schema