This is an automated email from the ASF dual-hosted git repository.
abh1sar pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack-go.git
The following commit(s) were added to refs/heads/main by this push:
new 70fb49a Scope GetTemplateByName/GetIsoByName by-ID lookup to the zone
(#87) (#153)
70fb49a is described below
commit 70fb49a01b425d6f7c6590980ca11c9e2b83f3d8
Author: James Peru Mmbono <[email protected]>
AuthorDate: Wed Aug 5 11:09:42 2026 +0300
Scope GetTemplateByName/GetIsoByName by-ID lookup to the zone (#87) (#153)
GetTemplateByName (and GetIsoByName) resolve the id with the zoneid
constraint via GetTemplateID, then call GetTemplateByID/GetIsoByID WITHOUT
the zone. A template/ISO registered in multiple zones lists one row per
zone for the same UUID, so the helper fails with 'There is more then one
result for Template UUID: ...!' (#87).
Fix the generator to pass the zone into the by-ID lookup via the existing
WithZone option for Template/Iso, and apply it to the two generated helpers.
WithZone is a no-op on empty zoneid and uses the id directly for a UUID.
Adds a regression test reproducing #87.
Signed-off-by: James Peru <[email protected]>
Co-authored-by: James Peru <[email protected]>
---
cloudstack/ISOService.go | 2 +-
cloudstack/TemplateService.go | 2 +-
generate/generate.go | 8 +++-
test/GetTemplateByNameZoneRegression_test.go | 66 ++++++++++++++++++++++++++++
4 files changed, 75 insertions(+), 3 deletions(-)
diff --git a/cloudstack/ISOService.go b/cloudstack/ISOService.go
index 5000bc5..d98f004 100644
--- a/cloudstack/ISOService.go
+++ b/cloudstack/ISOService.go
@@ -2300,7 +2300,7 @@ func (s *ISOService) GetIsoByName(name string, isofilter
string, zoneid string,
return nil, count, err
}
- r, count, err := s.GetIsoByID(id, opts...)
+ r, count, err := s.GetIsoByID(id, append(opts, WithZone(zoneid))...)
if err != nil {
return nil, count, err
}
diff --git a/cloudstack/TemplateService.go b/cloudstack/TemplateService.go
index e9f9071..dd7f68e 100644
--- a/cloudstack/TemplateService.go
+++ b/cloudstack/TemplateService.go
@@ -2844,7 +2844,7 @@ func (s *TemplateService) GetTemplateByName(name string,
templatefilter string,
return nil, count, err
}
- r, count, err := s.GetTemplateByID(id, templatefilter, opts...)
+ r, count, err := s.GetTemplateByID(id, templatefilter, append(opts,
WithZone(zoneid))...)
if err != nil {
return nil, count, err
}
diff --git a/generate/generate.go b/generate/generate.go
index 7fbeb79..c967967 100644
--- a/generate/generate.go
+++ b/generate/generate.go
@@ -1671,7 +1671,13 @@ func (s *service) generateHelperFuncs(a *API) {
p("%s, ",
s.parseParamName(ap.Name))
}
}
- pn("opts...)")
+ // Constrain the by-ID lookup to the same zone;
otherwise a Template/ISO
+ // registered in multiple zones returns
multiple rows for one UUID (#87).
+ if parseSingular(ln) == "Template" ||
parseSingular(ln) == "Iso" {
+ pn("append(opts, WithZone(zoneid))...)")
+ } else {
+ pn("opts...)")
+ }
pn(" if err != nil {")
pn(" return nil, count, err")
pn(" }")
diff --git a/test/GetTemplateByNameZoneRegression_test.go
b/test/GetTemplateByNameZoneRegression_test.go
new file mode 100644
index 0000000..f579f42
--- /dev/null
+++ b/test/GetTemplateByNameZoneRegression_test.go
@@ -0,0 +1,66 @@
+//
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+
+package test
+
+import (
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/apache/cloudstack-go/v2/cloudstack"
+)
+
+// Regression test for issue #87: GetTemplateByName must carry the zoneid
+// constraint into the by-ID lookup. Otherwise a template registered in
multiple
+// zones lists multiple rows for one UUID and the helper fails with
+// "There is more then one result for Template UUID: ...!".
+func TestGetTemplateByNameScopesByIDLookupToZone(t *testing.T) {
+ const tmplID = "06145677-058a-456a-89a0-af4afd6fffcf"
+ const zoneID = "11111111-2222-3333-4444-555555555555"
+
+ server := httptest.NewServer(http.HandlerFunc(func(w
http.ResponseWriter, r *http.Request) {
+ q := r.URL.Query()
+ w.Header().Set("Content-Type", "application/json")
+ if q.Get("id") != "" {
+ // by-ID lookup: a multi-zone template returns one row
PER zone unless
+ // the zoneid is passed through (the bug). With the
fix, zoneid is set.
+ if q.Get("zoneid") != "" {
+ fmt.Fprintf(w,
`{"listtemplatesresponse":{"count":1,"template":[{"id":%q,"name":"mytmpl","zoneid":"zoneA"}]}}`,
tmplID)
+ } else {
+ fmt.Fprintf(w,
`{"listtemplatesresponse":{"count":2,"template":[{"id":%q,"name":"mytmpl","zoneid":"zoneA"},{"id":%q,"name":"mytmpl","zoneid":"zoneB"}]}}`,
tmplID, tmplID)
+ }
+ return
+ }
+ // by-name lookup (GetTemplateID) resolves to a single template
id
+ fmt.Fprintf(w,
`{"listtemplatesresponse":{"count":1,"template":[{"id":%q,"name":"mytmpl"}]}}`,
tmplID)
+ }))
+ defer server.Close()
+
+ client := cloudstack.NewClient(server.URL, "APIKEY", "SECRETKEY", true)
+
+ tmpl, _, err := client.Template.GetTemplateByName("mytmpl", "all",
zoneID)
+ if err != nil {
+ t.Fatalf("expected zone-scoped GetTemplateByName to succeed,
got error: %v", err)
+ }
+ if tmpl == nil || tmpl.Id != tmplID {
+ t.Fatalf("expected template %s, got %+v", tmplID, tmpl)
+ }
+}