From 68e6cd88ddc16f32dc8a515dd3c6d42ba96ead1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Brod=C3=A9n?= Date: Tue, 1 Aug 2023 12:40:04 +0200 Subject: [PATCH 1/4] Patch update only one or multiple firewall rules. Instead of overwriting all firewall rules with the new set. Backend will go over each rule and only update the rule if there is a match on 'IP' field. --- api/security_firewall.go | 48 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/api/security_firewall.go b/api/security_firewall.go index 2dc6e95..241d76c 100644 --- a/api/security_firewall.go +++ b/api/security_firewall.go @@ -216,3 +216,51 @@ func DefaultFirewallSettings() map[string]interface{} { } return defaultRule } + +func (api *API) PatchFirewallSettings(instanceID int, params []map[string]interface{}, + sleep, timeout int) error { + attempt, err := api.patchFirewallSettingsWithRetry(instanceID, params, 1, sleep, timeout) + if err != nil { + return err + } + err = api.waitUntilFirewallConfigured(instanceID, attempt, sleep, timeout) + if err != nil { + return err + } + return nil +} + +func (api *API) patchFirewallSettingsWithRetry(instanceID int, params []map[string]interface{}, + attempt, sleep, timeout int) (int, error) { + var ( + failed map[string]interface{} + path = fmt.Sprintf("/api/instances/%d/security/firewall", instanceID) + ) + log.Printf("[DEBUG] go-api::security_firewall::patch instance ID: %v, params: %v", instanceID, params) + response, err := api.sling.New().Patch(path).BodyJSON(params).Receive(nil, &failed) + + if err != nil { + return attempt, err + } else if attempt*sleep > timeout { + return attempt, fmt.Errorf("Create firewall settings failed, reached timeout of %d seconds", timeout) + } + + switch { + case response.StatusCode == 201: + return attempt, nil + case response.StatusCode == 400: + switch { + case failed["error_code"] == nil: + break + case failed["error_code"].(float64) == 40001: + log.Printf("[INFO] go-api::security_firewall::patch Firewall not finished configuring "+ + "attempt: %d, until timeout: %d", attempt, (timeout - (attempt * sleep))) + attempt++ + time.Sleep(time.Duration(sleep) * time.Second) + return api.patchFirewallSettingsWithRetry(instanceID, params, attempt, sleep, timeout) + case failed["error_code"].(float64) == 40002: + return attempt, fmt.Errorf("Firewall rules validation failed due to: %s", failed["error"].(string)) + } + } + return attempt, fmt.Errorf("Patch firewall rules failed, status: %v, message: %s", response.StatusCode, failed) +} From 76c0cc9773e55eefeef9d8ac15f1527b8ab24a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Brod=C3=A9n?= Date: Tue, 1 Aug 2023 12:42:36 +0200 Subject: [PATCH 2/4] Read out a single firewall rule --- api/security_firewall.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/api/security_firewall.go b/api/security_firewall.go index 241d76c..44fdfa8 100644 --- a/api/security_firewall.go +++ b/api/security_firewall.go @@ -104,6 +104,22 @@ func (api *API) ReadFirewallSettings(instanceID int) ([]map[string]interface{}, return nil, fmt.Errorf("ReadFirewallSettings failed, status: %v, message: %s", response.StatusCode, failed) } +func (api *API) ReadFirewallRule(instanceID int, ip string) (map[string]interface{}, error) { + data, err := api.ReadFirewallSettings(instanceID) + if err != nil { + return nil, err + } + + for _, dt := range data { + for k, v := range dt { + if k == "ip" && v == ip { + return dt, nil + } + } + } + return nil, fmt.Errorf("ReadFirewallRule rule with CIDR: %s not found", ip) +} + func (api *API) UpdateFirewallSettings(instanceID int, params []map[string]interface{}, sleep, timeout int) ([]map[string]interface{}, error) { log.Printf("[DEBUG] go-api::security_firewall::update instance id: %v, params: %v, sleep: %d, timeout: %d", From 129c68095e976e69121fdd633437bb555a642929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Brod=C3=A9n?= Date: Fri, 4 Aug 2023 14:13:50 +0200 Subject: [PATCH 3/4] Update ranged variable name --- api/security_firewall.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/api/security_firewall.go b/api/security_firewall.go index 44fdfa8..f3cb41e 100644 --- a/api/security_firewall.go +++ b/api/security_firewall.go @@ -110,10 +110,10 @@ func (api *API) ReadFirewallRule(instanceID int, ip string) (map[string]interfac return nil, err } - for _, dt := range data { - for k, v := range dt { + for _, rule := range data { + for k, v := range rule { if k == "ip" && v == ip { - return dt, nil + return rule, nil } } } From 5984a841ee76857bb1603516b930f6f4c1d6161e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Brod=C3=A9n?= Date: Mon, 7 Aug 2023 08:31:32 +0200 Subject: [PATCH 4/4] Only wait until firewall updates is configured --- api/security_firewall.go | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/api/security_firewall.go b/api/security_firewall.go index f3cb41e..8f8c67f 100644 --- a/api/security_firewall.go +++ b/api/security_firewall.go @@ -38,16 +38,12 @@ func (api *API) waitUntilFirewallConfigured(instanceID, attempt, sleep, timeout } func (api *API) CreateFirewallSettings(instanceID int, params []map[string]interface{}, sleep, - timeout int) ([]map[string]interface{}, error) { + timeout int) error { attempt, err := api.createFirewallSettingsWithRetry(instanceID, params, 1, sleep, timeout) if err != nil { - return nil, err - } - err = api.waitUntilFirewallConfigured(instanceID, attempt, sleep, timeout) - if err != nil { - return nil, err + return err } - return api.ReadFirewallSettings(instanceID) + return api.waitUntilFirewallConfigured(instanceID, attempt, sleep, timeout) } func (api *API) createFirewallSettingsWithRetry(instanceID int, params []map[string]interface{}, @@ -121,18 +117,14 @@ func (api *API) ReadFirewallRule(instanceID int, ip string) (map[string]interfac } func (api *API) UpdateFirewallSettings(instanceID int, params []map[string]interface{}, - sleep, timeout int) ([]map[string]interface{}, error) { + sleep, timeout int) error { log.Printf("[DEBUG] go-api::security_firewall::update instance id: %v, params: %v, sleep: %d, timeout: %d", instanceID, params, sleep, timeout) attempt, err := api.updateFirewallSettingsWithRetry(instanceID, params, 1, sleep, timeout) if err != nil { - return nil, err - } - err = api.waitUntilFirewallConfigured(instanceID, attempt, sleep, timeout) - if err != nil { - return nil, err + return err } - return api.ReadFirewallSettings(instanceID) + return api.waitUntilFirewallConfigured(instanceID, attempt, sleep, timeout) } func (api *API) updateFirewallSettingsWithRetry(instanceID int, params []map[string]interface{},