Skip to content

Commit

Permalink
Added controls parameter to as3
Browse files Browse the repository at this point in the history
  • Loading branch information
urohit011 committed Jan 15, 2025
1 parent f4af77d commit f538abd
Show file tree
Hide file tree
Showing 4 changed files with 220 additions and 10 deletions.
131 changes: 127 additions & 4 deletions bigip/resource_bigip_as3.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
bigip "github.com/f5devcentral/go-bigip"
"github.com/f5devcentral/go-bigip/f5teem"
uuid "github.com/google/uuid"
"github.com/hashicorp/go-cty/cty"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure"
Expand Down Expand Up @@ -135,6 +136,15 @@ func resourceBigipAs3() *schema.Resource {
return
},
},
"controls": {
Type: schema.TypeMap,
Elem: &schema.Schema{
Type: schema.TypeString,
},
Optional: true,
Description: "Controls parameters for AS3, you can use the following parameters, dry_run, trace, trace_response, log_level, user_agent",
ValidateDiagFunc: validateControlsParam,
},
"ignore_metadata": {
Type: schema.TypeBool,
Optional: true,
Expand Down Expand Up @@ -180,6 +190,100 @@ func resourceBigipAs3() *schema.Resource {
}
}

func validateControlsParam(val interface{}, path cty.Path) diag.Diagnostics {
var diags diag.Diagnostics

controls, ok := val.(map[string]interface{})
if !ok {
return diag.Diagnostics{{
Severity: diag.Error,
Summary: "Invalid type",
Detail: "The controls parameter must be a map.",
}}
}

allowedKeys := map[string]bool{
"dry_run": true,
"trace": true,
"trace_response": true,
"log_level": true,
"user_agent": true,
}

for k, v := range controls {
value := fmt.Sprintf("%v", v)
if !allowedKeys[k] {
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "Invalid key",
Detail: fmt.Sprintf("The key %s is not allowed in the 'controls' attribute", k),
})
continue
}

switch k {
case "dry_run", "trace", "trace_response":
if value != "yes" && value != "no" {
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "Invalid value",
Detail: fmt.Sprintf("The value for key %s must be yes or no", k),
})
}
case "log_level":
if value != "emergency" &&
value != "alert" &&
value != "critical" &&
value != "error" &&
value != "warning" &&
value != "notice" &&
value != "info" &&
value != "debug" {
diags = append(diags, diag.Diagnostic{
Severity: diag.Error,
Summary: "Invalid value",
Detail: fmt.Sprintf("The value for key %s must be one of emergency, alert, critical, error, warning, notice, info, debug", k),
})
}
case "user_agent":
// No specific validation for user_agent, just ensure the key is valid
}
}

return diags
}

func controlsQueraString(d *schema.ResourceData) string {
controls := d.Get("controls").(map[string]interface{})
query := ""
if dryRun, ok := controls["dry_run"]; ok {
if dryRun.(string) == "yes" {
query += "&controls.dryRun=true"
} else if dryRun.(string) == "no" {
query += "&controls.dryRun=false"
}
}
if trace, ok := controls["trace"]; ok {
if trace.(string) == "yes" {
query += "&controls.trace=true"
} else if trace.(string) == "no" {
query += "&controls.trace=false"
}
}
if traceResponse, ok := controls["trace_response"]; ok {
if traceResponse.(string) == "yes" {
query += "&controls.traceResponse=true"
} else if traceResponse.(string) == "no" {
query += "&controls.traceResponse=false"
}
}
if logLevel, ok := controls["log_level"]; ok {
query += fmt.Sprintf("&controls.logLevel=%s", logLevel.(string))
}

return query
}

