diff --git a/bigip/provider.go b/bigip/provider.go index 4ec553a13..b5546ce56 100644 --- a/bigip/provider.go +++ b/bigip/provider.go @@ -14,6 +14,7 @@ import ( "reflect" "regexp" "strings" + "time" bigip "github.com/f5devcentral/go-bigip" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -85,6 +86,24 @@ func Provider() *schema.Provider { Description: "Login reference for token authentication (see BIG-IP REST docs for details)", DefaultFunc: schema.EnvDefaultFunc("BIGIP_LOGIN_REF", "tmos"), }, + "api_timeout": { + Type: schema.TypeInt, + Optional: true, + Description: "A timeout for AS3 requests, represented as a number of seconds. Default: 60", + DefaultFunc: schema.EnvDefaultFunc("API_TIMEOUT", 60), + }, + "token_timeout": { + Type: schema.TypeInt, + Optional: true, + Description: "A lifespan to request for the AS3 auth token, represented as a number of seconds. Default: 1200", + DefaultFunc: schema.EnvDefaultFunc("TOKEN_TIMEOUT", 1200), + }, + "api_retries": { + Type: schema.TypeInt, + Optional: true, + Description: "Amount of times to retry AS3 API requests. Default: 10.", + DefaultFunc: schema.EnvDefaultFunc("API_RETRIES", 10), + }, }, DataSourcesMap: map[string]*schema.Resource{ "bigip_ltm_datagroup": dataSourceBigipLtmDataGroup(), @@ -185,6 +204,12 @@ func Provider() *schema.Provider { } func providerConfigure(d *schema.ResourceData, terraformVersion string) (interface{}, diag.Diagnostics) { + configOptions := &bigip.ConfigOptions{ + APICallTimeout: time.Duration(d.Get("api_timeout").(int)) * time.Second, + TokenTimeout: time.Duration(d.Get("token_timeout").(int)) * time.Second, + APICallRetries: d.Get("api_retries").(int), + } + config := &bigip.Config{ Address: d.Get("address").(string), Port: d.Get("port").(string), @@ -192,6 +217,7 @@ func providerConfigure(d *schema.ResourceData, terraformVersion string) (interfa Password: d.Get("password").(string), Token: d.Get("token_value").(string), CertVerifyDisable: d.Get("validate_certs_disable").(bool), + ConfigOptions: configOptions, } if d.Get("token_auth").(bool) { config.LoginReference = d.Get("login_ref").(string) diff --git a/bigip/resource_bigip_ltm_profile_httpcompress_test.go b/bigip/resource_bigip_ltm_profile_httpcompress_test.go index cf06e00c3..9937771bf 100644 --- a/bigip/resource_bigip_ltm_profile_httpcompress_test.go +++ b/bigip/resource_bigip_ltm_profile_httpcompress_test.go @@ -19,13 +19,13 @@ var TestHttpcompressName = fmt.Sprintf("/%s/test-httpcompress", TestPartition) var TestHttpcompressResource = ` resource "bigip_ltm_profile_httpcompress" "test-httpcompress" { - name = "/Common/test-httpcompress" - defaults_from = "/Common/httpcompression" - uri_exclude = ["f5.com"] - uri_include = ["cisco.com"] - content_type_include = ["nicecontent.com"] - content_type_exclude = ["nicecontentexclude.com"] - } + name = "/Common/test-httpcompress" + defaults_from = "/Common/httpcompression" + uri_exclude = ["f5.com"] + uri_include = ["cisco.com"] + content_type_include = ["nicecontent.com"] + content_type_exclude = ["nicecontentexclude.com"] + } ` func TestAccBigipLtmProfileHttpcompress_create(t *testing.T) { @@ -39,7 +39,7 @@ func TestAccBigipLtmProfileHttpcompress_create(t *testing.T) { { Config: TestHttpcompressResource, Check: resource.ComposeTestCheckFunc( - testCheckHttpcompressExists(TestHttpcompressName, true), + testCheckHttpcompressExists("/Common/test-httpcompress", true), resource.TestCheckResourceAttr("bigip_ltm_profile_httpcompress.test-httpcompress", "name", "/Common/test-httpcompress"), resource.TestCheckResourceAttr("bigip_ltm_profile_httpcompress.test-httpcompress", "defaults_from", "/Common/httpcompression"), resource.TestCheckTypeSetElemAttr("bigip_ltm_profile_httpcompress.test-httpcompress", "uri_exclude.*", "f5.com"), @@ -146,7 +146,7 @@ func testCheckHttpcompressExists(name string, exists bool) resource.TestCheckFun return func(s *terraform.State) error { client := testAccProvider.Meta().(*bigip.BigIP) p, err := client.GetHttpcompress(name) - if err != nil { + if err != nil && exists { return err } if exists && p == nil { @@ -168,10 +168,10 @@ func testCheckHttpcompresssDestroyed(s *terraform.State) error { } name := rs.Primary.ID - httpcompress, err := client.GetHttpcompress(name) - if err != nil { - return err - } + httpcompress, _ := client.GetHttpcompress(name) + // if err != nil { + // return err + // } if httpcompress != nil { return fmt.Errorf("httpcompress %s not destroyed. ", name) } diff --git a/docs/index.md b/docs/index.md index 5011c674a..5267a54b0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -17,6 +17,7 @@ This provider uses the iControlREST API. All the resources are validated with Bi ~> **NOTE** For AWAF resources, F5 BIG-IP version should be > v16.x , and ASM need to be provisioned. ## Example Usage + ```hcl variable hostname {} variable username {} @@ -45,6 +46,9 @@ provider "bigip" { - `password` - (type `string`) BIG-IP Password for authentication. Can be set via the `BIGIP_PASSWORD` environment variable. - `token_auth` - (Optional, Default `true`) Enable to use token authentication. Can be set via the `BIGIP_TOKEN_AUTH` environment variable. - `token_value` - (Optional) A token generated outside the provider, in place of password +- `api_timeout` - (Optional, type `int`) A timeout for AS3 requests, represented as a number of seconds. +- `token_timeout` - (Optional, type `int`) A lifespan to request for the AS3 auth token, represented as a number of seconds. +- `api_retries` - (Optional, type `int`) Amount of times to retry AS3 API requests. - `login_ref` - (Optional,Default `tmos`) Login reference for token authentication (see BIG-IP REST docs for details). May be set via the `BIGIP_LOGIN_REF` environment variable. - `port` - (Optional) Management Port to connect to BIG-IP,this is mainly required if we have single nic BIG-IP in AWS/Azure/GCP (or) Management port other than `443`. Can be set via `BIGIP_PORT` environment variable. - `validate_certs_disable` - (Optional, Default `true`) If set to true, Disables TLS certificate check on BIG-IP. Can be set via the `BIGIP_VERIFY_CERT_DISABLE` environment variable. @@ -52,4 +56,4 @@ provider "bigip" { ~> **Note** For BIG-IQ resources these provider credentials `address`,`username`,`password` can be set to BIG-IQ credentials. -~> **Note** The F5 BIG-IP provider gathers non-identifiable usage data for the purposes of improving the product as outlined in the end user license agreement for BIG-IP. To opt out of data collection, use the following : `export TEEM_DISABLE=true` +~> **Note** The F5 BIG-IP provider gathers non-identifiable usage data for the purposes of improving the product as outlined in the end user license agreement for BIG-IP. To opt out of data collection, use the following : `export TEEM_DISABLE=true` \ No newline at end of file diff --git a/go.mod b/go.mod index 2ee88e4f5..c5195fca1 100644 --- a/go.mod +++ b/go.mod @@ -10,8 +10,8 @@ require ( github.com/Azure/azure-storage-blob-go v0.13.0 github.com/Azure/go-autorest/autorest v0.11.18 github.com/Azure/go-autorest/autorest/adal v0.9.13 - github.com/f5devcentral/go-bigip v0.0.0-20231120063103-95f22f4d262c - github.com/f5devcentral/go-bigip/f5teem v0.0.0-20231120063103-95f22f4d262c + github.com/f5devcentral/go-bigip v0.0.0-20240102182502-074c3e5c7aee + github.com/f5devcentral/go-bigip/f5teem v0.0.0-20240102182502-074c3e5c7aee github.com/google/uuid v1.3.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.25.0 github.com/stretchr/testify v1.8.4 diff --git a/go.sum b/go.sum index 8d8587b78..026d7030d 100644 --- a/go.sum +++ b/go.sum @@ -51,10 +51,10 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= -github.com/f5devcentral/go-bigip v0.0.0-20231120063103-95f22f4d262c h1:D0BniMWVM/IOkhNZk17d6ukX2CVnbAhr2MavEDrDQj4= -github.com/f5devcentral/go-bigip v0.0.0-20231120063103-95f22f4d262c/go.mod h1:0Lkr0fBU6O1yBxF2mt9JFwXpaFbIb/wAY7oM3dMJDdA= -github.com/f5devcentral/go-bigip/f5teem v0.0.0-20231120063103-95f22f4d262c h1:FEs8wSVxdTTZHPwR/GuESA5GXZJi/NulZuOjbiOHD1M= -github.com/f5devcentral/go-bigip/f5teem v0.0.0-20231120063103-95f22f4d262c/go.mod h1:r7o5I22EvO+fps2u10bz4ZUlTlNHopQSWzVcW19hK3U= +github.com/f5devcentral/go-bigip v0.0.0-20240102182502-074c3e5c7aee h1:RVNlRNmKTdRVEacKkgXM+LVM0HZEDY07wneeUXXZTeo= +github.com/f5devcentral/go-bigip v0.0.0-20240102182502-074c3e5c7aee/go.mod h1:0Lkr0fBU6O1yBxF2mt9JFwXpaFbIb/wAY7oM3dMJDdA= +github.com/f5devcentral/go-bigip/f5teem v0.0.0-20240102182502-074c3e5c7aee h1:fmGl57vb62P4gkOASOURc7IoAxfoaRmPpLXed4uBDoo= +github.com/f5devcentral/go-bigip/f5teem v0.0.0-20240102182502-074c3e5c7aee/go.mod h1:r7o5I22EvO+fps2u10bz4ZUlTlNHopQSWzVcW19hK3U= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= diff --git a/vendor/github.com/f5devcentral/go-bigip/bigip.go b/vendor/github.com/f5devcentral/go-bigip/bigip.go index 5b7f9959f..e649feb21 100644 --- a/vendor/github.com/f5devcentral/go-bigip/bigip.go +++ b/vendor/github.com/f5devcentral/go-bigip/bigip.go @@ -144,6 +144,19 @@ func NewTokenSession(bigipConfig *Config) (b *BigIP, err error) { Token struct { Token string } + Timeout struct { + Timeout int64 + } + } + + type timeoutReq struct { + Timeout int64 `json:"timeout"` + } + + type timeoutResp struct { + Timeout struct { + Timeout int64 + } } auth := authReq{ @@ -152,7 +165,7 @@ func NewTokenSession(bigipConfig *Config) (b *BigIP, err error) { bigipConfig.LoginReference, } - marshalJSON, err := json.Marshal(auth) + marshalJSONauth, err := json.Marshal(auth) if err != nil { return } @@ -160,7 +173,7 @@ func NewTokenSession(bigipConfig *Config) (b *BigIP, err error) { req := &APIRequest{ Method: "post", URL: "mgmt/shared/authn/login", - Body: string(marshalJSON), + Body: string(marshalJSONauth), ContentType: "application/json", } @@ -207,6 +220,42 @@ func NewTokenSession(bigipConfig *Config) (b *BigIP, err error) { b.Token = aresp.Token.Token + //Once we have obtained a token, we should actually apply the configured timeout to it + if time.Duration(aresp.Timeout.Timeout)*time.Second != bigipConfig.ConfigOptions.TokenTimeout { // The inital value is the max timespan + timeout := timeoutReq{ + int64(bigipConfig.ConfigOptions.TokenTimeout.Seconds()), + } + + marshalJSONtimeout, errToken := json.Marshal(timeout) + if errToken != nil { + return b, errToken + } + + timeoutReq := &APIRequest{ + Method: "patch", + URL: ("mgmt/shared/authz/tokens/" + b.Token), + Body: string(marshalJSONtimeout), + ContentType: "application/json", + } + resp, errToken := b.APICall(timeoutReq) + if errToken != nil { + return b, errToken + } + + if resp == nil { + errToken = fmt.Errorf("unable to update token timeout") + return b, errToken + } + var tresp map[string]interface{} + errToken = json.Unmarshal(resp, &tresp) + if err != nil { + return b, errToken + } + if time.Duration(int64(tresp["timeout"].(float64)))*time.Second != bigipConfig.ConfigOptions.TokenTimeout { + err = fmt.Errorf("failed to update token lifespan") + return + } + } return } diff --git a/vendor/modules.txt b/vendor/modules.txt index f50f56731..229a60ade 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -42,10 +42,10 @@ github.com/apparentlymart/go-textseg/v13/textseg # github.com/davecgh/go-spew v1.1.1 ## explicit github.com/davecgh/go-spew/spew -# github.com/f5devcentral/go-bigip v0.0.0-20231120063103-95f22f4d262c +# github.com/f5devcentral/go-bigip v0.0.0-20240102182502-074c3e5c7aee ## explicit; go 1.20 github.com/f5devcentral/go-bigip -# github.com/f5devcentral/go-bigip/f5teem v0.0.0-20231120063103-95f22f4d262c +# github.com/f5devcentral/go-bigip/f5teem v0.0.0-20240102182502-074c3e5c7aee ## explicit; go 1.13 github.com/f5devcentral/go-bigip/f5teem # github.com/fatih/color v1.13.0