1package testing
2
3import (
4	"fmt"
5	"net/http"
6	"testing"
7
8	"github.com/gophercloud/gophercloud"
9	fake "github.com/gophercloud/gophercloud/openstack/networking/v2/common"
10	"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules"
11	"github.com/gophercloud/gophercloud/pagination"
12	th "github.com/gophercloud/gophercloud/testhelper"
13)
14
15func TestList(t *testing.T) {
16	th.SetupHTTP()
17	defer th.TeardownHTTP()
18
19	th.Mux.HandleFunc("/v2.0/fw/firewall_rules", func(w http.ResponseWriter, r *http.Request) {
20		th.TestMethod(t, r, "GET")
21		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
22
23		w.Header().Add("Content-Type", "application/json")
24		w.WriteHeader(http.StatusOK)
25
26		fmt.Fprintf(w, `
27{
28    "firewall_rules": [
29        {
30            "protocol": "tcp",
31            "description": "ssh rule",
32            "source_port": null,
33            "source_ip_address": null,
34            "destination_ip_address": "192.168.1.0/24",
35            "firewall_policy_id": "e2a5fb51-698c-4898-87e8-f1eee6b50919",
36            "position": 2,
37            "destination_port": "22",
38            "id": "f03bd950-6c56-4f5e-a307-45967078f507",
39            "name": "ssh_form_any",
40            "tenant_id": "80cf934d6ffb4ef5b244f1c512ad1e61",
41            "enabled": true,
42            "action": "allow",
43            "ip_version": 4,
44            "shared": false
45        },
46        {
47            "protocol": "udp",
48            "description": "udp rule",
49            "source_port": null,
50            "source_ip_address": null,
51            "destination_ip_address": null,
52            "firewall_policy_id": "98d7fb51-698c-4123-87e8-f1eee6b5ab7e",
53            "position": 1,
54            "destination_port": null,
55            "id": "ab7bd950-6c56-4f5e-a307-45967078f890",
56            "name": "deny_all_udp",
57            "tenant_id": "80cf934d6ffb4ef5b244f1c512ad1e61",
58            "enabled": true,
59            "action": "deny",
60            "ip_version": 4,
61            "shared": false
62        }
63    ]
64}
65        `)
66	})
67
68	count := 0
69
70	rules.List(fake.ServiceClient(), rules.ListOpts{}).EachPage(func(page pagination.Page) (bool, error) {
71		count++
72		actual, err := rules.ExtractRules(page)
73		if err != nil {
74			t.Errorf("Failed to extract members: %v", err)
75			return false, err
76		}
77
78		expected := []rules.Rule{
79			{
80				Protocol:             "tcp",
81				Description:          "ssh rule",
82				SourcePort:           "",
83				SourceIPAddress:      "",
84				DestinationIPAddress: "192.168.1.0/24",
85				PolicyID:             "e2a5fb51-698c-4898-87e8-f1eee6b50919",
86				Position:             2,
87				DestinationPort:      "22",
88				ID:                   "f03bd950-6c56-4f5e-a307-45967078f507",
89				Name:                 "ssh_form_any",
90				TenantID:             "80cf934d6ffb4ef5b244f1c512ad1e61",
91				Enabled:              true,
92				Action:               "allow",
93				IPVersion:            4,
94				Shared:               false,
95			},
96			{
97				Protocol:             "udp",
98				Description:          "udp rule",
99				SourcePort:           "",
100				SourceIPAddress:      "",
101				DestinationIPAddress: "",
102				PolicyID:             "98d7fb51-698c-4123-87e8-f1eee6b5ab7e",
103				Position:             1,
104				DestinationPort:      "",
105				ID:                   "ab7bd950-6c56-4f5e-a307-45967078f890",
106				Name:                 "deny_all_udp",
107				TenantID:             "80cf934d6ffb4ef5b244f1c512ad1e61",
108				Enabled:              true,
109				Action:               "deny",
110				IPVersion:            4,
111				Shared:               false,
112			},
113		}
114
115		th.CheckDeepEquals(t, expected, actual)
116
117		return true, nil
118	})
119
120	if count != 1 {
121		t.Errorf("Expected 1 page, got %d", count)
122	}
123}
124
125func TestCreate(t *testing.T) {
126	th.SetupHTTP()
127	defer th.TeardownHTTP()
128
129	th.Mux.HandleFunc("/v2.0/fw/firewall_rules", func(w http.ResponseWriter, r *http.Request) {
130		th.TestMethod(t, r, "POST")
131		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
132		th.TestHeader(t, r, "Content-Type", "application/json")
133		th.TestHeader(t, r, "Accept", "application/json")
134		th.TestJSONRequest(t, r, `
135{
136	"firewall_rule": {
137		"protocol": "tcp",
138		"description": "ssh rule",
139		"destination_ip_address": "192.168.1.0/24",
140		"destination_port": "22",
141		"name": "ssh_form_any",
142		"action": "allow",
143		"tenant_id": "80cf934d6ffb4ef5b244f1c512ad1e61"
144	}
145}
146      `)
147
148		w.Header().Add("Content-Type", "application/json")
149		w.WriteHeader(http.StatusCreated)
150
151		fmt.Fprintf(w, `
152{
153	"firewall_rule":{
154		"protocol": "tcp",
155		"description": "ssh rule",
156		"source_port": null,
157		"source_ip_address": null,
158		"destination_ip_address": "192.168.1.0/24",
159		"firewall_policy_id": "e2a5fb51-698c-4898-87e8-f1eee6b50919",
160		"position": 2,
161		"destination_port": "22",
162		"id": "f03bd950-6c56-4f5e-a307-45967078f507",
163		"name": "ssh_form_any",
164		"tenant_id": "80cf934d6ffb4ef5b244f1c512ad1e61",
165		"enabled": true,
166		"action": "allow",
167		"ip_version": 4,
168		"shared": false
169	}
170}
171        `)
172	})
173
174	options := rules.CreateOpts{
175		TenantID:             "80cf934d6ffb4ef5b244f1c512ad1e61",
176		Protocol:             rules.ProtocolTCP,
177		Description:          "ssh rule",
178		DestinationIPAddress: "192.168.1.0/24",
179		DestinationPort:      "22",
180		Name:                 "ssh_form_any",
181		Action:               "allow",
182	}
183
184	_, err := rules.Create(fake.ServiceClient(), options).Extract()
185	th.AssertNoErr(t, err)
186}
187
188func TestCreateAnyProtocol(t *testing.T) {
189	th.SetupHTTP()
190	defer th.TeardownHTTP()
191
192	th.Mux.HandleFunc("/v2.0/fw/firewall_rules", func(w http.ResponseWriter, r *http.Request) {
193		th.TestMethod(t, r, "POST")
194		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
195		th.TestHeader(t, r, "Content-Type", "application/json")
196		th.TestHeader(t, r, "Accept", "application/json")
197		th.TestJSONRequest(t, r, `
198{
199	"firewall_rule": {
200		"protocol": null,
201		"description": "any to 192.168.1.0/24",
202		"destination_ip_address": "192.168.1.0/24",
203		"name": "any_to_192.168.1.0/24",
204		"action": "allow",
205		"tenant_id": "80cf934d6ffb4ef5b244f1c512ad1e61"
206	}
207}
208      `)
209
210		w.Header().Add("Content-Type", "application/json")
211		w.WriteHeader(http.StatusCreated)
212
213		fmt.Fprintf(w, `
214{
215	"firewall_rule":{
216		"protocol": null,
217		"description": "any to 192.168.1.0/24",
218		"source_port": null,
219		"source_ip_address": null,
220		"destination_ip_address": "192.168.1.0/24",
221		"firewall_policy_id": "e2a5fb51-698c-4898-87e8-f1eee6b50919",
222		"position": 2,
223		"destination_port": null,
224		"id": "f03bd950-6c56-4f5e-a307-45967078f507",
225		"name": "any_to_192.168.1.0/24",
226		"tenant_id": "80cf934d6ffb4ef5b244f1c512ad1e61",
227		"enabled": true,
228		"action": "allow",
229		"ip_version": 4,
230		"shared": false
231	}
232}
233        `)
234	})
235
236	options := rules.CreateOpts{
237		TenantID:             "80cf934d6ffb4ef5b244f1c512ad1e61",
238		Protocol:             rules.ProtocolAny,
239		Description:          "any to 192.168.1.0/24",
240		DestinationIPAddress: "192.168.1.0/24",
241		Name:                 "any_to_192.168.1.0/24",
242		Action:               "allow",
243	}
244
245	_, err := rules.Create(fake.ServiceClient(), options).Extract()
246	th.AssertNoErr(t, err)
247}
248
249func TestGet(t *testing.T) {
250	th.SetupHTTP()
251	defer th.TeardownHTTP()
252
253	th.Mux.HandleFunc("/v2.0/fw/firewall_rules/f03bd950-6c56-4f5e-a307-45967078f507", func(w http.ResponseWriter, r *http.Request) {
254		th.TestMethod(t, r, "GET")
255		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
256
257		w.Header().Add("Content-Type", "application/json")
258		w.WriteHeader(http.StatusOK)
259
260		fmt.Fprintf(w, `
261{
262	"firewall_rule":{
263		"protocol": "tcp",
264		"description": "ssh rule",
265		"source_port": null,
266		"source_ip_address": null,
267		"destination_ip_address": "192.168.1.0/24",
268		"firewall_policy_id": "e2a5fb51-698c-4898-87e8-f1eee6b50919",
269		"position": 2,
270		"destination_port": "22",
271		"id": "f03bd950-6c56-4f5e-a307-45967078f507",
272		"name": "ssh_form_any",
273		"tenant_id": "80cf934d6ffb4ef5b244f1c512ad1e61",
274		"enabled": true,
275		"action": "allow",
276		"ip_version": 4,
277		"shared": false
278	}
279}
280        `)
281	})
282
283	rule, err := rules.Get(fake.ServiceClient(), "f03bd950-6c56-4f5e-a307-45967078f507").Extract()
284	th.AssertNoErr(t, err)
285
286	th.AssertEquals(t, "tcp", rule.Protocol)
287	th.AssertEquals(t, "ssh rule", rule.Description)
288	th.AssertEquals(t, "192.168.1.0/24", rule.DestinationIPAddress)
289	th.AssertEquals(t, "e2a5fb51-698c-4898-87e8-f1eee6b50919", rule.PolicyID)
290	th.AssertEquals(t, 2, rule.Position)
291	th.AssertEquals(t, "22", rule.DestinationPort)
292	th.AssertEquals(t, "f03bd950-6c56-4f5e-a307-45967078f507", rule.ID)
293	th.AssertEquals(t, "ssh_form_any", rule.Name)
294	th.AssertEquals(t, "80cf934d6ffb4ef5b244f1c512ad1e61", rule.TenantID)
295	th.AssertEquals(t, true, rule.Enabled)
296	th.AssertEquals(t, "allow", rule.Action)
297	th.AssertEquals(t, 4, rule.IPVersion)
298	th.AssertEquals(t, false, rule.Shared)
299}
300
301func TestUpdate(t *testing.T) {
302	th.SetupHTTP()
303	defer th.TeardownHTTP()
304
305	th.Mux.HandleFunc("/v2.0/fw/firewall_rules/f03bd950-6c56-4f5e-a307-45967078f507", func(w http.ResponseWriter, r *http.Request) {
306		th.TestMethod(t, r, "PUT")
307		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
308		th.TestHeader(t, r, "Content-Type", "application/json")
309		th.TestHeader(t, r, "Accept", "application/json")
310		th.TestJSONRequest(t, r, `
311{
312	"firewall_rule":{
313		"protocol": "tcp",
314		"description": "ssh rule",
315		"destination_ip_address": "192.168.1.0/24",
316		"destination_port": "22",
317		"name": "ssh_form_any",
318		"action": "allow",
319		"enabled": false
320	}
321}
322	`)
323
324		w.Header().Add("Content-Type", "application/json")
325		w.WriteHeader(http.StatusOK)
326
327		fmt.Fprintf(w, `
328{
329	"firewall_rule":{
330		"protocol": "tcp",
331		"description": "ssh rule",
332		"destination_ip_address": "192.168.1.0/24",
333		"firewall_policy_id": "e2a5fb51-698c-4898-87e8-f1eee6b50919",
334		"position": 2,
335		"destination_port": "22",
336		"id": "f03bd950-6c56-4f5e-a307-45967078f507",
337		"name": "ssh_form_any",
338		"tenant_id": "80cf934d6ffb4ef5b244f1c512ad1e61",
339		"enabled": false,
340		"action": "allow",
341		"ip_version": 4,
342		"shared": false
343	}
344}
345		`)
346	})
347
348	newProtocol := "tcp"
349	newDescription := "ssh rule"
350	newDestinationIP := "192.168.1.0/24"
351	newDestintionPort := "22"
352	newName := "ssh_form_any"
353	newAction := "allow"
354
355	options := rules.UpdateOpts{
356		Protocol:             &newProtocol,
357		Description:          &newDescription,
358		DestinationIPAddress: &newDestinationIP,
359		DestinationPort:      &newDestintionPort,
360		Name:                 &newName,
361		Action:               &newAction,
362		Enabled:              gophercloud.Disabled,
363	}
364
365	_, err := rules.Update(fake.ServiceClient(), "f03bd950-6c56-4f5e-a307-45967078f507", options).Extract()
366	th.AssertNoErr(t, err)
367}
368
369func TestDelete(t *testing.T) {
370	th.SetupHTTP()
371	defer th.TeardownHTTP()
372
373	th.Mux.HandleFunc("/v2.0/fw/firewall_rules/4ec89077-d057-4a2b-911f-60a3b47ee304", func(w http.ResponseWriter, r *http.Request) {
374		th.TestMethod(t, r, "DELETE")
375		th.TestHeader(t, r, "X-Auth-Token", fake.TokenID)
376		w.WriteHeader(http.StatusNoContent)
377	})
378
379	res := rules.Delete(fake.ServiceClient(), "4ec89077-d057-4a2b-911f-60a3b47ee304")
380	th.AssertNoErr(t, res.Err)
381}
382