func resourceBigipAs3Create(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
client := meta.(*bigip.BigIP)
m.Lock()
Expand All @@ -193,6 +297,11 @@ func resourceBigipAs3Create(ctx context.Context, d *schema.ResourceData, meta in
}
tenantList, _, applicationList := client.GetTenantList(as3Json)

var controlsQuerParam string
if _, controls := d.GetOk("controls"); controls {
controlsQuerParam = controlsQueraString(d)
}

log.Printf("[DEBUG] perApplication:%+v", perApplication)

if perApplication && len(tenantList) == 0 {
Expand All @@ -209,7 +318,7 @@ func resourceBigipAs3Create(ctx context.Context, d *schema.ResourceData, meta in
log.Printf("[DEBUG] tenant name :%+v", tenant)

applicationList := client.GetAppsList(as3Json)
err, taskID := client.PostPerAppBigIp(as3Json, tenant)
err, taskID := client.PostPerAppBigIp(as3Json, tenant, controlsQuerParam)

Check failure on line 321 in bigip/resource_bigip_as3.go

View workflow job for this annotation

GitHub Actions / golint

too many arguments in call to client.PostPerAppBigIp

Check failure on line 321 in bigip/resource_bigip_as3.go

View workflow job for this annotation

GitHub Actions / golint

too many arguments in call to client.PostPerAppBigIp
log.Printf("[DEBUG] task Id from deployment :%+v", taskID)
if err != nil {
return diag.FromErr(fmt.Errorf("posting as3 config failed for tenants:(%s) with error: %v", tenantFilter, err))
Expand Down Expand Up @@ -239,7 +348,7 @@ func resourceBigipAs3Create(ctx context.Context, d *schema.ResourceData, meta in
return diag.FromErr(err)
}
log.Printf("[INFO] Creating as3 config in bigip:%s", strTrimSpace)
err, successfulTenants, taskID := client.PostAs3Bigip(strTrimSpace, tenantList)
err, successfulTenants, taskID := client.PostAs3Bigip(strTrimSpace, tenantList, controlsQuerParam)

Check failure on line 351 in bigip/resource_bigip_as3.go

View workflow job for this annotation

GitHub Actions / golint

too many arguments in call to client.PostAs3Bigip

Check failure on line 351 in bigip/resource_bigip_as3.go

View workflow job for this annotation

GitHub Actions / golint

too many arguments in call to client.PostAs3Bigip
log.Printf("[DEBUG] successfulTenants :%+v", successfulTenants)
if err != nil {
if successfulTenants == "" {
Expand Down Expand Up @@ -365,6 +474,12 @@ func resourceBigipAs3Update(ctx context.Context, d *schema.ResourceData, meta in
log.Printf("[INFO] Updating As3 Config :%s", as3Json)
oldApplicationList := d.Get("application_list").(string)
tenantList, _, applicationList := client.GetTenantList(as3Json)

var controlsQuerParam string
if _, controls := d.GetOk("controls"); controls {
controlsQuerParam = controlsQueraString(d)
}

_ = d.Set("application_list", applicationList)
perApplication, err := client.CheckSetting()
if err != nil {
Expand All @@ -389,7 +504,7 @@ func resourceBigipAs3Update(ctx context.Context, d *schema.ResourceData, meta in
}

log.Printf("[INFO] Updating As3 Config for tenant:%s with Per-Application Mode:%v", oldTenantList, perApplication)
err, task_id := client.PostPerAppBigIp(as3Json, oldTenantList)
err, task_id := client.PostPerAppBigIp(as3Json, oldTenantList, controlsQuerParam)

Check failure on line 507 in bigip/resource_bigip_as3.go

View workflow job for this annotation

GitHub Actions / golint

too many arguments in call to client.PostPerAppBigIp

Check failure on line 507 in bigip/resource_bigip_as3.go

View workflow job for this annotation

GitHub Actions / golint

too many arguments in call to client.PostPerAppBigIp
log.Printf("[DEBUG] task_id from PostPerAppBigIp:%+v", task_id)
if err != nil {
return diag.FromErr(fmt.Errorf("posting as3 config failed for tenant:(%s) with error: %v", oldTenantList, err))
Expand Down Expand Up @@ -436,7 +551,7 @@ func resourceBigipAs3Update(ctx context.Context, d *schema.ResourceData, meta in
if err != nil {
return diag.FromErr(err)
}
err, successfulTenants, taskID := client.PostAs3Bigip(strTrimSpace, tenantList)
err, successfulTenants, taskID := client.PostAs3Bigip(strTrimSpace, tenantList, controlsQuerParam)

Check failure on line 554 in bigip/resource_bigip_as3.go

View workflow job for this annotation

GitHub Actions / golint

too many arguments in call to client.PostAs3Bigip

Check failure on line 554 in bigip/resource_bigip_as3.go

View workflow job for this annotation

GitHub Actions / golint

too many arguments in call to client.PostAs3Bigip
log.Printf("[DEBUG] successfulTenants :%+v", successfulTenants)
if err != nil {
if successfulTenants == "" {
Expand Down Expand Up @@ -465,6 +580,14 @@ func resourceBigipAs3Delete(ctx context.Context, d *schema.ResourceData, meta in
var name string
var tList string

if c_attr, c_ok := d.GetOk("controls"); c_ok {
controls := c_attr.(map[string]interface{})
if dryRun, ok := controls["dry_run"]; ok && dryRun == "yes" {
d.SetId("")
return nil
}
}

if d.Get("as3_json") != nil {
tList, _, _ = client.GetTenantList(d.Get("as3_json").(string))
}
Expand Down
54 changes: 54 additions & 0 deletions bigip/resource_bigip_as3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,60 @@ resource "bigip_as3" "as3-example1" {
}
`

var TestAs3ControlParamDryRunTrue = `
resource "bigip_as3" "as3-controls" {
as3_json = "${file("` + dir + `/../examples/as3/controls.json")}"
controls = {
dry_run = "yes"
}
}
`

var TestAs3ControlParamDryRunFalse = `
resource "bigip_as3" "as3-controls" {
as3_json = "${file("` + dir + `/../examples/as3/controls.json")}"
controls = {
dry_run = "no"
}
}
`

func TestAccBigipAs3ControlsDryRunTrue(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAcctPreCheck(t)
},
Providers: testAccProviders,
CheckDestroy: testCheckAs3Destroy,
Steps: []resource.TestStep{
{
Config: TestAs3ControlParamDryRunTrue,
Check: resource.ComposeTestCheckFunc(
testCheckAs3Exists("Sample_01", false),
),
},
},
})
}

func TestAccBigipAs3ControlsDryRunFalse(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAcctPreCheck(t)
},
Providers: testAccProviders,
CheckDestroy: testCheckAs3Destroy,
Steps: []resource.TestStep{
{
Config: TestAs3ControlParamDryRunFalse,
Check: resource.ComposeTestCheckFunc(
testCheckAs3Exists("Sample_01", true),
),
},
},
})
}

func TestAccBigipAs3_create_SingleTenant(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {
Expand Down
32 changes: 32 additions & 0 deletions docs/resources/bigip_as3.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,21 @@ resource "bigip_as3" "as3-example1" {
}
```

## Example of controls parameters

```hcl
resource "bigip_as3" "as3-example1" {
as3_json = file("example1.json")
controls = {
dry_run = "no"
trace = "yes"
trace_response = "yes"
log_level = "debug"
user_agent = "dummy agent"
}
}
```

# Per-Application Deployment - Example Usage for json file with tenant name
resource "bigip_as3" "as3-example1" {
as3_json = file("perApplication_example.json")
Expand Down Expand Up @@ -110,6 +125,23 @@ resource "bigip_as3" "as3-example1" {

* `tenant_list` - (Optional) - List of tenants currently deployed on the Big-Ip

* `controls` - (Optional) - A map that allows you to configure specific behavior controls for the AS3 declaration. Each key represents a particular control setting, and the corresponding value defines its configuration.

* `dry_run` (Optional) - Enables or disables dry-run mode.
* Allowed values: "yes", "no"

* `trace` (Optional) - Enables or disables detailed trace of the configuration process.
* Allowed values: "yes", "no"

* `trace_response` (Optional) - If set to "yes" the response will contain the trace files.
* Allowed values: "yes", "no"

* `log_level` (Optional) - Controls the amount of detail in logs produced while configuring the Tenant.
* Allowed values: "emergency", "alert", "critical", "error", "warning", "notice", "info", "debug"

* `user_agent` (Optional) - Controls the User Agent information to include in TEEM report.


* `application_list` - (Optional) - List of applications currently deployed on the Big-Ip

* `ignore_metadata` - (Optional) Set True if you want to ignore metadata changes during update. By default it is set to false
Expand Down
13 changes: 7 additions & 6 deletions vendor/github.com/f5devcentral/go-bigip/as3bigip.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit f538abd

Please sign in to comment.