Skip to content
This repository has been archived by the owner on Jan 23, 2025. It is now read-only.

Commit

Permalink
Add configurable sleep and timeout (#30)
Browse files Browse the repository at this point in the history
Increase the total time configuring firewall settings before timeout.
  • Loading branch information
tbroden84 authored Dec 14, 2022
1 parent 036f1d2 commit 84a4f16
Showing 1 changed file with 88 additions and 60 deletions.
148 changes: 88 additions & 60 deletions api/security_firewall.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,135 +6,160 @@ import (
"time"
)

func (api *API) waitUntilFirewallConfigured(instanceID int) ([]map[string]interface{}, error) {
log.Printf("[DEBUG] go-api::security_firewall::waitUntilFirewallConfigured waiting")
var data []map[string]interface{}
failed := make(map[string]interface{})
path := fmt.Sprintf("/api/instances/%d/security/firewall/configured", instanceID)
func (api *API) waitUntilFirewallConfigured(instanceID, attempt, sleep, timeout int) error {
var (
data map[string]interface{}
failed map[string]interface{}
path = fmt.Sprintf("/api/instances/%d/security/firewall/configured", instanceID)
)

for {
response, err := api.sling.New().Path(path).Receive(&data, &failed)
if err != nil {
return nil, err
return err
} else if attempt*sleep > timeout {
return fmt.Errorf("Wait until firewall configured failed, reached timeout of %d seconds", timeout)
}
if response.StatusCode == 200 {
return data, nil
} else if response.StatusCode == 400 {

switch response.StatusCode {
case 200:
return nil
case 400:
log.Printf("[DEBUG] go-api::security_firewall#waitUntilFirewallConfigured: The cluster is unavailable, firewall configuring")
} else {
return nil, fmt.Errorf("waitUntilReady failed, status: %v, message: %s", response.StatusCode, failed)
default:
return fmt.Errorf("waitUntilReady failed, status: %v, message: %s", response.StatusCode, failed)
}

time.Sleep(30 * time.Second)
log.Printf("[INFO] go-api::security_firewall::waitUntilFirewallConfigured The cluster is unavailable, "+
"firewall configuring. Attempt: %d, until timeout: %d", attempt, (timeout - (attempt * sleep)))
attempt++
time.Sleep(time.Duration(sleep) * time.Second)
}
}

func (api *API) CreateFirewallSettings(instanceID int, params []map[string]interface{}) ([]map[string]interface{}, error) {
// Initiale values, 10 attempts, 30 second sleep
err := api.createFirewallSettingsWithReply(instanceID, params, 10, 30)
func (api *API) CreateFirewallSettings(instanceID int, params []map[string]interface{}, sleep,
timeout int) ([]map[string]interface{}, error) {
attempt, err := api.createFirewallSettingsWithReply(instanceID, params, 1, sleep, timeout)
if err != nil {
return nil, err
}
err = api.waitUntilFirewallConfigured(instanceID, attempt, sleep, timeout)
if err != nil {
return nil, err
}
api.waitUntilFirewallConfigured(instanceID)
return api.ReadFirewallSettings(instanceID)
}

func (api *API) createFirewallSettingsWithReply(instanceID int, params []map[string]interface{}, attempts int, sleep int) error {
failed := make(map[string]interface{})
func (api *API) createFirewallSettingsWithReply(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::create instance ID: %v, params: %v", instanceID, params)
path := fmt.Sprintf("/api/instances/%d/security/firewall", instanceID)
response, err := api.sling.New().Post(path).BodyJSON(params).Receive(nil, &failed)

if err != nil {
return err
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 nil
return attempt, nil
case response.StatusCode == 400:
switch {
case failed["error_code"] == nil:
break
case failed["error_code"].(float64) == 40001:
if attempts--; attempts > 0 {
log.Printf("[INFO] go-api::security_firewall::create Firewall not finished configuring "+
"attempts left %d and retry in %d seconds", attempts, sleep)
time.Sleep(time.Duration(sleep) * time.Second)
return api.createFirewallSettingsWithReply(instanceID, params, attempts, sleep)
} else {
break
}
log.Printf("[INFO] go-api::security_firewall::create Firewall not finished configuring "+
"attempt: %d, until timeout: %d", attempt, (timeout - (attempt * sleep)))
attempt++
time.Sleep(time.Duration(sleep) * time.Second)
return api.createFirewallSettingsWithReply(instanceID, params, attempt, sleep, timeout)
case failed["error_code"].(float64) == 40002:
return fmt.Errorf("Firewall rules validation failed due to: %s", failed["error"].(string))
return attempt, fmt.Errorf("Firewall rules validation failed due to: %s", failed["error"].(string))
}
}
return fmt.Errorf("Create new firewall rules failed, status: %v, message: %s", response.StatusCode, failed)
return attempt, fmt.Errorf("Create new firewall rules failed, status: %v, message: %s", response.StatusCode, failed)
}

func (api *API) ReadFirewallSettings(instanceID int) ([]map[string]interface{}, error) {
var data []map[string]interface{}
failed := make(map[string]interface{})
log.Printf("[DEBUG] go-api::security_firewall#read instanceID: %v", instanceID)
path := fmt.Sprintf("/api/instances/%d/security/firewall", instanceID)
var (
data []map[string]interface{}
failed map[string]interface{}
path = fmt.Sprintf("/api/instances/%d/security/firewall", instanceID)
)
response, err := api.sling.New().Path(path).Receive(&data, &failed)
log.Printf("[DEBUG] go-api::security_firewall::read data: %v", data)

if err != nil {
return nil, err
}

if response.StatusCode == 200 {
return data, nil
}
return nil, fmt.Errorf("ReadFirewallSettings failed, status: %v, message: %s", response.StatusCode, failed)
}

func (api *API) UpdateFirewallSettings(instanceID int, params []map[string]interface{}) ([]map[string]interface{}, error) {
// Initiale values, 10 attempts, 30 second sleep
err := api.updateFirewallSettingsWithRetry(instanceID, params, 10, 30)
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",
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
}
api.waitUntilFirewallConfigured(instanceID)
return api.ReadFirewallSettings(instanceID)
}

func (api *API) updateFirewallSettingsWithRetry(instanceID int, params []map[string]interface{}, attempts int, sleep int) error {
failed := make(map[string]interface{})
log.Printf("[DEBUG] go-api::security_firewall::update instance id: %v, params: %v", instanceID, params)
path := fmt.Sprintf("/api/instances/%d/security/firewall", instanceID)
func (api *API) updateFirewallSettingsWithRetry(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)
)

response, err := api.sling.New().Put(path).BodyJSON(params).Receive(nil, &failed)
if err != nil {
return err
return attempt, err
} else if attempt*sleep > timeout {
return attempt, fmt.Errorf("Update firewall settings failed, reached timeout of %d seconds", timeout)
}

switch {
case response.StatusCode == 204:
return nil
return attempt, nil
case response.StatusCode == 400:
switch {
case failed["error_code"] == nil:
break
case failed["error_code"].(float64) == 40001:
if attempts--; attempts > 0 {
log.Printf("[INFO] go-api::security_firewall::update Firewall not finished configuring "+
"attempts left %d and retry in %d seconds", attempts, sleep)
time.Sleep(time.Duration(sleep) * time.Second)
return api.updateFirewallSettingsWithRetry(instanceID, params, attempts, sleep)
} else {
break
}
log.Printf("[INFO] go-api::security_firewall::update Firewall not finished configuring "+
"attempt: %d until timeout: %d", attempt, (timeout - (attempt * sleep)))
attempt++
time.Sleep(time.Duration(sleep) * time.Second)
return api.updateFirewallSettingsWithRetry(instanceID, params, attempt, sleep, timeout)
case failed["error_code"].(float64) == 40002:
return fmt.Errorf("Firewall rules validation failed due to: %s", failed["error"].(string))
return attempt, fmt.Errorf("Firewall rules validation failed due to: %s", failed["error"].(string))
}
}
return fmt.Errorf("Update firewall rules failed, status: %v, message: %v", response.StatusCode, failed)
return attempt, fmt.Errorf("Update firewall rules failed, status: %v, message: %v", response.StatusCode, failed)
}

func (api *API) DeleteFirewallSettings(instanceID int) ([]map[string]interface{}, error) {
var params [1]map[string]interface{}
failed := make(map[string]interface{})
func (api *API) DeleteFirewallSettings(instanceID, sleep, timeout int) ([]map[string]interface{}, error) {
var (
params [1]map[string]interface{}
failed map[string]interface{}
path = fmt.Sprintf("/api/instances/%d/security/firewall", instanceID)
)
log.Printf("[DEBUG] go-api::security_firewall::delete instance id: %v", instanceID)
path := fmt.Sprintf("/api/instances/%d/security/firewall", instanceID)

// Use default firewall rule and update firewall upon delete.
params[0] = DefaultFirewallSettings()
Expand All @@ -148,7 +173,10 @@ func (api *API) DeleteFirewallSettings(instanceID int) ([]map[string]interface{}
return nil, fmt.Errorf("DeleteNotification failed, status: %v, message: %s", response.StatusCode, failed)
}

api.waitUntilFirewallConfigured(instanceID)
err = api.waitUntilFirewallConfigured(instanceID, 1, sleep, timeout)
if err != nil {
return nil, err
}
return api.ReadFirewallSettings(instanceID)
}

Expand Down

0 comments on commit 84a4f16

Please sign in to comment.