Skip to content

Commit

Permalink
set_response_header rewritten to work the same way as api
Browse files Browse the repository at this point in the history
  • Loading branch information
KNechaevWallarm committed Nov 29, 2024
1 parent a0e5000 commit d166ce2
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 94 deletions.
17 changes: 10 additions & 7 deletions docs/resources/rule_set_response_header.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,22 @@ This is because Terraform is designed to keep its configurations stable and not

```hcl
# Append the "Server" header with the "Wallarm solution" value
# and the "Blocked" header with the "Blocked by Wallarm" value
# and the "Server" header with the "Blocked by Wallarm" value
# to the requests sent to the application with ID 3
resource "wallarm_rule_set_response_header" "resp_headers" {
mode = "append"
name = "Server"
action {
point = {
instance = 3
}
}
headers = {
Server = "Wallarm solution"
Blocked = "Blocked by Wallarm"
values = {
"Wallarm solution"
"Blocked by Wallarm"
}
}
Expand All @@ -43,9 +44,10 @@ resource "wallarm_rule_set_response_header" "resp_headers" {
resource "wallarm_rule_set_response_header" "delete_header" {
mode = "replace"
name = "Wallarm component"
headers = {
Wallarm component = " "
" "
}
}
Expand All @@ -54,7 +56,8 @@ resource "wallarm_rule_set_response_header" "delete_header" {
## Argument Reference

* `mode` - (**required**) mode of header processing. Valid options: `append`, `replace`
* `headers` - (**required**) the associative array of key/value headers. Might be defined as much headers as need at once.
* `name` - (**required**) description.
* `values` - (**required**) array of headers. Might be defined as much headers as need at once.
* `action` - (optional) a series of conditions, see below for a
a full list .

Expand Down
145 changes: 58 additions & 87 deletions wallarm/resource_rule_set_response_header.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func resourceWallarmSetResponseHeader() *schema.Resource {
Schema: map[string]*schema.Schema{

"rule_id": {
Type: schema.TypeList,
Type: schema.TypeInt,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeInt},
},
Expand Down Expand Up @@ -67,8 +67,13 @@ func resourceWallarmSetResponseHeader() *schema.Resource {
ValidateFunc: validation.StringInSlice([]string{"append", "replace"}, false),
},

"headers": {
Type: schema.TypeMap,
"name": {
Type: schema.TypeString,
Optional: true,
},

"values": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
Expand Down Expand Up @@ -191,43 +196,34 @@ func resourceWallarmSetResponseHeaderCreate(d *schema.ResourceData, m interface{
clientID := retrieveClientID(d, client)
comment := d.Get("comment").(string)
mode := d.Get("mode").(string)
headers := d.Get("headers").(map[string]interface{})
name := d.Get("name").(string)
values := d.Get("values").([]string)

actionsFromState := d.Get("action").(*schema.Set)
action, err := expandSetToActionDetailsList(actionsFromState)
if err != nil {
return err
}

var ruleIDs []int
for k, v := range headers {
vp := &wallarm.ActionCreate{
Type: "set_response_header",
Clientid: clientID,
Action: &action,
Mode: mode,
Name: k,
Values: []string{v.(string)},
Validated: false,
Comment: comment,
VariativityDisabled: true,
}
actionResp, err := client.HintCreate(vp)
if err != nil {
return err
}

actionID := actionResp.Body.ActionID
d.Set("action_id", actionID)

ruleIDs = append(ruleIDs, actionResp.Body.ID)

resID := fmt.Sprintf("%d/%d/%d", clientID, actionID, actionResp.Body.ID)
d.SetId(resID)
vp := &wallarm.ActionCreate{
Type: "set_response_header",
Clientid: clientID,
Action: &action,
Mode: mode,
Name: name,
Values: values,
Validated: false,
Comment: comment,
VariativityDisabled: true,
}
actionResp, err := client.HintCreate(vp)

if err != nil {
return err
}

d.Set("rule_id", ruleIDs)
d.Set("action_id", actionResp.Body.ActionID)
d.Set("rule_id", actionResp.Body.ID)
d.Set("client_id", clientID)

return nil
Expand All @@ -236,25 +232,18 @@ func resourceWallarmSetResponseHeaderCreate(d *schema.ResourceData, m interface{
func resourceWallarmSetResponseHeaderRead(d *schema.ResourceData, m interface{}) error {
client := m.(wallarm.API)
clientID := retrieveClientID(d, client)
ruleID := d.Get("rule_id").(int)
actionID := d.Get("action_id").(int)
mode := d.Get("mode").(string)
ruleID := d.Get("rule_id").(int)
headers := d.Get("headers").(map[string]interface{})
name := d.Get("name").(string)
values := d.Get("values").([]string)

actionsFromState := d.Get("action").(*schema.Set)
action, err := expandSetToActionDetailsList(actionsFromState)
if err != nil {
return err
}

var ruleIDInterface []interface{}
if v, ok := d.GetOk("rule_id"); ok {
ruleIDInterface = v.([]interface{})
} else {
return nil
}
ruleIDs := expandInterfaceToIntList(ruleIDInterface)

hint := &wallarm.HintRead{
Limit: 1000,
Offset: 0,
Expand All @@ -263,6 +252,7 @@ func resourceWallarmSetResponseHeaderRead(d *schema.ResourceData, m interface{})
Filter: &wallarm.HintFilter{
Clientid: []int{clientID},
ID: []int{ruleID},
Type: []string{"set_response_header"},
},
}
actionHints, err := client.HintRead(hint)
Expand All @@ -274,52 +264,42 @@ func resourceWallarmSetResponseHeaderRead(d *schema.ResourceData, m interface{})
// Assign new values to the old struct slice.
fillInDefaultValues(&action)

expectedRule := wallarm.ActionBody{
ActionID: actionID,
Type: "set_response_header",
Mode: mode,
Name: name,
Values: stringSliceToInterfaceSlice(values),
}

var notFoundRules []int
var updatedRuleIDs []int
var updatedRuleID int
for _, rule := range *actionHints.Body {

// Check out by ID. The specific rule should be found.
if wallarm.Contains(ruleIDs, rule.ID) {
updatedRuleIDs = append(updatedRuleIDs, rule.ID)
if ruleID == rule.ID {
updatedRuleID = rule.ID
continue
}

for name, value := range headers {

expectedRule := wallarm.ActionBody{
ActionID: actionID,
Type: "set_response_header",
Action: action,
Mode: mode,
Name: name,
Values: []interface{}{value},
}

actualRule := &wallarm.ActionBody{
ActionID: rule.ActionID,
Type: rule.Type,
Action: rule.Action,
Mode: rule.Mode,
Name: rule.Name,
Values: rule.Values,
}
actualRule := &wallarm.ActionBody{
ActionID: rule.ActionID,
Type: rule.Type,
}

if cmp.Equal(expectedRule, *actualRule) && equalWithoutOrder(action, rule.Action) {
updatedRuleIDs = append(updatedRuleIDs, rule.ID)
continue
}
if cmp.Equal(expectedRule, *actualRule) && equalWithoutOrder(action, rule.Action) {
updatedRuleID = rule.ID
continue
}

notFoundRules = append(notFoundRules, rule.ID)
}

if err := d.Set("rule_id", updatedRuleIDs); err != nil {
if err := d.Set("rule_id", updatedRuleID); err != nil {
return err
}

d.Set("client_id", clientID)

if len(updatedRuleIDs) == 0 {
if updatedRuleID == 0 {
log.Printf("[WARN] these rule IDs: %v have been found under the action ID: %d. But it isn't in the Terraform Plan.", notFoundRules, actionID)
d.SetId("")
}
Expand All @@ -330,26 +310,17 @@ func resourceWallarmSetResponseHeaderRead(d *schema.ResourceData, m interface{})
func resourceWallarmSetResponseHeaderDelete(d *schema.ResourceData, m interface{}) error {
client := m.(wallarm.API)
clientID := retrieveClientID(d, client)
ruleID := d.Get("rule_id").(int)

var ruleIDInterface []interface{}
if v, ok := d.GetOk("rule_id"); ok {
ruleIDInterface = v.([]interface{})
} else {
return nil
h := &wallarm.HintDelete{
Filter: &wallarm.HintDeleteFilter{
Clientid: []int{clientID},
ID: ruleID,
},
}
ruleIDs := expandInterfaceToIntList(ruleIDInterface)

for _, ruleID := range ruleIDs {
h := &wallarm.HintDelete{
Filter: &wallarm.HintDeleteFilter{
Clientid: []int{clientID},
ID: ruleID,
},
}

if err := client.HintDelete(h); err != nil {
return err
}
if err := client.HintDelete(h); err != nil {
return err
}

return nil
Expand Down
10 changes: 10 additions & 0 deletions wallarm/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,16 @@ func equalWithoutOrder(conditions_a, conditions_b []wallarm.ActionDetails) bool
return true
}

func stringSliceToInterfaceSlice(strings []string) []interface{} {
var result []interface{}

for _, str := range strings {
result = append(result, str)
}

return result
}

// compare for action condition
func compareActionDetails(condition1, condition2 wallarm.ActionDetails) bool {
return condition1.Type == condition2.Type &&
Expand Down

0 comments on commit d166ce2

Please sign in to comment.