Fix service_offering lookup by filtering with zone parameter (#325)
* Fix service_offering lookup by filtering with zone parameter
The cloudstack_instance resource was not filtering service_offering lookups by zone,
which could cause failures when multiple service offerings share the same name but
are restricted to specific zones.
This change introduces a new retrieveServiceOfferingID function that filters
service offerings by both name and zone ID, similar to how templates are looked up.
Fixes: #260
diff --git a/cloudstack/resource_cloudstack_instance.go b/cloudstack/resource_cloudstack_instance.go
index 026ec4c..afa5093 100644
--- a/cloudstack/resource_cloudstack_instance.go
+++ b/cloudstack/resource_cloudstack_instance.go
@@ -264,14 +264,14 @@
cs := meta.(*cloudstack.CloudStackClient)
- // Retrieve the service_offering ID
- serviceofferingid, e := retrieveID(cs, "service_offering", d.Get("service_offering").(string))
+ // Retrieve the zone ID first (needed for service_offering lookup)
+ zoneid, e := retrieveID(cs, "zone", d.Get("zone").(string))
if e != nil {
return e.Error()
}
- // Retrieve the zone ID
- zoneid, e := retrieveID(cs, "zone", d.Get("zone").(string))
+ // Retrieve the service_offering ID (filtered by zone)
+ serviceofferingid, e := retrieveServiceOfferingID(cs, zoneid, d.Get("service_offering").(string))
if e != nil {
return e.Error()
}
@@ -727,8 +727,14 @@
if d.HasChange("service_offering") {
log.Printf("[DEBUG] Service offering changed for %s, starting update", name)
- // Retrieve the service_offering ID
- serviceofferingid, e := retrieveID(cs, "service_offering", d.Get("service_offering").(string))
+ // Retrieve the zone ID first (needed for service_offering lookup)
+ zoneid, e := retrieveID(cs, "zone", d.Get("zone").(string))
+ if e != nil {
+ return e.Error()
+ }
+
+ // Retrieve the service_offering ID (filtered by zone)
+ serviceofferingid, e := retrieveServiceOfferingID(cs, zoneid, d.Get("service_offering").(string))
if e != nil {
return e.Error()
}
diff --git a/cloudstack/resources.go b/cloudstack/resources.go
index 5a75b77..c08f202 100644
--- a/cloudstack/resources.go
+++ b/cloudstack/resources.go
@@ -128,6 +128,31 @@
return id, nil
}
+func retrieveServiceOfferingID(cs *cloudstack.CloudStackClient, zoneid, value string) (id string, e *retrieveError) {
+ // If the supplied value isn't a ID, try to retrieve the ID ourselves
+ if cloudstack.IsID(value) {
+ return value, nil
+ }
+
+ log.Printf("[DEBUG] Retrieving ID of service offering: %s in zone: %s", value, zoneid)
+
+ // List service offerings filtered by zone and name to handle zone-specific offerings
+ p := cs.ServiceOffering.NewListServiceOfferingsParams()
+ p.SetName(value)
+ p.SetZoneid(zoneid)
+ l, err := cs.ServiceOffering.ListServiceOfferings(p)
+ if err != nil {
+ return "", &retrieveError{name: "service_offering", value: value, err: err}
+ }
+
+ if l.Count != 1 {
+ err := fmt.Errorf("Found %d service offering(s) with name %s in zone %s", l.Count, value, zoneid)
+ return "", &retrieveError{name: "service_offering", value: value, err: err}
+ }
+
+ return l.ServiceOfferings[0].Id, nil
+}
+
// RetryFunc is the function retried n times
type RetryFunc func() (interface{}, error)