Handle Unmarshaling Compute Security Group IDs (#192)
* Handling integer secgroup IDs
* Handling integer secgroup rule IDs
* Updating unit tests for integer secgroup IDs and rule IDs
* Style updates
* Style updates
* Test formatting fix
diff --git a/openstack/compute/v2/extensions/secgroups/results.go b/openstack/compute/v2/extensions/secgroups/results.go
index 764f580..f49338a 100644
--- a/openstack/compute/v2/extensions/secgroups/results.go
+++ b/openstack/compute/v2/extensions/secgroups/results.go
@@ -1,6 +1,9 @@
package secgroups
import (
+ "encoding/json"
+ "strconv"
+
"github.com/gophercloud/gophercloud"
"github.com/gophercloud/gophercloud/pagination"
)
@@ -10,28 +13,51 @@
// The unique ID of the group. If Neutron is installed, this ID will be
// represented as a string UUID; if Neutron is not installed, it will be a
// numeric ID. For the sake of consistency, we always cast it to a string.
- ID string
+ ID string `json:"-"`
// The human-readable name of the group, which needs to be unique.
- Name string
+ Name string `json:"name"`
// The human-readable description of the group.
- Description string
+ Description string `json:"description"`
// The rules which determine how this security group operates.
- Rules []Rule
+ Rules []Rule `json:"rules"`
// The ID of the tenant to which this security group belongs.
TenantID string `json:"tenant_id"`
}
+func (r *SecurityGroup) UnmarshalJSON(b []byte) error {
+ type tmp SecurityGroup
+ var s struct {
+ tmp
+ ID interface{} `json:"id"`
+ }
+ err := json.Unmarshal(b, &s)
+ if err != nil {
+ return err
+ }
+
+ *r = SecurityGroup(s.tmp)
+
+ switch t := s.ID.(type) {
+ case float64:
+ r.ID = strconv.FormatFloat(t, 'f', -1, 64)
+ case string:
+ r.ID = t
+ }
+
+ return err
+}
+
// Rule represents a security group rule, a policy which determines how a
// security group operates and what inbound traffic it allows in.
type Rule struct {
// The unique ID. If Neutron is installed, this ID will be
// represented as a string UUID; if Neutron is not installed, it will be a
// numeric ID. For the sake of consistency, we always cast it to a string.
- ID string
+ ID string `json:"-"`
// The lower bound of the port range which this security group should open up
FromPort int `json:"from_port"`
@@ -52,6 +78,37 @@
Group Group
}
+func (r *Rule) UnmarshalJSON(b []byte) error {
+ type tmp Rule
+ var s struct {
+ tmp
+ ID interface{} `json:"id"`
+ ParentGroupID interface{} `json:"parent_group_id"`
+ }
+ err := json.Unmarshal(b, &s)
+ if err != nil {
+ return err
+ }
+
+ *r = Rule(s.tmp)
+
+ switch t := s.ID.(type) {
+ case float64:
+ r.ID = strconv.FormatFloat(t, 'f', -1, 64)
+ case string:
+ r.ID = t
+ }
+
+ switch t := s.ParentGroupID.(type) {
+ case float64:
+ r.ParentGroupID = strconv.FormatFloat(t, 'f', -1, 64)
+ case string:
+ r.ParentGroupID = t
+ }
+
+ return err
+}
+
// IPRange represents the IP range whose traffic will be accepted by the
// security group.
type IPRange struct {