Replace struct based mapping by manual mapping
The old way does not allow to handle updates correctly. When a nullable
field is set and we want to remove the value we need to be able to set
a null value in the json request body. For instance this happen in
firewall rules for field source_ip_address (among others).
diff --git a/openstack/networking/v2/extensions/fwaas/firewalls/requests.go b/openstack/networking/v2/extensions/fwaas/firewalls/requests.go
index 2c44713..950c14d 100644
--- a/openstack/networking/v2/extensions/fwaas/firewalls/requests.go
+++ b/openstack/networking/v2/extensions/fwaas/firewalls/requests.go
@@ -44,31 +44,45 @@
TenantID string
Name string
Description string
- AdminStateUp bool
- Shared bool
+ AdminStateUp *bool
+ Shared *bool
PolicyID string
}
+// ToPolicyCreateMap casts a CreateOpts struct to a map.
+func (opts CreateOpts) ToPolicyCreateMap() map[string]interface{} {
+ p := make(map[string]interface{})
+
+ if opts.TenantID != "" {
+ p["tenant_id"] = opts.TenantID
+ }
+ if opts.Name != "" {
+ p["name"] = opts.Name
+ }
+ if opts.Description != "" {
+ p["description"] = opts.Description
+ }
+ if opts.Shared != nil {
+ p["shared"] = *opts.Shared
+ }
+ if opts.AdminStateUp != nil {
+ p["admin_state_up"] = *opts.AdminStateUp
+ }
+ if opts.PolicyID != "" {
+ p["firewall_policy_id"] = opts.PolicyID
+ }
+
+ return p
+}
+
// Create accepts a CreateOpts struct and uses the values to create a new firewall
func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult {
- type firewall struct {
- TenantID string `json:"tenant_id,omitempty"`
- Name string `json:"name,omitempty"`
- Description string `json:"description,omitempty"`
- AdminStateUp bool `json:"admin_state_up,omitempty"`
- PolicyID string `json:"firewall_policy_id"`
- }
+
type request struct {
- Firewall firewall `json:"firewall"`
+ Firewall map[string]interface{} `json:"firewall"`
}
- reqBody := request{Firewall: firewall{
- TenantID: opts.TenantID,
- Name: opts.Name,
- Description: opts.Description,
- AdminStateUp: opts.AdminStateUp,
- PolicyID: opts.PolicyID,
- }}
+ reqBody := request{Firewall: opts.ToPolicyCreateMap()}
var res CreateResult
_, res.Err = perigee.Request("POST", rootURL(c), perigee.Options{
@@ -94,31 +108,44 @@
// UpdateOpts contains the values used when updating a firewall.
type UpdateOpts struct {
// Name of the firewall.
- Name string
- Description string
- AdminStateUp bool
- Status string
+ Name *string
+ Description *string
+ AdminStateUp *bool
+ Shared *bool
PolicyID string
}
+// ToPolicyUpdateMap casts a CreateOpts struct to a map.
+func (opts UpdateOpts) ToPolicyUpdateMap() map[string]interface{} {
+ p := make(map[string]interface{})
+
+ if opts.Name != nil {
+ p["name"] = *opts.Name
+ }
+ if opts.Description != nil {
+ p["description"] = *opts.Description
+ }
+ if opts.Shared != nil {
+ p["shared"] = *opts.Shared
+ }
+ if opts.AdminStateUp != nil {
+ p["admin_state_up"] = *opts.AdminStateUp
+ }
+ if opts.PolicyID != "" {
+ p["firewall_policy_id"] = opts.PolicyID
+ }
+
+ return p
+}
+
// Update allows firewalls to be updated.
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResult {
- type firewall struct {
- Name string `json:"name"`
- Description string `json:"description"`
- AdminStateUp bool `json:"admin_state_up,omitempty"`
- PolicyID string `json:"firewall_policy_id,omitempty"`
- }
+
type request struct {
- Firewall firewall `json:"firewall"`
+ Firewall map[string]interface{} `json:"firewall"`
}
- reqBody := request{Firewall: firewall{
- Name: opts.Name,
- Description: opts.Description,
- AdminStateUp: opts.AdminStateUp,
- PolicyID: opts.PolicyID,
- }}
+ reqBody := request{Firewall: opts.ToPolicyUpdateMap()}
// Send request to API
var res UpdateResult
diff --git a/openstack/networking/v2/extensions/fwaas/firewalls/results.go b/openstack/networking/v2/extensions/fwaas/firewalls/results.go
index 53c3029..a8c76ee 100644
--- a/openstack/networking/v2/extensions/fwaas/firewalls/results.go
+++ b/openstack/networking/v2/extensions/fwaas/firewalls/results.go
@@ -13,6 +13,7 @@
AdminStateUp bool `json:"admin_state_up" mapstructure:"admin_state_up"`
Status string `json:"status" mapstructure:"status"`
PolicyID string `json:"firewall_policy_id" mapstructure:"firewall_policy_id"`
+ TenantID string `json:"tenant_id" mapstructure:"tenant_id"`
}
type commonResult struct {
diff --git a/openstack/networking/v2/extensions/fwaas/policies/requests.go b/openstack/networking/v2/extensions/fwaas/policies/requests.go
index 5242f3a..260b728 100644
--- a/openstack/networking/v2/extensions/fwaas/policies/requests.go
+++ b/openstack/networking/v2/extensions/fwaas/policies/requests.go
@@ -10,6 +10,8 @@
TenantID string `q:"tenant_id"`
Name string `q:"name"`
Description string `q:"description"`
+ Shared bool `q:"shared"`
+ Audited bool `q:"audited"`
ID string `q:"id"`
Limit int `q:"limit"`
Marker string `q:"marker"`
@@ -38,30 +40,48 @@
type CreateOpts struct {
// Only required if the caller has an admin role and wants to create a firewall policy
// for another tenant.
- TenantId string
+ TenantID string
Name string
Description string
+ Shared *bool
+ Audited *bool
Rules []string
}
+// ToPolicyCreateMap casts a CreateOpts struct to a map.
+func (opts CreateOpts) ToPolicyCreateMap() map[string]interface{} {
+ p := make(map[string]interface{})
+
+ if opts.TenantID != "" {
+ p["tenant_id"] = opts.TenantID
+ }
+ if opts.Name != "" {
+ p["name"] = opts.Name
+ }
+ if opts.Description != "" {
+ p["description"] = opts.Description
+ }
+ if opts.Shared != nil {
+ p["shared"] = *opts.Shared
+ }
+ if opts.Audited != nil {
+ p["audited"] = *opts.Audited
+ }
+ if opts.Rules != nil {
+ p["firewall_rules"] = opts.Rules
+ }
+
+ return p
+}
+
// Create accepts a CreateOpts struct and uses the values to create a new firewall policy
func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult {
- type policy struct {
- TenantId string `json:"tenant_id,omitempty"`
- Name string `json:"name,omitempty"`
- Description string `json:"description,omitempty"`
- Rules []string `json:"firewall_rules,omitempty"`
- }
+
type request struct {
- Policy policy `json:"firewall_policy"`
+ Policy map[string]interface{} `json:"firewall_policy"`
}
- reqBody := request{Policy: policy{
- TenantId: opts.TenantId,
- Name: opts.Name,
- Description: opts.Description,
- Rules: opts.Rules,
- }}
+ reqBody := request{Policy: opts.ToPolicyCreateMap()}
var res CreateResult
_, res.Err = perigee.Request("POST", rootURL(c), perigee.Options{
@@ -87,27 +107,44 @@
// UpdateOpts contains the values used when updating a firewall policy.
type UpdateOpts struct {
// Name of the firewall policy.
- Name string
- Description string
+ Name *string
+ Description *string
+ Shared *bool
+ Audited *bool
Rules []string
}
+// ToPolicyUpdateMap casts a CreateOpts struct to a map.
+func (opts UpdateOpts) ToPolicyUpdateMap() map[string]interface{} {
+ p := make(map[string]interface{})
+
+ if opts.Name != nil {
+ p["name"] = *opts.Name
+ }
+ if opts.Description != nil {
+ p["description"] = *opts.Description
+ }
+ if opts.Shared != nil {
+ p["shared"] = *opts.Shared
+ }
+ if opts.Audited != nil {
+ p["audited"] = *opts.Audited
+ }
+ if opts.Rules != nil {
+ p["firewall_rules"] = opts.Rules
+ }
+
+ return p
+}
+
// Update allows firewall policies to be updated.
func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResult {
- type policy struct {
- Name string `json:"name"`
- Description string `json:"description"`
- Rules []string `json:"firewall_rules,omitempty"`
- }
+
type request struct {
- Policy policy `json:"firewall_policy"`
+ Policy map[string]interface{} `json:"firewall_policy"`
}
- reqBody := request{Policy: policy{
- Name: opts.Name,
- Description: opts.Description,
- Rules: opts.Rules,
- }}
+ reqBody := request{Policy: opts.ToPolicyUpdateMap()}
// Send request to API
var res UpdateResult
diff --git a/openstack/networking/v2/extensions/fwaas/rules/requests.go b/openstack/networking/v2/extensions/fwaas/rules/requests.go
index 181a758..18690b7 100644
--- a/openstack/networking/v2/extensions/fwaas/rules/requests.go
+++ b/openstack/networking/v2/extensions/fwaas/rules/requests.go
@@ -49,14 +49,14 @@
// CreateOpts contains all the values needed to create a new firewall rule.
type CreateOpts struct {
- // Mandatory
+ // Mandatory for create
Protocol string
Action string
// Optional
TenantID string
Name string
Description string
- IPVersion *int
+ IPVersion int
SourceIPAddress string
DestinationIPAddress string
SourcePort string
@@ -65,41 +65,55 @@
Enabled *bool
}
+// ToRuleCreateMap casts a CreateOpts struct to a map.
+func (opts CreateOpts) ToRuleCreateMap() map[string]interface{} {
+ r := make(map[string]interface{})
+
+ r["protocol"] = opts.Protocol
+ r["action"] = opts.Action
+
+ if opts.TenantID != "" {
+ r["tenant_id"] = opts.TenantID
+ }
+ if opts.Name != "" {
+ r["name"] = opts.Name
+ }
+ if opts.Description != "" {
+ r["description"] = opts.Description
+ }
+ if opts.IPVersion != 0 {
+ r["ip_version"] = opts.IPVersion
+ }
+ if opts.SourceIPAddress != "" {
+ r["source_ip_address"] = opts.SourceIPAddress
+ }
+ if opts.DestinationIPAddress != "" {
+ r["destination_ip_address"] = opts.DestinationIPAddress
+ }
+ if opts.SourcePort != "" {
+ r["source_port"] = opts.SourcePort
+ }
+ if opts.DestinationPort != "" {
+ r["destination_port"] = opts.DestinationPort
+ }
+ if opts.Shared != nil {
+ r["shared"] = *opts.Shared
+ }
+ if opts.Enabled != nil {
+ r["enabled"] = *opts.Enabled
+ }
+
+ return r
+}
+
// Create accepts a CreateOpts struct and uses the values to create a new firewall rule
func Create(c *gophercloud.ServiceClient, opts CreateOpts) CreateResult {
- type rule struct {
- TenantID string `json:"tenant_id,omitempty"`
- Name string `json:"name"`
- Description string `json:"description"`
- Protocol string `json:"protocol"`
- Action string `json:"action"`
- IPVersion *int `json:"ip_version,omitempty"`
- SourceIPAddress string `json:"source_ip_address,omitempty"`
- DestinationIPAddress string `json:"destination_ip_address,omitempty"`
- SourcePort string `json:"source_port,omitempty"`
- DestinationPort string `json:"destination_port,omitempty"`
- Shared *bool `json:"shared,omitempty"`
- Enabled *bool `json:"enabled,omitempty"`
- }
type request struct {
- Rule rule `json:"firewall_rule"`
+ Rule map[string]interface{} `json:"firewall_rule"`
}
- reqBody := request{Rule: rule{
- TenantID: opts.TenantID,
- Name: opts.Name,
- Description: opts.Description,
- Protocol: opts.Protocol,
- Action: opts.Action,
- IPVersion: opts.IPVersion,
- SourceIPAddress: opts.SourceIPAddress,
- DestinationIPAddress: opts.DestinationIPAddress,
- SourcePort: opts.SourcePort,
- DestinationPort: opts.DestinationPort,
- Shared: opts.Shared,
- Enabled: opts.Enabled,
- }}
+ reqBody := request{Rule: opts.ToRuleCreateMap()}
var res CreateResult
_, res.Err = perigee.Request("POST", rootURL(c), perigee.Options{
@@ -123,52 +137,90 @@
}
// UpdateOpts contains the values used when updating a firewall rule.
+// Optional
type UpdateOpts struct {
- Name string
- Description string
Protocol string
Action string
- IPVersion *int
- SourceIPAddress string
- DestinationIPAddress string
- SourcePort string
- DestinationPort string
+ Name *string
+ Description *string
+ IPVersion int
+ SourceIPAddress *string
+ DestinationIPAddress *string
+ SourcePort *string
+ DestinationPort *string
Shared *bool
Enabled *bool
}
-// Update allows firewall policies to be updated.
-func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResult {
- type rule struct {
- Name string `json:"name"`
- Description string `json:"description"`
- Protocol string `json:"protocol"`
- Action string `json:"action"`
- IPVersion *int `json:"ip_version,omitempty"`
- SourceIPAddress string `json:"source_ip_address"`
- DestinationIPAddress string `json:"destination_ip_address"`
- SourcePort string `json:"source_port"`
- DestinationPort string `json:"destination_port"`
- Shared *bool `json:"shared,omitempty"`
- Enabled *bool `json:"enabled,omitempty"`
+// ToRuleUpdateMap casts a UpdateOpts struct to a map.
+func (opts UpdateOpts) ToRuleUpdateMap() map[string]interface{} {
+ r := make(map[string]interface{})
+
+ if opts.Protocol != "" {
+ r["protocol"] = opts.Protocol
}
- type request struct {
- Rule rule `json:"firewall_rule"`
+ if opts.Action != "" {
+ r["action"] = opts.Action
+ }
+ if opts.Name != nil {
+ r["name"] = *opts.Name
+ }
+ if opts.Description != nil {
+ r["description"] = *opts.Description
+ }
+ if opts.IPVersion != 0 {
+ r["ip_version"] = opts.IPVersion
+ }
+ if opts.SourceIPAddress != nil {
+ s := *opts.SourceIPAddress
+ if s == "" {
+ r["source_ip_address"] = nil
+ } else {
+ r["source_ip_address"] = s
+ }
+ }
+ if opts.DestinationIPAddress != nil {
+ s := *opts.DestinationIPAddress
+ if s == "" {
+ r["destination_ip_address"] = nil
+ } else {
+ r["destination_ip_address"] = s
+ }
+ }
+ if opts.SourcePort != nil {
+ s := *opts.SourcePort
+ if s == "" {
+ r["source_port"] = nil
+ } else {
+ r["source_port"] = s
+ }
+ }
+ if opts.DestinationPort != nil {
+ s := *opts.DestinationPort
+ if s == "" {
+ r["destination_port"] = nil
+ } else {
+ r["destination_port"] = s
+ }
+ }
+ if opts.Shared != nil {
+ r["shared"] = *opts.Shared
+ }
+ if opts.Enabled != nil {
+ r["enabled"] = *opts.Enabled
}
- reqBody := request{Rule: rule{
- Name: opts.Name,
- Description: opts.Description,
- Protocol: opts.Protocol,
- Action: opts.Action,
- IPVersion: opts.IPVersion,
- SourceIPAddress: opts.SourceIPAddress,
- DestinationIPAddress: opts.DestinationIPAddress,
- SourcePort: opts.SourcePort,
- DestinationPort: opts.DestinationPort,
- Shared: opts.Shared,
- Enabled: opts.Enabled,
- }}
+ return r
+}
+
+// Update allows firewall policies to be updated.
+func Update(c *gophercloud.ServiceClient, id string, opts UpdateOpts) UpdateResult {
+
+ type request struct {
+ Rule map[string]interface{} `json:"firewall_rule"`
+ }
+
+ reqBody := request{Rule: opts.ToRuleUpdateMap()}
// Send request to API
var res UpdateResult
diff --git a/openstack/networking/v2/extensions/fwaas/rules/results.go b/openstack/networking/v2/extensions/fwaas/rules/results.go
index ff3de8a..d772024 100644
--- a/openstack/networking/v2/extensions/fwaas/rules/results.go
+++ b/openstack/networking/v2/extensions/fwaas/rules/results.go
@@ -20,6 +20,9 @@
DestinationPort string `json:"destination_port,omitempty" mapstructure:"destination_port"`
Shared bool `json:"shared,omitempty" mapstructure:"shared"`
Enabled bool `json:"enabled,omitempty" mapstructure:"enabled"`
+ PolicyID string `json:"firewall_policy_id" mapstructure:"firewall_policy_id"`
+ Position int `json:"position" mapstructure:"position"`
+ TenantID string `json:"tenant_id" mapstructure:"tenant_id"`
}
// RulePage is the page returned by a pager when traversing over a