Skip to content

Commit 3a3dded

Browse files
TPT-3388: Separated GET and POST/PUT options structs where needed (#969)
* Separated GET and POST/PUT options structs where needed * Separated additional structs that were reused for options and response * More struct fixes * Fix lint * Rename FirewallRule structs * integration test fixes * Addressed PR comments * FirewallRuleSetRule options; test updates; fixture refreshed * Address more PR comments --------- Co-authored-by: Zhiwei Liang <zliang@akamai.com>
1 parent bebb463 commit 3a3dded

20 files changed

Lines changed: 317 additions & 171 deletions

firewall_rules.go

Lines changed: 72 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,27 +22,69 @@ type NetworkAddresses struct {
2222
IPv6 []string `json:"ipv6,omitzero"`
2323
}
2424

25-
// A FirewallRule is a whitelist of ports, protocols, and addresses for which traffic should be allowed.
26-
// The ipv4/ipv6 address lists may contain Prefix List tokens (for example, "pl::..." or "pl:system:...")
27-
// in addition to literal IP addresses.
28-
type FirewallRule struct {
25+
type FirewallRuleInbound struct {
2926
Action string `json:"action"`
3027
Label string `json:"label"`
3128
Description string `json:"description,omitzero"`
3229
Ports string `json:"ports,omitzero"`
3330
Protocol NetworkProtocol `json:"protocol"`
3431
Addresses NetworkAddresses `json:"addresses"`
3532

36-
// FirewallRule references one `Rule Set` by ID. When provided, this entry
33+
// FirewallRuleInbound references one `Rule Set` by ID. When provided, this entry
3734
// represents a reference and should be mutually exclusive with ordinary
3835
// rule fields according to the API contract.
3936
RuleSet int `json:"ruleset,omitzero"`
4037
}
4138

42-
// MarshalJSON ensures that when a rule references a Rule Set (RuleSet != 0),
39+
type FirewallRuleOutbound struct {
40+
Action string `json:"action"`
41+
Label string `json:"label"`
42+
Description string `json:"description,omitzero"`
43+
Ports string `json:"ports,omitzero"`
44+
Protocol NetworkProtocol `json:"protocol"`
45+
Addresses NetworkAddresses `json:"addresses"`
46+
47+
// FirewallRuleOutbound references one `Rule Set` by ID. When provided, this entry
48+
// represents a reference and should be mutually exclusive with ordinary
49+
// rule fields according to the API contract.
50+
RuleSet int `json:"ruleset,omitzero"`
51+
}
52+
53+
// MarshalJSON ensures that when a rule references a Rule Set (FirewallRuleSet != 0),
54+
// only the reference shape { "ruleset": <id> } is emitted. Otherwise, the
55+
// ordinary rule fields are emitted without the ruleset key.
56+
func (r FirewallRuleInbound) MarshalJSON() ([]byte, error) {
57+
if r.RuleSet != 0 {
58+
type rulesetOnly struct {
59+
RuleSet int `json:"ruleset"`
60+
}
61+
62+
return json.Marshal(rulesetOnly{RuleSet: r.RuleSet})
63+
}
64+
65+
type normal struct {
66+
Action string `json:"action"`
67+
Label string `json:"label"`
68+
Description string `json:"description,omitzero"`
69+
Ports string `json:"ports,omitzero"`
70+
Protocol NetworkProtocol `json:"protocol"`
71+
Addresses NetworkAddresses `json:"addresses"`
72+
}
73+
74+
return json.Marshal(normal{
75+
Action: r.Action,
76+
Label: r.Label,
77+
Description: r.Description,
78+
Ports: r.Ports,
79+
Protocol: r.Protocol,
80+
Addresses: r.Addresses,
81+
})
82+
}
83+
84+
// MarshalJSON ensures that when a rule references a Rule Set (FirewallRuleSet != 0),
4385
// only the reference shape { "ruleset": <id> } is emitted. Otherwise, the
4486
// ordinary rule fields are emitted without the ruleset key.
45-
func (r FirewallRule) MarshalJSON() ([]byte, error) {
87+
func (r FirewallRuleOutbound) MarshalJSON() ([]byte, error) {
4688
if r.RuleSet != 0 {
4789
type rulesetOnly struct {
4890
RuleSet int `json:"ruleset"`
@@ -70,34 +112,36 @@ func (r FirewallRule) MarshalJSON() ([]byte, error) {
70112
})
71113
}
72114

73-
// FirewallRuleSet is a pair of inbound and outbound rules that specify what network traffic should be allowed.
74-
type FirewallRuleSet struct {
75-
Inbound []FirewallRule `json:"inbound"`
76-
InboundPolicy string `json:"inbound_policy"`
77-
Outbound []FirewallRule `json:"outbound"`
78-
OutboundPolicy string `json:"outbound_policy"`
79-
80-
// TODO: separate request and response types in linodego v2
81-
// read-only, can't be used in creating or updating a Firewall
82-
Version int `json:"version,omitzero"`
83-
// read-only, can't be used in creating or updating a Firewall
84-
Fingerprint string `json:"fingerprint,omitzero"`
115+
// FirewallRules is a pair of inbound and outbound rules that specify what network traffic should be allowed.
116+
type FirewallRules struct {
117+
Inbound []FirewallRuleInbound `json:"inbound"`
118+
InboundPolicy string `json:"inbound_policy"`
119+
Outbound []FirewallRuleOutbound `json:"outbound"`
120+
OutboundPolicy string `json:"outbound_policy"`
121+
Version int `json:"version,omitzero"`
122+
Fingerprint string `json:"fingerprint,omitzero"`
123+
}
124+
type FirewallRulesUpdateOptions struct {
125+
Inbound []FirewallRuleInbound `json:"inbound"`
126+
InboundPolicy string `json:"inbound_policy"`
127+
Outbound []FirewallRuleOutbound `json:"outbound"`
128+
OutboundPolicy string `json:"outbound_policy"`
85129
}
86130

87-
// GetFirewallRules gets the FirewallRuleSet for the given Firewall.
88-
func (c *Client) GetFirewallRules(ctx context.Context, firewallID int) (*FirewallRuleSet, error) {
131+
// GetFirewallRules gets the FirewallRules for the given Firewall.
132+
func (c *Client) GetFirewallRules(ctx context.Context, firewallID int) (*FirewallRules, error) {
89133
e := formatAPIPath("networking/firewalls/%d/rules", firewallID)
90-
return doGETRequest[FirewallRuleSet](ctx, c, e)
134+
return doGETRequest[FirewallRules](ctx, c, e)
91135
}
92136

93-
// GetFirewallRulesExpansion gets the expanded FirewallRuleSet for the given Firewall.
94-
func (c *Client) GetFirewallRulesExpansion(ctx context.Context, firewallID int) (*FirewallRuleSet, error) {
137+
// GetFirewallRulesExpansion gets the expanded FirewallRules for the given Firewall.
138+
func (c *Client) GetFirewallRulesExpansion(ctx context.Context, firewallID int) (*FirewallRules, error) {
95139
e := formatAPIPath("networking/firewalls/%d/rules/expansion", firewallID)
96-
return doGETRequest[FirewallRuleSet](ctx, c, e)
140+
return doGETRequest[FirewallRules](ctx, c, e)
97141
}
98142

99-
// UpdateFirewallRules updates the FirewallRuleSet for the given Firewall
100-
func (c *Client) UpdateFirewallRules(ctx context.Context, firewallID int, rules FirewallRuleSet) (*FirewallRuleSet, error) {
143+
// UpdateFirewallRules updates the FirewallRules for the given Firewall
144+
func (c *Client) UpdateFirewallRules(ctx context.Context, firewallID int, rules FirewallRulesUpdateOptions) (*FirewallRules, error) {
101145
e := formatAPIPath("networking/firewalls/%d/rules", firewallID)
102-
return doPUTRequest[FirewallRuleSet](ctx, c, e, rules)
146+
return doPUTRequest[FirewallRules](ctx, c, e, rules)
103147
}

firewall_rulesets.go

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,54 @@ const (
1717
FirewallRuleSetTypeOutbound FirewallRuleSetType = "outbound"
1818
)
1919

20-
// RuleSet represents the Rule Set resource.
20+
// FirewallRuleSet represents the Rule Set resource.
2121
// Note: created/updated/deleted are parsed via UnmarshalJSON into time.Time pointers.
22-
type RuleSet struct {
23-
ID int `json:"id"`
24-
Label string `json:"label"`
25-
Description string `json:"description,omitzero"`
26-
Type FirewallRuleSetType `json:"type"`
27-
Rules []FirewallRule `json:"rules"`
28-
IsServiceDefined bool `json:"is_service_defined"`
29-
Version int `json:"version"`
22+
type FirewallRuleSet struct {
23+
ID int `json:"id"`
24+
Label string `json:"label"`
25+
Description string `json:"description,omitzero"`
26+
Type FirewallRuleSetType `json:"type"`
27+
Rules []FirewallRuleSetRule `json:"rules"`
28+
IsServiceDefined bool `json:"is_service_defined"`
29+
Version int `json:"version"`
3030

3131
Created *time.Time `json:"-"`
3232
Updated *time.Time `json:"-"`
3333
Deleted *time.Time `json:"-"`
3434
}
3535

36-
// UnmarshalJSON implements custom timestamp parsing for RuleSet.
37-
func (r *RuleSet) UnmarshalJSON(b []byte) error {
38-
type Mask RuleSet
36+
// A FirewallRuleSetRule is a whitelist of ports, protocols, and addresses for which traffic should be allowed.
37+
// The ipv4/ipv6 address lists may contain Prefix List tokens (for example, "pl::..." or "pl:system:...")
38+
// in addition to literal IP addresses.
39+
type FirewallRuleSetRule struct {
40+
Action string `json:"action"`
41+
Label string `json:"label"`
42+
Ports string `json:"ports,omitzero"`
43+
Protocol NetworkProtocol `json:"protocol"`
44+
Addresses NetworkAddresses `json:"addresses"`
45+
}
46+
47+
// FirewallRuleSetRuleCreateOptions fields accepted in Firewall Rule Set create payloads.
48+
type FirewallRuleSetRuleCreateOptions struct {
49+
Action string `json:"action"`
50+
Label string `json:"label"`
51+
Ports string `json:"ports,omitzero"`
52+
Protocol NetworkProtocol `json:"protocol"`
53+
Addresses NetworkAddresses `json:"addresses"`
54+
}
55+
56+
// FirewallRuleSetRuleUpdateOptions fields accepted in Firewall Rule Set update payloads.
57+
type FirewallRuleSetRuleUpdateOptions struct {
58+
Action string `json:"action"`
59+
Label string `json:"label"`
60+
Ports string `json:"ports,omitzero"`
61+
Protocol NetworkProtocol `json:"protocol"`
62+
Addresses NetworkAddresses `json:"addresses"`
63+
}
64+
65+
// UnmarshalJSON implements custom timestamp parsing for FirewallRuleSet.
66+
func (r *FirewallRuleSet) UnmarshalJSON(b []byte) error {
67+
type Mask FirewallRuleSet
3968

4069
aux := struct {
4170
*Mask
@@ -66,44 +95,44 @@ func (r *RuleSet) UnmarshalJSON(b []byte) error {
6695
return nil
6796
}
6897

69-
// RuleSetCreateOptions fields accepted by CreateRuleSet.
70-
type RuleSetCreateOptions struct {
71-
Label string `json:"label"`
72-
Description string `json:"description,omitzero"`
73-
Type FirewallRuleSetType `json:"type"`
74-
Rules []FirewallRule `json:"rules"`
98+
// FirewallRuleSetCreateOptions fields accepted by CreateRuleSet.
99+
type FirewallRuleSetCreateOptions struct {
100+
Label string `json:"label"`
101+
Description string `json:"description,omitzero"`
102+
Type FirewallRuleSetType `json:"type"`
103+
Rules []FirewallRuleSetRuleCreateOptions `json:"rules"`
75104
}
76105

77-
// RuleSetUpdateOptions fields accepted by UpdateRuleSet.
106+
// FirewallRuleSetUpdateOptions fields accepted by UpdateRuleSet.
78107
// Omit a top-level field to leave it unchanged. If Rules is provided, it
79108
// replaces the entire ordered rules array.
80-
type RuleSetUpdateOptions struct {
81-
Label *string `json:"label,omitzero"`
82-
Description *string `json:"description,omitzero"`
83-
Rules []FirewallRule `json:"rules,omitzero"`
109+
type FirewallRuleSetUpdateOptions struct {
110+
Label *string `json:"label,omitzero"`
111+
Description *string `json:"description,omitzero"`
112+
Rules []FirewallRuleSetRuleUpdateOptions `json:"rules,omitzero"`
84113
}
85114

86115
// ListFirewallRuleSets returns a paginated list of Rule Sets.
87116
// Supports filtering (e.g., by label) via ListOptions.Filter.
88-
func (c *Client) ListFirewallRuleSets(ctx context.Context, opts *ListOptions) ([]RuleSet, error) {
89-
return getPaginatedResults[RuleSet](ctx, c, "networking/firewalls/rulesets", opts)
117+
func (c *Client) ListFirewallRuleSets(ctx context.Context, opts *ListOptions) ([]FirewallRuleSet, error) {
118+
return getPaginatedResults[FirewallRuleSet](ctx, c, "networking/firewalls/rulesets", opts)
90119
}
91120

92121
// CreateFirewallRuleSet creates a new Rule Set.
93-
func (c *Client) CreateFirewallRuleSet(ctx context.Context, opts RuleSetCreateOptions) (*RuleSet, error) {
94-
return doPOSTRequest[RuleSet](ctx, c, "networking/firewalls/rulesets", opts)
122+
func (c *Client) CreateFirewallRuleSet(ctx context.Context, opts FirewallRuleSetCreateOptions) (*FirewallRuleSet, error) {
123+
return doPOSTRequest[FirewallRuleSet](ctx, c, "networking/firewalls/rulesets", opts)
95124
}
96125

97126
// GetFirewallRuleSet fetches a Rule Set by ID.
98-
func (c *Client) GetFirewallRuleSet(ctx context.Context, rulesetID int) (*RuleSet, error) {
127+
func (c *Client) GetFirewallRuleSet(ctx context.Context, rulesetID int) (*FirewallRuleSet, error) {
99128
e := formatAPIPath("networking/firewalls/rulesets/%d", rulesetID)
100-
return doGETRequest[RuleSet](ctx, c, e)
129+
return doGETRequest[FirewallRuleSet](ctx, c, e)
101130
}
102131

103132
// UpdateFirewallRuleSet updates a Rule Set by ID.
104-
func (c *Client) UpdateFirewallRuleSet(ctx context.Context, rulesetID int, opts RuleSetUpdateOptions) (*RuleSet, error) {
133+
func (c *Client) UpdateFirewallRuleSet(ctx context.Context, rulesetID int, opts FirewallRuleSetUpdateOptions) (*FirewallRuleSet, error) {
105134
e := formatAPIPath("networking/firewalls/rulesets/%d", rulesetID)
106-
return doPUTRequest[RuleSet](ctx, c, e, opts)
135+
return doPUTRequest[FirewallRuleSet](ctx, c, e, opts)
107136
}
108137

109138
// DeleteFirewallRuleSet deletes a Rule Set by ID.

firewall_templates.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import (
55
)
66

77
type FirewallTemplate struct {
8-
Slug string `json:"slug"`
9-
Rules FirewallRuleSet `json:"rules"`
8+
Slug string `json:"slug"`
9+
Rules FirewallRules `json:"rules"`
1010
}
1111

1212
// GetFirewallTemplate gets a FirewallTemplate given a slug.

firewalls.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ type Firewall struct {
2424
Label string `json:"label"`
2525
Status FirewallStatus `json:"status"`
2626
Tags []string `json:"tags"`
27-
Rules FirewallRuleSet `json:"rules"`
27+
Rules FirewallRules `json:"rules"`
2828
Entities []FirewallDeviceEntity `json:"entities"`
2929
Created *time.Time `json:"-"`
3030
Updated *time.Time `json:"-"`
@@ -39,10 +39,17 @@ type DevicesCreationOptions struct {
3939

4040
// FirewallCreateOptions fields are those accepted by CreateFirewall
4141
type FirewallCreateOptions struct {
42-
Label string `json:"label,omitzero"`
43-
Rules FirewallRuleSet `json:"rules"`
44-
Tags []string `json:"tags,omitzero"`
45-
Devices DevicesCreationOptions `json:"devices,omitzero"`
42+
Label string `json:"label,omitzero"`
43+
Rules FirewallRulesCreateOptions `json:"rules"`
44+
Tags []string `json:"tags,omitzero"`
45+
Devices DevicesCreationOptions `json:"devices,omitzero"`
46+
}
47+
48+
type FirewallRulesCreateOptions struct {
49+
Inbound []FirewallRuleInbound `json:"inbound"`
50+
InboundPolicy string `json:"inbound_policy"`
51+
Outbound []FirewallRuleOutbound `json:"outbound"`
52+
OutboundPolicy string `json:"outbound_policy"`
4653
}
4754

4855
// FirewallUpdateOptions is an options struct used when Updating a Firewall

instance_config_interfaces.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,23 @@ type VPCIPv4 struct {
4949
NAT1To1 *string `json:"nat_1_1,omitzero"`
5050
}
5151

52+
type VPCIPv4CreateOptions struct {
53+
VPC string `json:"vpc,omitzero"`
54+
NAT1To1 *string `json:"nat_1_1,omitzero"`
55+
}
56+
57+
type VPCIPv4UpdateOptions struct {
58+
VPC string `json:"vpc,omitzero"`
59+
NAT1To1 *string `json:"nat_1_1,omitzero"`
60+
}
61+
5262
type InstanceConfigInterfaceCreateOptions struct {
5363
IPAMAddress string `json:"ipam_address,omitzero"`
5464
Label string `json:"label,omitzero"`
5565
Purpose ConfigInterfacePurpose `json:"purpose,omitzero"`
5666
Primary bool `json:"primary,omitzero"`
5767
SubnetID *int `json:"subnet_id,omitzero"`
58-
IPv4 *VPCIPv4 `json:"ipv4,omitzero"`
68+
IPv4 *VPCIPv4CreateOptions `json:"ipv4,omitzero"`
5969

6070
// NOTE: IPv6 interfaces may not currently be available to all users.
6171
IPv6 *InstanceConfigInterfaceCreateOptionsIPv6 `json:"ipv6,omitzero"`
@@ -87,8 +97,8 @@ type InstanceConfigInterfaceCreateOptionsIPv6Range struct {
8797
}
8898

8999
type InstanceConfigInterfaceUpdateOptions struct {
90-
Primary bool `json:"primary,omitzero"`
91-
IPv4 *VPCIPv4 `json:"ipv4,omitzero"`
100+
Primary bool `json:"primary,omitzero"`
101+
IPv4 *VPCIPv4UpdateOptions `json:"ipv4,omitzero"`
92102

93103
// NOTE: IPv6 interfaces may not currently be available to all users.
94104
IPv6 *InstanceConfigInterfaceUpdateOptionsIPv6 `json:"ipv6,omitzero"`
@@ -147,7 +157,7 @@ func (i InstanceConfigInterface) GetCreateOptions() InstanceConfigInterfaceCreat
147157
}
148158

149159
if i.IPv4 != nil {
150-
opts.IPv4 = &VPCIPv4{
160+
opts.IPv4 = &VPCIPv4CreateOptions{
151161
VPC: i.IPv4.VPC,
152162
NAT1To1: i.IPv4.NAT1To1,
153163
}
@@ -189,7 +199,7 @@ func (i InstanceConfigInterface) GetUpdateOptions() InstanceConfigInterfaceUpdat
189199

190200
if i.Purpose == InterfacePurposeVPC {
191201
if i.IPv4 != nil {
192-
opts.IPv4 = &VPCIPv4{
202+
opts.IPv4 = &VPCIPv4UpdateOptions{
193203
VPC: i.IPv4.VPC,
194204
NAT1To1: i.IPv4.NAT1To1,
195205
}

0 commit comments

Comments
 (0)