diff --git a/configs/testwaf.json b/configs/testwaf.json
new file mode 100644
index 0000000..5e09481
--- /dev/null
+++ b/configs/testwaf.json
@@ -0,0 +1,239 @@
+{
+ "policy": {
+ "app-protection": {
+ "enabled": true
+ },
+ "applicationLanguage": "utf-8",
+ "caseInsensitive": true,
+ "cookie-settings": {
+ "maximumCookieHeaderLength": "4096"
+ },
+ "csrf-protection": {
+ "enabled": false
+ },
+ "csrf-urls": [
+ {
+ "enforcementAction": "verify-origin",
+ "method": "POST",
+ "requiredParameters": "ignore",
+ "url": "*",
+ "wildcardOrder": 1
+ }
+ ],
+ "data-guard": {
+ "enabled": false,
+ "enforcementMode": "ignore-urls-in-list"
+ },
+ "description": "",
+ "dos-protection": {
+ "behavioral-dos": {
+ "badActorDetection": {
+ "enableTlsIndexing": true,
+ "enabled": true
+ },
+ "enableHttpSignatures": true,
+ "enableTlsSignatures": false,
+ "mitigationLevel": "standard"
+ },
+ "enabled": false
+ },
+ "enablePassiveMode": false,
+ "enforcementMode": "blocking",
+ "fullPath": "/Common/Rating-Based-Template",
+ "general": {
+ "allowedResponseCodes": [
+ 400,
+ 401,
+ 403,
+ 404,
+ 405,
+ 406,
+ 407,
+ 415,
+ 417,
+ 503
+ ],
+ "enableEventCorrelation": true,
+ "enforcementReadinessPeriod": 7,
+ "maskCreditCardNumbersInRequest": true,
+ "pathParameterHandling": "as-parameters",
+ "triggerAsmIruleEvent": "disabled",
+ "trustXff": false,
+ "useDynamicSessionIdInUrl": false
+ },
+ "header-settings": {
+ "maximumHttpHeaderLength": "8192"
+ },
+ "login-enforcement": {
+ "expirationTimePeriod": "disabled"
+ },
+ "name": "test",
+ "performStaging": true,
+ "policy-builder": {
+ "enableFullPolicyInspection": true,
+ "enableTrustedTrafficSiteChangeTracking": true,
+ "enableUntrustedTrafficSiteChangeTracking": true,
+ "inactiveEntityInactivityDurationInDays": 90,
+ "learnFromResponses": false,
+ "learnInactiveEntities": false,
+ "learnOnlyFromNonBotTraffic": true,
+ "learningMode": "on-demand",
+ "responseStatusCodes": [
+ "2xx",
+ "3xx",
+ "1xx"
+ ],
+ "trafficTighten": {
+ "maxModificationSuggestionScore": 50,
+ "minDaysBetweenSamples": 1,
+ "totalRequests": 15000
+ },
+ "trustAllIps": false,
+ "trustedTrafficLoosen": {
+ "differentSources": 1,
+ "maxDaysBetweenSamples": 7,
+ "minHoursBetweenSamples": 0
+ },
+ "trustedTrafficSiteChangeTracking": {
+ "differentSources": 1,
+ "maxDaysBetweenSamples": 7,
+ "minMinutesBetweenSamples": 0
+ },
+ "untrustedTrafficLoosen": {
+ "differentSources": 20,
+ "maxDaysBetweenSamples": 7,
+ "minHoursBetweenSamples": 1
+ },
+ "untrustedTrafficSiteChangeTracking": {
+ "differentSources": 10,
+ "maxDaysBetweenSamples": 7,
+ "minMinutesBetweenSamples": 20
+ }
+ },
+ "policy-builder-central-configuration": {
+ "buildingMode": "local",
+ "eventCorrelationMode": "local"
+ },
+ "policy-builder-cookie": {
+ "collapseCookiesIntoOneEntity": false,
+ "enforceUnmodifiedCookies": false,
+ "learnExplicitCookies": "never",
+ "maximumCookies": 100
+ },
+ "policy-builder-filetype": {
+ "learnExplicitFiletypes": "never",
+ "maximumFileTypes": 100
+ },
+ "policy-builder-header": {
+ "maximumHosts": 10000,
+ "validHostNames": false
+ },
+ "policy-builder-parameter": {
+ "classifyParameters": false,
+ "collapseParametersIntoOneEntity": false,
+ "dynamicParameters": {
+ "allHiddenFields": false,
+ "formParameters": false,
+ "linkParameters": false,
+ "uniqueValueSets": 10
+ },
+ "learnExplicitParameters": "never",
+ "maximumParameters": 10000,
+ "parameterLearningLevel": "global",
+ "parametersIntegerValue": false
+ },
+ "policy-builder-redirection-protection": {
+ "learnExplicitRedirectionDomains": "never",
+ "maximumRedirectionDomains": 100
+ },
+ "policy-builder-server-technologies": {
+ "enableServerTechnologiesDetection": false
+ },
+ "policy-builder-sessions-and-logins": {
+ "learnLoginPage": false
+ },
+ "policy-builder-url": {
+ "classifyUrls": false,
+ "classifyWebsocketUrls": false,
+ "collapseUrlsIntoOneEntity": false,
+ "learnExplicitUrls": "never",
+ "learnExplicitWebsocketUrls": "never",
+ "learnMethodsOnUrls": false,
+ "maximumUrls": 100,
+ "maximumWebsocketUrls": 100,
+ "wildcardUrlFiletypes": [
+ "bmp",
+ "wav",
+ "swf",
+ "gif",
+ "pcx",
+ "pdf",
+ "png",
+ "jpeg",
+ "ico",
+ "jpg"
+ ]
+ },
+ "protocolIndependent": true,
+ "redirection-protection": {
+ "redirectionProtectionEnabled": false
+ },
+ "request-loggers": [
+ {
+ "destination": "toda",
+ "escapingCharacters": [
+ {
+ "from": "\"",
+ "to": "\\\""
+ }
+ ],
+ "filter": [
+ {
+ "field": "enforcementState.hasViolations",
+ "values": [
+ true
+ ]
+ }
+ ],
+ "formatString": "{\"unit_hostname\":\"%unit_hostname%\",\"management_ip_address\":\"%management_ip_address%\",\"management_ip_address_2\":\"%management_ip_address_2%\",\"http_class_name\":\"%http_class_name%\",\"web_application_name\":\"%http_class_name%\",\"policy_name\":\"%policy_name%\",\"policy_apply_date\":\"%policy_apply_date%Z\",\"violations\":\"%violations%\",\"support_id\":\"%support_id%\",\"request_status\":\"%request_status%\",\"response_code\":\"%response_code%\",\"ip_client\":\"%ip_client%\",\"route_domain\":\"%route_domain%\",\"method\":\"%method%\",\"protocol\":\"%protocol%\",\"query_string\":\"%query_string%\",\"x_forwarded_for_header_value\":\"%x_forwarded_for_header_value%\",\"sig_ids\":\"%sig_ids%\",\"sig_names\":\"%sig_names%\",\"date_time\":\"%date_time%Z\",\"severity\":\"%severity%\",\"attack_type\":\"%attack_type%\",\"geo_location\":\"%geo_location%\",\"ip_address_intelligence\":\"%ip_address_intelligence%\",\"username\":\"%username%\",\"session_id\":\"%session_id%\",\"src_port\":\"%src_port%\",\"dest_port\":\"%dest_port%\",\"dest_ip\":\"%dest_ip%\",\"sub_violations\":\"%sub_violations%\",\"virus_name\":\"%virus_name%\",\"microservice\":\"%microservice%\",\"tap_event_id\":\"%tap_event_id%\",\"tap_vid\":\"%tap_vid%\",\"uri\":\"%uri%\",\"violation_details\":\"%violation_details%\",\"violation_rating\":\"%violation_rating%\",\"websocket_direction\":\"%websocket_direction%\",\"websocket_message_type\":\"%websocket_message_type%\",\"compression_method\":\"%compression_method%\",\"device_id\":\"%device_id%\",\"staged_sig_ids\":\"%staged_sig_ids%\",\"staged_sig_names\":\"%staged_sig_names%\",\"threat_campaign_names\":\"%threat_campaign_names%\",\"staged_threat_campaign_names\":\"%staged_threat_campaign_names%\",\"blocking_exception_reason\":\"%blocking_exception_reason%\",\"mobile_application_name\":\"%mobile_application_name%\",\"mobile_application_version\":\"%mobile_application_version%\",\"client_type\":\"%client_type%\",\"captcha_result\":\"%captcha_result%\",\"headers\":\"%headers%\",\"fragment\":\"%fragment%\",\"sig_cves\":\"%sig_cves%\",\"staged_sig_cves\":\"%staged_sig_cves%\",\"avr_id\":\"%avr_id%\",\"ip_with_route_domain\":\"%ip_with_route_domain%\",\"is_truncated\":\"%is_truncated%\",\"sig_set_names\":\"%sig_set_names%\",\"slot_number\":\"%slot_number%\",\"staged_sig_set_names\":\"%staged_sig_set_names%\",\"vs_name\":\"%vs_name%\",\"login_result\":\"%login_result%\",\"request\":\"%request%\",\"response\":\"%response%\",\"bot_signature_name\":\"%bot_signature_name%\",\"bot_anomalies\":\"%bot_anomalies%\",\"enforced_bot_anomalies\":\"%enforced_bot_anomalies%\",\"client_class\":\"%client_class%\",\"bot_category\":\"%bot_category%\",\"policy_builder_data\":\"%policy_builder_data%\"}",
+ "maxMessageSize": 65336,
+ "name": "waf-traffic-request"
+ }
+ ],
+ "sensitive-parameters": [
+ {
+ "name": "password"
+ }
+ ],
+ "signature-sets": [
+ {
+ "alarm": true,
+ "block": false,
+ "learn": true,
+ "name": "High Accuracy Signatures"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "learn": true,
+ "name": "All Signatures"
+ }
+ ],
+ "signature-settings": {
+ "attackSignatureFalsePositiveMode": "disabled",
+ "minimumAccuracyForAutoAddedSignatures": "high",
+ "placeSignaturesInStaging": false,
+ "signatureStaging": false,
+ "stagingCertificationDatetime": ""
+ },
+ "softwareVersion": "17.0.0",
+ "template": {
+ "name": "BlankTemplate"
+ },
+ "threat-campaign-settings": {
+ "threatCampaignEnforcementReadinessPeriod": 1,
+ "threatCampaignStaging": false
+ },
+ "type": "security"
+ }
+ }
\ No newline at end of file
diff --git a/docs/resources/cm_activate_instance_license.md b/docs/resources/cm_activate_instance_license.md
new file mode 100644
index 0000000..1e41154
--- /dev/null
+++ b/docs/resources/cm_activate_instance_license.md
@@ -0,0 +1,46 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "bigipnext_cm_activate_instance_license Resource - terraform-provider-bigipnext"
+subcategory: ""
+description: |-
+ Resource used for Activate/Deactivate License for Instances on Central Manager Using JWT Token
+---
+
+# bigipnext_cm_activate_instance_license (Resource)
+
+Resource used for Activate/Deactivate License for Instances on Central Manager Using JWT Token
+
+## Example Usage
+
+```terraform
+resource "bigipnext_cm_activate_instance_license" "tokenadd" {
+ instances = [{
+ instance_address = "10.xxx.xxx.xxx"
+ jwt_id = "8a3dc22e-xxxx-xxxxc-xxxx-xxxxxxxx4326"
+ },
+ {
+ instance_address = "10.146.194.174"
+ jwt_id = "8a3dc22e-xxxx-xxxxc-xxxx-xxxxxxxx4326"
+ }
+ ]
+}
+```
+
+
+## Schema
+
+### Required
+
+- `instances` (Attributes List) List of instances to activate the license (see [below for nested schema](#nestedatt--instances))
+
+### Read-Only
+
+- `id` (String) Unique Identifier for the resource
+
+
+### Nested Schema for `instances`
+
+Required:
+
+- `instance_address` (String) IP Address of the instance to activate the license
+- `jwt_id` (String) JWT ID to be used to activate the license
diff --git a/docs/resources/cm_add_jwt_token.md b/docs/resources/cm_add_jwt_token.md
new file mode 100644
index 0000000..e12919e
--- /dev/null
+++ b/docs/resources/cm_add_jwt_token.md
@@ -0,0 +1,34 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "bigipnext_cm_add_jwt_token Resource - terraform-provider-bigipnext"
+subcategory: ""
+description: |-
+ Resource used for add/copy JWT Token on Central Manager
+---
+
+# bigipnext_cm_add_jwt_token (Resource)
+
+Resource used for add/copy JWT Token on Central Manager
+
+## Example Usage
+
+```terraform
+resource "bigipnext_cm_add_jwt_token" "tokenadd" {
+ token_name = "paid_test_jwt"
+ jwt_token = "eyJhbG"
+}
+```
+
+
+## Schema
+
+### Required
+
+- `jwt_token` (String, Sensitive) JWT token to be added on Central Manager
+- `token_name` (String) Nickname to be used to add the JWT token on Central Manager
+
+### Read-Only
+
+- `id` (String) Unique Identifier for the resource
+- `order_type` (String) JWT token to be added on Central Manager
+- `subscription_expiry` (String) JWT token to be added on Central Manager
diff --git a/docs/resources/cm_bootstrap.md b/docs/resources/cm_bootstrap.md
new file mode 100644
index 0000000..d940d4b
--- /dev/null
+++ b/docs/resources/cm_bootstrap.md
@@ -0,0 +1,61 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "bigipnext_cm_bootstrap Resource - terraform-provider-bigipnext"
+subcategory: ""
+description: |-
+ Resource used for bootstrapping Central Manager
+ ~> NOTE This resource does not support update and delete. When doing terraform destroy it will only remove the resource from the state
+---
+
+# bigipnext_cm_bootstrap (Resource)
+
+Resource used for bootstrapping Central Manager
+
+~> **NOTE** This resource does not support update and delete. When doing `terraform destroy` it will only remove the resource from the state
+
+## Example Usage
+
+```terraform
+resource "bigipnext_cm_bootstrap" "name" {
+ run_setup = true
+ bootstrap_timeout = 800
+ external_storage = {
+ storage_type = "NFS"
+ storage_address = "10.28.14.22"
+ storage_path = "/exports/backup"
+ cm_storage_dir = "backuppqr"
+ }
+}
+```
+
+
+## Schema
+
+### Required
+
+- `run_setup` (Boolean) Run setup on Central Manager
+
+### Optional
+
+- `bootstrap_timeout` (Number) Timeout for the bootstrap operation
+- `external_storage` (Attributes) External storage configuration (see [below for nested schema](#nestedatt--external_storage))
+
+### Read-Only
+
+- `bootstrap_status` (String) Status of the bootstrap operation
+- `id` (String) ID of the resource
+
+
+### Nested Schema for `external_storage`
+
+Required:
+
+- `storage_address` (String) IP Address of the external storage
+- `storage_path` (String) Directory path that is mounted on the external storage server
+- `storage_type` (String) Type of external storage. Supported values are NFS and SAMBA
+
+Optional:
+
+- `cm_storage_dir` (String) Folder name created on the external storage server to store Central Manager data
+- `password` (String) Password to access the external storage, required if storage type is SAMBA
+- `username` (String) Username to access the external storage, required if storage type is SAMBA
diff --git a/examples/resources/bigipnext_cm_activate_instance_license/resource.tf b/examples/resources/bigipnext_cm_activate_instance_license/resource.tf
new file mode 100644
index 0000000..c2dbf13
--- /dev/null
+++ b/examples/resources/bigipnext_cm_activate_instance_license/resource.tf
@@ -0,0 +1,11 @@
+resource "bigipnext_cm_activate_instance_license" "tokenadd" {
+ instances = [{
+ instance_address = "10.xxx.xxx.xxx"
+ jwt_id = "8a3dc22e-xxxx-xxxxc-xxxx-xxxxxxxx4326"
+ },
+ {
+ instance_address = "10.146.194.174"
+ jwt_id = "8a3dc22e-xxxx-xxxxc-xxxx-xxxxxxxx4326"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/examples/resources/bigipnext_cm_add_jwt_token/resource.tf b/examples/resources/bigipnext_cm_add_jwt_token/resource.tf
new file mode 100644
index 0000000..159d12e
--- /dev/null
+++ b/examples/resources/bigipnext_cm_add_jwt_token/resource.tf
@@ -0,0 +1,4 @@
+resource "bigipnext_cm_add_jwt_token" "tokenadd" {
+ token_name = "paid_test_jwt"
+ jwt_token = "eyJhbG"
+}
\ No newline at end of file
diff --git a/examples/resources/bigipnext_cm_bootstrap/resource.tf b/examples/resources/bigipnext_cm_bootstrap/resource.tf
new file mode 100644
index 0000000..d2bd6f6
--- /dev/null
+++ b/examples/resources/bigipnext_cm_bootstrap/resource.tf
@@ -0,0 +1,10 @@
+resource "bigipnext_cm_bootstrap" "name" {
+ run_setup = true
+ bootstrap_timeout = 800
+ external_storage = {
+ storage_type = "NFS"
+ storage_address = "10.28.14.22"
+ storage_path = "/exports/backup"
+ cm_storage_dir = "backuppqr"
+ }
+}
\ No newline at end of file
diff --git a/examples/resources/bigipnextcm_as3/resource.tf b/examples/resources/bigipnextcm_as3/resource.tf
new file mode 100644
index 0000000..f47f3e5
--- /dev/null
+++ b/examples/resources/bigipnextcm_as3/resource.tf
@@ -0,0 +1,49 @@
+resource "bigipnext_cm_as3" "test2" {
+ as3_json = < **NOTE** This resource does not support update and delete. When doing `terraform destroy` it will only remove the resource from the state",
+ Attributes: map[string]schema.Attribute{
+ "run_setup": schema.BoolAttribute{
+ Required: true,
+ MarkdownDescription: "Run setup on Central Manager",
+ },
+ "external_storage": schema.SingleNestedAttribute{
+ Optional: true,
+ MarkdownDescription: "External storage configuration",
+ Attributes: map[string]schema.Attribute{
+ "storage_type": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Type of external storage. Supported values are NFS and SAMBA",
+ Validators: []validator.String{
+ stringvalidator.OneOf([]string{"NFS", "SAMBA"}...),
+ },
+ },
+ "storage_address": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "IP Address of the external storage",
+ },
+ "storage_path": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Directory path that is mounted on the external storage server",
+ },
+ "cm_storage_dir": schema.StringAttribute{
+ Optional: true,
+ MarkdownDescription: "Folder name created on the external storage server to store Central Manager data",
+ },
+ "username": schema.StringAttribute{
+ MarkdownDescription: "Username to access the external storage, required if storage type is SAMBA",
+ Optional: true,
+ },
+ "password": schema.StringAttribute{
+ MarkdownDescription: "Password to access the external storage, required if storage type is SAMBA",
+ Optional: true,
+ },
+ },
+ },
+ "bootstrap_timeout": schema.Int64Attribute{
+ Optional: true,
+ MarkdownDescription: "Timeout for the bootstrap operation",
+ },
+ "bootstrap_status": schema.StringAttribute{
+ Computed: true,
+ MarkdownDescription: "Status of the bootstrap operation",
+ },
+ "id": schema.StringAttribute{
+ Computed: true,
+ MarkdownDescription: "ID of the resource",
+ PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()},
+ },
+ },
+ }
+}
+
+func (r *CMNextBootstrapResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+ r.client, resp.Diagnostics = toBigipNextCMProvider(req.ProviderData)
+}
+
+func (r *CMNextBootstrapResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ var resCfg CMNextBootstrapResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
+
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ if !resCfg.ExternalStorage.IsNull() {
+ var externalStorageModel ExternalStorage
+ diag := resCfg.ExternalStorage.As(ctx, &externalStorageModel, basetypes.ObjectAsOptions{})
+
+ if diag.HasError() {
+ return
+ }
+
+ externalStorage := getExternalStorageData(&externalStorageModel)
+ res, err := r.client.AddExternalStorage(externalStorage)
+ if err != nil { // coverage-ignore
+ resp.Diagnostics.AddError("Failed to add external storage:", err.Error())
+ return
+ }
+
+ externalStoreResp := &bigipnextsdk.CMExternalStorageResp{}
+
+ tflog.Info(ctx, "External storage setup response: "+res)
+ err = json.Unmarshal([]byte(res), externalStoreResp)
+ if err != nil { // coverage-ignore
+ resp.Diagnostics.AddError("Failed to unmarshal external storage response:", err.Error())
+ return
+ }
+
+ if externalStoreResp.Status.Setup != "SUCCESSFUL" { // coverage-ignore
+ tflog.Error(ctx, "Failed to setup external storage")
+ resp.Diagnostics.AddError("Failed to setup external storage", externalStoreResp.Status.FailureMessage)
+ return
+ }
+
+ typeMap := map[string]attr.Type{
+ "storage_type": types.StringType,
+ "storage_address": types.StringType,
+ "storage_path": types.StringType,
+ "cm_storage_dir": types.StringType,
+ "username": types.StringType,
+ "password": types.StringType,
+ }
+ valMap := map[string]attr.Value{
+ "storage_type": types.StringValue(externalStoreResp.Spec.StorageType),
+ "storage_address": types.StringValue(externalStoreResp.Spec.StorageAddress),
+ "storage_path": types.StringValue(externalStoreResp.Spec.StorageSharePath),
+ }
+
+ if externalStoreResp.Spec.StorageType == "SAMBA" {
+ valMap["username"] = types.StringValue(externalStoreResp.Spec.StorageUser.Username)
+ valMap["password"] = types.StringValue(externalStoreResp.Spec.StorageUser.Password)
+ } else {
+ valMap["username"] = types.StringNull()
+ valMap["password"] = types.StringNull()
+ }
+ if externalStoreResp.Spec.StorageShareDir != "" {
+ valMap["cm_storage_dir"] = types.StringValue(externalStoreResp.Spec.StorageShareDir)
+ } else {
+ if !externalStorageModel.CMStorageDir.IsNull() {
+ valMap["cm_storage_dir"] = externalStorageModel.CMStorageDir
+ } else {
+ valMap["cm_storage_dir"] = types.StringNull()
+ }
+ }
+
+ resCfg.ExternalStorage, _ = types.ObjectValue(typeMap, valMap)
+ }
+
+ var cmBootstrapStatus string
+ if resCfg.RunSetup.ValueBool() {
+ var timeout int64
+ if resCfg.BootstrapTimeout.IsNull() {
+ timeout = 600
+ } else { // coverage-ignore
+ timeout = resCfg.BootstrapTimeout.ValueInt64()
+ }
+ res, err := r.client.BootstrapCM(timeout)
+
+ if err != nil { // coverage-ignore
+ resp.Diagnostics.AddError("Failed to bootstrap Central Manager:", err.Error())
+ return
+ }
+
+ bootStrapResp := &bigipnextsdk.BootstrapCMResp{}
+ err = json.Unmarshal([]byte(res), bootStrapResp)
+ if err != nil { // coverage-ignore
+ resp.Diagnostics.AddError("Failed to unmarshal Central Manager bootstrap response:", err.Error())
+ return
+ }
+
+ cmBootstrapStatus = bootStrapResp.Status
+
+ tflog.Info(ctx, "Central Manager bootstrap response: "+res)
+ }
+
+ id := extractIPFromUrl(r.client.Host)
+
+ resCfg.Id = types.StringValue(fmt.Sprintf("setup-%s", id))
+ resCfg.BootstrapStatus = types.StringValue(cmBootstrapStatus)
+ resp.Diagnostics.Append(resp.State.Set(ctx, &resCfg)...)
+}
+
+func (r *CMNextBootstrapResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var stateCfg *CMNextBootstrapResourceModel
+ resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ res, err := r.client.GetCMExternalStorage()
+ if err != nil { // coverage-ignore
+ resp.Diagnostics.AddError("Failed to read external storage status", err.Error())
+ }
+ externalStorageResp := &bigipnextsdk.CMExternalStorageResp{}
+ err = json.Unmarshal([]byte(res), externalStorageResp)
+ if err != nil { // coverage-ignore
+ resp.Diagnostics.AddError("Failed to unmarshal external storage response", err.Error())
+ }
+
+ typeMap := map[string]attr.Type{
+ "storage_type": types.StringType,
+ "storage_address": types.StringType,
+ "storage_path": types.StringType,
+ "cm_storage_dir": types.StringType,
+ "username": types.StringType,
+ "password": types.StringType,
+ }
+ valMap := map[string]attr.Value{
+ "storage_type": types.StringValue(externalStorageResp.Spec.StorageType),
+ "storage_address": types.StringValue(externalStorageResp.Spec.StorageAddress),
+ "storage_path": types.StringValue(externalStorageResp.Spec.StorageSharePath),
+ }
+
+ if externalStorageResp.Spec.StorageType == "SAMBA" {
+ valMap["username"] = types.StringValue(externalStorageResp.Spec.StorageUser.Username)
+ valMap["password"] = types.StringValue(externalStorageResp.Spec.StorageUser.Password)
+ } else {
+ valMap["username"] = types.StringNull()
+ valMap["password"] = types.StringNull()
+ }
+ if externalStorageResp.Spec.StorageShareDir != "" {
+ valMap["cm_storage_dir"] = types.StringValue(externalStorageResp.Spec.StorageShareDir)
+ } else {
+ valMap["cm_storage_dir"] = types.StringNull()
+ }
+
+ stateCfg.ExternalStorage, _ = types.ObjectValue(typeMap, valMap)
+
+ bootstrap, err := r.client.GetCMBootstrap()
+ if err != nil { // coverage-ignore
+ resp.Diagnostics.AddError("Failed to read the bootstrap status", err.Error())
+ }
+ bootstrapResp := &bigipnextsdk.BootstrapCMResp{}
+ err = json.Unmarshal([]byte(bootstrap), bootstrapResp)
+ if err != nil { // coverage-ignore
+ resp.Diagnostics.AddError("Failed to unmarshal the bootstrap response", err.Error())
+ }
+
+ id := extractIPFromUrl(r.client.Host)
+
+ stateCfg.Id = types.StringValue(fmt.Sprintf("setup-%s", id))
+ stateCfg.BootstrapStatus = types.StringValue(bootstrapResp.Status)
+}
+
+func (r *CMNextBootstrapResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ tflog.Info(ctx, "this resource does not support update operation")
+}
+
+func (r *CMNextBootstrapResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ tflog.Info(ctx, "this resource does not support delete operation, it can oly be removed from the state")
+ resp.State.SetAttribute(ctx, path.Root("id"), types.StringValue(""))
+}
+
+func getExternalStorageData(plan *ExternalStorage) *bigipnextsdk.CMExternalStorage {
+ externalStorage := &bigipnextsdk.CMExternalStorage{}
+
+ externalStorage.StorageType = plan.StorageType.ValueString()
+ externalStorage.StorageAddress = plan.StorageAddress.ValueString()
+ externalStorage.StorageSharePath = plan.StoragePath.ValueString()
+
+ if plan.CMStorageDir.IsNull() {
+ externalStorage.StorageShareDir = ""
+ } else {
+ externalStorage.StorageShareDir = plan.CMStorageDir.ValueString()
+ }
+
+ if !plan.Username.IsNull() {
+ externalStorage.StorageUser = &bigipnextsdk.CMExternalStorageUser{
+ Username: plan.Username.ValueString(),
+ Password: plan.Password.ValueString(),
+ }
+ }
+
+ return externalStorage
+}
diff --git a/internal/provider/cm_bootstrap_resource_test.go b/internal/provider/cm_bootstrap_resource_test.go
new file mode 100644
index 0000000..aaaca44
--- /dev/null
+++ b/internal/provider/cm_bootstrap_resource_test.go
@@ -0,0 +1,290 @@
+package provider
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ bigipnextsdk "gitswarm.f5net.com/terraform-providers/bigipnext"
+)
+
+func TestAccCMBootstrap(t *testing.T) {
+ t.Parallel()
+
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testAccCMBootstrapConfig,
+ Check: resource.ComposeAggregateTestCheckFunc(
+ resource.TestCheckResourceAttr("bigipnext_cm_bootstrap.cm_bootstrap", "run_setup", "false"),
+ resource.TestCheckResourceAttr("bigipnext_cm_bootstrap.cm_bootstrap", "external_storage.storage_type", "NFS"),
+ resource.TestCheckResourceAttr("bigipnext_cm_bootstrap.cm_bootstrap", "external_storage.storage_address", "10.218.134.22"),
+ ),
+ },
+ },
+ })
+}
+
+func TestUnitCMBootstrap(t *testing.T) {
+ testAccPreUnitCheck(t)
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+
+ mux.HandleFunc("/api/v1/system/infra/external-storage", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == http.MethodPost {
+ payload, err := io.ReadAll(r.Body)
+ if err != nil && err.Error() != "EOF" {
+ t.Fatal(err)
+ }
+
+ payloadStruct := &bigipnextsdk.CMExternalStorage{}
+ err = json.Unmarshal(payload, payloadStruct)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if payloadStruct.StorageAddress != "10.218.134.22" {
+ t.Errorf("Expected storage address to be 10.218.134.22, got %v", payloadStruct.StorageAddress)
+ }
+ if payloadStruct.StorageType != "NFS" {
+ t.Errorf("Expected storage type to be NFS, got %v", payloadStruct.StorageType)
+ }
+ if payloadStruct.StorageSharePath != "/exports/backup" {
+ t.Errorf("Expected storage path to be /exports/backup, got %v", payloadStruct.StorageSharePath)
+ }
+
+ fmt.Fprint(w, `
+ {
+ "spec": {
+ "storage_address": "10.218.134.22",
+ "storage_share_dir": "",
+ "storage_share_path": "/exports/backup",
+ "storage_type": "NFS"
+ },
+ "status": {
+ "setup": "SUCCESSFUL"
+ }
+ }`)
+ }
+ if r.Method == http.MethodGet {
+ fmt.Fprint(w, `
+ {
+ "spec": {
+ "storage_address": "10.218.134.22",
+ "storage_share_dir": "9fb2d367-e8e6-4c09-abd2-faaee96ebe93",
+ "storage_share_path": "/exports/backup",
+ "storage_type": "NFS"
+ },
+ "status": {
+ "setup": "SUCCESSFUL"
+ }
+ }`)
+ }
+ })
+
+ i := 0
+ bootstrapStatuses := []string{
+ `{
+ "created": "2024-07-15T06:31:49.322459826Z",
+ "status": "RUNNING",
+ "step": "Installing Elasticsearch",
+ "updated": "2024-07-15T06:40:36.083148739Z"
+ }`,
+ `{
+ "created": "2024-07-15T06:31:49.322459826Z",
+ "status": "RUNNING",
+ "step": "Installing Central Manager applications",
+ "updated": "2024-07-15T06:40:36.083148739Z"
+ }`,
+ `{
+ "created": "2024-07-15T06:31:49.322459826Z",
+ "status": "COMPLETED",
+ "step": "Done",
+ "updated": "2024-07-15T06:40:36.083148739Z"
+ }`,
+ `{
+ "created": "2024-07-15T06:31:49.322459826Z",
+ "status": "COMPLETED",
+ "step": "Done",
+ "updated": "2024-07-15T06:40:36.083148739Z"
+ }`,
+ }
+
+ mux.HandleFunc("/api/v1/system/infra/bootstrap", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == http.MethodPost {
+ fmt.Fprint(w, `
+ {
+ "created": "2024-07-15T06:31:49.322459826Z",
+ "status": "RUNNING",
+ "step": "Installing Kafka",
+ "updated": "2024-07-15T06:40:36.083148739Z"
+ }
+ `)
+ }
+ if r.Method == http.MethodGet {
+ fmt.Fprint(w, bootstrapStatuses[i])
+ i += 1
+ }
+ })
+ defer teardown()
+ resource.Test(t, resource.TestCase{
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testUnitCMBootstrapConfig,
+ },
+ },
+ })
+}
+
+func TestUnitCMBootstrapSAMBA(t *testing.T) {
+ testAccPreUnitCheck(t)
+ defer teardown()
+
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+
+ mux.HandleFunc("/api/v1/system/infra/external-storage", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == http.MethodPost {
+ payload, err := io.ReadAll(r.Body)
+ if err != nil && err.Error() != "EOF" {
+ t.Fatal(err)
+ }
+
+ payloadStruct := &bigipnextsdk.CMExternalStorage{}
+ err = json.Unmarshal(payload, payloadStruct)
+
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if payloadStruct.StorageAddress != "10.22.33.44" {
+ t.Errorf("Expected storage address to be 10.22.33.44, got %v", payloadStruct.StorageAddress)
+ }
+ if payloadStruct.StorageType != "SAMBA" {
+ t.Errorf("Expected storage type to be SAMBA, got %v", payloadStruct.StorageType)
+ }
+ if payloadStruct.StorageSharePath != "/exports/backup" {
+ t.Errorf("Expected storage path to be /exports/backup, got %v", payloadStruct.StorageSharePath)
+ }
+ if payloadStruct.StorageShareDir != "backup" {
+ t.Errorf("Expected storage path to be backup, got %v", payloadStruct.StorageShareDir)
+ }
+
+ fmt.Fprint(w, `
+ {
+ "spec": {
+ "storage_address": "10.22.33.44",
+ "storage_share_dir": "",
+ "storage_share_path": "/exports/backup",
+ "storage_type": "SAMBA",
+ "storage_user": {
+ "username": "admin",
+ "password": "password"
+ }
+ },
+ "status": {
+ "setup": "SUCCESSFUL"
+ }
+ }`)
+ }
+ if r.Method == http.MethodGet {
+ fmt.Fprint(w, `
+ {
+ "spec": {
+ "storage_address": "10.22.33.44",
+ "storage_share_dir": "backup",
+ "storage_share_path": "/exports/backup",
+ "storage_type": "SAMBA",
+ "storage_user": {
+ "username": "admin",
+ "password": "password"
+ }
+ },
+ "status": {
+ "setup": "SUCCESSFUL"
+ }
+ }`)
+ }
+ })
+
+ mux.HandleFunc("/api/v1/system/infra/bootstrap", func(w http.ResponseWriter, r *http.Request) {
+ fmt.Fprint(w, `
+ {
+ "created": "2024-07-15T06:31:49.322459826Z",
+ "status": "SUCCESSFUL",
+ "step": "Installing Kafka",
+ "updated": "2024-07-15T06:40:36.083148739Z"
+ }
+ `)
+ })
+
+ defer teardown()
+ resource.Test(t, resource.TestCase{
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testUnitCMBootstrapConfigSAMBA,
+ },
+ },
+ })
+}
+
+const testAccCMBootstrapConfig = `
+resource "bigipnext_cm_bootstrap" "cm_bootstrap" {
+ run_setup = false
+ external_storage = {
+ storage_type = "NFS"
+ storage_address = "10.218.134.22"
+ storage_path = "/exports/backup"
+ }
+}
+`
+
+const testUnitCMBootstrapConfig = `
+resource "bigipnext_cm_bootstrap" "cm_bootstrap" {
+ run_setup = true
+ external_storage = {
+ storage_type = "NFS"
+ storage_address = "10.218.134.22"
+ storage_path = "/exports/backup"
+ }
+}
+`
+
+const testUnitCMBootstrapConfigSAMBA = `
+resource "bigipnext_cm_bootstrap" "cm_bootstrap" {
+ run_setup = false
+ external_storage = {
+ storage_type = "SAMBA"
+ storage_address = "10.22.33.44"
+ storage_path = "/exports/backup"
+ cm_storage_dir = "backup"
+ username = "admin"
+ password = "password"
+ }
+}
+`
diff --git a/internal/provider/cm_discovery_next_resource.go b/internal/provider/cm_discovery_next_resource.go
index 585f5fd..ad8b8d5 100644
--- a/internal/provider/cm_discovery_next_resource.go
+++ b/internal/provider/cm_discovery_next_resource.go
@@ -89,7 +89,7 @@ func (r *CMDiscoveryNextResource) Configure(ctx context.Context, req resource.Co
func (r *CMDiscoveryNextResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var resCfg *CMDiscoveryNextResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
tflog.Info(ctx, fmt.Sprintf("[CREATE] CMDiscoveryNextResource:%+v\n", resCfg.Address.ValueString()))
@@ -99,7 +99,7 @@ func (r *CMDiscoveryNextResource) Create(ctx context.Context, req resource.Creat
tflog.Info(ctx, fmt.Sprintf("[CREATE] Device Provider config:%+v\n", providerConfig))
respData, err := r.client.DiscoverInstance(providerConfig)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Create Certificate, got error: %s", err))
return
}
@@ -111,14 +111,14 @@ func (r *CMDiscoveryNextResource) Create(ctx context.Context, req resource.Creat
func (r *CMDiscoveryNextResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var stateCfg *CMDiscoveryNextResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
id := stateCfg.Id.ValueString()
tflog.Info(ctx, fmt.Sprintf("Reading Instance Info : %+v", id))
deviceInfo, err := r.client.GetDeviceInfoByID(id)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Read Instance Info, got error: %s", err))
return
}
@@ -138,7 +138,7 @@ func (r *CMDiscoveryNextResource) Update(ctx context.Context, req resource.Updat
var resCfg *CMDiscoveryNextResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
tflog.Info(ctx, fmt.Sprintf("[UPDATE] Updating Device Provider: %s", resCfg.Id.ValueString()))
@@ -148,13 +148,13 @@ func (r *CMDiscoveryNextResource) Update(ctx context.Context, req resource.Updat
func (r *CMDiscoveryNextResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var stateCfg *CMDiscoveryNextResourceModel
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
id := stateCfg.Id.ValueString()
err := r.client.DeleteDevice(id)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to Delete Instance, got error: %s", err))
return
}
diff --git a/internal/provider/cm_ha_cluster_resource.go b/internal/provider/cm_ha_cluster_resource.go
index f5c73fa..d54c6d1 100644
--- a/internal/provider/cm_ha_cluster_resource.go
+++ b/internal/provider/cm_ha_cluster_resource.go
@@ -115,7 +115,7 @@ func (r *NextCMHAClusterResource) Create(ctx context.Context, req resource.Creat
var nodeCheck []string
for _, node := range resCfg.Nodes {
- if node.Fingerprint.IsNull() {
+ if node.Fingerprint.IsNull() { // coverage-ignore
fingerprint, err := getFingerPrint(node.NodeIP.String())
if err != nil {
resp.Diagnostics.AddError(fmt.Sprintf("error getting fingerprint of the node %s: ", node.NodeIP), err.Error())
@@ -137,7 +137,7 @@ func (r *NextCMHAClusterResource) Create(ctx context.Context, req resource.Creat
res, err := r.client.CreateCMHACluster(nodes)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("error creating CM HA cluster", err.Error())
return
}
@@ -145,7 +145,7 @@ func (r *NextCMHAClusterResource) Create(ctx context.Context, req resource.Creat
log.Printf("Started CM HA Cluster creation: %v", res)
res2, err := r.client.CheckCMHANodesStatus(nodeCheck)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("error creating CM HA cluster", err.Error())
return
}
@@ -220,7 +220,7 @@ func (r *NextCMHAClusterResource) Update(ctx context.Context, req resource.Updat
if !doAddOperation {
continue
}
- if node.Fingerprint.IsNull() {
+ if node.Fingerprint.IsNull() { // coverage-ignore
fingerprint, err := getFingerPrint(node.NodeIP.String())
if err != nil {
resp.Diagnostics.AddError(fmt.Sprintf("error getting fingerprint of the node %s: ", node.NodeIP), err.Error())
@@ -241,7 +241,7 @@ func (r *NextCMHAClusterResource) Update(ctx context.Context, req resource.Updat
}
_, err := r.client.CreateCMHACluster(nodes)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("error updating CM HA cluster", err.Error())
return
}
@@ -249,7 +249,7 @@ func (r *NextCMHAClusterResource) Update(ctx context.Context, req resource.Updat
}
res, err := r.client.CheckCMHANodesStatus(nodeCheck)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("error reading CM HA cluster", err.Error())
return
}
@@ -283,7 +283,7 @@ func (r *NextCMHAClusterResource) Delete(ctx context.Context, req resource.Delet
}
}
- if nodeCount > 1 {
+ if nodeCount > 1 { // coverage-ignore
tflog.Error(ctx, "unable to delete all the nodes of the cluster")
resp.Diagnostics.AddError("delete operation failed", "unable to delete all the nodes of the cluster")
}
diff --git a/internal/provider/cm_ha_cluster_resource_test.go b/internal/provider/cm_ha_cluster_resource_test.go
index 49af772..9a95ad5 100644
--- a/internal/provider/cm_ha_cluster_resource_test.go
+++ b/internal/provider/cm_ha_cluster_resource_test.go
@@ -1,11 +1,14 @@
package provider
import (
+ "encoding/json"
"fmt"
+ "net/http"
"os"
"testing"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "gitswarm.f5net.com/terraform-providers/bigipnext"
)
func TestAccCMHAClusterTC(t *testing.T) {
@@ -36,11 +39,218 @@ func TestAccCMHAClusterTC(t *testing.T) {
})
}
+func TestUnitCMHAClusterCreate(t *testing.T) {
+ testAccPreUnitCheck(t)
+ defer teardown()
+
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+
+ afterDeleteCall := false
+
+ mux.HandleFunc("/api/v1/system/infra/nodes", func(w http.ResponseWriter, r *http.Request) {
+
+ if r.Method == http.MethodPost {
+ payload := make([]byte, r.ContentLength)
+
+ _, err := r.Body.Read(payload)
+
+ if err != nil && err.Error() != "EOF" {
+ t.Errorf("Error reading request body: %v", err)
+ }
+
+ defer r.Body.Close()
+ var nodes []bigipnext.CMHANodes
+
+ err = json.Unmarshal(payload, &nodes)
+ if err != nil {
+ t.Errorf("Error unmarshalling request body: %v", err)
+ }
+
+ if nodes[0].NodeAddress != "10.146.164.150" {
+ t.Errorf("Expected node address to be 10.146.164.150, got %s", nodes[0].NodeAddress)
+ }
+ if nodes[0].Username != "admin" {
+ t.Errorf("Expected username to be admin, got %s", nodes[0].Username)
+ }
+ if nodes[0].Password != "F5site02@123" {
+ t.Errorf("Expected password to be F5site02@123, got %s", nodes[0].Password)
+ }
+ if nodes[0].Fingerprint != "c2b2472624cd7f3a053c4f6e0bd4b322" {
+ t.Errorf("Expected fingerprint to be c2b2472624cd7f3a053c4f6e0bd4b322, got %s", nodes[0].Fingerprint)
+ }
+
+ if nodes[1].NodeAddress != "10.146.165.89" {
+ t.Errorf("Expected node address to be 10.146.165.89, got %s", nodes[1].NodeAddress)
+ }
+ if nodes[1].Username != "admin" {
+ t.Errorf("Expected username to be admin, got %s", nodes[1].Username)
+ }
+ if nodes[1].Password != "F5site02@123" {
+ t.Errorf("Expected password to be F5site02@123, got %s", nodes[1].Password)
+ }
+ if nodes[1].Fingerprint != "c2b2472624cd7f3a053c4f6e0bd4b322" {
+ t.Errorf("Expected fingerprint to be c2b2472624cd7f3a053c4f6e0bd4b322, got %s", nodes[1].Fingerprint)
+ }
+
+ postResp, _ := os.ReadFile("fixtures/cm_ha_nodes_post.json")
+ fmt.Fprint(w, postResp)
+ }
+
+ if r.Method == http.MethodGet {
+ getResp, _ := os.ReadFile("fixtures/cm_ha_nodes_get.json")
+ fmt.Fprint(w, getResp)
+ }
+
+ if r.Method == http.MethodGet && afterDeleteCall {
+ getAfterDeleteResp, _ := os.ReadFile("fixtures/cm_ha_nodes_get_after_delete.json")
+ fmt.Fprint(w, getAfterDeleteResp)
+ }
+ })
+
+ mux.HandleFunc("/api/v1/system/infra/nodes/central-manager-10-146-165-89", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == http.MethodDelete {
+ afterDeleteCall = true
+ w.WriteHeader(http.StatusAccepted)
+ fmt.Fprint(w, "node central-manager-10-146-165-89 is in process of deregistration.")
+ }
+ })
+
+ mux.HandleFunc("/api/v1/system/infra/nodes/central-manager-10-146-164-150", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == http.MethodDelete {
+ afterDeleteCall = true
+ w.WriteHeader(http.StatusAccepted)
+ fmt.Fprint(w, "node central-manager-10-146-164-150 is in process of deregistration.")
+ }
+ })
+
+ resource.Test(t, resource.TestCase{
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testUnitCMHAClusterConfig,
+ },
+ },
+ })
+}
+
+func TestUnitCMHAClusterUpdate(t *testing.T) {
+ testAccPreUnitCheck(t)
+ defer teardown()
+
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+
+ afterDeleteCall := false
+ updateCall := false
+ mux.HandleFunc("/api/v1/system/infra/nodes", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == http.MethodPost {
+ postResp, _ := os.ReadFile("fixtures/cm_ha_nodes_post.json")
+ fmt.Fprint(w, postResp)
+ updateCall = true
+ }
+
+ if r.Method == http.MethodPost && updateCall {
+ postResp, _ := os.ReadFile("fixtures/cm_ha_nodes_post_update.json")
+ fmt.Fprint(w, postResp)
+ }
+
+ if r.Method == http.MethodGet {
+ getResp, _ := os.ReadFile("fixtures/cm_ha_nodes_get.json")
+ fmt.Fprint(w, getResp)
+ }
+
+ if r.Method == http.MethodGet && afterDeleteCall {
+ getAfterDeleteResp, _ := os.ReadFile("fixtures/cm_ha_nodes_get_after_delete.json")
+ fmt.Fprint(w, getAfterDeleteResp)
+ }
+ })
+
+ resource.Test(t, resource.TestCase{
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testUnitCMHAClusterConfig,
+ Destroy: false,
+ },
+ {
+ Config: testUnitCMHAClusterUpdateConfig,
+ Destroy: false,
+ },
+ },
+ })
+}
+
+func TestUnitCMHAClusterGetFingerprint(t *testing.T) {
+ fp1, err := getFingerPrint("8.8.8.8")
+ if len(fp1) != 64 {
+ t.Errorf("Expected fingerprint length to be 64, got %d", len(fp1))
+ }
+ if err != nil {
+ t.Errorf("Expected no error, got %v", err)
+ }
+
+ _, err = getFingerPrint("a.b.c.d")
+ if err == nil {
+ t.Errorf("Expected error for a bogus IP address, got nil")
+ }
+}
+
+func TestUnitCMHAClusterGetServerAndAgentNodes(t *testing.T) {
+ nodes := []bigipnext.CMHANodesStatus{
+ {
+ Spec: bigipnext.CMHANodeSpec{
+ NodeAddress: "1.2.3.4",
+ NodeType: "server",
+ },
+ },
+ {
+ Spec: bigipnext.CMHANodeSpec{
+ NodeAddress: "5.6.7.8",
+ NodeType: "agent",
+ },
+ },
+ }
+
+ serverNodes, agentNodes := getServerAndAgentNodes(nodes)
+ if len(serverNodes) != 1 {
+ t.Errorf("Expected server nodes length to be 1, got %d", len(serverNodes))
+ }
+ if len(agentNodes) != 1 {
+ t.Errorf("Expected agent nodes length to be 1, got %d", len(agentNodes))
+ }
+
+ if serverNodes[0] != "1.2.3.4" {
+ t.Errorf("Expected server node address to be 1.2.3.4, got %s", nodes[0].Spec.NodeAddress)
+ }
+ if agentNodes[0] != "5.6.7.8" {
+ t.Errorf("Expected agent node address to be 5.6.7.8, got %s", nodes[1].Spec.NodeAddress)
+ }
+}
+
const testAccCMHAClusterConfig = `
resource "bigipnext_cm_ha_cluster" "cm_ha_2_nodes" {
nodes = [
{
- node_ip = "10.146.164.150"
+ node_ip = "10.146.164.150"
username = "admin",
password = "F5site02@123"
}
@@ -52,15 +262,59 @@ const testAccCMHAClusterUpdateConfig = `
resource "bigipnext_cm_ha_cluster" "cm_ha_2_nodes" {
nodes = [
{
- node_ip = "10.146.164.150"
+ node_ip = "10.146.164.150"
username = "admin",
password = "F5site02@123"
},
{
- node_ip = "10.146.165.89"
+ node_ip = "10.146.165.89"
username = "admin",
password = "F5site02@123"
}
]
}
`
+
+const testUnitCMHAClusterConfig = `
+resource "bigipnext_cm_ha_cluster" "cm_ha_2_nodes" {
+ nodes = [
+ {
+ node_ip = "10.146.164.150"
+ username = "admin",
+ password = "F5site02@123"
+ fingerprint = "c2b2472624cd7f3a053c4f6e0bd4b322"
+ },
+ {
+ node_ip = "10.146.165.89"
+ username = "admin",
+ password = "F5site02@123"
+ fingerprint = "c2b2472624cd7f3a053c4f6e0bd4b322"
+ }
+ ]
+}
+`
+
+const testUnitCMHAClusterUpdateConfig = `
+resource "bigipnext_cm_ha_cluster" "cm_ha_2_nodes" {
+ nodes = [
+ {
+ node_ip = "10.146.164.150"
+ username = "admin",
+ password = "F5site02@123"
+ fingerprint = "c2b2472624cd7f3a053c4f6e0bd4b322"
+ },
+ {
+ node_ip = "10.146.165.89"
+ username = "admin",
+ password = "F5site02@123"
+ fingerprint = "c2b2472624cd7f3a053c4f6e0bd4b322"
+ },
+ {
+ node_ip = "12.34.56.77"
+ username = "admin",
+ password = "F5site02@123"
+ fingerprint = "c2b2472624cd7f3a053c4f6e0bd4b322"
+ }
+ ]
+}
+`
diff --git a/internal/provider/cm_next_add_jwt_token_resource.go b/internal/provider/cm_next_add_jwt_token_resource.go
new file mode 100644
index 0000000..10a04c8
--- /dev/null
+++ b/internal/provider/cm_next_add_jwt_token_resource.go
@@ -0,0 +1,174 @@
+package provider
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/hashicorp/terraform-plugin-framework/path"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+ bigipnextsdk "gitswarm.f5net.com/terraform-providers/bigipnext"
+)
+
+var (
+ _ resource.Resource = &CMNextJwtTokenResource{}
+ _ resource.ResourceWithImportState = &CMNextJwtTokenResource{}
+)
+
+func NewCMNextJwtTokenResource() resource.Resource {
+ return &CMNextJwtTokenResource{}
+}
+
+type CMNextJwtTokenResource struct {
+ client *bigipnextsdk.BigipNextCM
+}
+
+type CMNextJwtTokenResourceModel struct {
+ TokenName types.String `tfsdk:"token_name"`
+ JwtToken types.String `tfsdk:"jwt_token"`
+ OrderType types.String `tfsdk:"order_type"`
+ SubscriptionExpiry types.String `tfsdk:"subscription_expiry"`
+ Id types.String `tfsdk:"id"`
+}
+
+func (r *CMNextJwtTokenResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_cm_add_jwt_token"
+}
+
+func (r *CMNextJwtTokenResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ MarkdownDescription: "Resource used for add/copy JWT Token on Central Manager",
+ Attributes: map[string]schema.Attribute{
+ "token_name": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Nickname to be used to add the JWT token on Central Manager",
+ },
+ "jwt_token": schema.StringAttribute{
+ Required: true,
+ Sensitive: true,
+ MarkdownDescription: "JWT token to be added on Central Manager",
+ },
+ "order_type": schema.StringAttribute{
+ Computed: true,
+ MarkdownDescription: "JWT token to be added on Central Manager",
+ },
+ "subscription_expiry": schema.StringAttribute{
+ Computed: true,
+ MarkdownDescription: "JWT token to be added on Central Manager",
+ },
+ "id": schema.StringAttribute{
+ Computed: true,
+ MarkdownDescription: "Unique Identifier for the resource",
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
+ },
+ },
+ }
+}
+
+func (r *CMNextJwtTokenResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+ r.client, resp.Diagnostics = toBigipNextCMProvider(req.ProviderData)
+}
+
+func (r *CMNextJwtTokenResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ var resCfg *CMNextJwtTokenResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
+ if resp.Diagnostics.HasError() { // coverage-ignore
+ return
+ }
+ tflog.Info(ctx, fmt.Sprintf("[CREATE] CMNextJwtTokenResource:%+v\n", resCfg.TokenName.ValueString()))
+
+ providerConfig := getCMNextJwtTokenConfig(ctx, resCfg)
+ respData, err := r.client.PostLicenseToken(providerConfig)
+ if err != nil { // coverage-ignore
+ resp.Diagnostics.AddError("Failed to Create Jwt token", fmt.Sprintf(", got error: %s", err))
+ return
+ }
+ tflog.Info(ctx, fmt.Sprintf("[CREATE] JWT token ID :%+v\n", string(respData)))
+
+ resCfg.Id = types.StringValue(string(respData))
+
+ tokenInfo, err := r.client.GetLicenseToken(string(respData))
+ if err != nil { // coverage-ignore
+ resp.Diagnostics.AddError("Failed to Get JWT Token Info", fmt.Sprintf(", got error: %s", err))
+ return
+ }
+ tflog.Info(ctx, fmt.Sprintf("JWT Token Info : %+v", tokenInfo))
+
+ r.NextJwtTokenResourceModeltoState(ctx, tokenInfo, resCfg)
+ resp.Diagnostics.Append(resp.State.Set(ctx, resCfg)...)
+}
+
+func (r *CMNextJwtTokenResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var stateCfg *CMNextJwtTokenResourceModel
+ resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
+ if resp.Diagnostics.HasError() { // coverage-ignore
+ return
+ }
+ id := stateCfg.Id.ValueString()
+ tflog.Info(ctx, fmt.Sprintf("JWT Token ID : %+v", id))
+
+ tokenInfo, err := r.client.GetLicenseToken(id)
+ if err != nil { // coverage-ignore
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Get JWT Token Info, got error: %s", err))
+ return
+ }
+ tflog.Info(ctx, fmt.Sprintf("JWT Token Info : %+v", tokenInfo))
+
+ r.NextJwtTokenResourceModeltoState(ctx, tokenInfo, stateCfg)
+
+ resp.Diagnostics.Append(resp.State.Set(ctx, &stateCfg)...)
+}
+
+func (r *CMNextJwtTokenResource) NextJwtTokenResourceModeltoState(ctx context.Context, respData interface{}, data *CMNextJwtTokenResourceModel) {
+ tflog.Debug(ctx, fmt.Sprintf("respData %+v", respData))
+ data.OrderType = types.StringValue(respData.(map[string]interface{})["orderType"].(string))
+ data.SubscriptionExpiry = types.StringValue(respData.(map[string]interface{})["subscriptionExpiry"].(string))
+ data.TokenName = types.StringValue(respData.(map[string]interface{})["nickName"].(string))
+}
+
+func (r *CMNextJwtTokenResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ var resCfg *CMNextJwtTokenResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
+
+ if resp.Diagnostics.HasError() { // coverage-ignore
+ return
+ }
+ tflog.Info(ctx, "[UPDATE] Updating JWT Tokens Not Supported!!!!")
+ resCfg.OrderType = types.StringValue(resCfg.OrderType.ValueString())
+ resCfg.SubscriptionExpiry = types.StringValue(resCfg.SubscriptionExpiry.ValueString())
+ resp.Diagnostics.Append(resp.State.Set(ctx, &resCfg)...)
+}
+
+func (r *CMNextJwtTokenResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ var stateCfg *CMNextJwtTokenResourceModel
+ if resp.Diagnostics.HasError() { // coverage-ignore
+ return
+ }
+ resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
+ id := stateCfg.Id.ValueString()
+
+ err := r.client.DeleteLicenseToken(id)
+ if err != nil { // coverage-ignore
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to Delete JWT Token, got error: %s", err))
+ return
+ }
+ stateCfg.Id = types.StringValue("")
+}
+
+func (r *CMNextJwtTokenResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+ resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
+
+func getCMNextJwtTokenConfig(ctx context.Context, data *CMNextJwtTokenResourceModel) *bigipnextsdk.JWTRequestDraft {
+ jwtRequest := &bigipnextsdk.JWTRequestDraft{}
+ tflog.Info(ctx, fmt.Sprintf("jwtRequest:%+v\n", jwtRequest))
+ jwtRequest.NickName = data.TokenName.ValueString()
+ jwtRequest.JWT = data.JwtToken.ValueString()
+ return jwtRequest
+}
diff --git a/internal/provider/cm_next_add_jwt_token_resource_test.go b/internal/provider/cm_next_add_jwt_token_resource_test.go
new file mode 100644
index 0000000..ff3e2f5
--- /dev/null
+++ b/internal/provider/cm_next_add_jwt_token_resource_test.go
@@ -0,0 +1,327 @@
+package provider
+
+import (
+ "fmt"
+ "net/http"
+ "os"
+ "regexp"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestUnitCMNextAddJwtTokenResourceTC1(t *testing.T) {
+ testAccPreUnitCheck(t)
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+ mux.HandleFunc("/api/v1/spaces/default/license/tokens", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "NewToken": {
+ "id": "94ff6fac-8920-492d-9545-9e837fe31a23",
+ "nickName": "paid_test_jwt",
+ "entitlement": "string",
+ "orderType": "string",
+ "orderSubType": "string",
+ "subscriptionExpiry": "string"
+ },
+ "DuplicatesTokenValue": {
+ "id": "94ff6fac-8920-492d-9545-9e837fe31a23",
+ "nickName": "paid_test_jwt",
+ "entitlement": "string",
+ "orderType": "string",
+ "orderSubType": "string",
+ "subscriptionExpiry": "string"
+ },
+ "DuplicatesTokenNickName": {
+ "id": "94ff6fac-8920-492d-9545-9e837fe31a23",
+ "nickName": "paid_test_jwt",
+ "entitlement": "string",
+ "orderType": "string",
+ "orderSubType": "string",
+ "subscriptionExpiry": "string"
+ },
+ "_links": {
+ "self": {
+ "href": "string"
+ }
+ },
+ "duplicateToken": {
+ "_links": {
+ "self": {
+ "href": "string"
+ }
+ }
+ },
+ "duplicateShortname": {
+ "_links": {
+ "self": {
+ "href": "string"
+ }
+ }
+ }
+ }`)
+ })
+ mux.HandleFunc("/api/v1/spaces/default/license/tokens/94ff6fac-8920-492d-9545-9e837fe31a23", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "id": "94ff6fac-8920-492d-9545-9e837fe31a23",
+ "nickName": "paid_test_jwt",
+ "entitlement": "string",
+ "orderType": "string",
+ "orderSubType": "string",
+ "subscriptionExpiry": "string"
+ }`)
+ })
+ defer teardown()
+ resource.Test(t, resource.TestCase{
+ // PreCheck: func() { testAccPreUnitCheck(t) },
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testUnitCMNextAddJwtTokenResourceTC1,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ {
+ Config: testUnitCMNextAddJwtTokenResourceTC2,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ },
+ })
+}
+
+func TestUnitCMNextAddJwtTokenResourceTC2(t *testing.T) {
+ testAccPreUnitCheck(t)
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+ mux.HandleFunc("/api/v1/spaces/default/license/tokens", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusBadRequest)
+ _, _ = fmt.Fprintf(w, `
+ {
+ "message": "description explaining the error cause in short",
+ "help": "help to recover from the error",
+ "code": "LICENSING-2245",
+ "status": 400,
+ "details": "inner details of the error"
+ }`)
+ })
+ mux.HandleFunc("/api/v1/spaces/default/license/tokens/94ff6fac-8920-492d-9545-9e837fe31a23", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "id": "94ff6fac-8920-492d-9545-9e837fe31a23",
+ "nickName": "paid_test_jwt",
+ "entitlement": "string",
+ "orderType": "string",
+ "orderSubType": "string",
+ "subscriptionExpiry": "string"
+ }`)
+ })
+ defer teardown()
+ resource.Test(t, resource.TestCase{
+ // PreCheck: func() { testAccPreUnitCheck(t) },
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testUnitCMNextAddJwtTokenResourceTC1,
+ ExpectError: regexp.MustCompile(`Failed to Create Jwt token`),
+ },
+ },
+ })
+}
+
+func TestUnitCMNextAddJwtTokenResourceTC3(t *testing.T) {
+ testAccPreUnitCheck(t)
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+ mux.HandleFunc("/api/v1/spaces/default/license/tokens", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "NewToken": {
+ "id": "94ff6fac-8920-492d-9545-9e837fe31a23",
+ "nickName": "paid_test_jwt",
+ "entitlement": "string",
+ "orderType": "string",
+ "orderSubType": "string",
+ "subscriptionExpiry": "string"
+ },
+ "DuplicatesTokenValue": {
+ "id": "94ff6fac-8920-492d-9545-9e837fe31a23",
+ "nickName": "paid_test_jwt",
+ "entitlement": "string",
+ "orderType": "string",
+ "orderSubType": "string",
+ "subscriptionExpiry": "string"
+ },
+ "DuplicatesTokenNickName": {
+ "id": "94ff6fac-8920-492d-9545-9e837fe31a23",
+ "nickName": "paid_test_jwt",
+ "entitlement": "string",
+ "orderType": "string",
+ "orderSubType": "string",
+ "subscriptionExpiry": "string"
+ },
+ "_links": {
+ "self": {
+ "href": "string"
+ }
+ },
+ "duplicateToken": {
+ "_links": {
+ "self": {
+ "href": "string"
+ }
+ }
+ },
+ "duplicateShortname": {
+ "_links": {
+ "self": {
+ "href": "string"
+ }
+ }
+ }
+ }`)
+ })
+ mux.HandleFunc("/api/v1/spaces/default/license/tokens/94ff6fac-8920-492d-9545-9e837fe31a23", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "id": "94ff6fac-8920-492d-9545-9e837fe31a23",
+ "nickName": "paid_test_jwt",
+ "entitlement": "string",
+ "orderType": "paid",
+ "orderSubType": "string",
+ "subscriptionExpiry": "string"
+ }`)
+ })
+ defer teardown()
+ resource.Test(t, resource.TestCase{
+ // PreCheck: func() { testAccPreUnitCheck(t) },
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testUnitCMNextAddJwtTokenResourceTC1,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ {
+ Config: testUnitCMNextAddJwtTokenResourceTC1Update,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ },
+ })
+}
+
+// {
+// "code": 400,
+// "error": {
+// "code": "LICENSING-0004",
+// "message": "LICENSING-0004: JWT is not verifiable: token contains an invalid number of segments",
+// "details": "",
+// "help": "please retry or contact admin"
+// }
+// }
+//
+// TC1: Test case when JWT token is not verifiable
+func TestAccCMNextAddJwtTokenResourceTC1(t *testing.T) {
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testUnitCMNextAddJwtTokenResourceTC1,
+ ExpectError: regexp.MustCompile(`Failed to Create Jwt token`),
+ },
+ },
+ })
+}
+
+// {"code":409,"error":{"DuplicatesTokenNickName":{"orderType":"","shortName":"","tokenId":"00000000-0000-0000-0000-000000000000"},"DuplicatesTokenValue":{"entitlement":"{\"compliance\":{\"digitalAssetComplianceStatus\":\"valid\",\"digitalAssetDaysRemainingInState\":0,\"digitalAssetExpiringSoon\":false,\"digitalAssetOutOfComplianceDate\":\"\",\"entitlementCheckStatus\":\"valid\",\"entitlementExpiryStatus\":\"valid\",\"telemetryStatus\":\"valid\",\"usageExceededStatus\":\"valid\"},\"documentType\":\"\",\"documentVersion\":\"\",\"digitalAsset\":{\"digitalAssetId\":\"\",\"digitalAssetName\":\"\",\"digitalAssetVersion\":\"\",\"telemetryId\":\"\"},\"entitlementMetadata\":{\"complianceEnforcements\":[\"entitlement\"],\"complianceStates\":{\"device-twin\":[\"in-grace-period\",\"in-enforcement-period\",\"non-functional\"],\"entitlement\":[\"in-grace-period\",\"in-enforcement-period\",\"non-functional\"],\"telemetry\":[\"in-grace-period\",\"in-enforcement-period\",\"non-functional\"],\"usage\":[\"in-grace-period\",\"in-enforcement-period\"]},\"enforcementBehavior\":\"visibility\",\"enforcementPeriodDays\":0,\"entitlementModel\":\"aggregated\",\"expiringSoonNotificationDays\":7,\"entitlementExpiryDate\":\"2024-12-07T00:00:00Z\",\"gracePeriodDays\":0,\"nonContactPeriodHours\":0,\"nonFunctionalPeriodDays\":14,\"orderSubType\":\"internal\",\"orderType\":\"paid\"},\"subscriptionMetadata\":{\"programName\":\"big_ip_next_internal\",\"programTypeDescription\":\"big_ip_next_internal\",\"subscriptionId\":\"A-S00019374\",\"subscriptionExpiryDate\":\"2024-12-07T00:00:00.000Z\",\"subscriptionNotifyDays\":\"\"},\"RepositoryCertificateMetadata\":{\"sslCertificate\":\"\",\"privateKey\":\"\"},\"entitledFeatures\":[{\"entitledFeatureId\":\"\",\"featureFlag\":\"UNKNOWN_set-bigip_ltm_module_8_bigip_vcpus\",\"featurePermitted\":0,\"featureRemain\":0,\"featureUnlimited\":true,\"featureUsed\":14,\"featureValueType\":\"integral\",\"uomCode\":\"\",\"uomTerm\":\"\",\"uomTermStart\":0},{\"entitledFeatureId\":\"\",\"featureFlag\":\"UNKNOWN_set-bigip_waf_module_8_bigip_vcpus\",\"featurePermitted\":0,\"featureRemain\":0,\"featureUnlimited\":true,\"featureUsed\":14,\"featureValueType\":\"integral\",\"uomCode\":\"\",\"uomTerm\":\"\",\"uomTermStart\":0},{\"entitledFeatureId\":\"\",\"featureFlag\":\"UNKNOWN_set-bigip_ltm_module_1_bigip_system\",\"featurePermitted\":0,\"featureRemain\":0,\"featureUnlimited\":true,\"featureUsed\":1,\"featureValueType\":\"integral\",\"uomCode\":\"\",\"uomTerm\":\"\",\"uomTermStart\":0},{\"entitledFeatureId\":\"\",\"featureFlag\":\"UNKNOWN_set-bigip_waf_module_1_bigip_system\",\"featurePermitted\":0,\"featureRemain\":0,\"featureUnlimited\":true,\"featureUsed\":1,\"featureValueType\":\"integral\",\"uomCode\":\"\",\"uomTerm\":\"\",\"uomTermStart\":0},{\"entitledFeatureId\":\"\",\"featureFlag\":\"UNKNOWN_set-bigip_waf_module_2_bigip_vcpus\",\"featurePermitted\":0,\"featureRemain\":0,\"featureUnlimited\":true,\"featureUsed\":2,\"featureValueType\":\"integral\",\"uomCode\":\"\",\"uomTerm\":\"\",\"uomTermStart\":0},{\"entitledFeatureId\":\"\",\"featureFlag\":\"UNKNOWN_set-bigip_ltm_module_2_bigip_vcpus\",\"featurePermitted\":0,\"featureRemain\":0,\"featureUnlimited\":true,\"featureUsed\":2,\"featureValueType\":\"integral\",\"uomCode\":\"\",\"uomTerm\":\"\",\"uomTermStart\":0}]}","orderSubType":"internal","orderType":"paid","shortName":"token2","tokenId":"f88665b2-2ad3-4110-a7be-e0ccdf8667ff"},"NewToken":{"orderType":"","shortName":"","tokenId":"00000000-0000-0000-0000-000000000000"}}
+// TC2: Test case when JWT token is already present
+func TestAccCMNextAddJwtTokenResourceTC2(t *testing.T) {
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testAccCMNextAddJwtTokenResourceTC2,
+ ExpectError: regexp.MustCompile(`Failed to Create Jwt token`),
+ },
+ },
+ })
+}
+
+// TC3: Test case when JWT token is not verifiable
+func TestAccCMNextAddJwtTokenResourceTC3(t *testing.T) {
+ os.Setenv("BIGIPNEXT_HOST", "10.145.64.3")
+ os.Setenv("BIGIPNEXT_USERNAME", "admin")
+ os.Setenv("BIGIPNEXT_PASSWORD", "F5site02@123")
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testAccCMNextAddJwtTokenResourceTC2,
+ // ExpectError: regexp.MustCompile(`Failed to Create Jwt token`),
+ },
+ },
+ })
+}
+
+const testUnitCMNextAddJwtTokenResourceTC1 = `
+resource "bigipnext_cm_add_jwt_token" "tokenadd" {
+ token_name = "paid_test_jwt"
+ jwt_token = "eyJhbG"
+ }
+`
+
+const testUnitCMNextAddJwtTokenResourceTC2 = `
+resource "bigipnext_cm_add_jwt_token" "tokenadd" {
+ token_name = "paid_test_jwt"
+ jwt_token = "eyJhbG"
+ }
+`
+
+const testUnitCMNextAddJwtTokenResourceTC1Update = `
+resource "bigipnext_cm_add_jwt_token" "tokenadd" {
+ token_name = "paid_test_jwt"
+ jwt_token = "eyJhbGC"
+ }
+`
+
+const testAccCMNextAddJwtTokenResourceTC2 = `
+resource "bigipnext_cm_add_jwt_token" "tokenadd2" {
+ token_name = "paid_test_jwt"
+ jwt_token = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InYxIiwiamt1IjoiaHR0cHM6Ly9wcm9kdWN0LmFwaXMuZjUuY29tL2VlL3YxL2tleXMvandrcyJ9.eyJzdWIiOiJGTkktZGM5MTFhYjctNDlhYi00ZWUzLTkwYjItNTNmNmVmOGY5ZTc0IiwiaWF0IjoxNzA1NjIyMDY5LCJpc3MiOiJGNSBJbmMuIiwiYXVkIjoidXJuOmY1OnRlZW0iLCJqdGkiOiJlYjIyZDhjMS1iNjVjLTExZWUtODQ1MC1mM2M0OTkzMmJmOTIiLCJmNV9vcmRlcl90eXBlIjoicGFpZCIsImY1X29yZGVyX3N1YnR5cGUiOiJpbnRlcm5hbCJ9.c6V5gAVGd-Pj62krRj8740bLq0_YyuRUvtKmat-oEJdiQn10GFbHNqBH8l3x0stcdE0UldrGszVQI3CmukDceRYi1XiTQpB69EubbOpx8Pe4qc6ht7kErmkDvsLlpy6ALYhdl8j2m5_npy3HvmoDnE2jjzWQkiQeFZjdxT4Gqc05LmRsO4_RnMOkvZFECfbRU6dEhtmP1es7L2FxJaJyJ8JEL2mz9kC8XtwaoW_jS_lxq_l5brDCnXJuFmLF882xyCReCT62FvIb4P4vzN1OQzYkRFVOJeodhHy2OdckgJC6yFlFBL0LmyA2lXUpy8mFtqxQuelmQZbD-wsxrNDzJ72CkIdg1fD6MLHQpmKQDIYEMaSFkz68nfQLsoIEOKVq6UPr0Yc-4YTsmqogaF_YN4lbUn5czmhHZgBtieitwhr4uKGJskj090kWPOQGAJae0GSUelPTk03v4vTP-efKVBb1Rj4INL1R6-la41HNJi5YXwUj1yU_gMaqzTD7G3et-fbVeMG0HuJfSENVAwzdcwmivBH-C6Iaq9g9B0BP0gC1HH_L6NSceOdSKWBYRnQZg67S3C9cGyDL8Sf29zcyNKDmjdyRnISxIy0sZZ3X3svt5QVlPS9xODl1ZztefeyfnDdgT1Rlw6bpj-UMhQSqMztclYvJXfvZOt4vQ97HYU8"
+ }
+`
diff --git a/internal/provider/cm_next_backup_restore.go b/internal/provider/cm_next_backup_restore.go
index 95a83f1..1ec1d99 100644
--- a/internal/provider/cm_next_backup_restore.go
+++ b/internal/provider/cm_next_backup_restore.go
@@ -128,20 +128,20 @@ func (r *NextCMBackupRestoreResource) Configure(ctx context.Context, req resourc
}
func (r *NextCMBackupRestoreResource) GetDeviceId(data *NextCMBackupRestoreResourceModel) (deviceId *string, err error) {
- if data.DeviceIp.ValueString() == "" && data.DeviceHostname.ValueString() == "" {
+ if data.DeviceIp.ValueString() == "" && data.DeviceHostname.ValueString() == "" { // coverage-ignore
return nil, fmt.Errorf("the 'device_ip' or 'device_hostname' parameter must be specified")
}
if data.DeviceIp.ValueString() == "" {
device := data.DeviceHostname.ValueString()
deviceId, err := r.client.GetDeviceIdByHostname(device)
- if err != nil {
+ if err != nil { // coverage-ignore
return nil, err
}
return deviceId, nil
} else {
device := data.DeviceIp.ValueString()
deviceId, err = r.client.GetDeviceIdByIp(device)
- if err != nil {
+ if err != nil { // coverage-ignore
return nil, err
}
return deviceId, nil
@@ -154,11 +154,11 @@ func (r *NextCMBackupRestoreResource) Create(ctx context.Context, req resource.C
// Read Terraform plan data into the model
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
deviceId, err := r.GetDeviceId(data)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to obtain device id, got error: %s", err))
return
}
@@ -167,7 +167,7 @@ func (r *NextCMBackupRestoreResource) Create(ctx context.Context, req resource.C
if data.Operation.ValueString() == "backup" {
mutex.Lock()
respData, err := r.client.BackupTenant(deviceId, config, int(data.Timeout.ValueInt64()))
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to create config backup, got error: %s", err))
return
}
@@ -178,7 +178,7 @@ func (r *NextCMBackupRestoreResource) Create(ctx context.Context, req resource.C
if data.Operation.ValueString() == "restore" {
mutex.Lock()
respData, err := r.client.RestoreTenant(deviceId, config, int(data.Timeout.ValueInt64()))
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to restore config backup, got error: %s", err))
return
}
@@ -190,7 +190,7 @@ func (r *NextCMBackupRestoreResource) Create(ctx context.Context, req resource.C
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
-func (r *NextCMBackupRestoreResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+func (r *NextCMBackupRestoreResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { // coverage-ignore
var data *NextCMBackupRestoreResourceModel
// Read Terraform plan data into the model
@@ -243,12 +243,12 @@ func (r *NextCMBackupRestoreResource) Delete(ctx context.Context, req resource.D
// Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
err := r.client.DeleteBackupFile(data.FileName.ValueStringPointer())
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to Delete backup file, got error: %s", err))
return
}
@@ -260,13 +260,13 @@ func (r *NextCMBackupRestoreResource) Read(ctx context.Context, req resource.Rea
// Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
//respByte, err := r.client.GetTenant(data.Name.ValueString())
respByte, err := r.client.GetBackupFile(data.FileName.ValueStringPointer())
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to find backup file, got error: %s", err))
return
}
@@ -276,7 +276,7 @@ func (r *NextCMBackupRestoreResource) Read(ctx context.Context, req resource.Rea
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
-func (r *NextCMBackupRestoreResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+func (r *NextCMBackupRestoreResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { // coverage-ignore
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}
@@ -298,7 +298,7 @@ func getCreateBackupRestoreConfig(ctx context.Context, req resource.CreateReques
return &config
}
-func getUpdateBackupRestoreConfig(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) *bigipnextsdk.BackupRestoreTenantRequest {
+func getUpdateBackupRestoreConfig(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) *bigipnextsdk.BackupRestoreTenantRequest { // coverage-ignore
var data *NextCMBackupRestoreResourceModel
// Read Terraform plan data into the model
diff --git a/internal/provider/cm_next_backup_restore_test.go b/internal/provider/cm_next_backup_restore_test.go
new file mode 100644
index 0000000..f0db921
--- /dev/null
+++ b/internal/provider/cm_next_backup_restore_test.go
@@ -0,0 +1,576 @@
+package provider
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+// backup with device Ip
+func TestUnitNextCMBackupCreateResourceTC1(t *testing.T) {
+ testAccPreUnitCheck(t)
+ // var getCount = 0
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+
+ // Get Device info by address
+ mux.HandleFunc("/api/device/v1/inventory", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, "%s", loadFixtureString("./fixtures/getDeviceIdByIp.json"))
+ })
+
+ // Post backup call
+ mux.HandleFunc("/api/device/v1/inventory/494975ee-5eba-420a-90a6-f3aeb75bbf5b/backup", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/backup-tasks/c41f1566-61f8-4be2-942a-9b01c687f81a"
+ }
+ },
+ "path": "/v1/backup-tasks/c41f1566-61f8-4be2-942a-9b01c687f81a"
+ }`)
+ })
+
+ // Check Status
+ mux.HandleFunc("/api/device/v1/backup-tasks/c41f1566-61f8-4be2-942a-9b01c687f81a", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/backup-tasks/c41f1566-61f8-4be2-942a-9b01c687f81a"
+ }
+ },
+ "completed": "2024-07-23T08:07:45.267699Z",
+ "created": "2024-07-23T08:07:24.079439Z",
+ "failure_reason": "",
+ "file_name": "test",
+ "file_path": "storage/backups",
+ "id": "c41f1566-61f8-4be2-942a-9b01c687f81a",
+ "instance_id": "494975ee-5eba-420a-90a6-f3aeb75bbf5b",
+ "instance_name": "big-ip-next",
+ "run_id": "",
+ "state": "backupDone",
+ "status": "completed"
+ }`)
+ })
+
+ //Get/Delete call
+ mux.HandleFunc("/api/device/v1/backups/test.tar.gz", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "DELETE" {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, ``)
+ } else {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/backups/test.tar.gz"
+ }
+ },
+ "file_date": "2024-07-23T10:49:22Z",
+ "file_name": "test.tar.gz",
+ "file_size": 1894032,
+ "instance_id": "",
+ "instance_name": ""
+ }`)
+ }
+ })
+
+ defer teardown()
+ resource.Test(t, resource.TestCase{
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testAccNextCMBackupByIpResourceConfig,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ },
+ })
+}
+
+// backup with device hostname
+func TestUnitNextCMBackupCreateResourceTC2(t *testing.T) {
+ testAccPreUnitCheck(t)
+ // var getCount = 0
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+
+ // Get Device info by hostname
+ mux.HandleFunc("/api/device/v1/inventory", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, "%s", loadFixtureString("./fixtures/getDeviceIdByHostname.json"))
+ })
+
+ // Post backup call
+ mux.HandleFunc("/api/device/v1/inventory/494975ee-5eba-420a-90a6-f3aeb75bbf5b/backup", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/backup-tasks/c41f1566-61f8-4be2-942a-9b01c687f81a"
+ }
+ },
+ "path": "/v1/backup-tasks/c41f1566-61f8-4be2-942a-9b01c687f81a"
+ }`)
+ })
+
+ // Check Status
+ mux.HandleFunc("/api/device/v1/backup-tasks/c41f1566-61f8-4be2-942a-9b01c687f81a", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/backup-tasks/c41f1566-61f8-4be2-942a-9b01c687f81a"
+ }
+ },
+ "completed": "2024-07-23T08:07:45.267699Z",
+ "created": "2024-07-23T08:07:24.079439Z",
+ "failure_reason": "",
+ "file_name": "test",
+ "file_path": "storage/backups",
+ "id": "c41f1566-61f8-4be2-942a-9b01c687f81a",
+ "instance_id": "494975ee-5eba-420a-90a6-f3aeb75bbf5b",
+ "instance_name": "big-ip-next",
+ "run_id": "",
+ "state": "backupDone",
+ "status": "completed"
+ }`)
+ })
+
+ //Get/Delete call
+ mux.HandleFunc("/api/device/v1/backups/test.tar.gz", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "DELETE" {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, ``)
+ } else {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/backups/test.tar.gz"
+ }
+ },
+ "file_date": "2024-07-23T10:49:22Z",
+ "file_name": "test.tar.gz",
+ "file_size": 1894032,
+ "instance_id": "",
+ "instance_name": ""
+ }`)
+ }
+ })
+
+ defer teardown()
+ resource.Test(t, resource.TestCase{
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testAccNextCMBackupByHostnameResourceConfig,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ },
+ })
+}
+
+// restore with device Ip
+func TestUnitNextCMBackupCreateResourceTC3(t *testing.T) {
+ testAccPreUnitCheck(t)
+ // var getCount = 0
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+
+ // Get Device info by address
+ mux.HandleFunc("/api/device/v1/inventory", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, "%s", loadFixtureString("./fixtures/getDeviceIdByIp.json"))
+ })
+
+ // Post restore call
+ mux.HandleFunc("/api/device/v1/inventory/494975ee-5eba-420a-90a6-f3aeb75bbf5b/restore", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/restore-tasks/016bba84-2abc-4acd-8acc-0239dbc2ec2d"
+ }
+ },
+ "path": "/v1/restore-tasks/016bba84-2abc-4acd-8acc-0239dbc2ec2d"
+ }`)
+ })
+
+ // Check Status
+ mux.HandleFunc("/api/device/v1/restore-tasks/016bba84-2abc-4acd-8acc-0239dbc2ec2d", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/restore-tasks/016bba84-2abc-4acd-8acc-0239dbc2ec2d"
+ }
+ },
+ "completed": "2024-07-23T13:32:01.982649Z",
+ "created": "2024-07-23T13:30:11.312178Z",
+ "failure_reason": "",
+ "file_name": "test.tar.gz",
+ "id": "016bba84-2abc-4acd-8acc-0239dbc2ec2d",
+ "instance_id": "494975ee-5eba-420a-90a6-f3aeb75bbf5b",
+ "instance_name": "big-ip-next",
+ "state": "restoreDone",
+ "status": "completed"
+ }`)
+ })
+
+ //Get/Delete call
+ mux.HandleFunc("/api/device/v1/backups/test.tar.gz", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "DELETE" {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, ``)
+ } else {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/backups/test.tar.gz"
+ }
+ },
+ "file_date": "2024-07-23T10:49:22Z",
+ "file_name": "test.tar.gz",
+ "file_size": 1894032,
+ "instance_id": "",
+ "instance_name": ""
+ }`)
+ }
+ })
+
+ defer teardown()
+ resource.Test(t, resource.TestCase{
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testAccNextCMRestoreByIpResourceConfig,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ },
+ })
+}
+
+// restore with device hostname
+func TestUnitNextCMBackupCreateResourceTC4(t *testing.T) {
+ testAccPreUnitCheck(t)
+ // var getCount = 0
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+
+ // // Get Device info by address
+ // mux.HandleFunc("/api/device/v1/inventory", func(w http.ResponseWriter, r *http.Request) {
+ // w.WriteHeader(http.StatusOK)
+ // _, _ = fmt.Fprintf(w, "%s", loadFixtureString("./fixtures/getDeviceIdByIp.json"))
+ // })
+
+ // Get Device info by hostname
+ mux.HandleFunc("/api/device/v1/inventory", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, "%s", loadFixtureString("./fixtures/getDeviceIdByHostname.json"))
+ })
+
+ // Post restore call
+ mux.HandleFunc("/api/device/v1/inventory/494975ee-5eba-420a-90a6-f3aeb75bbf5b/restore", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/restore-tasks/016bba84-2abc-4acd-8acc-0239dbc2ec2d"
+ }
+ },
+ "path": "/v1/restore-tasks/016bba84-2abc-4acd-8acc-0239dbc2ec2d"
+ }`)
+ })
+
+ // Check Status
+ mux.HandleFunc("/api/device/v1/restore-tasks/016bba84-2abc-4acd-8acc-0239dbc2ec2d", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/restore-tasks/016bba84-2abc-4acd-8acc-0239dbc2ec2d"
+ }
+ },
+ "completed": "2024-07-23T13:32:01.982649Z",
+ "created": "2024-07-23T13:30:11.312178Z",
+ "failure_reason": "",
+ "file_name": "test.tar.gz",
+ "id": "016bba84-2abc-4acd-8acc-0239dbc2ec2d",
+ "instance_id": "494975ee-5eba-420a-90a6-f3aeb75bbf5b",
+ "instance_name": "big-ip-next",
+ "state": "restoreDone",
+ "status": "completed"
+ }`)
+ })
+
+ //Get/Delete call
+ mux.HandleFunc("/api/device/v1/backups/test.tar.gz", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "DELETE" {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, ``)
+ } else {
+ // if getCount < 2 {
+ // w.WriteHeader(http.StatusAccepted)
+ // _, _ = fmt.Fprintf(w, "")
+ // } else {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/backups/test.tar.gz"
+ }
+ },
+ "file_date": "2024-07-23T10:49:22Z",
+ "file_name": "test.tar.gz",
+ "file_size": 1894032,
+ "instance_id": "",
+ "instance_name": ""
+ }`)
+ // }
+
+ // getCount++
+
+ }
+ })
+
+ defer teardown()
+ resource.Test(t, resource.TestCase{
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testAccNextCMRestoreByHostnameResourceConfig,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ // {
+ // Config: testAccNextCMWafPolicyImportUpdateResourceConfig,
+ // Check: resource.ComposeAggregateTestCheckFunc(),
+ // },
+ },
+ })
+}
+
+// update backup with device Ip
+func TestUnitNextCMBackupUpdateResourceTC1(t *testing.T) {
+ testAccPreUnitCheck(t)
+ // var getCount = 0
+ var postCount = 0
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+
+ // Get Device info by address
+ mux.HandleFunc("/api/device/v1/inventory", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, "%s", loadFixtureString("./fixtures/getDeviceIdByIp.json"))
+ })
+
+ // Post backup call
+ mux.HandleFunc("/api/device/v1/inventory/494975ee-5eba-420a-90a6-f3aeb75bbf5b/backup", func(w http.ResponseWriter, r *http.Request) {
+ t.Log("Post call")
+ if postCount == 0 {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/backup-tasks/c41f1566-61f8-4be2-942a-9b01c687f81a"
+ }
+ },
+ "path": "/v1/backup-tasks/c41f1566-61f8-4be2-942a-9b01c687f81a"
+ }`)
+ } else {
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/backup-tasks/0d1d9fb0-74d5-4924-ab11-85db571d26af"
+ }
+ },
+ "path": "/v1/backup-tasks/0d1d9fb0-74d5-4924-ab11-85db571d26af"
+ }`)
+ }
+ postCount++
+ })
+
+ // Check Status
+ mux.HandleFunc("/api/device/v1/backup-tasks/c41f1566-61f8-4be2-942a-9b01c687f81a", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/backup-tasks/c41f1566-61f8-4be2-942a-9b01c687f81a"
+ }
+ },
+ "completed": "2024-07-23T08:07:45.267699Z",
+ "created": "2024-07-23T08:07:24.079439Z",
+ "failure_reason": "",
+ "file_name": "test",
+ "file_path": "storage/backups",
+ "id": "c41f1566-61f8-4be2-942a-9b01c687f81a",
+ "instance_id": "494975ee-5eba-420a-90a6-f3aeb75bbf5b",
+ "instance_name": "big-ip-next",
+ "run_id": "",
+ "state": "backupDone",
+ "status": "completed"
+ }`)
+ })
+
+ mux.HandleFunc("/api/device/v1/backup-tasks/0d1d9fb0-74d5-4924-ab11-85db571d26af", func(w http.ResponseWriter, r *http.Request) {
+ t.Log("Checking the status of task 6af")
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/backup-tasks/0d1d9fb0-74d5-4924-ab11-85db571d26af"
+ }
+ },
+ "completed": "2024-07-23T08:07:45.267699Z",
+ "created": "2024-07-23T08:07:24.079439Z",
+ "failure_reason": "",
+ "file_name": "test",
+ "file_path": "storage/backups",
+ "id": "0d1d9fb0-74d5-4924-ab11-85db571d26af",
+ "instance_id": "494975ee-5eba-420a-90a6-f3aeb75bbf5b",
+ "instance_name": "big-ip-next",
+ "run_id": "",
+ "state": "backupDone",
+ "status": "completed"
+ }`)
+ })
+
+ //Get/Delete call
+ mux.HandleFunc("/api/device/v1/backups/test.tar.gz", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "DELETE" {
+ t.Log("Inside the Delete Condition")
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, ``)
+ } else {
+ t.Log("Inside the Get Condition")
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/v1/backups/test.tar.gz"
+ }
+ },
+ "file_date": "2024-07-23T10:49:22Z",
+ "file_name": "test.tar.gz",
+ "file_size": 1894032,
+ "instance_id": "",
+ "instance_name": ""
+ }`)
+ }
+ })
+
+ defer teardown()
+ resource.Test(t, resource.TestCase{
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testAccNextCMBackupByIpResourceConfig,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ // {
+ // Config: testAccNextCMBackupByIpUpdateResourceConfig,
+ // Check: resource.ComposeAggregateTestCheckFunc(),
+ // },
+ },
+ })
+}
+
+const testAccNextCMBackupByIpResourceConfig = `
+resource "bigipnext_cm_backup_restore" "sample" {
+ backup_password = "F5site02@123"
+ operation = "backup"
+ file_name = "test.tar.gz"
+ device_ip = "10.218.132.39"
+ }
+`
+
+// const testAccNextCMBackupByIpUpdateResourceConfig = `
+// resource "bigipnext_cm_backup_restore" "sample" {
+// backup_password = "F5site02@1234"
+// operation = "backup"
+// file_name = "test.tar.gz"
+// device_ip = "10.218.132.39"
+// }
+// `
+
+const testAccNextCMBackupByHostnameResourceConfig = `
+resource "bigipnext_cm_backup_restore" "sample" {
+ backup_password = "F5site02@123"
+ operation = "backup"
+ file_name = "test.tar.gz"
+ device_hostname = "big-ip-next"
+ }
+`
+
+const testAccNextCMRestoreByIpResourceConfig = `
+resource "bigipnext_cm_backup_restore" "sample" {
+ backup_password = "F5site02@123"
+ operation = "restore"
+ file_name = "test.tar.gz"
+ device_ip = "10.218.132.39"
+ }
+`
+
+const testAccNextCMRestoreByHostnameResourceConfig = `
+resource "bigipnext_cm_backup_restore" "sample" {
+ backup_password = "F5site02@123"
+ operation = "restore"
+ file_name = "test.tar.gz"
+ device_hostname = "big-ip-next"
+ }
+`
diff --git a/internal/provider/cm_next_ha_resource.go b/internal/provider/cm_next_ha_resource.go
index 416164e..8d24e2f 100644
--- a/internal/provider/cm_next_ha_resource.go
+++ b/internal/provider/cm_next_ha_resource.go
@@ -133,17 +133,17 @@ func (r *NextHAResource) Configure(ctx context.Context, req resource.ConfigureRe
func (r *NextHAResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var resCfg *NextHAResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
// get activeNodeID by IP
activeNodeID, err := r.client.GetDeviceIdByIp(resCfg.ActiveNodeIp.ValueString())
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Read Active Device Info, got error: %s", err))
return
}
standbyNodeID, err := r.client.GetDeviceIdByIp(resCfg.StandbyNodeIp.ValueString())
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Read Standby Device Info, got error: %s", err))
return
}
@@ -152,7 +152,7 @@ func (r *NextHAResource) Create(ctx context.Context, req resource.CreateRequest,
haDeployConfig := haConfig(ctx, *activeNodeID, *standbyNodeID, resCfg)
tflog.Info(ctx, fmt.Sprintf("[CREATE] Deploy HA :%+v\n", haDeployConfig.ClusterName))
respData, err := r.client.PostDeviceHA(*activeNodeID, haDeployConfig, int(resCfg.Timeout.ValueInt64()))
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Deploy Instance, got error: %s", err))
return
}
@@ -165,14 +165,14 @@ func (r *NextHAResource) Create(ctx context.Context, req resource.CreateRequest,
func (r *NextHAResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var stateCfg *NextHAResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
id := stateCfg.Id.ValueString()
tflog.Info(ctx, fmt.Sprintf("Reading Device info for : %+v", id))
haNodeInfo, err := r.client.GetDeviceInfoByIp(id)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Read HA Device Info, got error: %s", err))
return
}
@@ -180,7 +180,7 @@ func (r *NextHAResource) Read(ctx context.Context, req resource.ReadRequest, res
// map[_links:map[self:map[href:/v1/inventory?filter=address+eq+%2710.146.168.20%27/23254958-db28-4d10-b42f-ff58bc16228d]] address:10.146.168.20 certificate_validated:2023-11-27T09:58:27.605586Z certificate_validation_error:tls: failed to verify certificate: x509: cannot validate certificate for 10.146.194.141 because it doesn't contain any IP SANs certificate_validity:false hostname:raviecosyshydha id:23254958-db28-4d10-b42f-ff58bc16228d mode:HA platform_name:VMware platform_type:VE port:5443 version:20.0.1-2.139.10+0.0.136]
// check if mode is HA from above response map
- if haNodeInfo.(map[string]interface{})["mode"] != "HA" {
+ if haNodeInfo.(map[string]interface{})["mode"] != "HA" { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Read HA Device Info, got error: %s", err))
return
}
@@ -200,7 +200,7 @@ func (r *NextHAResource) Update(ctx context.Context, req resource.UpdateRequest,
func (r *NextHAResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var stateCfg *NextHAResourceModel
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
@@ -208,7 +208,7 @@ func (r *NextHAResource) Delete(ctx context.Context, req resource.DeleteRequest,
tflog.Info(ctx, fmt.Sprintf("[DELETE] Deleting Instance from CM : %s", id))
deviceID := stateCfg.DeviceId.ValueString()
err := r.client.DeleteDevice(deviceID)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to Delete Instance, got error: %s", err))
return
}
diff --git a/internal/provider/cm_next_ha_resource_test.go b/internal/provider/cm_next_ha_resource_test.go
new file mode 100644
index 0000000..275367c
--- /dev/null
+++ b/internal/provider/cm_next_ha_resource_test.go
@@ -0,0 +1,143 @@
+package provider
+
+import (
+ "fmt"
+ "net/http"
+ "net/url"
+ "os"
+ "strings"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestUnitCMNextHA(t *testing.T) {
+ testAccPreUnitCheck(t)
+ defer teardown()
+
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+
+ mux.HandleFunc("/api/device/v1/inventory", func(w http.ResponseWriter, r *http.Request) {
+ query, _ := url.Parse(r.URL.String())
+ filterQuery := query.Query().Get("filter")
+
+ queryStr := strings.Split(filterQuery, " ")
+
+ if strings.Contains(queryStr[2], "10.218.33.22") {
+ fmt.Fprint(w, `
+ {
+ "_embedded": {
+ "devices": [
+ {
+ "id": "1"
+ }
+ ]
+ },
+ "count": 1
+ }
+ `)
+ }
+
+ if strings.Contains(queryStr[2], "10.218.33.23") {
+ fmt.Fprint(w, `
+ {
+ "_embedded": {
+ "devices": [{
+ "id": "2"
+ }]
+ },
+ "count": 1
+ }
+ `)
+ }
+
+ if strings.Contains(queryStr[2], "10.218.46.27") {
+ fmt.Fprint(w, `
+ {
+ "_embedded": {
+ "devices": [{
+ "id": "2",
+ "mode": "HA"
+ }]
+ },
+ "count": 1
+ }
+ `)
+ }
+ })
+
+ mux.HandleFunc("/api/device/v1/inventory/1/ha", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == http.MethodPost {
+ fmt.Fprint(w, `
+ {
+ "_links":{
+ "self":{
+ "href":"/v1/ha-creation-tasks/task-id-1"
+ }
+ },
+ "path":"/v1/ha-creation-tasks/task-id-1"
+ }
+ `)
+ }
+ })
+
+ mux.HandleFunc("/api/device/v1/ha-creation-tasks/task-id-1", func(w http.ResponseWriter, r *http.Request) {
+ getTaskResp, _ := os.ReadFile("fixtures/cm_next_ha_task_status.json")
+ fmt.Fprint(w, string(getTaskResp))
+ })
+
+ mux.HandleFunc("/api/v1/spaces/default/instances/06aea4ed-7425-4db3-a728-2574929885d9", func(w http.ResponseWriter, r *http.Request) {
+
+ fmt.Fprint(w, `
+ {
+ "_links":{
+ "self":{
+ "href":"/v1/deletion-tasks/delete-ha-task"
+ }
+ },
+ "path":"/v1/deletion-tasks/delete-ha-task"
+ }
+ `)
+ })
+
+ mux.HandleFunc("/api/device/v1/deletion-tasks/delete-ha-task", func(w http.ResponseWriter, r *http.Request) {
+ deleteTaskStatus, _ := os.ReadFile("fixtures/cm_next_ha_delete_task_status.json")
+ fmt.Fprint(w, string(deleteTaskStatus))
+ })
+
+ resource.Test(t, resource.TestCase{
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: testUnitCMNextHAConfig,
+ },
+ },
+ })
+}
+
+const testUnitCMNextHAConfig = `
+resource "bigipnext_cm_next_ha" "test" {
+ ha_name = "testnextha"
+ ha_ip = "10.218.46.27"
+ active_node_ip = "10.218.33.22"
+ standby_node_ip = "10.218.33.23"
+ control_plane_vlan = "ha-cp-vlan"
+ control_plane_vlan_tag = 101
+ data_plane_vlan = "ha-dp-vlan"
+ data_plane_vlan_tag = 102
+ active_node_control_plane_ip = "10.211.44.0/8"
+ standby_node_control_plane_ip = "10.211.31.0/8"
+ active_node_data_plane_ip = "10.211.98.0/8"
+ standby_node_data_plane_ip = "10.211.76.0/8"
+}
+`
diff --git a/internal/provider/cm_next_license_activate_resource.go b/internal/provider/cm_next_license_activate_resource.go
new file mode 100644
index 0000000..c27fe85
--- /dev/null
+++ b/internal/provider/cm_next_license_activate_resource.go
@@ -0,0 +1,185 @@
+package provider
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "github.com/hashicorp/terraform-plugin-framework/path"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+ bigipnextsdk "gitswarm.f5net.com/terraform-providers/bigipnext"
+)
+
+var (
+ _ resource.Resource = &CMNextLicenseActivateResource{}
+ _ resource.ResourceWithImportState = &CMNextLicenseActivateResource{}
+)
+
+func NewCMNextLicenseActivateResource() resource.Resource {
+ return &CMNextLicenseActivateResource{}
+}
+
+type CMNextLicenseActivateResource struct {
+ client *bigipnextsdk.BigipNextCM
+}
+
+type CMNextLicenseActivateResourceModel struct {
+ Instances []InstanceActivateModel `tfsdk:"instances"`
+ Id types.String `tfsdk:"id"`
+}
+
+type InstanceActivateModel struct {
+ InstanceAddress types.String `tfsdk:"instance_address"`
+ JwtId types.String `tfsdk:"jwt_id"`
+}
+
+func (r *CMNextLicenseActivateResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_cm_activate_instance_license"
+}
+
+func (r *CMNextLicenseActivateResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ MarkdownDescription: "Resource used for Activate/Deactivate License for Instances on Central Manager Using JWT Token",
+ Attributes: map[string]schema.Attribute{
+ "instances": schema.ListNestedAttribute{
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "instance_address": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "IP Address of the instance to activate the license",
+ },
+ "jwt_id": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "JWT ID to be used to activate the license",
+ },
+ },
+ },
+ Required: true,
+ MarkdownDescription: "List of instances to activate the license",
+ },
+ "id": schema.StringAttribute{
+ Computed: true,
+ MarkdownDescription: "Unique Identifier for the resource",
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
+ },
+ },
+ }
+}
+
+func (r *CMNextLicenseActivateResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+ r.client, resp.Diagnostics = toBigipNextCMProvider(req.ProviderData)
+}
+
+func (r *CMNextLicenseActivateResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ var resCfg *CMNextLicenseActivateResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
+ if resp.Diagnostics.HasError() { // coverage-ignore
+ return
+ }
+ tflog.Info(ctx, "[CREATE] Activate License for Instances on Central Manager Using JWT Token")
+ providerConfig := getCMNextLicenseActivateConfig(ctx, r.client, resCfg)
+ respData, err := r.client.PostActivateLicense(providerConfig)
+ if err != nil { // coverage-ignore
+ resp.Diagnostics.AddError("Failed to Activate license", fmt.Sprintf("%+v", err))
+ return
+ }
+ tflog.Info(ctx, fmt.Sprintf("[CREATE] License Task IDs :%+v\n", respData))
+ var deviceID []string
+ for _, value := range providerConfig {
+ deviceID = append(deviceID, value.DigitalAssetId)
+ }
+ tflog.Info(ctx, fmt.Sprintf("Device ID : %+v", deviceID))
+ // join all keys into a single string
+ deviceString := strings.Join(deviceID, ",")
+ resCfg.Id = types.StringValue(deviceString)
+ resp.Diagnostics.Append(resp.State.Set(ctx, resCfg)...)
+}
+
+func (r *CMNextLicenseActivateResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var stateCfg *CMNextLicenseActivateResourceModel
+ resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
+ if resp.Diagnostics.HasError() { // coverage-ignore
+ return
+ }
+ id := stateCfg.Id.ValueString()
+ tflog.Info(ctx, fmt.Sprintf("Instance IDs : %+v", id))
+ deviceIDs := strings.Split(id, ",")
+ deactivateReq := &bigipnextsdk.LicenseDeactivaeReq{}
+ digitalAssetID := deviceIDs
+ deactivateReq.DigitalAssetIds = digitalAssetID
+
+ licenseInfo, err := r.client.PostLicenseInfo(deactivateReq)
+ if err != nil { // coverage-ignore
+ resp.Diagnostics.AddError("Failed to get License Info", fmt.Sprintf("%+v", err))
+ return
+ }
+ // get the license info by loop over map
+ var licenseStatus []string
+ for _, val := range licenseInfo.(map[string]interface{}) {
+ licenseStatus = append(licenseStatus, val.(map[string]interface{})["deviceLicenseStatus"].(map[string]interface{})["licenseStatus"].(string))
+ tflog.Info(ctx, fmt.Sprintf("License Info : %+v", val.(map[string]interface{})["deviceLicenseStatus"].(map[string]interface{})["licenseStatus"]))
+ }
+ tflog.Info(ctx, fmt.Sprintf("Instance License Info : %+v", licenseStatus))
+ // diags := resp.State.SetAttribute(ctx, path.Root("license_status"), licenseStatus)
+ // resp.Diagnostics.Append(diags...)
+ resp.Diagnostics.Append(resp.State.Set(ctx, &stateCfg)...)
+}
+
+// func (r *CMNextLicenseActivateResource) NextJwtTokenResourceModeltoState(ctx context.Context, respData interface{}, data *CMNextLicenseActivateResourceModel) {
+// tflog.Debug(ctx, fmt.Sprintf("respData %+v", respData))
+// }
+
+func (r *CMNextLicenseActivateResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ // var resCfg *CMNextLicenseActivateResourceModel
+ // resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
+
+ // if resp.Diagnostics.HasError() {
+ // return
+ // }
+ tflog.Info(ctx, "[UPDATE] Update Call on Activating License Not Supported!!!!")
+ // resp.Diagnostics.Append(resp.State.Set(ctx, &resCfg)...)
+}
+
+func (r *CMNextLicenseActivateResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ var stateCfg *CMNextLicenseActivateResourceModel
+ if resp.Diagnostics.HasError() { // coverage-ignore
+ return
+ }
+ resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
+ id := stateCfg.Id.ValueString()
+ deviceIDs := strings.Split(id, ",")
+ deactivateReq := &bigipnextsdk.LicenseDeactivaeReq{}
+ digitalAssetID := deviceIDs
+ deactivateReq.DigitalAssetIds = digitalAssetID
+ res, err := r.client.PostDeactivateLicense(deactivateReq)
+ if err != nil { // coverage-ignore
+ resp.Diagnostics.AddError("Failed to deactivate license", fmt.Sprintf("%+v", err))
+ return
+ }
+ tflog.Info(ctx, fmt.Sprintf("Deactivate License Response : %+v", res))
+ stateCfg.Id = types.StringValue("")
+}
+
+func (r *CMNextLicenseActivateResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { // coverage-ignore
+ resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
+
+func getCMNextLicenseActivateConfig(ctx context.Context, p *bigipnextsdk.BigipNextCM, data *CMNextLicenseActivateResourceModel) []*bigipnextsdk.LicenseReq {
+ listLicenseRequest := []*bigipnextsdk.LicenseReq{}
+ for _, val := range data.Instances {
+ licenseRequest := &bigipnextsdk.LicenseReq{}
+ licenseRequest.JwtId = val.JwtId.ValueString()
+ deviceID, _ := p.GetDeviceIdByIp(val.InstanceAddress.ValueString())
+ licenseRequest.DigitalAssetId = *deviceID
+ tflog.Info(ctx, fmt.Sprintf("licenseRequest:%+v", licenseRequest))
+ listLicenseRequest = append(listLicenseRequest, licenseRequest)
+ }
+ return listLicenseRequest
+}
diff --git a/internal/provider/cm_next_license_activate_resource_test.go b/internal/provider/cm_next_license_activate_resource_test.go
new file mode 100644
index 0000000..1cae543
--- /dev/null
+++ b/internal/provider/cm_next_license_activate_resource_test.go
@@ -0,0 +1,147 @@
+package provider
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestUnitCMNextLicenseActivateResourceTC1(t *testing.T) {
+ testAccPreUnitCheck(t)
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+ mux.HandleFunc("/api/device/v1/inventory", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{"_embedded":{"devices":[{"_links":{"self":{"href":"/v1/inventory?filter=hostname+eq+demovm01-ravi-r10800/6cdf38ed-a258-4d92-a64d-972238b27400'"}},"address":"10.144.10.182","certificate_validated":"2024-07-16T17:24:12.848618Z","certificate_validity":false,"hostname":"demovm01-ravi-r10800","id":"6cdf38ed-a258-4d92-a64d-972238b27400","mode":"STANDALONE","platform_name":"R10K","platform_type":"APPLIANCE","port":5443,"short_id":"bcpED8hJ","version":"20.2.1-2.430.2+0.0.48"}]},"_links":{"self":{"href":"/v1/inventory?filter=hostname+eq+demovm01-ravi-r10800"}},"count":1,"total":1}`)
+ })
+ mux.HandleFunc("/api/v1/spaces/default/instances/license/activate", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{"422b0cec-03b9-4499-a26e-c88f57869637": {
+ "_links": {
+ "self": {
+ "href": "/license-task/41e49d68-d146-4e16-b286-7b57731fe14d"
+ }
+ },
+ "accepted": true,
+ "deviceId": "422b0cec-03b9-4499-a26e-c88f57869637",
+ "reason": "",
+ "taskId": "41e49d68-d146-4e16-b286-7b57731fe14d"}}`)
+ })
+ mux.HandleFunc("/api/v1/spaces/default/license/tasks", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "41e49d68-d146-4e16-b286-7b57731fe14d": {
+ "_links": {
+ "self": {
+ "href": "/license-task/41e49d68-d146-4e16-b286-7b57731fe14d"
+ }
+ },
+ "taskExecutionStatus": {
+ "created": "2024-06-27T15:59:25.928845Z",
+ "failureReason": "",
+ "status": "completed",
+ "subStatus": "TERMINATE_ACK_VERIFICATION_COMPLETE",
+ "taskType": "activate"
+ }}}`)
+ })
+ mux.HandleFunc("/api/v1/spaces/default/instances/license/license-info", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{"3c815d06-0fe4-407d-b5b4-a380f550565d":{"_links":{"self":{"href":"/license/3c815d06-0fe4-407d-b5b4-a380f550565d/status"}},"deviceLicenseStatus":{"enabledFeatures":"[{\"entitledFeatureId\":\"\",\"featureFlag\":\"bigip_ltm_module\",\"featurePermitted\":1,\"featureRemain\":0,\"featureUnlimited\":false,\"featureUsed\":0,\"featureValueType\":\"boolean\",\"uomCode\":\"\",\"uomTerm\":\"\",\"uomTermStart\":0},{\"entitledFeatureId\":\"\",\"featureFlag\":\"bigip_waf_module\",\"featurePermitted\":1,\"featureRemain\":0,\"featureUnlimited\":false,\"featureUsed\":0,\"featureValueType\":\"boolean\",\"uomCode\":\"\",\"uomTerm\":\"\",\"uomTermStart\":0}]","expiryDate":"2024-12-07T00:00:00Z","licenseStatus":"Active","licenseSubStatus":"ACK_VERIFICATION_COMPLETE","licenseToken":{"_links":{"self":{"href":"/token/dd50dae9-a9a7-49f0-ac30-5d6d44efbedb"}},"tokenId":"dd50dae9-a9a7-49f0-ac30-5d6d44efbedb","tokenName":"ravitoken"},"subscriptionSubType":"internal","subscriptionType":"paid"}}}`)
+ })
+ mux.HandleFunc("/api/v1/spaces/default/instances/license/deactivate", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "3c815d06-0fe4-407d-b5b4-a380f550565d": {
+ "accepted": true,
+ "reason": "failed to create task",
+ "taskId": "d290f1ee-6c54-4b01-90e6-d701748f0982",
+ "deviceId": "3c815d06-0fe4-407d-b5b4-a380f550565d",
+ "_links": {
+ "self": {
+ "href": "/license-task/a01eeeaa-7cb1-4ce1-9d7e-6ea20e7693bb"
+ }}}}`)
+ })
+ defer teardown()
+ resource.Test(t, resource.TestCase{
+ // PreCheck: func() { testAccPreUnitCheck(t) },
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testUnitCMNextLicenseActivateResourceTC1,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ {
+ Config: testUnitCMNextLicenseActivateResourceTC2,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ },
+ })
+}
+
+// TC1: Test case when JWT token is not verifiable
+func TestAccCMNextLicenseActivateResourceTC1(t *testing.T) {
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testAccCMNextLicenseActivateResourceTC1,
+ // ExpectError: regexp.MustCompile(`Failed to Create Jwt token`),
+ },
+ },
+ })
+}
+
+const testUnitCMNextLicenseActivateResourceTC1 = `
+resource "bigipnext_cm_activate_instance_license" "tokenadd" {
+ instances = [{
+ instance_address = "10.10.10.10"
+ jwt_id="eyJhbGciOi"
+ }]
+}
+`
+
+const testUnitCMNextLicenseActivateResourceTC2 = `
+resource "bigipnext_cm_activate_instance_license" "tokenadd" {
+ instances = [{
+ instance_address = "10.10.10.10"
+ jwt_id="eyJhbGciOi"
+ }]
+}
+`
+
+// jwtID := "8a3dc22e-dd51-4a5c-bb3a-cb239b904326"
+
+const testAccCMNextLicenseActivateResourceTC1 = `
+resource "bigipnext_cm_add_jwt_token" "tokenadd2" {
+ token_name = "ravitoken"
+ jwt_token = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InYxIiwiamt1IjoiaHR0cHM6Ly9wcm9kdWN0LmFwaXMuZjUuY29tL2VlL3YxL2tleXMvandrcyJ9.eyJzdWIiOiJGTkktZGM5MTFhYjctNDlhYi00ZWUzLTkwYjItNTNmNmVmOGY5ZTc0IiwiaWF0IjoxNzA1NjIyMDY5LCJpc3MiOiJGNSBJbmMuIiwiYXVkIjoidXJuOmY1OnRlZW0iLCJqdGkiOiJlYjIyZDhjMS1iNjVjLTExZWUtODQ1MC1mM2M0OTkzMmJmOTIiLCJmNV9vcmRlcl90eXBlIjoicGFpZCIsImY1X29yZGVyX3N1YnR5cGUiOiJpbnRlcm5hbCJ9.c6V5gAVGd-Pj62krRj8740bLq0_YyuRUvtKmat-oEJdiQn10GFbHNqBH8l3x0stcdE0UldrGszVQI3CmukDceRYi1XiTQpB69EubbOpx8Pe4qc6ht7kErmkDvsLlpy6ALYhdl8j2m5_npy3HvmoDnE2jjzWQkiQeFZjdxT4Gqc05LmRsO4_RnMOkvZFECfbRU6dEhtmP1es7L2FxJaJyJ8JEL2mz9kC8XtwaoW_jS_lxq_l5brDCnXJuFmLF882xyCReCT62FvIb4P4vzN1OQzYkRFVOJeodhHy2OdckgJC6yFlFBL0LmyA2lXUpy8mFtqxQuelmQZbD-wsxrNDzJ72CkIdg1fD6MLHQpmKQDIYEMaSFkz68nfQLsoIEOKVq6UPr0Yc-4YTsmqogaF_YN4lbUn5czmhHZgBtieitwhr4uKGJskj090kWPOQGAJae0GSUelPTk03v4vTP-efKVBb1Rj4INL1R6-la41HNJi5YXwUj1yU_gMaqzTD7G3et-fbVeMG0HuJfSENVAwzdcwmivBH-C6Iaq9g9B0BP0gC1HH_L6NSceOdSKWBYRnQZg67S3C9cGyDL8Sf29zcyNKDmjdyRnISxIy0sZZ3X3svt5QVlPS9xODl1ZztefeyfnDdgT1Rlw6bpj-UMhQSqMztclYvJXfvZOt4vQ97HYU8"
+}
+
+resource "bigipnext_cm_activate_instance_license" "tokenadd" {
+ instances = [{
+ instance_address = "10.144.10.181"
+ jwt_id = bigipnext_cm_add_jwt_token.tokenadd2.id
+ }]
+}
+`
+
+// const testAccCMNextLicenseActivateResourceTC2 = `
+// resource "bigipnext_cm_add_jwt_token" "tokenadd2" {
+// token_name = "paid_test_jwt"
+// jwt_token = "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InYxIiwiamt1IjoiaHR0cHM6Ly9wcm9kdWN0LmFwaXMuZjUuY29tL2VlL3YxL2tleXMvandrcyJ9.eyJzdWIiOiJGTkktZGM5MTFhYjctNDlhYi00ZWUzLTkwYjItNTNmNmVmOGY5ZTc0IiwiaWF0IjoxNzA1NjIyMDY5LCJpc3MiOiJGNSBJbmMuIiwiYXVkIjoidXJuOmY1OnRlZW0iLCJqdGkiOiJlYjIyZDhjMS1iNjVjLTExZWUtODQ1MC1mM2M0OTkzMmJmOTIiLCJmNV9vcmRlcl90eXBlIjoicGFpZCIsImY1X29yZGVyX3N1YnR5cGUiOiJpbnRlcm5hbCJ9.c6V5gAVGd-Pj62krRj8740bLq0_YyuRUvtKmat-oEJdiQn10GFbHNqBH8l3x0stcdE0UldrGszVQI3CmukDceRYi1XiTQpB69EubbOpx8Pe4qc6ht7kErmkDvsLlpy6ALYhdl8j2m5_npy3HvmoDnE2jjzWQkiQeFZjdxT4Gqc05LmRsO4_RnMOkvZFECfbRU6dEhtmP1es7L2FxJaJyJ8JEL2mz9kC8XtwaoW_jS_lxq_l5brDCnXJuFmLF882xyCReCT62FvIb4P4vzN1OQzYkRFVOJeodhHy2OdckgJC6yFlFBL0LmyA2lXUpy8mFtqxQuelmQZbD-wsxrNDzJ72CkIdg1fD6MLHQpmKQDIYEMaSFkz68nfQLsoIEOKVq6UPr0Yc-4YTsmqogaF_YN4lbUn5czmhHZgBtieitwhr4uKGJskj090kWPOQGAJae0GSUelPTk03v4vTP-efKVBb1Rj4INL1R6-la41HNJi5YXwUj1yU_gMaqzTD7G3et-fbVeMG0HuJfSENVAwzdcwmivBH-C6Iaq9g9B0BP0gC1HH_L6NSceOdSKWBYRnQZg67S3C9cGyDL8Sf29zcyNKDmjdyRnISxIy0sZZ3X3svt5QVlPS9xODl1ZztefeyfnDdgT1Rlw6bpj-UMhQSqMztclYvJXfvZOt4vQ97HYU8"
+// }
+// `
diff --git a/internal/provider/cm_waf_policy_import_resource.go b/internal/provider/cm_waf_policy_import_resource.go
index 8fad343..c47cac7 100644
--- a/internal/provider/cm_waf_policy_import_resource.go
+++ b/internal/provider/cm_waf_policy_import_resource.go
@@ -105,14 +105,14 @@ func (r *NextCMWAFPolicyImportResource) Create(ctx context.Context, req resource
var resCfg *NextCMWAFPolicyImportResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
reqDraft := getCMWAFPolicyImportConfig(ctx, resCfg)
tflog.Info(ctx, fmt.Sprintf("[CREATE] CM WAF Policy Import config : %+v\n", reqDraft))
id, err := r.client.PolicyImport(reqDraft)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Error", fmt.Sprintf("Failed to Import WAF Policy, got error: %s", err))
return
}
@@ -124,13 +124,13 @@ func (r *NextCMWAFPolicyImportResource) Create(ctx context.Context, req resource
func (r *NextCMWAFPolicyImportResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var stateCfg *NextCMWAFPolicyImportResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
id := stateCfg.Id.ValueString()
tflog.Info(ctx, fmt.Sprintf("[READ] Reading WAF Policy : %s", id))
wafData, err := r.client.GetWAFPolicyDetails(id)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Error", fmt.Sprintf("Failed to Read WAF Policy, got error: %s", err))
return
}
@@ -142,7 +142,7 @@ func (r *NextCMWAFPolicyImportResource) Update(ctx context.Context, req resource
var resCfg *NextCMWAFPolicyImportResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
tflog.Info(ctx, fmt.Sprintf("[UPDATE] Updating WAF Policy : %s", resCfg.Name.ValueString()))
@@ -155,7 +155,7 @@ func (r *NextCMWAFPolicyImportResource) Update(ctx context.Context, req resource
tflog.Info(ctx, fmt.Sprintf("[UPDATE] CM WAF Policy Import config : %+v\n", reqDraft))
reqDraft.Override = "true"
id, err := r.client.PolicyImport(reqDraft)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Error", fmt.Sprintf("Failed to Import WAF Policy, got error: %s", err))
return
}
@@ -167,7 +167,7 @@ func (r *NextCMWAFPolicyImportResource) Update(ctx context.Context, req resource
func (r *NextCMWAFPolicyImportResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var stateCfg *NextCMWAFPolicyImportResourceModel
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
@@ -176,7 +176,7 @@ func (r *NextCMWAFPolicyImportResource) Delete(ctx context.Context, req resource
tflog.Info(ctx, fmt.Sprintf("[DELETE] Deleting WAF Policy : %s", id))
err := r.client.DeleteWAFPolicy(id)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to Delete WAF Policy, got error: %s", err))
return
}
@@ -201,8 +201,14 @@ func getCMWAFPolicyImportConfig(ctx context.Context, data *NextCMWAFPolicyImport
func (r *NextCMWAFPolicyImportResource) WafPolicyModeltoState(ctx context.Context, respData interface{}, data *NextCMWAFPolicyImportResourceModel) {
tflog.Info(ctx, fmt.Sprintf("WafPolicyModeltoState \t name: %+v", respData.(map[string]interface{})["name"]))
data.Name = types.StringValue(respData.(map[string]interface{})["name"].(string))
- description, ok := respData.(map[string]interface{})["description"]
+ declaration, ok := respData.(map[string]interface{})["declaration"]
if ok {
- data.Description = types.StringValue(description.(string))
+ policy, ok := declaration.(map[string]interface{})["policy"]
+ if ok {
+ description, ok := policy.(map[string]interface{})["description"]
+ if ok {
+ data.Description = types.StringValue(description.(string))
+ }
+ }
}
}
diff --git a/internal/provider/cm_waf_policy_import_resource_test.go b/internal/provider/cm_waf_policy_import_resource_test.go
new file mode 100644
index 0000000..5c131c9
--- /dev/null
+++ b/internal/provider/cm_waf_policy_import_resource_test.go
@@ -0,0 +1,155 @@
+package provider
+
+import (
+ "fmt"
+ "net/http"
+ "os"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccNextCMWafPolicyImportCreateTC1Resource(t *testing.T) {
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testAccNextCMWafPolicyImportResourceConfig,
+ Check: resource.ComposeAggregateTestCheckFunc(
+ resource.TestCheckResourceAttr("bigipnext_cm_waf_policy_import.sample", "name", "new_waf_policy"),
+ resource.TestCheckResourceAttr("bigipnext_cm_waf_policy_import.sample", "description", "new_waf_policy desc"),
+ ),
+ },
+ },
+ })
+}
+
+func TestAccNextCMWafPolicyImportCreateTC2Resource(t *testing.T) {
+ resource.Test(t, resource.TestCase{
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testAccNextCMWafPolicyImportResourceConfig,
+ Check: resource.ComposeAggregateTestCheckFunc(
+ resource.TestCheckResourceAttr("bigipnext_cm_waf_policy_import.sample", "name", "new_waf_policy"),
+ resource.TestCheckResourceAttr("bigipnext_cm_waf_policy_import.sample", "description", "new_waf_policy desc"),
+ ),
+ },
+ {
+ Config: testAccNextCMWafPolicyImportUpdateResourceConfig,
+ Check: resource.ComposeAggregateTestCheckFunc(
+ resource.TestCheckResourceAttr("bigipnext_cm_waf_policy_import.sample", "name", "new_waf_policy"),
+ resource.TestCheckResourceAttr("bigipnext_cm_waf_policy_import.sample", "description", "new_waf_policy desc updated"),
+ ),
+ },
+ },
+ })
+}
+
+func TestUnitNextCMWafPolicyImportCreateResourceTC1(t *testing.T) {
+ testAccPreUnitCheck(t)
+ var getCount = 0
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+
+ // Post call
+ mux.HandleFunc("/api/waf/v1/tasks/policy-import", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/api/waf/v1/tasks/policy-import/1a4453fe-b37a-4212-a813-a3d2f789dad1"
+ }
+ },
+ "path": "/v1/tasks/policy-import/1a4453fe-b37a-4212-a813-a3d2f789dad1"
+ }`)
+ })
+
+ // Check Status
+ mux.HandleFunc("/api/waf/v1/tasks/policy-import/1a4453fe-b37a-4212-a813-a3d2f789dad1", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "_links": {
+ "self": {
+ "href": "/api/waf/v1/tasks/policy-import/1a4453fe-b37a-4212-a813-a3d2f789dad1"
+ }
+ },
+ "completed": "2024-07-17T11:59:25.7393Z",
+ "created": "2024-07-17T11:59:21.058179Z",
+ "failure_reason": "",
+ "id": "1a4453fe-b37a-4212-a813-a3d2f789dad1",
+ "policy_id": "1a4453fe-b37a-4212-a813-a3d2f789dad1",
+ "policy_name": "new_waf_policy",
+ "state": "updatingTaskDataTable",
+ "status": "completed",
+ "warnings": []
+ }`)
+ })
+
+ // Get/Delete call
+ mux.HandleFunc("/api/v1/spaces/default/security/waf-policies/1a4453fe-b37a-4212-a813-a3d2f789dad1", func(w http.ResponseWriter, r *http.Request) {
+ if r.Method == "DELETE" {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, ``)
+ } else {
+ if getCount < 2 {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, "%s", loadFixtureString("./fixtures/getWaf.json"))
+ } else {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, "%s", loadFixtureString("./fixtures/getWafUpdated.json"))
+ }
+
+ getCount++
+
+ }
+ })
+
+ defer teardown()
+ resource.Test(t, resource.TestCase{
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testAccNextCMWafPolicyImportResourceConfig,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ {
+ Config: testAccNextCMWafPolicyImportUpdateResourceConfig,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ },
+ })
+}
+
+var dir, _ = os.Getwd()
+
+var testAccNextCMWafPolicyImportResourceConfig = `
+resource "bigipnext_cm_waf_policy_import" "sample" {
+ name = "new_waf_policy"
+ description = "new_waf_policy desc"
+ file_path = "` + dir + `/../../configs/testwaf.json"
+ file_md5 = md5(file("` + dir + `/../../configs/testwaf.json"))
+ }`
+
+var testAccNextCMWafPolicyImportUpdateResourceConfig = `
+resource "bigipnext_cm_waf_policy_import" "sample" {
+ name = "new_waf_policy"
+ description = "new_waf_policy desc updated"
+ file_path = "` + dir + `/../../configs/testwaf.json"
+ file_md5 = md5(file("` + dir + `/../../configs/testwaf.json"))
+ }
+`
diff --git a/internal/provider/cm_waf_policy_resource.go b/internal/provider/cm_waf_policy_resource.go
index 1c665a9..2af5448 100644
--- a/internal/provider/cm_waf_policy_resource.go
+++ b/internal/provider/cm_waf_policy_resource.go
@@ -192,7 +192,7 @@ func (r *NextCMWAFPolicyResource) Create(ctx context.Context, req resource.Creat
var resCfg *NextCMWAFPolicyResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
tflog.Info(ctx, fmt.Sprintf("[CREATE] NextCMWAFPolicyResource:%+v\n", resCfg))
@@ -200,7 +200,7 @@ func (r *NextCMWAFPolicyResource) Create(ctx context.Context, req resource.Creat
tflog.Info(ctx, fmt.Sprintf("[CREATE] WAF Policy config :%+v\n", reqDraft))
id, err := r.client.PostWAFPolicy("POST", reqDraft)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("WAF Policy Error", fmt.Sprintf("Failed to Create WAF Policy, got error: %s", err))
return
}
@@ -249,13 +249,13 @@ func (r *NextCMWAFPolicyResource) Create(ctx context.Context, req resource.Creat
func (r *NextCMWAFPolicyResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var stateCfg *NextCMWAFPolicyResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
id := stateCfg.Id.ValueString()
tflog.Info(ctx, fmt.Sprintf("[READ] Reading WAF Policy : %s", id))
wafData, err := r.client.GetWAFPolicyDetails(id)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Error", fmt.Sprintf("Failed to Read WAF Policy, got error: %s", err))
return
}
@@ -268,7 +268,7 @@ func (r *NextCMWAFPolicyResource) Update(ctx context.Context, req resource.Updat
var resCfg *NextCMWAFPolicyResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
tflog.Info(ctx, fmt.Sprintf("[UPDATE] Updating WAF Policy : %s", resCfg.Name.ValueString()))
@@ -280,7 +280,7 @@ func (r *NextCMWAFPolicyResource) Update(ctx context.Context, req resource.Updat
tflog.Info(ctx, fmt.Sprintf("[UPDATE] :%+v\n", reqDraft))
id, err := r.client.PostWAFPolicy("PUT", reqDraft)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Update WAF Policy, got error: %s", err))
return
}
@@ -294,7 +294,7 @@ func (r *NextCMWAFPolicyResource) Update(ctx context.Context, req resource.Updat
func (r *NextCMWAFPolicyResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var stateCfg *NextCMWAFPolicyResourceModel
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
@@ -303,7 +303,7 @@ func (r *NextCMWAFPolicyResource) Delete(ctx context.Context, req resource.Delet
tflog.Info(ctx, fmt.Sprintf("[DELETE] Deleting WAF Policy : %s", id))
err := r.client.DeleteWAFPolicy(id)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to Delete WAF Policy, got error: %s", err))
return
}
@@ -311,7 +311,7 @@ func (r *NextCMWAFPolicyResource) Delete(ctx context.Context, req resource.Delet
stateCfg.Id = types.StringValue("")
}
-func (r *NextCMWAFPolicyResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+func (r *NextCMWAFPolicyResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { // coverage-ignore
// resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}
@@ -337,7 +337,7 @@ func getCMWAFPolicyRequestDraft(ctx context.Context, data *NextCMWAFPolicyResour
botdefenseModel.Enabled = types.BoolValue(true)
if !data.BotDefense.IsNull() && !data.BotDefense.IsUnknown() {
diag := data.BotDefense.As(ctx, &botdefenseModel, basetypes.ObjectAsOptions{})
- if diag.HasError() {
+ if diag.HasError() { // coverage-ignore
tflog.Error(ctx, fmt.Sprintf("[getCMWAFPolicyRequestDraft] diag Error: %+v", diag.Errors()))
}
}
@@ -347,7 +347,7 @@ func getCMWAFPolicyRequestDraft(ctx context.Context, data *NextCMWAFPolicyResour
ipintelligenceModel.Enabled = types.BoolValue(true)
if !data.IpIntelligence.IsNull() && !data.IpIntelligence.IsUnknown() {
diag := data.IpIntelligence.As(ctx, &ipintelligenceModel, basetypes.ObjectAsOptions{})
- if diag.HasError() {
+ if diag.HasError() { // coverage-ignore
tflog.Error(ctx, fmt.Sprintf("[getCMWAFPolicyRequestDraft] diag Error: %+v", diag.Errors()))
}
}
@@ -357,7 +357,7 @@ func getCMWAFPolicyRequestDraft(ctx context.Context, data *NextCMWAFPolicyResour
dosprotectionModel.Enabled = types.BoolValue(false)
if !data.DosProtection.IsNull() && !data.DosProtection.IsUnknown() {
diag := data.DosProtection.As(ctx, &dosprotectionModel, basetypes.ObjectAsOptions{})
- if diag.HasError() {
+ if diag.HasError() { // coverage-ignore
tflog.Error(ctx, fmt.Sprintf("[getCMWAFPolicyRequestDraft] diag Error: %+v", diag.Errors()))
}
}
@@ -367,7 +367,7 @@ func getCMWAFPolicyRequestDraft(ctx context.Context, data *NextCMWAFPolicyResour
blockingsettingdModel.Enabled = types.BoolValue(true)
if !data.BlockingSettings.IsNull() && !data.BlockingSettings.IsUnknown() {
diag := data.BlockingSettings.As(ctx, &blockingsettingdModel, basetypes.ObjectAsOptions{})
- if diag.HasError() {
+ if diag.HasError() { // coverage-ignore
tflog.Error(ctx, fmt.Sprintf("[getCMWAFPolicyRequestDraft] diag Error: %+v", diag.Errors()))
}
}
@@ -398,7 +398,14 @@ func (r *NextCMWAFPolicyResource) WafPolicyModeltoState(ctx context.Context, res
if ok {
data.Description = types.StringValue(description.(string))
}
- data.Tags, _ = types.ListValueFrom(ctx, types.StringType, respData.(map[string]interface{})["tags"])
+ tags := respData.(map[string]interface{})["tags"]
+ if tags != nil {
+ if _, ok := tags.([]interface{}); ok {
+ data.Tags, _ = types.ListValueFrom(ctx, types.StringType, tags)
+ }
+ } else {
+ data.Tags = types.ListNull(types.StringType)
+ }
data.EnforecementMode = types.StringValue(respData.(map[string]interface{})["enforcement_mode"].(string))
data.ApplicationLanguage = types.StringValue(respData.(map[string]interface{})["application_language"].(string))
data.Id = types.StringValue(respData.(map[string]interface{})["id"].(string))
diff --git a/internal/provider/cm_waf_report_resource.go b/internal/provider/cm_waf_report_resource.go
index 3385d85..d2085d6 100644
--- a/internal/provider/cm_waf_report_resource.go
+++ b/internal/provider/cm_waf_report_resource.go
@@ -4,6 +4,8 @@ import (
"context"
"encoding/json"
"fmt"
+ "regexp"
+
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
@@ -13,7 +15,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
bigipnextsdk "gitswarm.f5net.com/terraform-providers/bigipnext"
- "regexp"
)
var (
@@ -160,7 +161,7 @@ func (r *NextCMWAFReportResource) Create(ctx context.Context, req resource.Creat
var resCfg *NextCMWAFReportResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
tflog.Info(ctx, fmt.Sprintf("[CREATE] NextCMWAFReportResource:%+v\n", resCfg.Name.ValueString()))
@@ -171,7 +172,7 @@ func (r *NextCMWAFReportResource) Create(ctx context.Context, req resource.Creat
tflog.Info(ctx, fmt.Sprintf("[CREATE] :%+v\n", reqDraft))
id, created_by, user_defined, err := r.client.PostWAFReport("POST", reqDraft)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("WAF Security Report Error", fmt.Sprintf("Failed to Create WAF Security Report, got error: %s", err))
return
}
@@ -187,13 +188,13 @@ func (r *NextCMWAFReportResource) Create(ctx context.Context, req resource.Creat
func (r *NextCMWAFReportResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var stateCfg *NextCMWAFReportResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
id := stateCfg.Id.ValueString()
tflog.Info(ctx, fmt.Sprintf("[READ] Reading WAF Security Report : %s", id))
wafData, err := r.client.GetWAFReportDetails(id)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Error", fmt.Sprintf("Failed to Read WAF Security Report, got error: %s", err))
return
}
@@ -206,7 +207,7 @@ func (r *NextCMWAFReportResource) Update(ctx context.Context, req resource.Updat
var resCfg *NextCMWAFReportResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
tflog.Info(ctx, fmt.Sprintf("[UPDATE] Updating WAF Security Report: %s", resCfg.Name.ValueString()))
@@ -218,7 +219,7 @@ func (r *NextCMWAFReportResource) Update(ctx context.Context, req resource.Updat
tflog.Info(ctx, fmt.Sprintf("[UPDATE] :%+v\n", reqDraft))
id, created_by, user_defined, err := r.client.PostWAFReport("PUT", reqDraft)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Update WAF Security Report, got error: %s", err))
return
}
@@ -234,7 +235,7 @@ func (r *NextCMWAFReportResource) Update(ctx context.Context, req resource.Updat
func (r *NextCMWAFReportResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var stateCfg *NextCMWAFReportResourceModel
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
@@ -243,7 +244,7 @@ func (r *NextCMWAFReportResource) Delete(ctx context.Context, req resource.Delet
tflog.Info(ctx, fmt.Sprintf("[DELETE] Deleting WAF Security Report : %s", id))
err := r.client.DeleteWAFReport(id)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to Delete WAF Security Report, got error: %s", err))
return
}
@@ -251,7 +252,7 @@ func (r *NextCMWAFReportResource) Delete(ctx context.Context, req resource.Delet
stateCfg.Id = types.StringValue("")
}
-func (r *NextCMWAFReportResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+func (r *NextCMWAFReportResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { // coverage-ignore
// resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}
diff --git a/internal/provider/device_inventory_data_source.go b/internal/provider/device_inventory_data_source.go
index 6da7e3c..fe33a17 100644
--- a/internal/provider/device_inventory_data_source.go
+++ b/internal/provider/device_inventory_data_source.go
@@ -65,12 +65,12 @@ func (d *DeviceInventorySource) Read(ctx context.Context, req datasource.ReadReq
// Read Terraform configuration data into the model
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
deviceInventory, err := d.client.GetDeviceInventory()
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read Device inventory, got error: %s", err))
return
}
diff --git a/internal/provider/device_inventory_data_source_test.go b/internal/provider/device_inventory_data_source_test.go
new file mode 100644
index 0000000..c2aff58
--- /dev/null
+++ b/internal/provider/device_inventory_data_source_test.go
@@ -0,0 +1,53 @@
+package provider
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestUnitNextCMDeviceInventoryDatasourceTC1(t *testing.T) {
+ testAccPreUnitCheck(t)
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+ mux.HandleFunc("/api/device/v1/inventory", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{"_embedded":{"devices":[{"_links":{"self":{"href":"/v1/inventory?filter=hostname+eq+demovm01-ravi-r10800/6cdf38ed-a258-4d92-a64d-972238b27400'"}},"address":"10.144.10.182","certificate_validated":"2024-07-16T17:24:12.848618Z","certificate_validity":false,"hostname":"demovm01-ravi-r10800","id":"6cdf38ed-a258-4d92-a64d-972238b27400","mode":"STANDALONE","platform_name":"R10K","platform_type":"APPLIANCE","port":5443,"short_id":"bcpED8hJ","version":"20.2.1-2.430.2+0.0.48"}]},"_links":{"self":{"href":"/v1/inventory?filter=hostname+eq+demovm01-ravi-r10800"}},"count":1,"total":1}`)
+ })
+ // mux.HandleFunc("/api/v1/spaces/default/providers/f5os/f05d420e-781b-409e-a17a-3c321371b3ea", func(w http.ResponseWriter, r *http.Request) {
+ // w.WriteHeader(http.StatusOK)
+ // count++
+ // t.Logf("\n#####################count: %d\n", count)
+ // if count >= 4 {
+ // _, _ = fmt.Fprintf(w, `{"_links":{"self":{"href":"/api/v1/spaces/default/providers/f5os/f05d420e-781b-409e-a17a-3c321371b3ea"}},"connection":{"authentication":{"type":"basic","username":"admin"},"host":"10.14.10.14:8888"},"id":"f05d420e-781b-409e-a17a-3c321371b3ea","name":"tfnext-cm-rseries01","type":"RSERIES"}`)
+ // } else {
+ // _, _ = fmt.Fprintf(w, `{"_links":{"self":{"href":"/api/v1/spaces/default/providers/f5os/f05d420e-781b-409e-a17a-3c321371b3ea"}},"connection":{"authentication":{"type":"basic","username":"admin"},"host":"10.14.10.14:443"},"id":"f05d420e-781b-409e-a17a-3c321371b3ea","name":"tfnext-cm-rseries01","type":"RSERIES"}`)
+ // }
+ // })
+ defer teardown()
+ resource.Test(t, resource.TestCase{
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testAccNextCMDeviceInventoryDarasourceTC1Config,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ },
+ })
+}
+
+const testAccNextCMDeviceInventoryDarasourceTC1Config = `
+data "bigipnext_cm_device_inventory" "test" {}
+`
diff --git a/internal/provider/device_provider_resource.go b/internal/provider/device_provider_resource.go
index 43b549b..3623b5c 100644
--- a/internal/provider/device_provider_resource.go
+++ b/internal/provider/device_provider_resource.go
@@ -14,8 +14,6 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
bigipnextsdk "gitswarm.f5net.com/terraform-providers/bigipnext"
- // "strings"
- // "sync"
)
var (
@@ -90,7 +88,7 @@ func (r *NextCMDeviceProviderResource) Configure(ctx context.Context, req resour
func (r *NextCMDeviceProviderResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var resCfg *NextCMDeviceProviderResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
tflog.Info(ctx, fmt.Sprintf("[CREATE] NextCMDeviceProviderResource:%+v\n", resCfg.Name.ValueString()))
@@ -100,7 +98,7 @@ func (r *NextCMDeviceProviderResource) Create(ctx context.Context, req resource.
tflog.Info(ctx, fmt.Sprintf("[CREATE] Device Provider config:%+v\n", providerConfig))
respData, err := r.client.PostDeviceProvider(providerConfig)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Adding Provider failed with: %s", err))
return
}
@@ -116,14 +114,14 @@ func (r *NextCMDeviceProviderResource) Create(ctx context.Context, req resource.
func (r *NextCMDeviceProviderResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var stateCfg *NextCMDeviceProviderResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
id := stateCfg.Id.ValueString()
tflog.Info(ctx, fmt.Sprintf("Reading Device Provider : %+v", stateCfg.Name.ValueString()))
deviceProvider, err := r.client.GetDeviceProvider(id, stateCfg.Type.ValueString())
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Read Device Provider, got error: %s", err))
return
}
@@ -144,7 +142,7 @@ func (r *NextCMDeviceProviderResource) Update(ctx context.Context, req resource.
var resCfg *NextCMDeviceProviderResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
tflog.Info(ctx, fmt.Sprintf("[UPDATE] Updating Device Provider: %s", resCfg.Name.ValueString()))
@@ -154,7 +152,7 @@ func (r *NextCMDeviceProviderResource) Update(ctx context.Context, req resource.
respData, err := r.client.UpdateDeviceProvider(resCfg.Id.ValueString(), providerConfig)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Update Device provider, got error: %s", err))
return
}
@@ -165,7 +163,7 @@ func (r *NextCMDeviceProviderResource) Update(ctx context.Context, req resource.
func (r *NextCMDeviceProviderResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var stateCfg *NextCMDeviceProviderResourceModel
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
@@ -173,14 +171,14 @@ func (r *NextCMDeviceProviderResource) Delete(ctx context.Context, req resource.
tflog.Info(ctx, fmt.Sprintf("[DELETE] Deleting Device Provider : %s", id))
_, err := r.client.DeleteDeviceProvider(id, stateCfg.Type.ValueString())
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to Delete Device Provider, got error: %s", err))
return
}
stateCfg.Id = types.StringValue("")
}
-func (r *NextCMDeviceProviderResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+func (r *NextCMDeviceProviderResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { // coverage-ignore
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}
diff --git a/internal/provider/device_provider_resource_test.go b/internal/provider/device_provider_resource_test.go
index c313691..e17cd81 100644
--- a/internal/provider/device_provider_resource_test.go
+++ b/internal/provider/device_provider_resource_test.go
@@ -1,11 +1,65 @@
package provider
import (
+ "fmt"
+ "net/http"
"testing"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)
+// {\"name\":\"tfnext-cm-vpshere01\",\"type\":\"VSPHERE\",\"connection\":{\"host\":\"mbip-70-vcenter.pdsea.f5net.com\",\"authentication\":{\"type\":\"basic\",\"username\":\"r.chinthalapalli@f5.com\",\"password\":\"TrisRav@2024\"}}}
+
+// {"_links":{"self":{"href":"/api/v1/spaces/default/providers/vsphere/9527cb70-182e-4185-a2f8-b8e6d898d379"}},"connection":{"authentication":{"type":"basic","username":"r.chinthalapalli@f5.com"},"host":"mbip-70-vcenter.pdsea.f5net.com"},"id":"9527cb70-182e-4185-a2f8-b8e6d898d379","name":"tfnext-cm-vpshere01","type":"VSPHERE"}
+
+// {"_links":{"self":{"href":"/api/v1/spaces/default/providers/vsphere/9527cb70-182e-4185-a2f8-b8e6d898d379"}},"connection":{"authentication":{"type":"basic","username":"r.chinthalapalli@f5.com"},"host":"mbip-70-vcenter.pdsea.f5net.com"},"id":"9527cb70-182e-4185-a2f8-b8e6d898d379","name":"tfnext-cm-vpshere01","type":"VSPHERE"}
+
+func TestUnitNextCMDeviceProviderResourceTC1(t *testing.T) {
+ testAccPreUnitCheck(t)
+ count := 0
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+ mux.HandleFunc("/api/v1/spaces/default/providers/f5os", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{"_links":{"self":{"href":"/api/v1/spaces/default/providers/f5os/f05d420e-781b-409e-a17a-3c321371b3ea"}},"connection":{"authentication":{"type":"basic","username":"admin"},"host":"10.14.10.14:443"},"id":"f05d420e-781b-409e-a17a-3c321371b3ea","name":"tfnext-cm-rseries01","type":"RSERIES"}`)
+ })
+ mux.HandleFunc("/api/v1/spaces/default/providers/f5os/f05d420e-781b-409e-a17a-3c321371b3ea", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ count++
+ t.Logf("\n#####################count: %d\n", count)
+ if count >= 4 {
+ _, _ = fmt.Fprintf(w, `{"_links":{"self":{"href":"/api/v1/spaces/default/providers/f5os/f05d420e-781b-409e-a17a-3c321371b3ea"}},"connection":{"authentication":{"type":"basic","username":"admin"},"host":"10.14.10.14:8888"},"id":"f05d420e-781b-409e-a17a-3c321371b3ea","name":"tfnext-cm-rseries01","type":"RSERIES"}`)
+ } else {
+ _, _ = fmt.Fprintf(w, `{"_links":{"self":{"href":"/api/v1/spaces/default/providers/f5os/f05d420e-781b-409e-a17a-3c321371b3ea"}},"connection":{"authentication":{"type":"basic","username":"admin"},"host":"10.14.10.14:443"},"id":"f05d420e-781b-409e-a17a-3c321371b3ea","name":"tfnext-cm-rseries01","type":"RSERIES"}`)
+ }
+ })
+ defer teardown()
+ resource.Test(t, resource.TestCase{
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testAccNextCMDeviceProviderResourceTC1Config,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ {
+ Config: testAccNextCMDeviceProviderResourceTC1UpdateConfig,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ ExpectNonEmptyPlan: false,
+ },
+ },
+ })
+}
+
func TestAccNextCMDeviceProviderResourceTC1(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
@@ -44,10 +98,19 @@ func TestAccNextCMDeviceProviderResourceTC2(t *testing.T) {
const testAccNextCMDeviceProviderResourceTC1Config = `
resource "bigipnext_cm_provider" "rseries" {
- name = "testrseriesprovvm01"
- address = "10.14.1.80:443"
+ name = "tfnext-cm-rseries01"
+ address = "10.14.10.14:443"
+ type = "RSERIES"
+ username = "admin"
+ password = "xxxxxxxx"
+}
+`
+const testAccNextCMDeviceProviderResourceTC1UpdateConfig = `
+resource "bigipnext_cm_provider" "rseries" {
+ name = "tfnext-cm-rseries01"
+ address = "10.14.10.14:8888"
type = "RSERIES"
- username = "xxxxxx"
+ username = "admin"
password = "xxxxxxxx"
}
`
diff --git a/internal/provider/fast_http_resource.go b/internal/provider/fast_http_resource.go
new file mode 100644
index 0000000..296ba01
--- /dev/null
+++ b/internal/provider/fast_http_resource.go
@@ -0,0 +1,247 @@
+//go:build !test
+
+package provider
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/hashicorp/terraform-plugin-framework/path"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+ bigipnextsdk "gitswarm.f5net.com/terraform-providers/bigipnext"
+)
+
+var (
+ _ resource.Resource = &NextCMFastHttpResource{}
+ _ resource.ResourceWithImportState = &NextCMFastHttpResource{}
+)
+
+func NewNextCMFastHttpResource() resource.Resource {
+ return &NextCMFastHttpResource{}
+}
+
+type NextCMFastHttpResource struct {
+ client *bigipnextsdk.BigipNextCM
+}
+type NextCMFastHttpResourceModel struct {
+ Name types.String `tfsdk:"name"`
+ ApplicationDescription types.String `tfsdk:"application_description"`
+ ApplicationName types.String `tfsdk:"application_name"`
+ Pools types.List `tfsdk:"pools"`
+ Virtuals types.List `tfsdk:"virtuals"`
+ SetName types.String `tfsdk:"set_name"`
+ TemplateName types.String `tfsdk:"template_name"`
+ TenantName types.String `tfsdk:"tenant_name"`
+ AllowOverwrite types.Bool `tfsdk:"allow_overwrite"`
+ Id types.String `tfsdk:"id"`
+}
+
+type NextCMFastHttpPoolModel struct {
+ LoadBalancingMode types.String `tfsdk:"load_balancing_mode"`
+ MonitorType types.List `tfsdk:"monitor_type"`
+ PoolName types.String `tfsdk:"pool_name"`
+ ServicePort types.Int64 `tfsdk:"service_port"`
+}
+
+// pool_name
+type NextCMFastHttpVirtualModel struct {
+ PoolName types.String `tfsdk:"pool_name"`
+ VirtualName types.String `tfsdk:"virtual_name"`
+ VirtualPort types.Int64 `tfsdk:"virtual_port"`
+}
+
+func (r *NextCMFastHttpResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_cm_fast_http"
+}
+
+func (r *NextCMFastHttpResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ MarkdownDescription: "Resource used to manage(CRUD) AS3 declarations using BIG-IP Next CM onto target BIG-IP Next",
+ Attributes: map[string]schema.Attribute{
+ "name": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Name of the Application",
+ },
+ "application_name": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Name of the Application",
+ },
+ "tenant_name": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Name of the Tenant",
+ },
+ "application_description": schema.StringAttribute{
+ Optional: true,
+ MarkdownDescription: "Description of the Application",
+ },
+ "pools": schema.ListNestedAttribute{
+ Optional: true,
+ MarkdownDescription: "List of Pools",
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "load_balancing_mode": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Load Balancing Mode",
+ },
+ "monitor_type": schema.ListAttribute{
+ Required: true,
+ ElementType: types.StringType,
+ MarkdownDescription: "Monitor Type",
+ },
+ "pool_name": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Name of the Pool",
+ },
+ "service_port": schema.Int64Attribute{
+ Required: true,
+ MarkdownDescription: "Service Port",
+ },
+ },
+ },
+ },
+ "virtuals": schema.ListNestedAttribute{
+ Optional: true,
+ MarkdownDescription: "List of Virtuals",
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "pool_name": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Name of the Pool",
+ },
+ "virtual_name": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Name of the Virtual",
+ },
+ "virtual_port": schema.Int64Attribute{
+ Required: true,
+ MarkdownDescription: "Virtual Port",
+ },
+ },
+ },
+ },
+ "set_name": schema.StringAttribute{
+ Optional: true,
+ Computed: true,
+ MarkdownDescription: "Name of the AS3 Set",
+ Default: stringdefault.StaticString("Examples"),
+ },
+ "template_name": schema.StringAttribute{
+ Optional: true,
+ Computed: true,
+ MarkdownDescription: "Name of the AS3 Template",
+ Default: stringdefault.StaticString("http"),
+ },
+ "allow_overwrite": schema.BoolAttribute{
+ Optional: true,
+ Computed: true,
+ MarkdownDescription: "Allow Overwrite",
+ Default: booldefault.StaticBool(false),
+ },
+ "id": schema.StringAttribute{
+ Computed: true,
+ MarkdownDescription: "Unique Identifier for the resource",
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
+ },
+ },
+ }
+}
+
+func (r *NextCMFastHttpResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+ r.client, resp.Diagnostics = toBigipNextCMProvider(req.ProviderData)
+}
+
+func (r *NextCMFastHttpResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ var resCfg *NextCMFastHttpResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+ tflog.Info(ctx, fmt.Sprintf("[CREATE] NextCMFastHttpResource:%+v\n", resCfg.Name.ValueString()))
+ reqDraft := getFastRequestDraft(ctx, resCfg)
+
+ tflog.Info(ctx, fmt.Sprintf("[CREATE] Https:%+v\n", reqDraft))
+
+ draftID, err := r.client.PostFastApplicationDraft(reqDraft)
+ if err != nil {
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Create FAST Draft config, got error: %s", err))
+ return
+ }
+ tflog.Info(ctx, fmt.Sprintf("[CREATE] draftID:%+v\n", draftID))
+ resp.Diagnostics.Append(resp.State.Set(ctx, resCfg)...)
+}
+
+func (r *NextCMFastHttpResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var stateCfg *NextCMFastHttpResourceModel
+ resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+ resp.Diagnostics.Append(resp.State.Set(ctx, &stateCfg)...)
+}
+
+func (r *NextCMFastHttpResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ var resCfg *NextCMFastHttpResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+ resp.Diagnostics.Append(resp.State.Set(ctx, &resCfg)...)
+}
+
+func (r *NextCMFastHttpResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ var stateCfg *NextCMFastHttpResourceModel
+ if resp.Diagnostics.HasError() {
+ return
+ }
+ resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
+ stateCfg.Id = types.StringValue("")
+}
+
+func (r *NextCMFastHttpResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+ resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
+
+func getFastRequestDraft(ctx context.Context, data *NextCMFastHttpResourceModel) *bigipnextsdk.FastRequestDraft {
+ var fastReqDraft bigipnextsdk.FastRequestDraft
+ fastReqDraft.Name = data.Name.ValueString()
+ fastReqDraft.Parameters.ApplicationDescription = data.ApplicationDescription.ValueString()
+ fastReqDraft.Parameters.ApplicationName = data.ApplicationName.ValueString()
+ fastReqDraft.SetName = data.SetName.ValueString()
+ fastReqDraft.TemplateName = data.TemplateName.ValueString()
+ fastReqDraft.TenantName = data.TenantName.ValueString()
+ fastReqDraft.AllowOverwrite = data.AllowOverwrite.ValueBool()
+ elements := make([]types.Object, 0, len(data.Pools.Elements()))
+ data.Pools.ElementsAs(ctx, &elements, false)
+ for _, element := range elements {
+ var fastPool bigipnextsdk.FastPool
+ var objectModel NextCMFastHttpPoolModel
+ element.As(ctx, &objectModel, basetypes.ObjectAsOptions{})
+ fastPool.LoadBalancingMode = objectModel.LoadBalancingMode.ValueString()
+ objectModel.MonitorType.ElementsAs(ctx, &fastPool.MonitorType, false)
+ fastPool.PoolName = objectModel.PoolName.ValueString()
+ fastPool.ServicePort = int(objectModel.ServicePort.ValueInt64())
+ fastReqDraft.Parameters.Pools = append(fastReqDraft.Parameters.Pools, fastPool)
+ }
+ vsLists := make([]types.Object, 0, len(data.Virtuals.Elements()))
+ data.Virtuals.ElementsAs(ctx, &vsLists, false)
+ for _, element := range vsLists {
+ var fastVS bigipnextsdk.VirtualServer
+ var objectModel NextCMFastHttpVirtualModel
+ element.As(ctx, &objectModel, basetypes.ObjectAsOptions{})
+ fastVS.VirtualName = objectModel.VirtualName.ValueString()
+ fastVS.VirtualPort = int(objectModel.VirtualPort.ValueInt64())
+ fastReqDraft.Parameters.Virtuals = append(fastReqDraft.Parameters.Virtuals, fastVS)
+ }
+ tflog.Info(ctx, fmt.Sprintf("fastReqDraft:%+v\n", fastReqDraft))
+ return &fastReqDraft
+}
diff --git a/internal/provider/fast_template_resource.go b/internal/provider/fast_template_resource.go
new file mode 100644
index 0000000..800bc24
--- /dev/null
+++ b/internal/provider/fast_template_resource.go
@@ -0,0 +1,196 @@
+//go:build !test
+
+package provider
+
+import (
+ "context"
+
+ "github.com/hashicorp/terraform-plugin-framework/path"
+ "github.com/hashicorp/terraform-plugin-framework/resource"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault"
+ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ bigipnextsdk "gitswarm.f5net.com/terraform-providers/bigipnext"
+)
+
+var (
+ _ resource.Resource = &NextCMFastTemplateResource{}
+ _ resource.ResourceWithImportState = &NextCMFastTemplateResource{}
+)
+
+func NewNextCMFastTemplateResource() resource.Resource {
+ return &NextCMFastTemplateResource{}
+}
+
+type NextCMFastTemplateResource struct {
+ client *bigipnextsdk.BigipNextCM
+}
+type NextCMFastTemplateResourceModel struct {
+ TemplateName types.String `tfsdk:"template_name"`
+ ApplicationDescription types.String `tfsdk:"application_description"`
+ ApplicationName types.String `tfsdk:"application_name"`
+ Pools types.List `tfsdk:"pools"`
+ Virtuals types.List `tfsdk:"virtuals"`
+ SetName types.String `tfsdk:"set_name"`
+ TenantName types.String `tfsdk:"tenant_name"`
+ AllowOverwrite types.Bool `tfsdk:"allow_overwrite"`
+ Id types.String `tfsdk:"id"`
+}
+
+type NextCMFastTemplatePoolModel struct {
+ LoadBalancingMode types.String `tfsdk:"load_balancing_mode"`
+ MonitorType types.List `tfsdk:"monitor_type"`
+ PoolName types.String `tfsdk:"pool_name"`
+ ServicePort types.Int64 `tfsdk:"service_port"`
+}
+
+// pool_name
+type NextCMFastTemplateVirtualModel struct {
+ PoolName types.String `tfsdk:"pool_name"`
+ VirtualName types.String `tfsdk:"virtual_name"`
+ VirtualPort types.Int64 `tfsdk:"virtual_port"`
+}
+
+func (r *NextCMFastTemplateResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_cm_fast_template"
+}
+
+func (r *NextCMFastTemplateResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
+ resp.Schema = schema.Schema{
+ MarkdownDescription: "Resource used to Manages FAST templates on Central Manager",
+ Attributes: map[string]schema.Attribute{
+ "template_name": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Name of the FAST template to be created",
+ },
+ "template_set": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Name of the FAST template set to use\nIf a set with given name does not exist a new set will be created automatically",
+ },
+ "application_name": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Name of the Application",
+ },
+ "tenant_name": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Name of the Tenant",
+ },
+ "application_description": schema.StringAttribute{
+ Optional: true,
+ MarkdownDescription: "Description of the Application",
+ },
+ "pools": schema.ListNestedAttribute{
+ Optional: true,
+ MarkdownDescription: "List of Pools",
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "load_balancing_mode": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Load Balancing Mode",
+ },
+ "monitor_type": schema.ListAttribute{
+ Required: true,
+ ElementType: types.StringType,
+ MarkdownDescription: "Monitor Type",
+ },
+ "pool_name": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Name of the Pool",
+ },
+ "service_port": schema.Int64Attribute{
+ Required: true,
+ MarkdownDescription: "Service Port",
+ },
+ },
+ },
+ },
+ "virtuals": schema.ListNestedAttribute{
+ Optional: true,
+ MarkdownDescription: "List of Virtuals",
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "pool_name": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Name of the Pool",
+ },
+ "virtual_name": schema.StringAttribute{
+ Required: true,
+ MarkdownDescription: "Name of the Virtual",
+ },
+ "virtual_port": schema.Int64Attribute{
+ Required: true,
+ MarkdownDescription: "Virtual Port",
+ },
+ },
+ },
+ },
+ "set_name": schema.StringAttribute{
+ Optional: true,
+ Computed: true,
+ MarkdownDescription: "Name of the AS3 Set",
+ Default: stringdefault.StaticString("Examples"),
+ },
+ "allow_overwrite": schema.BoolAttribute{
+ Optional: true,
+ Computed: true,
+ MarkdownDescription: "Allow Overwrite",
+ Default: booldefault.StaticBool(false),
+ },
+ "id": schema.StringAttribute{
+ Computed: true,
+ MarkdownDescription: "Unique Identifier for the resource",
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.UseStateForUnknown(),
+ },
+ },
+ },
+ }
+}
+
+func (r *NextCMFastTemplateResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
+ r.client, resp.Diagnostics = toBigipNextCMProvider(req.ProviderData)
+}
+
+func (r *NextCMFastTemplateResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
+ var resCfg *NextCMFastTemplateResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+ //git tflog.Info(ctx, fmt.Sprintf("[CREATE] NextCMFastTemplateResource:%+v\n", resCfg.Name.ValueString()))
+ resp.Diagnostics.Append(resp.State.Set(ctx, resCfg)...)
+}
+
+func (r *NextCMFastTemplateResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
+ var stateCfg *NextCMFastTemplateResourceModel
+ resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+ resp.Diagnostics.Append(resp.State.Set(ctx, &stateCfg)...)
+}
+
+func (r *NextCMFastTemplateResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
+ var resCfg *NextCMFastTemplateResourceModel
+ resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+ resp.Diagnostics.Append(resp.State.Set(ctx, &resCfg)...)
+}
+
+func (r *NextCMFastTemplateResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
+ var stateCfg *NextCMFastTemplateResourceModel
+ if resp.Diagnostics.HasError() {
+ return
+ }
+ resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
+ stateCfg.Id = types.StringValue("")
+}
+
+func (r *NextCMFastTemplateResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+ resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
diff --git a/internal/provider/fixtures/cm_ha_nodes_get.json b/internal/provider/fixtures/cm_ha_nodes_get.json
new file mode 100644
index 0000000..37e6472
--- /dev/null
+++ b/internal/provider/fixtures/cm_ha_nodes_get.json
@@ -0,0 +1,47 @@
+[
+ {
+ "metadata": {
+ "id": "979423f5-0e8a-4994-98j92813umio21m3",
+ "machine_id": "972b14606bf74c8291e95298u3j89ddc",
+ "name": "central-manager-10.146.165.89"
+ },
+ "spec": {
+ "node_address": "10.146.165.89",
+ "node_type": "server"
+ },
+ "status": {
+ "ready": true,
+ "registration": "SUCCESSFUL"
+ }
+ },
+ {
+ "metadata": {
+ "id": "979423f5-0e8a-4994-98j92813umio21m3",
+ "machine_id": "972b14606bf74c8291e95298u3j89ddc",
+ "name": "central-manager-10.146.164.150"
+ },
+ "spec": {
+ "node_address": "10.146.164.150",
+ "node_type": "server"
+ },
+ "status": {
+ "ready": true,
+ "registration": "SUCCESSFUL"
+ }
+ },
+ {
+ "metadata": {
+ "id": "979423f5-0e8a-4994-98j92813umio21m3",
+ "machine_id": "972b14606bf74c8291e95298u3j89ddc",
+ "name": "central-manager-server"
+ },
+ "spec": {
+ "node_address": "10.123.111.88",
+ "node_type": "server"
+ },
+ "status": {
+ "ready": true,
+ "registration": "SUCCESSFUL"
+ }
+ }
+]
\ No newline at end of file
diff --git a/internal/provider/fixtures/cm_ha_nodes_get_after_delete.json b/internal/provider/fixtures/cm_ha_nodes_get_after_delete.json
new file mode 100644
index 0000000..502fef6
--- /dev/null
+++ b/internal/provider/fixtures/cm_ha_nodes_get_after_delete.json
@@ -0,0 +1,17 @@
+[
+ {
+ "metadata": {
+ "id": "979423f5-0e8a-4994-98j92813umio21m3",
+ "machine_id": "972b14606bf74c8291e95298u3j89ddc",
+ "name": "central-manager-server"
+ },
+ "spec": {
+ "node_address": "10.123.111.88",
+ "node_type": "server"
+ },
+ "status": {
+ "ready": true,
+ "registration": "SUCCESSFUL"
+ }
+ }
+]
\ No newline at end of file
diff --git a/internal/provider/fixtures/cm_ha_nodes_post.json b/internal/provider/fixtures/cm_ha_nodes_post.json
new file mode 100644
index 0000000..154ec8e
--- /dev/null
+++ b/internal/provider/fixtures/cm_ha_nodes_post.json
@@ -0,0 +1,32 @@
+[
+ {
+ "metadata": {
+ "id": "",
+ "machine_id": "",
+ "name": "central-manager-10.146.164.150"
+ },
+ "spec": {
+ "node_address": "10.146.164.150",
+ "node_type": "server"
+ },
+ "status": {
+ "ready": false,
+ "registration": "PENDING"
+ }
+ },
+ {
+ "metadata": {
+ "id": "",
+ "machine_id": "",
+ "name": "central-manager-10.146.165.89"
+ },
+ "spec": {
+ "node_address": "10.146.165.89",
+ "node_type": "server"
+ },
+ "status": {
+ "ready": false,
+ "registration": "PENDING"
+ }
+ }
+]
diff --git a/internal/provider/fixtures/cm_ha_nodes_post_update.json b/internal/provider/fixtures/cm_ha_nodes_post_update.json
new file mode 100644
index 0000000..fe7e457
--- /dev/null
+++ b/internal/provider/fixtures/cm_ha_nodes_post_update.json
@@ -0,0 +1,17 @@
+[
+ {
+ "metadata": {
+ "id": "",
+ "machine_id": "",
+ "name": "central-manager-12.34.56.77"
+ },
+ "spec": {
+ "node_address": "12.34.56.77",
+ "node_type": "server"
+ },
+ "status": {
+ "ready": false,
+ "registration": "PENDING"
+ }
+ }
+]
diff --git a/internal/provider/fixtures/cm_next_ha_delete_task_status.json b/internal/provider/fixtures/cm_next_ha_delete_task_status.json
new file mode 100644
index 0000000..cb6b7ca
--- /dev/null
+++ b/internal/provider/fixtures/cm_next_ha_delete_task_status.json
@@ -0,0 +1,13 @@
+{
+ "_links":{
+ "self":{
+ "href":"/v1/deletion-tasks/642d5964-8cd9-4881-9086-1ed5ca682101"
+ }
+ },
+ "address":"10.146.168.20",
+ "created":"2023-11-28T07:55:50.924918Z",
+ "device_id":"8d6c8c85-1738-4a34-b57b-d3644a2ecfcc",
+ "id":"642d5964-8cd9-4881-9086-1ed5ca682101",
+ "state":"factoryResetInstance",
+ "status":"completed"
+}
\ No newline at end of file
diff --git a/internal/provider/fixtures/cm_next_ha_task_status.json b/internal/provider/fixtures/cm_next_ha_task_status.json
new file mode 100644
index 0000000..212fe4b
--- /dev/null
+++ b/internal/provider/fixtures/cm_next_ha_task_status.json
@@ -0,0 +1,41 @@
+{
+ "_links":{
+ "self":{
+ "href":"/v1/ha-creation-tasks/06aea4ed-7425-4db3-a728-2574929885d9"
+ }
+ },
+ "active_instance_id":"8d6c8c85-1738-4a34-b57b-d3644a2ecfcc",
+ "auto_failback":false,
+ "cluster_management_ip":"10.146.168.20",
+ "cluster_name":"raviecosyshydha",
+ "control_plane_vlan":{
+ "tag":101,
+ "name":"ha-cp-vlan"
+ },
+ "created":"2023-11-28T05:56:57.618962Z",
+ "data_plane_vlan":{
+ "tag":102,
+ "name":"ha-dp-vlan",
+ "NetworkInterface":"1.3"
+ },
+ "id":"06aea4ed-7425-4db3-a728-2574929885d9",
+ "name":"create HA from 8d6c8c85-1738-4a34-b57b-d3644a2ecfcc",
+ "nodes":[
+ {
+ "name":"active-node",
+ "control_plane_address":"10.146.168.21/16",
+ "data_plane_primary_address":"10.3.0.10/16"
+ },
+ {
+ "name":"standby-node",
+ "control_plane_address":"10.146.168.22/16",
+ "data_plane_primary_address":"10.3.0.10/16"
+ }
+ ],
+ "standby_instance_id":"d0e9cda1-4460-4132-87fd-0f3aa18f3872",
+ "state":"haGetNodesLoginInfo",
+ "status":"completed",
+ "task_type":"instance_ha_creation",
+ "traffic_vlan":null,
+ "updated":"2023-11-28T05:56:57.712342Z"
+}
\ No newline at end of file
diff --git a/internal/provider/fixtures/getDeviceIdByHostname.json b/internal/provider/fixtures/getDeviceIdByHostname.json
new file mode 100644
index 0000000..8c38fbb
--- /dev/null
+++ b/internal/provider/fixtures/getDeviceIdByHostname.json
@@ -0,0 +1,32 @@
+{
+ "_embedded": {
+ "devices": [
+ {
+ "_links": {
+ "self": {
+ "href": "/v1/inventory?filter=hostname+eq+%27big-ip-next%27/494975ee-5eba-420a-90a6-f3aeb75bbf5b"
+ }
+ },
+ "address": "10.218.132.39",
+ "certificate_validated": "2024-07-01T07:44:31.174615Z",
+ "certificate_validation_error": "tls: failed to verify certificate: x509: certificate signed by unknown authority",
+ "certificate_validity": false,
+ "hostname": "big-ip-next",
+ "id": "494975ee-5eba-420a-90a6-f3aeb75bbf5b",
+ "mode": "STANDALONE",
+ "platform_name": "KVM",
+ "platform_type": "VE",
+ "port": 5443,
+ "short_id": "fYYPFbrB",
+ "version": "20.2.1-2.430.2"
+ }
+ ]
+ },
+ "_links": {
+ "self": {
+ "href": "/v1/inventory?filter=hostname+eq+%27big-ip-next%27"
+ }
+ },
+ "count": 1,
+ "total": 1
+}
\ No newline at end of file
diff --git a/internal/provider/fixtures/getDeviceIdByIp.json b/internal/provider/fixtures/getDeviceIdByIp.json
new file mode 100644
index 0000000..01ae756
--- /dev/null
+++ b/internal/provider/fixtures/getDeviceIdByIp.json
@@ -0,0 +1,32 @@
+{
+ "_embedded": {
+ "devices": [
+ {
+ "_links": {
+ "self": {
+ "href": "/v1/inventory?filter=address+eq+%2710.218.132.39%27/494975ee-5eba-420a-90a6-f3aeb75bbf5b"
+ }
+ },
+ "address": "10.218.132.39",
+ "certificate_validated": "2024-07-01T07:44:31.174615Z",
+ "certificate_validation_error": "tls: failed to verify certificate: x509: certificate signed by unknown authority",
+ "certificate_validity": false,
+ "hostname": "big-ip-next",
+ "id": "494975ee-5eba-420a-90a6-f3aeb75bbf5b",
+ "mode": "STANDALONE",
+ "platform_name": "KVM",
+ "platform_type": "VE",
+ "port": 5443,
+ "short_id": "fYYPFbrB",
+ "version": "20.2.1-2.430.2"
+ }
+ ]
+ },
+ "_links": {
+ "self": {
+ "href": "/v1/inventory?filter=address+eq+%2710.218.132.39%27"
+ }
+ },
+ "count": 1,
+ "total": 1
+}
\ No newline at end of file
diff --git a/internal/provider/fixtures/getWaf.json b/internal/provider/fixtures/getWaf.json
new file mode 100644
index 0000000..96a4493
--- /dev/null
+++ b/internal/provider/fixtures/getWaf.json
@@ -0,0 +1,6583 @@
+{
+ "_links": {
+ "self": {
+ "href": "/api/v1/spaces/default/security/waf-policies/1a4453fe-b37a-4212-a813-a3d2f789dad1"
+ }
+ },
+ "application_language": "utf-8",
+ "created_by": "",
+ "created_time": "2024-07-17T11:59:25.304423Z",
+ "declaration": {
+ "policy": {
+ "app-protection": {
+ "enabled": true
+ },
+ "applicationLanguage": "utf-8",
+ "behavioral-enforcement": {
+ "behavioralEnforcementViolations": [
+ {
+ "name": "VIOL_GEOLOCATION"
+ },
+ {
+ "name": "VIOL_URL"
+ },
+ {
+ "name": "VIOL_FILETYPE"
+ },
+ {
+ "name": "VIOL_BLACKLISTED_IP"
+ },
+ {
+ "name": "VIOL_THREAT_CAMPAIGN"
+ },
+ {
+ "name": "VIOL_BLOCKING_CONDITION"
+ },
+ {
+ "name": "VIOL_THREAT_ANALYSIS"
+ },
+ {
+ "name": "VIOL_CONVICTION"
+ }
+ ],
+ "enableBehavioralEnforcement": false,
+ "enableBlockingCveSignatures": true,
+ "enableBlockingHighAccuracySignatures": true,
+ "enableBlockingLikelyMaliciousTransactions": true,
+ "enableBlockingSuspiciousTransactions": false,
+ "enableBlockingViolations": true
+ },
+ "blocking-settings": {
+ "evasions": [
+ {
+ "description": "Trailing slash",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Trailing dot",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Semicolon path parameters",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Bad unescape",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Apache whitespace",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Bare byte decoding",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "IIS Unicode codepoints",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "IIS backslashes",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "%u decoding",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Multiple decoding",
+ "enabled": true,
+ "learn": true,
+ "maxDecodingPasses": 2
+ },
+ {
+ "description": "Directory traversals",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Multiple slashes",
+ "enabled": false,
+ "learn": true
+ }
+ ],
+ "http-protocols": [
+ {
+ "description": "Check maximum number of cookies",
+ "enabled": false,
+ "learn": true,
+ "maxCookies": 50
+ },
+ {
+ "description": "Unescaped space in URL",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Multiple host headers",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Check maximum number of parameters",
+ "enabled": true,
+ "learn": true,
+ "maxParams": 100
+ },
+ {
+ "description": "Bad host header value",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Check maximum number of headers",
+ "enabled": true,
+ "learn": true,
+ "maxHeaders": 100
+ },
+ {
+ "description": "Unparsable request content",
+ "enabled": true
+ },
+ {
+ "description": "High ASCII characters in headers",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Null in request",
+ "enabled": true
+ },
+ {
+ "description": "Bad HTTP version",
+ "enabled": true
+ },
+ {
+ "description": "Content length should be a positive number",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Host header contains IP address",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "CRLF characters before request start",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "No Host header in HTTP/1.1 request",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Bad multipart parameters parsing",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Bad multipart/form-data request parsing",
+ "enabled": true,
+ "learn": false
+ },
+ {
+ "description": "Body in GET or HEAD requests",
+ "enabled": false,
+ "learn": false
+ },
+ {
+ "description": "Chunked request with Content-Length header",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Several Content-Length headers",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Header name with no header value",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "POST request with Content-Length: 0",
+ "enabled": false,
+ "learn": true
+ }
+ ],
+ "violations": [
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Failed to convert character",
+ "name": "VIOL_ENCODING"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal redirection attempt",
+ "learn": true,
+ "name": "VIOL_REDIRECT"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal parameter",
+ "learn": true,
+ "name": "VIOL_PARAMETER"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal cross-origin request",
+ "learn": true,
+ "name": "VIOL_CROSS_ORIGIN_REQUEST"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Brute Force: Maximum login attempts are exceeded",
+ "name": "VIOL_BRUTE_FORCE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal URL length",
+ "learn": true,
+ "name": "VIOL_URL_LENGTH"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Login URL bypassed",
+ "learn": true,
+ "name": "VIOL_LOGIN_URL_BYPASSED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal parameter data type",
+ "learn": true,
+ "name": "VIOL_PARAMETER_DATA_TYPE"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Unauthorized access attempt",
+ "name": "VIOL_ACCESS_UNAUTHORIZED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal attachment in SOAP message",
+ "learn": true,
+ "name": "VIOL_XML_SOAP_ATTACHMENT"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal meta character in parameter name",
+ "learn": true,
+ "name": "VIOL_PARAMETER_NAME_METACHAR"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Host name mismatch",
+ "name": "VIOL_HOSTNAME_MISMATCH"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Missing Access Token",
+ "name": "VIOL_ACCESS_MISSING"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Illegal session ID in URL",
+ "learn": true,
+ "name": "VIOL_DYNAMIC_SESSION"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "GraphQL disallowed pattern in response",
+ "name": "VIOL_GRAPHQL_ERROR_RESPONSE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal dynamic parameter value",
+ "learn": true,
+ "name": "VIOL_PARAMETER_DYNAMIC_VALUE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Data Guard: Information leakage detected",
+ "learn": true,
+ "name": "VIOL_DATA_GUARD"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Malformed JSON data",
+ "learn": true,
+ "name": "VIOL_JSON_MALFORMED"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Leaked Credentials Detection",
+ "name": "VIOL_LEAKED_CREDENTIALS"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal cookie length",
+ "learn": true,
+ "name": "VIOL_COOKIE_LENGTH"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal query string length",
+ "learn": true,
+ "name": "VIOL_QUERY_STRING_LENGTH"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "SOAP method not allowed",
+ "learn": true,
+ "name": "VIOL_XML_SOAP_METHOD"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal parameter numeric value",
+ "learn": true,
+ "name": "VIOL_PARAMETER_NUMERIC_VALUE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal repeated header",
+ "learn": true,
+ "name": "VIOL_HEADER_REPEATED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal empty parameter value",
+ "learn": true,
+ "name": "VIOL_PARAMETER_EMPTY_VALUE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal file type",
+ "learn": true,
+ "name": "VIOL_FILETYPE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Access from disallowed User/Session/IP/Device ID",
+ "name": "VIOL_SESSION_AWARENESS"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Login URL expired",
+ "learn": true,
+ "name": "VIOL_LOGIN_URL_EXPIRED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "XML data does not comply with format settings",
+ "learn": true,
+ "name": "VIOL_XML_FORMAT"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Mandatory parameter is missing",
+ "name": "VIOL_MANDATORY_PARAMETER"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal request content type",
+ "learn": true,
+ "name": "VIOL_URL_CONTENT_TYPE"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Bot Client Detected",
+ "learn": true,
+ "name": "VIOL_BOT_CLIENT"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "HTTP protocol compliance failed",
+ "learn": true,
+ "name": "VIOL_HTTP_PROTOCOL"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal parameter array value",
+ "name": "VIOL_PARAMETER_ARRAY_VALUE"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "GWT data does not comply with format settings",
+ "learn": true,
+ "name": "VIOL_GWT_FORMAT"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "IP is blacklisted",
+ "name": "VIOL_BLACKLISTED_IP"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Malformed XML data",
+ "learn": true,
+ "name": "VIOL_XML_MALFORMED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Null in multi-part parameter value",
+ "learn": true,
+ "name": "VIOL_PARAMETER_MULTIPART_NULL_VALUE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Server-side access to disallowed host",
+ "name": "VIOL_SERVER_SIDE_HOST"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Expired timestamp",
+ "learn": true,
+ "name": "VIOL_COOKIE_EXPIRED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal meta character in value",
+ "learn": true,
+ "name": "VIOL_PARAMETER_VALUE_METACHAR"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Illegal flow to URL",
+ "learn": true,
+ "name": "VIOL_FLOW"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "CSRF attack detected",
+ "name": "VIOL_CSRF"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Illegal entry point",
+ "learn": true,
+ "name": "VIOL_FLOW_ENTRY_POINT"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Mandatory HTTP header is missing",
+ "learn": true,
+ "name": "VIOL_MANDATORY_HEADER"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Parameter value does not comply with regular expression",
+ "learn": true,
+ "name": "VIOL_PARAMETER_VALUE_REGEXP"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Illegal query string or POST data",
+ "learn": true,
+ "name": "VIOL_FLOW_DISALLOWED_INPUT"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "JSON data does not comply with JSON schema",
+ "name": "VIOL_JSON_SCHEMA"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal repeated parameter name",
+ "learn": true,
+ "name": "VIOL_PARAMETER_REPEATED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal parameter value length",
+ "learn": true,
+ "name": "VIOL_PARAMETER_VALUE_LENGTH"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Web Services Security failure",
+ "learn": true,
+ "name": "VIOL_XML_WEB_SERVICES_SECURITY"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "GraphQL data does not comply with format settings",
+ "learn": true,
+ "name": "VIOL_GRAPHQL_FORMAT"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Virus detected",
+ "learn": true,
+ "name": "VIOL_VIRUS"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal header length",
+ "learn": true,
+ "name": "VIOL_HEADER_LENGTH"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Malformed GWT data",
+ "learn": true,
+ "name": "VIOL_GWT_MALFORMED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal parameter location",
+ "name": "VIOL_PARAMETER_LOCATION"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal meta character in header",
+ "learn": true,
+ "name": "VIOL_HEADER_METACHAR"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "GraphQL introspection query",
+ "name": "VIOL_GRAPHQL_INTROSPECTION_QUERY"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Evasion technique detected",
+ "learn": true,
+ "name": "VIOL_EVASION"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Malformed GraphQL data",
+ "learn": true,
+ "name": "VIOL_GRAPHQL_MALFORMED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "JSON data does not comply with format settings",
+ "learn": true,
+ "name": "VIOL_JSON_FORMAT"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Disallowed file upload content detected",
+ "learn": true,
+ "name": "VIOL_FILE_UPLOAD"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Mitigation action determined by Threat Analysis Platform",
+ "name": "VIOL_THREAT_ANALYSIS"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal static parameter value",
+ "learn": true,
+ "name": "VIOL_PARAMETER_STATIC_VALUE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "XML data does not comply with schema or WSDL document",
+ "learn": true,
+ "name": "VIOL_XML_SCHEMA"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Unsupported browser",
+ "learn": true,
+ "name": "VIOL_BROWSER"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal method",
+ "learn": true,
+ "name": "VIOL_METHOD"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal Base64 value",
+ "learn": true,
+ "name": "VIOL_PARAMETER_VALUE_BASE64"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "ASM Cookie Hijacking",
+ "learn": true,
+ "name": "VIOL_ASM_COOKIE_HIJACKING"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "DataSafe Data Integrity",
+ "name": "VIOL_DATA_INTEGRITY"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal URL",
+ "learn": true,
+ "name": "VIOL_URL"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Threat Campaign detected",
+ "name": "VIOL_THREAT_CAMPAIGN"
+ },
+ {
+ "description": "Attack signature detected",
+ "name": "VIOL_ATTACK_SIGNATURE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal meta character in URL",
+ "learn": true,
+ "name": "VIOL_URL_METACHAR"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Access from malicious IP address",
+ "name": "VIOL_MALICIOUS_IP"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Request length exceeds defined buffer size",
+ "learn": true,
+ "name": "VIOL_REQUEST_MAX_LENGTH"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Bad Actor Detected",
+ "name": "VIOL_MALICIOUS_DEVICE"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Modified WAF cookie",
+ "learn": true,
+ "name": "VIOL_ASM_COOKIE_MODIFIED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Violation Rating Need Examination detected",
+ "name": "VIOL_RATING_NEED_EXAMINATION"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "CSRF authentication expired",
+ "learn": true,
+ "name": "VIOL_CSRF_EXPIRED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal request length",
+ "learn": true,
+ "name": "VIOL_REQUEST_LENGTH"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Blocking Condition Detected",
+ "name": "VIOL_BLOCKING_CONDITION"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Modified domain cookie(s)",
+ "learn": true,
+ "name": "VIOL_COOKIE_MODIFIED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Mandatory request body is missing",
+ "name": "VIOL_MANDATORY_REQUEST_BODY"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Access token does not comply with the profile requirements",
+ "name": "VIOL_ACCESS_INVALID"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Illegal host name",
+ "name": "VIOL_HOSTNAME"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Cookie not RFC-compliant",
+ "learn": true,
+ "name": "VIOL_COOKIE_MALFORMED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Disallowed file upload content detected in body",
+ "name": "VIOL_FILE_UPLOAD_IN_BODY"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal POST data length",
+ "learn": true,
+ "name": "VIOL_POST_DATA_LENGTH"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Access from disallowed Geolocation",
+ "learn": true,
+ "name": "VIOL_GEOLOCATION"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Illegal number of mandatory parameters",
+ "learn": true,
+ "name": "VIOL_FLOW_MANDATORY_PARAMS"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Violation Rating Threat detected",
+ "name": "VIOL_RATING_THREAT"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Illegal HTTP status in response",
+ "learn": true,
+ "name": "VIOL_HTTP_RESPONSE_STATUS"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Malformed Access Token",
+ "name": "VIOL_ACCESS_MALFORMED"
+ }
+ ],
+ "web-services-securities": [
+ {
+ "description": "UnSigned Timestamp",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Timestamp expiration is too far in the future",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Expired Timestamp",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Invalid Timestamp",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Missing Timestamp",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Verification Error",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Signing Error",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Encryption Error",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Decryption Error",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Certificate Error",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Certificate Expired",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Malformed Error",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Internal Error",
+ "enabled": false,
+ "learn": true
+ }
+ ]
+ },
+ "bot-defense": {
+ "mitigations": {
+ "classes": [
+ {
+ "action": "block",
+ "name": "malicious-bot"
+ },
+ {
+ "action": "ignore",
+ "name": "suspicious-browser"
+ },
+ {
+ "action": "ignore",
+ "name": "untrusted-bot"
+ },
+ {
+ "action": "ignore",
+ "name": "trusted-bot"
+ },
+ {
+ "action": "detect",
+ "name": "browser"
+ },
+ {
+ "action": "ignore",
+ "name": "unknown"
+ }
+ ]
+ },
+ "settings": {
+ "caseSensitiveHttpHeaders": true,
+ "isEnabled": true
+ }
+ },
+ "brute-force-attack-preventions": [
+ {
+ "bruteForceProtectionForAllLoginPages": false,
+ "captchaBypassCriteria": {
+ "action": "alarm-and-drop",
+ "enabled": false,
+ "threshold": 5
+ },
+ "clientSideIntegrityBypassCriteria": {
+ "action": "alarm-and-captcha",
+ "threshold": 3
+ },
+ "detectionCriteria": {
+ "action": "alarm",
+ "credentialsStuffingMatchesReached": 100,
+ "failedLoginAttemptsRateReached": 100
+ },
+ "leakedCredentialsCriteria": {
+ "action": "alarm-and-blocking-page"
+ },
+ "loginAttemptsFromTheSameDeviceId": {
+ "action": "alarm",
+ "threshold": 3
+ },
+ "loginAttemptsFromTheSameIp": {
+ "action": "alarm-and-blocking-page",
+ "enabled": true,
+ "threshold": 20
+ },
+ "loginAttemptsFromTheSameUser": {
+ "action": "alarm",
+ "enabled": true,
+ "threshold": 3
+ },
+ "measurementPeriod": 900,
+ "preventionDuration": "3600",
+ "reEnableLoginAfter": 3600,
+ "sourceBasedProtectionDetectionPeriod": 3600
+ }
+ ],
+ "caseInsensitive": true,
+ "character-sets": [
+ {
+ "characterSet": [
+ {
+ "isAllowed": false,
+ "metachar": "0x0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xc"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x10"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x11"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x12"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x13"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x14"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x15"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x16"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x17"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x18"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x19"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x20"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x21"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x22"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x23"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x24"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x25"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x26"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x27"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x28"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x29"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x30"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x31"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x32"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x33"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x34"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x35"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x36"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x37"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x38"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x39"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x40"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x41"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x42"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x43"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x44"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x45"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x46"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x47"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x48"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x49"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x50"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x51"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x52"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x53"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x54"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x55"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x56"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x57"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x58"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x59"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x60"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x61"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x62"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x63"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x64"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x65"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x66"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x67"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x68"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x69"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x70"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x71"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x72"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x73"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x74"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x75"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x76"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x77"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x78"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x79"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x80"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x81"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x82"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x83"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x84"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x85"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x86"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x87"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x88"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x89"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x90"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x91"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x92"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x93"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x94"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x95"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x96"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x97"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x98"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x99"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xaa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xab"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xac"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xad"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xae"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xaf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xba"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xbb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xbc"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xbd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xbe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xbf"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc0"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc1"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc2"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc3"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc4"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc5"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc6"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc7"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc8"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc9"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xca"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xcb"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xcc"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xcd"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xce"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xcf"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd0"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd1"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd2"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd3"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd4"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd5"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xd7"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd8"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd9"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xda"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xdb"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xdc"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xdd"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xde"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xdf"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe0"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe1"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe2"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe3"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe4"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe5"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe6"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe7"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe8"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe9"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xea"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xeb"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xec"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xed"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xee"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xef"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf0"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf1"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf2"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf3"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf4"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf5"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf7"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf8"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf9"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xfa"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xfb"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xfc"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xfd"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xfe"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xff"
+ }
+ ],
+ "characterSetType": "header"
+ },
+ {
+ "characterSet": [
+ {
+ "isAllowed": false,
+ "metachar": "0x0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xc"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x10"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x11"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x12"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x13"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x14"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x15"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x16"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x17"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x18"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x19"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x20"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x21"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x22"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x23"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x24"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x25"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x26"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x27"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x28"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x29"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x30"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x31"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x32"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x33"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x34"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x35"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x36"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x37"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x38"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x39"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x40"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x41"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x42"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x43"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x44"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x45"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x46"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x47"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x48"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x49"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x50"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x51"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x52"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x53"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x54"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x55"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x56"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x57"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x58"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x59"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x60"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x61"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x62"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x63"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x64"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x65"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x66"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x67"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x68"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x69"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x70"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x71"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x72"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x73"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x74"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x75"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x76"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x77"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x78"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x79"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7f"
+ }
+ ],
+ "characterSetType": "url"
+ },
+ {
+ "characterSet": [
+ {
+ "isAllowed": false,
+ "metachar": "0x0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xc"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x10"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x11"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x12"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x13"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x14"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x15"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x16"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x17"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x18"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x19"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x20"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x21"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x22"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x23"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x24"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x25"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x26"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x27"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x28"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x29"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x30"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x31"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x32"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x33"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x34"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x35"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x36"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x37"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x38"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x39"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x40"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x41"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x42"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x43"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x44"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x45"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x46"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x47"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x48"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x49"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x50"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x51"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x52"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x53"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x54"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x55"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x56"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x57"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x58"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x59"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x60"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x61"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x62"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x63"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x64"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x65"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x66"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x67"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x68"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x69"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x70"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x71"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x72"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x73"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x74"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x75"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x76"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x77"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x78"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x79"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7f"
+ }
+ ],
+ "characterSetType": "parameter-name"
+ },
+ {
+ "characterSet": [
+ {
+ "isAllowed": false,
+ "metachar": "0x0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xc"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x10"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x11"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x12"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x13"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x14"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x15"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x16"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x17"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x18"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x19"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x20"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x21"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x22"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x23"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x24"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x25"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x26"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x27"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x28"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x29"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x30"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x31"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x32"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x33"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x34"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x35"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x36"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x37"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x38"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x39"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x40"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x41"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x42"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x43"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x44"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x45"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x46"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x47"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x48"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x49"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x50"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x51"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x52"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x53"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x54"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x55"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x56"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x57"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x58"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x59"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x60"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x61"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x62"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x63"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x64"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x65"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x66"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x67"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x68"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x69"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x70"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x71"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x72"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x73"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x74"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x75"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x76"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x77"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x78"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x79"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7f"
+ }
+ ],
+ "characterSetType": "parameter-value"
+ },
+ {
+ "characterSet": [
+ {
+ "isAllowed": false,
+ "metachar": "0x0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xc"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x10"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x11"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x12"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x13"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x14"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x15"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x16"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x17"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x18"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x19"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x20"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x21"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x22"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x23"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x24"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x25"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x26"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x27"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x28"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x29"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x30"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x31"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x32"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x33"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x34"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x35"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x36"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x37"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x38"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x39"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x40"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x41"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x42"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x43"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x44"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x45"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x46"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x47"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x48"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x49"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x50"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x51"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x52"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x53"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x54"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x55"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x56"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x57"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x58"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x59"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x60"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x61"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x62"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x63"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x64"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x65"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x66"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x67"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x68"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x69"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x70"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x71"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x72"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x73"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x74"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x75"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x76"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x77"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x78"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x79"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7f"
+ }
+ ],
+ "characterSetType": "xml-content"
+ },
+ {
+ "characterSet": [
+ {
+ "isAllowed": false,
+ "metachar": "0x0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xc"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x10"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x11"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x12"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x13"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x14"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x15"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x16"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x17"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x18"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x19"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x20"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x21"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x22"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x23"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x24"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x25"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x26"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x27"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x28"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x29"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x30"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x31"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x32"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x33"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x34"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x35"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x36"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x37"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x38"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x39"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x40"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x41"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x42"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x43"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x44"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x45"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x46"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x47"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x48"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x49"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x50"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x51"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x52"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x53"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x54"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x55"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x56"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x57"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x58"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x59"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x60"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x61"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x62"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x63"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x64"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x65"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x66"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x67"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x68"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x69"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x70"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x71"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x72"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x73"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x74"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x75"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x76"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x77"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x78"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x79"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7f"
+ }
+ ],
+ "characterSetType": "json-content"
+ },
+ {
+ "characterSet": [
+ {
+ "isAllowed": false,
+ "metachar": "0x0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xc"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x10"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x11"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x12"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x13"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x14"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x15"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x16"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x17"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x18"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x19"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x20"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x21"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x22"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x23"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x24"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x25"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x26"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x27"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x28"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x29"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x30"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x31"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x32"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x33"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x34"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x35"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x36"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x37"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x38"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x39"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x40"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x41"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x42"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x43"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x44"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x45"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x46"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x47"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x48"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x49"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x50"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x51"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x52"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x53"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x54"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x55"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x56"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x57"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x58"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x59"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x60"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x61"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x62"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x63"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x64"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x65"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x66"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x67"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x68"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x69"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x70"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x71"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x72"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x73"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x74"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x75"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x76"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x77"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x78"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x79"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7f"
+ }
+ ],
+ "characterSetType": "gwt-content"
+ },
+ {
+ "characterSet": [
+ {
+ "isAllowed": false,
+ "metachar": "0x0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xc"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x10"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x11"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x12"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x13"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x14"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x15"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x16"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x17"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x18"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x19"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x20"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x21"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x22"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x23"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x24"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x25"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x26"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x27"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x28"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x29"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x30"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x31"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x32"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x33"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x34"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x35"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x36"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x37"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x38"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x39"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x40"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x41"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x42"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x43"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x44"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x45"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x46"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x47"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x48"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x49"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x50"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x51"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x52"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x53"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x54"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x55"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x56"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x57"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x58"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x59"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x60"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x61"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x62"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x63"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x64"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x65"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x66"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x67"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x68"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x69"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x70"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x71"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x72"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x73"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x74"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x75"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x76"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x77"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x78"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x79"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7f"
+ }
+ ],
+ "characterSetType": "plain-text-content"
+ }
+ ],
+ "cookie-settings": {
+ "maximumCookieHeaderLength": "4096"
+ },
+ "cookies": [
+ {
+ "accessibleOnlyThroughTheHttpProtocol": false,
+ "attackSignaturesCheck": true,
+ "enforcementType": "allow",
+ "insertSameSiteAttribute": "lax",
+ "isBase64": false,
+ "maskValueInLogs": false,
+ "name": "*",
+ "performStaging": false,
+ "securedOverHttpsConnection": true,
+ "type": "wildcard",
+ "wildcardOrder": 1
+ }
+ ],
+ "csrf-protection": {
+ "enabled": false
+ },
+ "csrf-urls": [
+ {
+ "enforcementAction": "verify-origin",
+ "method": "POST",
+ "requiredParameters": "ignore",
+ "url": "*",
+ "wildcardOrder": 1
+ }
+ ],
+ "data-guard": {
+ "enabled": false,
+ "enforcementMode": "ignore-urls-in-list"
+ },
+ "description": "new_waf_policy desc",
+ "dos-protection": {
+ "behavioral-dos": {
+ "badActorDetection": {
+ "enableTlsIndexing": true,
+ "enabled": true
+ },
+ "enableHttpSignatures": true,
+ "enableTlsSignatures": false,
+ "mitigationLevel": "standard"
+ },
+ "enabled": false
+ },
+ "enablePassiveMode": false,
+ "enforcementMode": "blocking",
+ "filetypes": [
+ {
+ "allowed": false,
+ "name": "bat"
+ },
+ {
+ "allowed": false,
+ "name": "sav"
+ },
+ {
+ "allowed": false,
+ "name": "pfx"
+ },
+ {
+ "allowed": false,
+ "name": "eml"
+ },
+ {
+ "allowed": false,
+ "name": "wmz"
+ },
+ {
+ "allowed": false,
+ "name": "crt"
+ },
+ {
+ "allowed": false,
+ "name": "nws"
+ },
+ {
+ "allowed": false,
+ "name": "idq"
+ },
+ {
+ "allowed": false,
+ "name": "conf"
+ },
+ {
+ "allowed": false,
+ "name": "dat"
+ },
+ {
+ "allowed": false,
+ "name": "msi"
+ },
+ {
+ "allowed": false,
+ "name": "key"
+ },
+ {
+ "allowed": false,
+ "name": "temp"
+ },
+ {
+ "allowed": false,
+ "name": "idc"
+ },
+ {
+ "allowed": false,
+ "name": "pol"
+ },
+ {
+ "allowed": false,
+ "name": "cer"
+ },
+ {
+ "allowed": false,
+ "name": "pem"
+ },
+ {
+ "allowed": false,
+ "name": "ida"
+ },
+ {
+ "allowed": false,
+ "name": "stm"
+ },
+ {
+ "allowed": false,
+ "name": "log"
+ },
+ {
+ "allowed": false,
+ "name": "sys"
+ },
+ {
+ "allowed": false,
+ "name": "p7c"
+ },
+ {
+ "allowed": false,
+ "name": "cgi"
+ },
+ {
+ "allowed": false,
+ "name": "ini"
+ },
+ {
+ "allowed": false,
+ "name": "shtm"
+ },
+ {
+ "allowed": false,
+ "name": "cfg"
+ },
+ {
+ "allowed": false,
+ "name": "dll"
+ },
+ {
+ "allowed": false,
+ "name": "save"
+ },
+ {
+ "allowed": false,
+ "name": "htr"
+ },
+ {
+ "allowed": false,
+ "name": "hta"
+ },
+ {
+ "allowed": false,
+ "name": "bck"
+ },
+ {
+ "allowed": false,
+ "name": "exe"
+ },
+ {
+ "allowed": false,
+ "name": "old"
+ },
+ {
+ "allowed": false,
+ "name": "p7b"
+ },
+ {
+ "allowed": false,
+ "name": "com"
+ },
+ {
+ "allowed": false,
+ "name": "cmd"
+ },
+ {
+ "allowed": false,
+ "name": "tmp"
+ },
+ {
+ "allowed": false,
+ "name": "reg"
+ },
+ {
+ "allowed": false,
+ "name": "der"
+ },
+ {
+ "allowed": false,
+ "name": "htw"
+ },
+ {
+ "allowed": false,
+ "name": "shtml"
+ },
+ {
+ "allowed": false,
+ "name": "bkp"
+ },
+ {
+ "allowed": false,
+ "name": "p12"
+ },
+ {
+ "allowed": false,
+ "name": "bak"
+ },
+ {
+ "allowed": false,
+ "name": "config"
+ },
+ {
+ "allowed": false,
+ "name": "printer"
+ },
+ {
+ "allowed": false,
+ "name": "bin"
+ },
+ {
+ "allowed": true,
+ "checkPostDataLength": true,
+ "checkQueryStringLength": true,
+ "checkRequestLength": true,
+ "checkUrlLength": true,
+ "name": "*",
+ "performStaging": false,
+ "postDataLength": 4096,
+ "queryStringLength": 2048,
+ "requestLength": 8196,
+ "responseCheck": false,
+ "responseCheckLength": 20000,
+ "type": "wildcard",
+ "urlLength": 1024,
+ "wildcardOrder": 1
+ }
+ ],
+ "fullPath": "/Common/Rating-Based-Template",
+ "general": {
+ "allowedResponseCodes": [
+ 400,
+ 401,
+ 403,
+ 404,
+ 405,
+ 406,
+ 407,
+ 415,
+ 417,
+ 503
+ ],
+ "enableEventCorrelation": true,
+ "enforcementReadinessPeriod": 7,
+ "maskCreditCardNumbersInRequest": true,
+ "pathParameterHandling": "as-parameters",
+ "triggerAsmIruleEvent": "disabled",
+ "trustXff": false,
+ "useDynamicSessionIdInUrl": false
+ },
+ "graphql-profiles": [
+ {
+ "attackSignaturesCheck": true,
+ "defenseAttributes": {
+ "allowIntrospectionQueries": false,
+ "maximumBatchedQueries": "any",
+ "maximumStructureDepth": 10,
+ "maximumTotalLength": "any",
+ "maximumValueLength": "any",
+ "tolerateParsingWarnings": false
+ },
+ "description": "Default GraphQL Profile",
+ "hasIdlFiles": false,
+ "metacharElementCheck": true,
+ "name": "Default",
+ "responseEnforcement": {
+ "blockDisallowedPatterns": false
+ }
+ }
+ ],
+ "gwt-profiles": [
+ {
+ "attackSignaturesCheck": true,
+ "defenseAttributes": {
+ "maximumTotalLengthOfGWTData": 10000,
+ "maximumValueLength": 100,
+ "tolerateGWTParsingWarnings": false
+ },
+ "description": "Default GWT Profile",
+ "metacharElementCheck": true,
+ "name": "Default"
+ }
+ ],
+ "header-settings": {
+ "maximumHttpHeaderLength": "8192"
+ },
+ "headers": [
+ {
+ "allowRepeatedOccurrences": false,
+ "checkSignatures": false,
+ "mandatory": false,
+ "maskValueInLogs": false,
+ "name": "cookie",
+ "type": "explicit"
+ },
+ {
+ "allowRepeatedOccurrences": true,
+ "base64Decoding": false,
+ "checkSignatures": true,
+ "htmlNormalization": false,
+ "mandatory": false,
+ "maskValueInLogs": false,
+ "name": "referer",
+ "normalizationViolations": true,
+ "percentDecoding": false,
+ "type": "explicit",
+ "urlNormalization": true
+ },
+ {
+ "allowRepeatedOccurrences": false,
+ "base64Decoding": false,
+ "checkSignatures": true,
+ "htmlNormalization": false,
+ "mandatory": false,
+ "maskValueInLogs": false,
+ "name": "transfer-encoding",
+ "normalizationViolations": false,
+ "percentDecoding": false,
+ "type": "explicit",
+ "urlNormalization": false
+ },
+ {
+ "allowRepeatedOccurrences": false,
+ "base64Decoding": false,
+ "checkSignatures": true,
+ "htmlNormalization": false,
+ "mandatory": false,
+ "maskValueInLogs": true,
+ "name": "authorization",
+ "normalizationViolations": false,
+ "percentDecoding": true,
+ "type": "explicit",
+ "urlNormalization": false
+ },
+ {
+ "allowRepeatedOccurrences": true,
+ "base64Decoding": false,
+ "checkSignatures": true,
+ "htmlNormalization": false,
+ "mandatory": false,
+ "maskValueInLogs": false,
+ "name": "*",
+ "normalizationViolations": false,
+ "percentDecoding": true,
+ "type": "wildcard",
+ "urlNormalization": false,
+ "wildcardOrder": 1
+ }
+ ],
+ "ip-intelligence": {
+ "enabled": true,
+ "ipIntelligenceCategories": [
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Spam Sources"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Windows Exploits"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Web Attacks"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "BotNets"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Scanners"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Denial of Service"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Infected Sources"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Phishing Proxies"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Anonymous Proxy"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Cloud-based Services"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Mobile Threats"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Tor Proxies"
+ }
+ ]
+ },
+ "json-profiles": [
+ {
+ "defenseAttributes": {
+ "maximumArrayLength": 1000,
+ "maximumStructureDepth": 10,
+ "maximumTotalLengthOfJSONData": 10000,
+ "maximumValueLength": 100,
+ "tolerateJSONParsingWarnings": false
+ },
+ "description": "Default JSON Profile",
+ "handleJsonValuesAsParameters": true,
+ "hasValidationFiles": false,
+ "name": "Default",
+ "validationFiles": []
+ }
+ ],
+ "login-enforcement": {
+ "expirationTimePeriod": "disabled"
+ },
+ "methods": [
+ {
+ "actAsMethod": "POST",
+ "name": "PATCH"
+ },
+ {
+ "actAsMethod": "GET",
+ "name": "DELETE"
+ },
+ {
+ "actAsMethod": "GET",
+ "name": "OPTIONS"
+ },
+ {
+ "actAsMethod": "GET",
+ "name": "HEAD"
+ },
+ {
+ "actAsMethod": "POST",
+ "name": "PUT"
+ },
+ {
+ "actAsMethod": "GET",
+ "name": "GET"
+ },
+ {
+ "actAsMethod": "POST",
+ "name": "POST"
+ }
+ ],
+ "name": "new_waf_policy",
+ "parameters": [
+ {
+ "allowEmptyValue": true,
+ "allowRepeatedParameterName": false,
+ "attackSignaturesCheck": true,
+ "checkMaxValueLength": false,
+ "checkMetachars": true,
+ "isBase64": false,
+ "isCookie": false,
+ "isHeader": false,
+ "level": "global",
+ "metacharsOnParameterValueCheck": true,
+ "name": "*",
+ "parameterLocation": "any",
+ "performStaging": false,
+ "sensitiveParameter": false,
+ "type": "wildcard",
+ "valueType": "auto-detect",
+ "wildcardOrder": 1
+ }
+ ],
+ "performStaging": true,
+ "policy-builder": {
+ "enableFullPolicyInspection": true,
+ "enableTrustedTrafficSiteChangeTracking": true,
+ "enableUntrustedTrafficSiteChangeTracking": true,
+ "inactiveEntityInactivityDurationInDays": 90,
+ "learnFromResponses": false,
+ "learnInactiveEntities": false,
+ "learnOnlyFromNonBotTraffic": true,
+ "learningMode": "on-demand",
+ "responseStatusCodes": [
+ "2xx",
+ "3xx",
+ "1xx"
+ ],
+ "trafficTighten": {
+ "maxModificationSuggestionScore": 50,
+ "minDaysBetweenSamples": 1,
+ "totalRequests": 15000
+ },
+ "trustAllIps": false,
+ "trustedTrafficLoosen": {
+ "differentSources": 1,
+ "maxDaysBetweenSamples": 7,
+ "minHoursBetweenSamples": 0
+ },
+ "trustedTrafficSiteChangeTracking": {
+ "differentSources": 1,
+ "maxDaysBetweenSamples": 7,
+ "minMinutesBetweenSamples": 0
+ },
+ "untrustedTrafficLoosen": {
+ "differentSources": 20,
+ "maxDaysBetweenSamples": 7,
+ "minHoursBetweenSamples": 1
+ },
+ "untrustedTrafficSiteChangeTracking": {
+ "differentSources": 10,
+ "maxDaysBetweenSamples": 7,
+ "minMinutesBetweenSamples": 20
+ }
+ },
+ "policy-builder-central-configuration": {
+ "buildingMode": "local",
+ "eventCorrelationMode": "local"
+ },
+ "policy-builder-cookie": {
+ "collapseCookiesIntoOneEntity": false,
+ "enforceUnmodifiedCookies": false,
+ "learnExplicitCookies": "never",
+ "maximumCookies": 100
+ },
+ "policy-builder-filetype": {
+ "learnExplicitFiletypes": "never",
+ "maximumFileTypes": 100
+ },
+ "policy-builder-header": {
+ "maximumHosts": 10000,
+ "validHostNames": false
+ },
+ "policy-builder-parameter": {
+ "classifyParameters": false,
+ "collapseParametersIntoOneEntity": false,
+ "dynamicParameters": {
+ "allHiddenFields": false,
+ "formParameters": false,
+ "linkParameters": false,
+ "uniqueValueSets": 10
+ },
+ "learnExplicitParameters": "never",
+ "maximumParameters": 10000,
+ "parameterLearningLevel": "global",
+ "parametersIntegerValue": false
+ },
+ "policy-builder-redirection-protection": {
+ "learnExplicitRedirectionDomains": "never",
+ "maximumRedirectionDomains": 100
+ },
+ "policy-builder-server-technologies": {
+ "enableServerTechnologiesDetection": false
+ },
+ "policy-builder-sessions-and-logins": {
+ "learnLoginPage": false
+ },
+ "policy-builder-url": {
+ "classifyUrls": false,
+ "classifyWebsocketUrls": false,
+ "collapseUrlsIntoOneEntity": false,
+ "learnExplicitUrls": "never",
+ "learnExplicitWebsocketUrls": "never",
+ "learnMethodsOnUrls": false,
+ "maximumUrls": 100,
+ "maximumWebsocketUrls": 100,
+ "wildcardUrlFiletypes": [
+ "swf",
+ "wav",
+ "bmp",
+ "gif",
+ "pcx",
+ "pdf",
+ "png",
+ "jpeg",
+ "ico",
+ "jpg"
+ ]
+ },
+ "protocolIndependent": true,
+ "redirection-protection": {
+ "redirectionProtectionEnabled": false
+ },
+ "response-pages": [
+ {
+ "responseActionType": "soap-fault",
+ "responsePageType": "xml"
+ },
+ {
+ "responseActionType": "default",
+ "responsePageType": "graphql"
+ },
+ {
+ "responseActionType": "default",
+ "responsePageType": "default"
+ },
+ {
+ "responseActionType": "default",
+ "responsePageType": "captcha"
+ },
+ {
+ "ajaxActionType": "alert-popup",
+ "ajaxPopupMessage": "Login Failed. Username or password is incorrect. Please try to log in again.",
+ "responsePageType": "failed-login-honeypot-ajax"
+ },
+ {
+ "ajaxActionType": "alert-popup",
+ "ajaxPopupMessage": "The requested URL was rejected. Please consult with your administrator. Your support ID is: <%TS.request.ID()%>",
+ "responsePageType": "ajax-login"
+ },
+ {
+ "responseActionType": "default",
+ "responsePageType": "hijack"
+ },
+ {
+ "responseActionType": "default",
+ "responsePageType": "captcha-fail"
+ },
+ {
+ "grpcStatusCode": "UNKNOWN",
+ "grpcStatusMessage": "The request was rejected. Please consult with your administrator. Your support ID is: <%TS.request.ID()%>",
+ "responsePageType": "grpc"
+ },
+ {
+ "responseActionType": "default",
+ "responsePageType": "persistent-flow"
+ },
+ {
+ "ajaxActionType": "alert-popup",
+ "ajaxEnabled": false,
+ "ajaxPopupMessage": "The requested URL was rejected. Please consult with your administrator. Your support ID is: <%TS.request.ID()%>",
+ "responsePageType": "ajax"
+ },
+ {
+ "responseActionType": "default",
+ "responsePageType": "failed-login-honeypot"
+ },
+ {
+ "responseActionType": "default",
+ "responsePageType": "mobile"
+ }
+ ],
+ "sensitive-parameters": [
+ {
+ "name": "password"
+ }
+ ],
+ "signature-sets": [
+ {
+ "name": "High Accuracy Signatures",
+ "alarm": true,
+ "block": false,
+ "learn": true
+ },
+ {
+ "name": "All Signatures",
+ "alarm": true,
+ "block": false,
+ "learn": true
+ }
+ ],
+ "signature-settings": {
+ "attackSignatureFalsePositiveMode": "disabled",
+ "minimumAccuracyForAutoAddedSignatures": "high",
+ "placeSignaturesInStaging": false,
+ "signatureStaging": false,
+ "stagingCertificationDatetime": ""
+ },
+ "softwareVersion": "17.0.0",
+ "ssrf-hosts": [
+ {
+ "action": "disallow",
+ "host": "*.burpcollaborator.net"
+ },
+ {
+ "action": "disallow",
+ "host": "metadata.google.internal"
+ },
+ {
+ "action": "disallow",
+ "host": "localhost"
+ },
+ {
+ "action": "disallow",
+ "host": "rancher-metadata"
+ },
+ {
+ "action": "disallow",
+ "host": "127.0.0.0/24"
+ },
+ {
+ "action": "disallow",
+ "host": "192.0.2.0/24"
+ },
+ {
+ "action": "disallow",
+ "host": "198.51.100.0/24"
+ },
+ {
+ "action": "disallow",
+ "host": "203.0.113.0/24"
+ },
+ {
+ "action": "disallow",
+ "host": "169.254.0.0/16"
+ },
+ {
+ "action": "disallow",
+ "host": "192.168.0.0/16"
+ },
+ {
+ "action": "disallow",
+ "host": "172.16.0.0/12"
+ },
+ {
+ "action": "disallow",
+ "host": "fe80::/10"
+ },
+ {
+ "action": "disallow",
+ "host": "10.0.0.0/8"
+ },
+ {
+ "action": "disallow",
+ "host": "127.0.0.0/8"
+ },
+ {
+ "action": "disallow",
+ "host": "0.0.0.0"
+ },
+ {
+ "action": "disallow",
+ "host": "0:0:0:0:0:ffff:7f00:1"
+ },
+ {
+ "action": "disallow",
+ "host": "100.100.100.200"
+ },
+ {
+ "action": "disallow",
+ "host": "168.63.129.16"
+ },
+ {
+ "action": "disallow",
+ "host": "169.254.169.254"
+ },
+ {
+ "action": "disallow",
+ "host": "192.0.0.192"
+ },
+ {
+ "action": "disallow",
+ "host": "::"
+ },
+ {
+ "action": "disallow",
+ "host": "::1"
+ },
+ {
+ "action": "resolve",
+ "host": "*"
+ }
+ ],
+ "template": {
+ "name": ""
+ },
+ "threat-campaign-settings": {
+ "threatCampaignEnforcementReadinessPeriod": 1,
+ "threatCampaignStaging": false
+ },
+ "type": "security",
+ "urls": [
+ {
+ "attackSignaturesCheck": true,
+ "clickjackingProtection": false,
+ "description": "",
+ "disallowFileUploadOfExecutables": true,
+ "html5CrossOriginRequestsEnforcement": {
+ "enforcementMode": "enforce"
+ },
+ "isAllowed": true,
+ "mandatoryBody": false,
+ "metacharsOnUrlCheck": true,
+ "method": "*",
+ "methodsOverrideOnUrlCheck": false,
+ "name": "*",
+ "performStaging": false,
+ "protocol": "http",
+ "type": "wildcard",
+ "urlContentProfiles": [
+ {
+ "headerName": "*",
+ "headerOrder": "default",
+ "headerValue": "*",
+ "type": "apply-value-and-content-signatures"
+ },
+ {
+ "headerName": "Content-Type",
+ "headerOrder": "1",
+ "headerValue": "*form*",
+ "type": "form-data"
+ },
+ {
+ "contentProfile": {
+ "name": "Default"
+ },
+ "headerName": "Content-Type",
+ "headerOrder": "2",
+ "headerValue": "*json*",
+ "type": "json"
+ },
+ {
+ "contentProfile": {
+ "name": "Default"
+ },
+ "headerName": "Content-Type",
+ "headerOrder": "3",
+ "headerValue": "*xml*",
+ "type": "xml"
+ }
+ ],
+ "wildcardIncludesSlash": true,
+ "wildcardOrder": 2
+ }
+ ],
+ "xml-profiles": [
+ {
+ "attachmentsInSoapMessages": false,
+ "attackSignaturesCheck": true,
+ "defenseAttributes": {
+ "allowCDATA": false,
+ "allowDTDs": false,
+ "allowExternalReferences": false,
+ "allowProcessingInstructions": true,
+ "maximumAttributeValueLength": 1024,
+ "maximumAttributesPerElement": 16,
+ "maximumChildrenPerElement": 1024,
+ "maximumDocumentDepth": 32,
+ "maximumDocumentSize": 1024000,
+ "maximumElements": 65536,
+ "maximumNSDeclarations": 64,
+ "maximumNameLength": 256,
+ "maximumNamespaceLength": 256,
+ "tolerateCloseTagShorthand": false,
+ "tolerateLeadingWhiteSpace": false,
+ "tolerateNumericNames": false
+ },
+ "description": "Default XML Profile",
+ "enableWss": false,
+ "followSchemaLinks": false,
+ "inspectSoapAttachments": false,
+ "metacharAttributeCheck": false,
+ "metacharElementCheck": true,
+ "name": "Default",
+ "useXmlResponsePage": false,
+ "validationFiles": [],
+ "validationSoapActionHeader": false
+ }
+ ]
+ }
+ },
+ "enforcement_mode": "blocking",
+ "id": "1a4453fe-b37a-4212-a813-a3d2f789dad1",
+ "last_modified": "2024-07-17T11:59:25.304421Z",
+ "name": "new_waf_policy"
+}
\ No newline at end of file
diff --git a/internal/provider/fixtures/getWafUpdated.json b/internal/provider/fixtures/getWafUpdated.json
new file mode 100644
index 0000000..4ccc049
--- /dev/null
+++ b/internal/provider/fixtures/getWafUpdated.json
@@ -0,0 +1,6583 @@
+{
+ "_links": {
+ "self": {
+ "href": "/api/v1/spaces/default/security/waf-policies/1a4453fe-b37a-4212-a813-a3d2f789dad1"
+ }
+ },
+ "application_language": "utf-8",
+ "created_by": "",
+ "created_time": "2024-07-17T11:59:25.304423Z",
+ "declaration": {
+ "policy": {
+ "app-protection": {
+ "enabled": true
+ },
+ "applicationLanguage": "utf-8",
+ "behavioral-enforcement": {
+ "behavioralEnforcementViolations": [
+ {
+ "name": "VIOL_GEOLOCATION"
+ },
+ {
+ "name": "VIOL_URL"
+ },
+ {
+ "name": "VIOL_FILETYPE"
+ },
+ {
+ "name": "VIOL_BLACKLISTED_IP"
+ },
+ {
+ "name": "VIOL_THREAT_CAMPAIGN"
+ },
+ {
+ "name": "VIOL_BLOCKING_CONDITION"
+ },
+ {
+ "name": "VIOL_THREAT_ANALYSIS"
+ },
+ {
+ "name": "VIOL_CONVICTION"
+ }
+ ],
+ "enableBehavioralEnforcement": false,
+ "enableBlockingCveSignatures": true,
+ "enableBlockingHighAccuracySignatures": true,
+ "enableBlockingLikelyMaliciousTransactions": true,
+ "enableBlockingSuspiciousTransactions": false,
+ "enableBlockingViolations": true
+ },
+ "blocking-settings": {
+ "evasions": [
+ {
+ "description": "Trailing slash",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Trailing dot",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Semicolon path parameters",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Bad unescape",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Apache whitespace",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Bare byte decoding",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "IIS Unicode codepoints",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "IIS backslashes",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "%u decoding",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Multiple decoding",
+ "enabled": true,
+ "learn": true,
+ "maxDecodingPasses": 2
+ },
+ {
+ "description": "Directory traversals",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Multiple slashes",
+ "enabled": false,
+ "learn": true
+ }
+ ],
+ "http-protocols": [
+ {
+ "description": "Check maximum number of cookies",
+ "enabled": false,
+ "learn": true,
+ "maxCookies": 50
+ },
+ {
+ "description": "Unescaped space in URL",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Multiple host headers",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Check maximum number of parameters",
+ "enabled": true,
+ "learn": true,
+ "maxParams": 100
+ },
+ {
+ "description": "Bad host header value",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Check maximum number of headers",
+ "enabled": true,
+ "learn": true,
+ "maxHeaders": 100
+ },
+ {
+ "description": "Unparsable request content",
+ "enabled": true
+ },
+ {
+ "description": "High ASCII characters in headers",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Null in request",
+ "enabled": true
+ },
+ {
+ "description": "Bad HTTP version",
+ "enabled": true
+ },
+ {
+ "description": "Content length should be a positive number",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Host header contains IP address",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "CRLF characters before request start",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "No Host header in HTTP/1.1 request",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Bad multipart parameters parsing",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Bad multipart/form-data request parsing",
+ "enabled": true,
+ "learn": false
+ },
+ {
+ "description": "Body in GET or HEAD requests",
+ "enabled": false,
+ "learn": false
+ },
+ {
+ "description": "Chunked request with Content-Length header",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Several Content-Length headers",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "Header name with no header value",
+ "enabled": true,
+ "learn": true
+ },
+ {
+ "description": "POST request with Content-Length: 0",
+ "enabled": false,
+ "learn": true
+ }
+ ],
+ "violations": [
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Failed to convert character",
+ "name": "VIOL_ENCODING"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal redirection attempt",
+ "learn": true,
+ "name": "VIOL_REDIRECT"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal parameter",
+ "learn": true,
+ "name": "VIOL_PARAMETER"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal cross-origin request",
+ "learn": true,
+ "name": "VIOL_CROSS_ORIGIN_REQUEST"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Brute Force: Maximum login attempts are exceeded",
+ "name": "VIOL_BRUTE_FORCE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal URL length",
+ "learn": true,
+ "name": "VIOL_URL_LENGTH"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Login URL bypassed",
+ "learn": true,
+ "name": "VIOL_LOGIN_URL_BYPASSED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal parameter data type",
+ "learn": true,
+ "name": "VIOL_PARAMETER_DATA_TYPE"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Unauthorized access attempt",
+ "name": "VIOL_ACCESS_UNAUTHORIZED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal attachment in SOAP message",
+ "learn": true,
+ "name": "VIOL_XML_SOAP_ATTACHMENT"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal meta character in parameter name",
+ "learn": true,
+ "name": "VIOL_PARAMETER_NAME_METACHAR"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Host name mismatch",
+ "name": "VIOL_HOSTNAME_MISMATCH"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Missing Access Token",
+ "name": "VIOL_ACCESS_MISSING"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Illegal session ID in URL",
+ "learn": true,
+ "name": "VIOL_DYNAMIC_SESSION"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "GraphQL disallowed pattern in response",
+ "name": "VIOL_GRAPHQL_ERROR_RESPONSE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal dynamic parameter value",
+ "learn": true,
+ "name": "VIOL_PARAMETER_DYNAMIC_VALUE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Data Guard: Information leakage detected",
+ "learn": true,
+ "name": "VIOL_DATA_GUARD"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Malformed JSON data",
+ "learn": true,
+ "name": "VIOL_JSON_MALFORMED"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Leaked Credentials Detection",
+ "name": "VIOL_LEAKED_CREDENTIALS"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal cookie length",
+ "learn": true,
+ "name": "VIOL_COOKIE_LENGTH"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal query string length",
+ "learn": true,
+ "name": "VIOL_QUERY_STRING_LENGTH"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "SOAP method not allowed",
+ "learn": true,
+ "name": "VIOL_XML_SOAP_METHOD"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal parameter numeric value",
+ "learn": true,
+ "name": "VIOL_PARAMETER_NUMERIC_VALUE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal repeated header",
+ "learn": true,
+ "name": "VIOL_HEADER_REPEATED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal empty parameter value",
+ "learn": true,
+ "name": "VIOL_PARAMETER_EMPTY_VALUE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal file type",
+ "learn": true,
+ "name": "VIOL_FILETYPE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Access from disallowed User/Session/IP/Device ID",
+ "name": "VIOL_SESSION_AWARENESS"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Login URL expired",
+ "learn": true,
+ "name": "VIOL_LOGIN_URL_EXPIRED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "XML data does not comply with format settings",
+ "learn": true,
+ "name": "VIOL_XML_FORMAT"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Mandatory parameter is missing",
+ "name": "VIOL_MANDATORY_PARAMETER"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal request content type",
+ "learn": true,
+ "name": "VIOL_URL_CONTENT_TYPE"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Bot Client Detected",
+ "learn": true,
+ "name": "VIOL_BOT_CLIENT"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "HTTP protocol compliance failed",
+ "learn": true,
+ "name": "VIOL_HTTP_PROTOCOL"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal parameter array value",
+ "name": "VIOL_PARAMETER_ARRAY_VALUE"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "GWT data does not comply with format settings",
+ "learn": true,
+ "name": "VIOL_GWT_FORMAT"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "IP is blacklisted",
+ "name": "VIOL_BLACKLISTED_IP"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Malformed XML data",
+ "learn": true,
+ "name": "VIOL_XML_MALFORMED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Null in multi-part parameter value",
+ "learn": true,
+ "name": "VIOL_PARAMETER_MULTIPART_NULL_VALUE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Server-side access to disallowed host",
+ "name": "VIOL_SERVER_SIDE_HOST"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Expired timestamp",
+ "learn": true,
+ "name": "VIOL_COOKIE_EXPIRED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal meta character in value",
+ "learn": true,
+ "name": "VIOL_PARAMETER_VALUE_METACHAR"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Illegal flow to URL",
+ "learn": true,
+ "name": "VIOL_FLOW"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "CSRF attack detected",
+ "name": "VIOL_CSRF"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Illegal entry point",
+ "learn": true,
+ "name": "VIOL_FLOW_ENTRY_POINT"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Mandatory HTTP header is missing",
+ "learn": true,
+ "name": "VIOL_MANDATORY_HEADER"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Parameter value does not comply with regular expression",
+ "learn": true,
+ "name": "VIOL_PARAMETER_VALUE_REGEXP"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Illegal query string or POST data",
+ "learn": true,
+ "name": "VIOL_FLOW_DISALLOWED_INPUT"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "JSON data does not comply with JSON schema",
+ "name": "VIOL_JSON_SCHEMA"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal repeated parameter name",
+ "learn": true,
+ "name": "VIOL_PARAMETER_REPEATED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal parameter value length",
+ "learn": true,
+ "name": "VIOL_PARAMETER_VALUE_LENGTH"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Web Services Security failure",
+ "learn": true,
+ "name": "VIOL_XML_WEB_SERVICES_SECURITY"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "GraphQL data does not comply with format settings",
+ "learn": true,
+ "name": "VIOL_GRAPHQL_FORMAT"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Virus detected",
+ "learn": true,
+ "name": "VIOL_VIRUS"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal header length",
+ "learn": true,
+ "name": "VIOL_HEADER_LENGTH"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Malformed GWT data",
+ "learn": true,
+ "name": "VIOL_GWT_MALFORMED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal parameter location",
+ "name": "VIOL_PARAMETER_LOCATION"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal meta character in header",
+ "learn": true,
+ "name": "VIOL_HEADER_METACHAR"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "GraphQL introspection query",
+ "name": "VIOL_GRAPHQL_INTROSPECTION_QUERY"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Evasion technique detected",
+ "learn": true,
+ "name": "VIOL_EVASION"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Malformed GraphQL data",
+ "learn": true,
+ "name": "VIOL_GRAPHQL_MALFORMED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "JSON data does not comply with format settings",
+ "learn": true,
+ "name": "VIOL_JSON_FORMAT"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Disallowed file upload content detected",
+ "learn": true,
+ "name": "VIOL_FILE_UPLOAD"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Mitigation action determined by Threat Analysis Platform",
+ "name": "VIOL_THREAT_ANALYSIS"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal static parameter value",
+ "learn": true,
+ "name": "VIOL_PARAMETER_STATIC_VALUE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "XML data does not comply with schema or WSDL document",
+ "learn": true,
+ "name": "VIOL_XML_SCHEMA"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Unsupported browser",
+ "learn": true,
+ "name": "VIOL_BROWSER"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal method",
+ "learn": true,
+ "name": "VIOL_METHOD"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal Base64 value",
+ "learn": true,
+ "name": "VIOL_PARAMETER_VALUE_BASE64"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "ASM Cookie Hijacking",
+ "learn": true,
+ "name": "VIOL_ASM_COOKIE_HIJACKING"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "DataSafe Data Integrity",
+ "name": "VIOL_DATA_INTEGRITY"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal URL",
+ "learn": true,
+ "name": "VIOL_URL"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Threat Campaign detected",
+ "name": "VIOL_THREAT_CAMPAIGN"
+ },
+ {
+ "description": "Attack signature detected",
+ "name": "VIOL_ATTACK_SIGNATURE"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal meta character in URL",
+ "learn": true,
+ "name": "VIOL_URL_METACHAR"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Access from malicious IP address",
+ "name": "VIOL_MALICIOUS_IP"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Request length exceeds defined buffer size",
+ "learn": true,
+ "name": "VIOL_REQUEST_MAX_LENGTH"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Bad Actor Detected",
+ "name": "VIOL_MALICIOUS_DEVICE"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Modified WAF cookie",
+ "learn": true,
+ "name": "VIOL_ASM_COOKIE_MODIFIED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Violation Rating Need Examination detected",
+ "name": "VIOL_RATING_NEED_EXAMINATION"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "CSRF authentication expired",
+ "learn": true,
+ "name": "VIOL_CSRF_EXPIRED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal request length",
+ "learn": true,
+ "name": "VIOL_REQUEST_LENGTH"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Blocking Condition Detected",
+ "name": "VIOL_BLOCKING_CONDITION"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Modified domain cookie(s)",
+ "learn": true,
+ "name": "VIOL_COOKIE_MODIFIED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Mandatory request body is missing",
+ "name": "VIOL_MANDATORY_REQUEST_BODY"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Access token does not comply with the profile requirements",
+ "name": "VIOL_ACCESS_INVALID"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Illegal host name",
+ "name": "VIOL_HOSTNAME"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Cookie not RFC-compliant",
+ "learn": true,
+ "name": "VIOL_COOKIE_MALFORMED"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Disallowed file upload content detected in body",
+ "name": "VIOL_FILE_UPLOAD_IN_BODY"
+ },
+ {
+ "alarm": true,
+ "block": false,
+ "description": "Illegal POST data length",
+ "learn": true,
+ "name": "VIOL_POST_DATA_LENGTH"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Access from disallowed Geolocation",
+ "learn": true,
+ "name": "VIOL_GEOLOCATION"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Illegal number of mandatory parameters",
+ "learn": true,
+ "name": "VIOL_FLOW_MANDATORY_PARAMS"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Violation Rating Threat detected",
+ "name": "VIOL_RATING_THREAT"
+ },
+ {
+ "alarm": true,
+ "block": true,
+ "description": "Illegal HTTP status in response",
+ "learn": true,
+ "name": "VIOL_HTTP_RESPONSE_STATUS"
+ },
+ {
+ "alarm": false,
+ "block": false,
+ "description": "Malformed Access Token",
+ "name": "VIOL_ACCESS_MALFORMED"
+ }
+ ],
+ "web-services-securities": [
+ {
+ "description": "UnSigned Timestamp",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Timestamp expiration is too far in the future",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Expired Timestamp",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Invalid Timestamp",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Missing Timestamp",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Verification Error",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Signing Error",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Encryption Error",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Decryption Error",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Certificate Error",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Certificate Expired",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Malformed Error",
+ "enabled": false,
+ "learn": true
+ },
+ {
+ "description": "Internal Error",
+ "enabled": false,
+ "learn": true
+ }
+ ]
+ },
+ "bot-defense": {
+ "mitigations": {
+ "classes": [
+ {
+ "action": "block",
+ "name": "malicious-bot"
+ },
+ {
+ "action": "ignore",
+ "name": "suspicious-browser"
+ },
+ {
+ "action": "ignore",
+ "name": "untrusted-bot"
+ },
+ {
+ "action": "ignore",
+ "name": "trusted-bot"
+ },
+ {
+ "action": "detect",
+ "name": "browser"
+ },
+ {
+ "action": "ignore",
+ "name": "unknown"
+ }
+ ]
+ },
+ "settings": {
+ "caseSensitiveHttpHeaders": true,
+ "isEnabled": true
+ }
+ },
+ "brute-force-attack-preventions": [
+ {
+ "bruteForceProtectionForAllLoginPages": false,
+ "captchaBypassCriteria": {
+ "action": "alarm-and-drop",
+ "enabled": false,
+ "threshold": 5
+ },
+ "clientSideIntegrityBypassCriteria": {
+ "action": "alarm-and-captcha",
+ "threshold": 3
+ },
+ "detectionCriteria": {
+ "action": "alarm",
+ "credentialsStuffingMatchesReached": 100,
+ "failedLoginAttemptsRateReached": 100
+ },
+ "leakedCredentialsCriteria": {
+ "action": "alarm-and-blocking-page"
+ },
+ "loginAttemptsFromTheSameDeviceId": {
+ "action": "alarm",
+ "threshold": 3
+ },
+ "loginAttemptsFromTheSameIp": {
+ "action": "alarm-and-blocking-page",
+ "enabled": true,
+ "threshold": 20
+ },
+ "loginAttemptsFromTheSameUser": {
+ "action": "alarm",
+ "enabled": true,
+ "threshold": 3
+ },
+ "measurementPeriod": 900,
+ "preventionDuration": "3600",
+ "reEnableLoginAfter": 3600,
+ "sourceBasedProtectionDetectionPeriod": 3600
+ }
+ ],
+ "caseInsensitive": true,
+ "character-sets": [
+ {
+ "characterSet": [
+ {
+ "isAllowed": false,
+ "metachar": "0x0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xc"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x10"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x11"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x12"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x13"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x14"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x15"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x16"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x17"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x18"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x19"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x20"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x21"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x22"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x23"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x24"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x25"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x26"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x27"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x28"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x29"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x30"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x31"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x32"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x33"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x34"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x35"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x36"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x37"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x38"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x39"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x40"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x41"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x42"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x43"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x44"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x45"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x46"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x47"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x48"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x49"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x50"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x51"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x52"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x53"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x54"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x55"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x56"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x57"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x58"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x59"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x60"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x61"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x62"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x63"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x64"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x65"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x66"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x67"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x68"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x69"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x70"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x71"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x72"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x73"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x74"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x75"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x76"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x77"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x78"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x79"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x80"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x81"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x82"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x83"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x84"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x85"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x86"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x87"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x88"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x89"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x90"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x91"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x92"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x93"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x94"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x95"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x96"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x97"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x98"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x99"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xaa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xab"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xac"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xad"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xae"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xaf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xba"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xbb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xbc"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xbd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xbe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xbf"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc0"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc1"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc2"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc3"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc4"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc5"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc6"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc7"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc8"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xc9"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xca"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xcb"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xcc"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xcd"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xce"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xcf"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd0"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd1"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd2"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd3"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd4"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd5"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xd7"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd8"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd9"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xda"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xdb"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xdc"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xdd"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xde"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xdf"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe0"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe1"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe2"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe3"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe4"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe5"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe6"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe7"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe8"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xe9"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xea"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xeb"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xec"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xed"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xee"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xef"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf0"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf1"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf2"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf3"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf4"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf5"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf7"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf8"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xf9"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xfa"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xfb"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xfc"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xfd"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xfe"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xff"
+ }
+ ],
+ "characterSetType": "header"
+ },
+ {
+ "characterSet": [
+ {
+ "isAllowed": false,
+ "metachar": "0x0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xc"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x10"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x11"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x12"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x13"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x14"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x15"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x16"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x17"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x18"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x19"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x20"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x21"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x22"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x23"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x24"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x25"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x26"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x27"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x28"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x29"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x30"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x31"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x32"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x33"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x34"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x35"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x36"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x37"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x38"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x39"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x40"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x41"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x42"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x43"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x44"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x45"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x46"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x47"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x48"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x49"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x50"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x51"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x52"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x53"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x54"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x55"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x56"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x57"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x58"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x59"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x60"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x61"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x62"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x63"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x64"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x65"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x66"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x67"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x68"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x69"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x70"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x71"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x72"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x73"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x74"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x75"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x76"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x77"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x78"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x79"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7f"
+ }
+ ],
+ "characterSetType": "url"
+ },
+ {
+ "characterSet": [
+ {
+ "isAllowed": false,
+ "metachar": "0x0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xc"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x10"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x11"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x12"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x13"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x14"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x15"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x16"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x17"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x18"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x19"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x20"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x21"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x22"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x23"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x24"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x25"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x26"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x27"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x28"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x29"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x30"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x31"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x32"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x33"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x34"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x35"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x36"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x37"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x38"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x39"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x40"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x41"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x42"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x43"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x44"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x45"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x46"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x47"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x48"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x49"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x50"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x51"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x52"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x53"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x54"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x55"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x56"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x57"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x58"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x59"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x60"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x61"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x62"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x63"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x64"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x65"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x66"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x67"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x68"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x69"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x70"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x71"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x72"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x73"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x74"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x75"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x76"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x77"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x78"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x79"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7f"
+ }
+ ],
+ "characterSetType": "parameter-name"
+ },
+ {
+ "characterSet": [
+ {
+ "isAllowed": false,
+ "metachar": "0x0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xc"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x10"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x11"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x12"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x13"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x14"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x15"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x16"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x17"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x18"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x19"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x20"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x21"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x22"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x23"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x24"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x25"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x26"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x27"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x28"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x29"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x30"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x31"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x32"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x33"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x34"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x35"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x36"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x37"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x38"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x39"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x40"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x41"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x42"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x43"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x44"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x45"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x46"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x47"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x48"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x49"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x50"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x51"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x52"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x53"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x54"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x55"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x56"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x57"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x58"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x59"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x60"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x61"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x62"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x63"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x64"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x65"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x66"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x67"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x68"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x69"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x70"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x71"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x72"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x73"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x74"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x75"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x76"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x77"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x78"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x79"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7f"
+ }
+ ],
+ "characterSetType": "parameter-value"
+ },
+ {
+ "characterSet": [
+ {
+ "isAllowed": false,
+ "metachar": "0x0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xc"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0xd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x10"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x11"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x12"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x13"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x14"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x15"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x16"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x17"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x18"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x19"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x20"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x21"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x22"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x23"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x24"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x25"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x26"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x27"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x28"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x29"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x30"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x31"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x32"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x33"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x34"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x35"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x36"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x37"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x38"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x39"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x40"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x41"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x42"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x43"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x44"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x45"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x46"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x47"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x48"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x49"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x50"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x51"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x52"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x53"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x54"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x55"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x56"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x57"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x58"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x59"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x60"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x61"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x62"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x63"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x64"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x65"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x66"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x67"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x68"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x69"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x70"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x71"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x72"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x73"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x74"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x75"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x76"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x77"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x78"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x79"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7f"
+ }
+ ],
+ "characterSetType": "xml-content"
+ },
+ {
+ "characterSet": [
+ {
+ "isAllowed": false,
+ "metachar": "0x0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xc"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x10"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x11"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x12"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x13"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x14"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x15"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x16"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x17"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x18"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x19"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x20"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x21"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x22"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x23"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x24"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x25"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x26"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x27"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x28"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x29"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x30"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x31"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x32"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x33"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x34"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x35"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x36"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x37"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x38"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x39"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x40"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x41"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x42"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x43"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x44"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x45"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x46"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x47"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x48"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x49"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x50"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x51"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x52"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x53"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x54"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x55"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x56"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x57"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x58"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x59"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x60"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x61"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x62"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x63"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x64"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x65"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x66"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x67"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x68"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x69"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x70"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x71"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x72"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x73"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x74"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x75"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x76"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x77"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x78"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x79"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7f"
+ }
+ ],
+ "characterSetType": "json-content"
+ },
+ {
+ "characterSet": [
+ {
+ "isAllowed": false,
+ "metachar": "0x0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xc"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x10"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x11"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x12"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x13"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x14"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x15"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x16"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x17"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x18"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x19"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x20"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x21"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x22"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x23"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x24"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x25"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x26"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x27"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x28"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x29"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x30"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x31"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x32"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x33"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x34"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x35"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x36"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x37"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x38"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x39"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x40"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x41"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x42"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x43"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x44"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x45"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x46"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x47"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x48"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x49"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x50"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x51"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x52"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x53"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x54"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x55"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x56"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x57"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x58"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x59"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5f"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x60"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x61"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x62"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x63"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x64"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x65"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x66"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x67"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x68"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x69"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x70"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x71"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x72"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x73"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x74"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x75"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x76"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x77"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x78"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x79"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7f"
+ }
+ ],
+ "characterSetType": "gwt-content"
+ },
+ {
+ "characterSet": [
+ {
+ "isAllowed": false,
+ "metachar": "0x0"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x2"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x3"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x4"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x5"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x6"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x7"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x8"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x9"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xa"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xb"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xc"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xd"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xe"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0xf"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x10"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x11"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x12"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x13"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x14"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x15"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x16"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x17"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x18"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x19"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1a"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1b"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1c"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1d"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1e"
+ },
+ {
+ "isAllowed": false,
+ "metachar": "0x1f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x20"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x21"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x22"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x23"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x24"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x25"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x26"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x27"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x28"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x29"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x2f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x30"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x31"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x32"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x33"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x34"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x35"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x36"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x37"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x38"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x39"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x3f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x40"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x41"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x42"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x43"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x44"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x45"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x46"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x47"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x48"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x49"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x4f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x50"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x51"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x52"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x53"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x54"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x55"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x56"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x57"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x58"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x59"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x5f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x60"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x61"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x62"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x63"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x64"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x65"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x66"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x67"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x68"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x69"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x6f"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x70"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x71"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x72"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x73"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x74"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x75"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x76"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x77"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x78"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x79"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7a"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7b"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7c"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7d"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7e"
+ },
+ {
+ "isAllowed": true,
+ "metachar": "0x7f"
+ }
+ ],
+ "characterSetType": "plain-text-content"
+ }
+ ],
+ "cookie-settings": {
+ "maximumCookieHeaderLength": "4096"
+ },
+ "cookies": [
+ {
+ "accessibleOnlyThroughTheHttpProtocol": false,
+ "attackSignaturesCheck": true,
+ "enforcementType": "allow",
+ "insertSameSiteAttribute": "lax",
+ "isBase64": false,
+ "maskValueInLogs": false,
+ "name": "*",
+ "performStaging": false,
+ "securedOverHttpsConnection": true,
+ "type": "wildcard",
+ "wildcardOrder": 1
+ }
+ ],
+ "csrf-protection": {
+ "enabled": false
+ },
+ "csrf-urls": [
+ {
+ "enforcementAction": "verify-origin",
+ "method": "POST",
+ "requiredParameters": "ignore",
+ "url": "*",
+ "wildcardOrder": 1
+ }
+ ],
+ "data-guard": {
+ "enabled": false,
+ "enforcementMode": "ignore-urls-in-list"
+ },
+ "description": "new_waf_policy desc updated",
+ "dos-protection": {
+ "behavioral-dos": {
+ "badActorDetection": {
+ "enableTlsIndexing": true,
+ "enabled": true
+ },
+ "enableHttpSignatures": true,
+ "enableTlsSignatures": false,
+ "mitigationLevel": "standard"
+ },
+ "enabled": false
+ },
+ "enablePassiveMode": false,
+ "enforcementMode": "blocking",
+ "filetypes": [
+ {
+ "allowed": false,
+ "name": "bat"
+ },
+ {
+ "allowed": false,
+ "name": "sav"
+ },
+ {
+ "allowed": false,
+ "name": "pfx"
+ },
+ {
+ "allowed": false,
+ "name": "eml"
+ },
+ {
+ "allowed": false,
+ "name": "wmz"
+ },
+ {
+ "allowed": false,
+ "name": "crt"
+ },
+ {
+ "allowed": false,
+ "name": "nws"
+ },
+ {
+ "allowed": false,
+ "name": "idq"
+ },
+ {
+ "allowed": false,
+ "name": "conf"
+ },
+ {
+ "allowed": false,
+ "name": "dat"
+ },
+ {
+ "allowed": false,
+ "name": "msi"
+ },
+ {
+ "allowed": false,
+ "name": "key"
+ },
+ {
+ "allowed": false,
+ "name": "temp"
+ },
+ {
+ "allowed": false,
+ "name": "idc"
+ },
+ {
+ "allowed": false,
+ "name": "pol"
+ },
+ {
+ "allowed": false,
+ "name": "cer"
+ },
+ {
+ "allowed": false,
+ "name": "pem"
+ },
+ {
+ "allowed": false,
+ "name": "ida"
+ },
+ {
+ "allowed": false,
+ "name": "stm"
+ },
+ {
+ "allowed": false,
+ "name": "log"
+ },
+ {
+ "allowed": false,
+ "name": "sys"
+ },
+ {
+ "allowed": false,
+ "name": "p7c"
+ },
+ {
+ "allowed": false,
+ "name": "cgi"
+ },
+ {
+ "allowed": false,
+ "name": "ini"
+ },
+ {
+ "allowed": false,
+ "name": "shtm"
+ },
+ {
+ "allowed": false,
+ "name": "cfg"
+ },
+ {
+ "allowed": false,
+ "name": "dll"
+ },
+ {
+ "allowed": false,
+ "name": "save"
+ },
+ {
+ "allowed": false,
+ "name": "htr"
+ },
+ {
+ "allowed": false,
+ "name": "hta"
+ },
+ {
+ "allowed": false,
+ "name": "bck"
+ },
+ {
+ "allowed": false,
+ "name": "exe"
+ },
+ {
+ "allowed": false,
+ "name": "old"
+ },
+ {
+ "allowed": false,
+ "name": "p7b"
+ },
+ {
+ "allowed": false,
+ "name": "com"
+ },
+ {
+ "allowed": false,
+ "name": "cmd"
+ },
+ {
+ "allowed": false,
+ "name": "tmp"
+ },
+ {
+ "allowed": false,
+ "name": "reg"
+ },
+ {
+ "allowed": false,
+ "name": "der"
+ },
+ {
+ "allowed": false,
+ "name": "htw"
+ },
+ {
+ "allowed": false,
+ "name": "shtml"
+ },
+ {
+ "allowed": false,
+ "name": "bkp"
+ },
+ {
+ "allowed": false,
+ "name": "p12"
+ },
+ {
+ "allowed": false,
+ "name": "bak"
+ },
+ {
+ "allowed": false,
+ "name": "config"
+ },
+ {
+ "allowed": false,
+ "name": "printer"
+ },
+ {
+ "allowed": false,
+ "name": "bin"
+ },
+ {
+ "allowed": true,
+ "checkPostDataLength": true,
+ "checkQueryStringLength": true,
+ "checkRequestLength": true,
+ "checkUrlLength": true,
+ "name": "*",
+ "performStaging": false,
+ "postDataLength": 4096,
+ "queryStringLength": 2048,
+ "requestLength": 8196,
+ "responseCheck": false,
+ "responseCheckLength": 20000,
+ "type": "wildcard",
+ "urlLength": 1024,
+ "wildcardOrder": 1
+ }
+ ],
+ "fullPath": "/Common/Rating-Based-Template",
+ "general": {
+ "allowedResponseCodes": [
+ 400,
+ 401,
+ 403,
+ 404,
+ 405,
+ 406,
+ 407,
+ 415,
+ 417,
+ 503
+ ],
+ "enableEventCorrelation": true,
+ "enforcementReadinessPeriod": 7,
+ "maskCreditCardNumbersInRequest": true,
+ "pathParameterHandling": "as-parameters",
+ "triggerAsmIruleEvent": "disabled",
+ "trustXff": false,
+ "useDynamicSessionIdInUrl": false
+ },
+ "graphql-profiles": [
+ {
+ "attackSignaturesCheck": true,
+ "defenseAttributes": {
+ "allowIntrospectionQueries": false,
+ "maximumBatchedQueries": "any",
+ "maximumStructureDepth": 10,
+ "maximumTotalLength": "any",
+ "maximumValueLength": "any",
+ "tolerateParsingWarnings": false
+ },
+ "description": "Default GraphQL Profile",
+ "hasIdlFiles": false,
+ "metacharElementCheck": true,
+ "name": "Default",
+ "responseEnforcement": {
+ "blockDisallowedPatterns": false
+ }
+ }
+ ],
+ "gwt-profiles": [
+ {
+ "attackSignaturesCheck": true,
+ "defenseAttributes": {
+ "maximumTotalLengthOfGWTData": 10000,
+ "maximumValueLength": 100,
+ "tolerateGWTParsingWarnings": false
+ },
+ "description": "Default GWT Profile",
+ "metacharElementCheck": true,
+ "name": "Default"
+ }
+ ],
+ "header-settings": {
+ "maximumHttpHeaderLength": "8192"
+ },
+ "headers": [
+ {
+ "allowRepeatedOccurrences": false,
+ "checkSignatures": false,
+ "mandatory": false,
+ "maskValueInLogs": false,
+ "name": "cookie",
+ "type": "explicit"
+ },
+ {
+ "allowRepeatedOccurrences": true,
+ "base64Decoding": false,
+ "checkSignatures": true,
+ "htmlNormalization": false,
+ "mandatory": false,
+ "maskValueInLogs": false,
+ "name": "referer",
+ "normalizationViolations": true,
+ "percentDecoding": false,
+ "type": "explicit",
+ "urlNormalization": true
+ },
+ {
+ "allowRepeatedOccurrences": false,
+ "base64Decoding": false,
+ "checkSignatures": true,
+ "htmlNormalization": false,
+ "mandatory": false,
+ "maskValueInLogs": false,
+ "name": "transfer-encoding",
+ "normalizationViolations": false,
+ "percentDecoding": false,
+ "type": "explicit",
+ "urlNormalization": false
+ },
+ {
+ "allowRepeatedOccurrences": false,
+ "base64Decoding": false,
+ "checkSignatures": true,
+ "htmlNormalization": false,
+ "mandatory": false,
+ "maskValueInLogs": true,
+ "name": "authorization",
+ "normalizationViolations": false,
+ "percentDecoding": true,
+ "type": "explicit",
+ "urlNormalization": false
+ },
+ {
+ "allowRepeatedOccurrences": true,
+ "base64Decoding": false,
+ "checkSignatures": true,
+ "htmlNormalization": false,
+ "mandatory": false,
+ "maskValueInLogs": false,
+ "name": "*",
+ "normalizationViolations": false,
+ "percentDecoding": true,
+ "type": "wildcard",
+ "urlNormalization": false,
+ "wildcardOrder": 1
+ }
+ ],
+ "ip-intelligence": {
+ "enabled": true,
+ "ipIntelligenceCategories": [
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Spam Sources"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Windows Exploits"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Web Attacks"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "BotNets"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Scanners"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Denial of Service"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Infected Sources"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Phishing Proxies"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Anonymous Proxy"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Cloud-based Services"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Mobile Threats"
+ },
+ {
+ "__metadata": {
+ "groupbyCount": 1
+ },
+ "alarm": true,
+ "block": true,
+ "category": "Tor Proxies"
+ }
+ ]
+ },
+ "json-profiles": [
+ {
+ "defenseAttributes": {
+ "maximumArrayLength": 1000,
+ "maximumStructureDepth": 10,
+ "maximumTotalLengthOfJSONData": 10000,
+ "maximumValueLength": 100,
+ "tolerateJSONParsingWarnings": false
+ },
+ "description": "Default JSON Profile",
+ "handleJsonValuesAsParameters": true,
+ "hasValidationFiles": false,
+ "name": "Default",
+ "validationFiles": []
+ }
+ ],
+ "login-enforcement": {
+ "expirationTimePeriod": "disabled"
+ },
+ "methods": [
+ {
+ "actAsMethod": "POST",
+ "name": "PATCH"
+ },
+ {
+ "actAsMethod": "GET",
+ "name": "DELETE"
+ },
+ {
+ "actAsMethod": "GET",
+ "name": "OPTIONS"
+ },
+ {
+ "actAsMethod": "GET",
+ "name": "HEAD"
+ },
+ {
+ "actAsMethod": "POST",
+ "name": "PUT"
+ },
+ {
+ "actAsMethod": "GET",
+ "name": "GET"
+ },
+ {
+ "actAsMethod": "POST",
+ "name": "POST"
+ }
+ ],
+ "name": "new_waf_policy",
+ "parameters": [
+ {
+ "allowEmptyValue": true,
+ "allowRepeatedParameterName": false,
+ "attackSignaturesCheck": true,
+ "checkMaxValueLength": false,
+ "checkMetachars": true,
+ "isBase64": false,
+ "isCookie": false,
+ "isHeader": false,
+ "level": "global",
+ "metacharsOnParameterValueCheck": true,
+ "name": "*",
+ "parameterLocation": "any",
+ "performStaging": false,
+ "sensitiveParameter": false,
+ "type": "wildcard",
+ "valueType": "auto-detect",
+ "wildcardOrder": 1
+ }
+ ],
+ "performStaging": true,
+ "policy-builder": {
+ "enableFullPolicyInspection": true,
+ "enableTrustedTrafficSiteChangeTracking": true,
+ "enableUntrustedTrafficSiteChangeTracking": true,
+ "inactiveEntityInactivityDurationInDays": 90,
+ "learnFromResponses": false,
+ "learnInactiveEntities": false,
+ "learnOnlyFromNonBotTraffic": true,
+ "learningMode": "on-demand",
+ "responseStatusCodes": [
+ "2xx",
+ "3xx",
+ "1xx"
+ ],
+ "trafficTighten": {
+ "maxModificationSuggestionScore": 50,
+ "minDaysBetweenSamples": 1,
+ "totalRequests": 15000
+ },
+ "trustAllIps": false,
+ "trustedTrafficLoosen": {
+ "differentSources": 1,
+ "maxDaysBetweenSamples": 7,
+ "minHoursBetweenSamples": 0
+ },
+ "trustedTrafficSiteChangeTracking": {
+ "differentSources": 1,
+ "maxDaysBetweenSamples": 7,
+ "minMinutesBetweenSamples": 0
+ },
+ "untrustedTrafficLoosen": {
+ "differentSources": 20,
+ "maxDaysBetweenSamples": 7,
+ "minHoursBetweenSamples": 1
+ },
+ "untrustedTrafficSiteChangeTracking": {
+ "differentSources": 10,
+ "maxDaysBetweenSamples": 7,
+ "minMinutesBetweenSamples": 20
+ }
+ },
+ "policy-builder-central-configuration": {
+ "buildingMode": "local",
+ "eventCorrelationMode": "local"
+ },
+ "policy-builder-cookie": {
+ "collapseCookiesIntoOneEntity": false,
+ "enforceUnmodifiedCookies": false,
+ "learnExplicitCookies": "never",
+ "maximumCookies": 100
+ },
+ "policy-builder-filetype": {
+ "learnExplicitFiletypes": "never",
+ "maximumFileTypes": 100
+ },
+ "policy-builder-header": {
+ "maximumHosts": 10000,
+ "validHostNames": false
+ },
+ "policy-builder-parameter": {
+ "classifyParameters": false,
+ "collapseParametersIntoOneEntity": false,
+ "dynamicParameters": {
+ "allHiddenFields": false,
+ "formParameters": false,
+ "linkParameters": false,
+ "uniqueValueSets": 10
+ },
+ "learnExplicitParameters": "never",
+ "maximumParameters": 10000,
+ "parameterLearningLevel": "global",
+ "parametersIntegerValue": false
+ },
+ "policy-builder-redirection-protection": {
+ "learnExplicitRedirectionDomains": "never",
+ "maximumRedirectionDomains": 100
+ },
+ "policy-builder-server-technologies": {
+ "enableServerTechnologiesDetection": false
+ },
+ "policy-builder-sessions-and-logins": {
+ "learnLoginPage": false
+ },
+ "policy-builder-url": {
+ "classifyUrls": false,
+ "classifyWebsocketUrls": false,
+ "collapseUrlsIntoOneEntity": false,
+ "learnExplicitUrls": "never",
+ "learnExplicitWebsocketUrls": "never",
+ "learnMethodsOnUrls": false,
+ "maximumUrls": 100,
+ "maximumWebsocketUrls": 100,
+ "wildcardUrlFiletypes": [
+ "swf",
+ "wav",
+ "bmp",
+ "gif",
+ "pcx",
+ "pdf",
+ "png",
+ "jpeg",
+ "ico",
+ "jpg"
+ ]
+ },
+ "protocolIndependent": true,
+ "redirection-protection": {
+ "redirectionProtectionEnabled": false
+ },
+ "response-pages": [
+ {
+ "responseActionType": "soap-fault",
+ "responsePageType": "xml"
+ },
+ {
+ "responseActionType": "default",
+ "responsePageType": "graphql"
+ },
+ {
+ "responseActionType": "default",
+ "responsePageType": "default"
+ },
+ {
+ "responseActionType": "default",
+ "responsePageType": "captcha"
+ },
+ {
+ "ajaxActionType": "alert-popup",
+ "ajaxPopupMessage": "Login Failed. Username or password is incorrect. Please try to log in again.",
+ "responsePageType": "failed-login-honeypot-ajax"
+ },
+ {
+ "ajaxActionType": "alert-popup",
+ "ajaxPopupMessage": "The requested URL was rejected. Please consult with your administrator. Your support ID is: <%TS.request.ID()%>",
+ "responsePageType": "ajax-login"
+ },
+ {
+ "responseActionType": "default",
+ "responsePageType": "hijack"
+ },
+ {
+ "responseActionType": "default",
+ "responsePageType": "captcha-fail"
+ },
+ {
+ "grpcStatusCode": "UNKNOWN",
+ "grpcStatusMessage": "The request was rejected. Please consult with your administrator. Your support ID is: <%TS.request.ID()%>",
+ "responsePageType": "grpc"
+ },
+ {
+ "responseActionType": "default",
+ "responsePageType": "persistent-flow"
+ },
+ {
+ "ajaxActionType": "alert-popup",
+ "ajaxEnabled": false,
+ "ajaxPopupMessage": "The requested URL was rejected. Please consult with your administrator. Your support ID is: <%TS.request.ID()%>",
+ "responsePageType": "ajax"
+ },
+ {
+ "responseActionType": "default",
+ "responsePageType": "failed-login-honeypot"
+ },
+ {
+ "responseActionType": "default",
+ "responsePageType": "mobile"
+ }
+ ],
+ "sensitive-parameters": [
+ {
+ "name": "password"
+ }
+ ],
+ "signature-sets": [
+ {
+ "name": "High Accuracy Signatures",
+ "alarm": true,
+ "block": false,
+ "learn": true
+ },
+ {
+ "name": "All Signatures",
+ "alarm": true,
+ "block": false,
+ "learn": true
+ }
+ ],
+ "signature-settings": {
+ "attackSignatureFalsePositiveMode": "disabled",
+ "minimumAccuracyForAutoAddedSignatures": "high",
+ "placeSignaturesInStaging": false,
+ "signatureStaging": false,
+ "stagingCertificationDatetime": ""
+ },
+ "softwareVersion": "17.0.0",
+ "ssrf-hosts": [
+ {
+ "action": "disallow",
+ "host": "*.burpcollaborator.net"
+ },
+ {
+ "action": "disallow",
+ "host": "metadata.google.internal"
+ },
+ {
+ "action": "disallow",
+ "host": "localhost"
+ },
+ {
+ "action": "disallow",
+ "host": "rancher-metadata"
+ },
+ {
+ "action": "disallow",
+ "host": "127.0.0.0/24"
+ },
+ {
+ "action": "disallow",
+ "host": "192.0.2.0/24"
+ },
+ {
+ "action": "disallow",
+ "host": "198.51.100.0/24"
+ },
+ {
+ "action": "disallow",
+ "host": "203.0.113.0/24"
+ },
+ {
+ "action": "disallow",
+ "host": "169.254.0.0/16"
+ },
+ {
+ "action": "disallow",
+ "host": "192.168.0.0/16"
+ },
+ {
+ "action": "disallow",
+ "host": "172.16.0.0/12"
+ },
+ {
+ "action": "disallow",
+ "host": "fe80::/10"
+ },
+ {
+ "action": "disallow",
+ "host": "10.0.0.0/8"
+ },
+ {
+ "action": "disallow",
+ "host": "127.0.0.0/8"
+ },
+ {
+ "action": "disallow",
+ "host": "0.0.0.0"
+ },
+ {
+ "action": "disallow",
+ "host": "0:0:0:0:0:ffff:7f00:1"
+ },
+ {
+ "action": "disallow",
+ "host": "100.100.100.200"
+ },
+ {
+ "action": "disallow",
+ "host": "168.63.129.16"
+ },
+ {
+ "action": "disallow",
+ "host": "169.254.169.254"
+ },
+ {
+ "action": "disallow",
+ "host": "192.0.0.192"
+ },
+ {
+ "action": "disallow",
+ "host": "::"
+ },
+ {
+ "action": "disallow",
+ "host": "::1"
+ },
+ {
+ "action": "resolve",
+ "host": "*"
+ }
+ ],
+ "template": {
+ "name": ""
+ },
+ "threat-campaign-settings": {
+ "threatCampaignEnforcementReadinessPeriod": 1,
+ "threatCampaignStaging": false
+ },
+ "type": "security",
+ "urls": [
+ {
+ "attackSignaturesCheck": true,
+ "clickjackingProtection": false,
+ "description": "",
+ "disallowFileUploadOfExecutables": true,
+ "html5CrossOriginRequestsEnforcement": {
+ "enforcementMode": "enforce"
+ },
+ "isAllowed": true,
+ "mandatoryBody": false,
+ "metacharsOnUrlCheck": true,
+ "method": "*",
+ "methodsOverrideOnUrlCheck": false,
+ "name": "*",
+ "performStaging": false,
+ "protocol": "http",
+ "type": "wildcard",
+ "urlContentProfiles": [
+ {
+ "headerName": "*",
+ "headerOrder": "default",
+ "headerValue": "*",
+ "type": "apply-value-and-content-signatures"
+ },
+ {
+ "headerName": "Content-Type",
+ "headerOrder": "1",
+ "headerValue": "*form*",
+ "type": "form-data"
+ },
+ {
+ "contentProfile": {
+ "name": "Default"
+ },
+ "headerName": "Content-Type",
+ "headerOrder": "2",
+ "headerValue": "*json*",
+ "type": "json"
+ },
+ {
+ "contentProfile": {
+ "name": "Default"
+ },
+ "headerName": "Content-Type",
+ "headerOrder": "3",
+ "headerValue": "*xml*",
+ "type": "xml"
+ }
+ ],
+ "wildcardIncludesSlash": true,
+ "wildcardOrder": 2
+ }
+ ],
+ "xml-profiles": [
+ {
+ "attachmentsInSoapMessages": false,
+ "attackSignaturesCheck": true,
+ "defenseAttributes": {
+ "allowCDATA": false,
+ "allowDTDs": false,
+ "allowExternalReferences": false,
+ "allowProcessingInstructions": true,
+ "maximumAttributeValueLength": 1024,
+ "maximumAttributesPerElement": 16,
+ "maximumChildrenPerElement": 1024,
+ "maximumDocumentDepth": 32,
+ "maximumDocumentSize": 1024000,
+ "maximumElements": 65536,
+ "maximumNSDeclarations": 64,
+ "maximumNameLength": 256,
+ "maximumNamespaceLength": 256,
+ "tolerateCloseTagShorthand": false,
+ "tolerateLeadingWhiteSpace": false,
+ "tolerateNumericNames": false
+ },
+ "description": "Default XML Profile",
+ "enableWss": false,
+ "followSchemaLinks": false,
+ "inspectSoapAttachments": false,
+ "metacharAttributeCheck": false,
+ "metacharElementCheck": true,
+ "name": "Default",
+ "useXmlResponsePage": false,
+ "validationFiles": [],
+ "validationSoapActionHeader": false
+ }
+ ]
+ }
+ },
+ "enforcement_mode": "blocking",
+ "id": "1a4453fe-b37a-4212-a813-a3d2f789dad1",
+ "last_modified": "2024-07-17T11:59:25.304421Z",
+ "name": "new_waf_policy"
+}
\ No newline at end of file
diff --git a/internal/provider/global_resiliency_resource.go b/internal/provider/global_resiliency_resource.go
index 73545e8..066d5dc 100644
--- a/internal/provider/global_resiliency_resource.go
+++ b/internal/provider/global_resiliency_resource.go
@@ -157,7 +157,7 @@ func (r *NextGlobalResiliencyResource) Create(ctx context.Context, req resource.
var resCfg *NextGlobalResiliencyResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
tflog.Info(ctx, fmt.Sprintf("[CREATE] NextGlobalResiliencyResource:%+v\n", resCfg.Name.ValueString()))
@@ -168,7 +168,7 @@ func (r *NextGlobalResiliencyResource) Create(ctx context.Context, req resource.
tflog.Info(ctx, fmt.Sprintf("[CREATE] :%+v\n", reqDraft))
id, err := r.client.PostGlobalResiliencyGroup("POST", reqDraft)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Global Resiliency Error", fmt.Sprintf("Failed to Create Global Resiliency Group, got error: %s", err))
return
}
@@ -183,13 +183,13 @@ func (r *NextGlobalResiliencyResource) Create(ctx context.Context, req resource.
func (r *NextGlobalResiliencyResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var stateCfg *NextGlobalResiliencyResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
id := stateCfg.Id.ValueString()
tflog.Info(ctx, fmt.Sprintf("Reading Global Resiliency Group : %s", id))
grData, err := r.client.GetGlobalResiliencyGroupDetails(id)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Error", fmt.Sprintf("Failed to Read Global Resiliency Group, got error: %s", err))
return
}
@@ -222,7 +222,7 @@ func (r *NextGlobalResiliencyResource) Update(ctx context.Context, req resource.
var resCfg *NextGlobalResiliencyResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
tflog.Info(ctx, fmt.Sprintf("[UPDATE] Updating Global Resiliency Group: %s", resCfg.Name.ValueString()))
@@ -234,7 +234,7 @@ func (r *NextGlobalResiliencyResource) Update(ctx context.Context, req resource.
tflog.Info(ctx, fmt.Sprintf("[UPDATE] :%+v\n", reqDraft))
id, err := r.client.PostGlobalResiliencyGroup("PUT", reqDraft)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Update Global Resiliency Group, got error: %s", err))
return
}
@@ -246,7 +246,7 @@ func (r *NextGlobalResiliencyResource) Update(ctx context.Context, req resource.
func (r *NextGlobalResiliencyResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var stateCfg *NextGlobalResiliencyResourceModel
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
@@ -255,7 +255,7 @@ func (r *NextGlobalResiliencyResource) Delete(ctx context.Context, req resource.
tflog.Info(ctx, fmt.Sprintf("Deleting Global Resiliency Group : %s", id))
err := r.client.DeleteGlobalResiliencyGroup(id)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to Delete Global Resiliency Group, got error: %s", err))
return
}
@@ -263,7 +263,7 @@ func (r *NextGlobalResiliencyResource) Delete(ctx context.Context, req resource.
stateCfg.Id = types.StringValue("")
}
-func (r *NextGlobalResiliencyResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+func (r *NextGlobalResiliencyResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { // coverage-ignore
// resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}
diff --git a/internal/provider/import_certificate_resource.go b/internal/provider/import_certificate_resource.go
index 3232dba..7fe8ad2 100644
--- a/internal/provider/import_certificate_resource.go
+++ b/internal/provider/import_certificate_resource.go
@@ -91,7 +91,7 @@ func (r *NextCMImportCertificateResource) Configure(ctx context.Context, req res
func (r *NextCMImportCertificateResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var resCfg *NextCMImportCertificateResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
tflog.Info(ctx, fmt.Sprintf("[CREATE] NextCMImportCertificateResource:%+v\n", resCfg.Name.ValueString()))
@@ -101,7 +101,7 @@ func (r *NextCMImportCertificateResource) Create(ctx context.Context, req resour
// tflog.Info(ctx, fmt.Sprintf("[CREATE] :%+v\n", reqDraft))
draftID, err := r.client.PostCertificateCreate(reqDraft, "IMPORT")
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Import Certificate, got error: %s", err))
return
}
@@ -114,20 +114,20 @@ func (r *NextCMImportCertificateResource) Create(ctx context.Context, req resour
func (r *NextCMImportCertificateResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var stateCfg *NextCMImportCertificateResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
id := stateCfg.Id.ValueString()
tflog.Info(ctx, fmt.Sprintf("Reading Certificate : %s", id))
keycertData, err := r.client.GetNextCMImportCertificateKeyData(id)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Read Certificate, Key Data, got error: %s", err))
return
}
tflog.Info(ctx, fmt.Sprintf("Certificate/Key Data : %+v", keycertData))
certData, err := r.client.GetNextCMCertificate(id)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Read Certificate, got error: %s", err))
return
}
@@ -147,7 +147,7 @@ func (r *NextCMImportCertificateResource) Update(ctx context.Context, req resour
var resCfg *NextCMImportCertificateResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
tflog.Info(ctx, fmt.Sprintf("[UPDATE]Posting Certificate: %s", resCfg.Name.ValueString()))
@@ -159,7 +159,7 @@ func (r *NextCMImportCertificateResource) Update(ctx context.Context, req resour
tflog.Info(ctx, fmt.Sprintf("[UPDATE] :%+v\n", reqDraft))
draftID, err := r.client.PostCertificateCreate(reqDraft, "UPDATEIMPORT")
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Update Certificate, got error: %s", err))
return
}
@@ -170,7 +170,7 @@ func (r *NextCMImportCertificateResource) Update(ctx context.Context, req resour
func (r *NextCMImportCertificateResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var stateCfg *NextCMImportCertificateResourceModel
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
@@ -179,7 +179,7 @@ func (r *NextCMImportCertificateResource) Delete(ctx context.Context, req resour
tflog.Info(ctx, fmt.Sprintf("Deleting Certificate : %s", id))
err := r.client.DeleteNextCMCertificate(id)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to Delete Certificate, got error: %s", err))
return
}
diff --git a/internal/provider/next_deploy_f5os_resource.go b/internal/provider/next_deploy_f5os_resource.go
index bf2ef40..34f37db 100644
--- a/internal/provider/next_deploy_f5os_resource.go
+++ b/internal/provider/next_deploy_f5os_resource.go
@@ -130,6 +130,7 @@ func (r *NextDeployF5osResource) Schema(ctx context.Context, req resource.Schema
Optional: true,
Computed: true,
ElementType: types.Int64Type,
+ // Default: listdefault.StaticValue([]int64{1}),
},
"cpu_cores": schema.Int64Attribute{
Optional: true,
@@ -177,25 +178,27 @@ func (r *NextDeployF5osResource) Configure(ctx context.Context, req resource.Con
func (r *NextDeployF5osResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var resCfg *NextDeployF5osResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
var providerModel F5OSProviderModel
diag := resCfg.F5OSProvider.As(ctx, &providerModel, basetypes.ObjectAsOptions{})
- if diag.HasError() {
+ if diag.HasError() { // coverage-ignore
return
}
var instanceModel F5OSInstanceModel
diag = resCfg.F5OSInstance.As(ctx, &instanceModel, basetypes.ObjectAsOptions{})
- if diag.HasError() {
+ if diag.HasError() { // coverage-ignore
return
}
providerID, err := r.client.GetDeviceProviderIDByHostname(providerModel.ProviderName.ValueString())
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to get provider ID:, got error: %s", err))
return
}
+ tflog.Info(ctx, fmt.Sprintf("[CREATE] providerID:%+v\n", providerID))
resCfg.ProviderId = types.StringValue(providerID.(string))
+
var providerConfig *bigipnextsdk.CMReqDeviceInstance
if providerModel.ProviderType.ValueString() == "velos" {
providerConfig = f5osVelosConfig(ctx, resCfg)
@@ -205,26 +208,45 @@ func (r *NextDeployF5osResource) Create(ctx context.Context, req resource.Create
}
tflog.Info(ctx, fmt.Sprintf("[CREATE] Deploy Next Instance:%+v\n", providerConfig.Parameters.Hostname))
respData, err := r.client.PostDeviceInstance(providerConfig, int(resCfg.Timeout.ValueInt64()))
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Deploy Instance, got error: %s", err))
return
}
tflog.Info(ctx, fmt.Sprintf("[CREATE] respData ID:%+v\n", string(respData)))
resCfg.Id = types.StringValue(providerConfig.Parameters.Hostname)
+
+ elements := []int64{1}
+ listValue, diags := types.ListValueFrom(ctx, types.Int64Type, elements)
+ if diags.HasError() { // coverage-ignore
+ resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to set vlan_ids, got error: %s", diags))
+ return
+ }
+
+ f5osInstanceModel := &F5OSInstanceModel{}
+ f5osInstanceModel.SlotIDs = listValue
+ resCfg.F5OSInstance.As(ctx, f5osInstanceModel, basetypes.ObjectAsOptions{})
+
+ tflog.Info(ctx, fmt.Sprintf("[CREATE] listValue :%+v\n", listValue))
+
+ // resCfg.F5OSInstance.As(ctx, path.Root("slot_ids"), listValue)
+ // if diags.HasError() {
+ // resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to set slot_ids, got error: %s", diags))
+ // return
+ // }
resp.Diagnostics.Append(resp.State.Set(ctx, resCfg)...)
}
func (r *NextDeployF5osResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var stateCfg *NextDeployF5osResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
id := stateCfg.Id.ValueString()
tflog.Info(ctx, fmt.Sprintf("Reading Device info for : %+v", id))
deviceDetails, err := r.client.GetDeviceIdByHostname(stateCfg.Id.ValueString())
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Read Device Info, got error: %s", err))
return
}
@@ -236,7 +258,7 @@ func (r *NextDeployF5osResource) Update(ctx context.Context, req resource.Update
var resCfg *NextDeployF5osResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
tflog.Info(ctx, "[UPDATE] Updating Next Instance deployment is not supported")
@@ -247,7 +269,7 @@ func (r *NextDeployF5osResource) Update(ctx context.Context, req resource.Update
func (r *NextDeployF5osResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var stateCfg *NextDeployF5osResourceModel
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
@@ -255,21 +277,21 @@ func (r *NextDeployF5osResource) Delete(ctx context.Context, req resource.Delete
tflog.Info(ctx, fmt.Sprintf("[DELETE] Deleting Instance from CM : %s", id))
deviceDetails, err := r.client.GetDeviceIdByHostname(stateCfg.Id.ValueString())
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Read Device Info, got error: %s", err))
return
}
tflog.Info(ctx, fmt.Sprintf("Device Info : %+v", *deviceDetails))
err = r.client.DeleteDevice(*deviceDetails)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to Delete Instance, got error: %s", err))
return
}
stateCfg.Id = types.StringValue("")
}
-func (r *NextDeployF5osResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
+func (r *NextDeployF5osResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { // coverage-ignore
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}
diff --git a/internal/provider/next_deploy_f5os_resource_test.go b/internal/provider/next_deploy_f5os_resource_test.go
index 408530b..f8b6314 100644
--- a/internal/provider/next_deploy_f5os_resource_test.go
+++ b/internal/provider/next_deploy_f5os_resource_test.go
@@ -1,11 +1,153 @@
package provider
import (
+ "fmt"
+ "net/http"
"testing"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
)
+func TestUnitNextDeployF5OSResourceTC1(t *testing.T) {
+ testAccPreUnitCheck(t)
+ // count := 0
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+ mux.HandleFunc("/api/v1/spaces/default/providers", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `[{"instances":[],"provider_host":"10.144.10.146:443","provider_id":"171d5623-e25a-45e5-8e2a-043fc952cbf1","provider_name":"myrseries","provider_type":"RSERIES","provider_username":"admin","updated":"2024-07-16T17:16:42.638833Z"}]`)
+ })
+ mux.HandleFunc("/api/device/v1/instances", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{"_links":{"self":{"href":"/v1/instances/tasks/7597ff87-d26d-4154-b03d-9e7999d24f0e"}},"path":"/v1/instances/tasks/7597ff87-d26d-4154-b03d-9e7999d24f0e"}`)
+ })
+
+ mux.HandleFunc("/api/device/v1/instances/tasks/7597ff87-d26d-4154-b03d-9e7999d24f0e", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{"_links":{"self":{"href":"/v1/instances/tasks/7597ff87-d26d-4154-b03d-9e7999d24f0e"}},"completed":"2024-07-16T17:25:01.919956Z","created":"2024-07-16T17:16:46.036781Z","failure_reason":"","id":"7597ff87-d26d-4154-b03d-9e7999d24f0e","name":"instance creation","payload":{"discovery":{"port":5443,"address":"10.144.10.182","device_user":"admin","device_password":"*****","management_user":"admin-cm","management_password":"*****"},"onboarding":{"mode":"STANDALONE","nodes":[{"password":"*****","username":"admin","managementAddress":"10.144.10.182"}],"platformType":"RSERIES"},"instantiation":{"Request":{"F5osRequest":{"provider_id":"171d5623-e25a-45e5-8e2a-043fc952cbf1","provider_type":"rseries","next_instances":[{"nodes":[1],"vlans":[444,555],"mgmt_ip":"10.144.10.182","timeout":600,"hostname":"demovm01-ravi-r10800","cpu_cores":4,"disk_size":30,"mgmt_prefix":24,"mgmt_gateway":"10.144.10.254","admin_password":"*****","tenant_image_name":"BIG-IP-Next-20.2.1-2.430.2+0.0.48","tenant_deployment_file":"BIG-IP-Next-20.2.1-2.430.2+0.0.48.yaml"}]},"VsphereRequest":null},"BaseTask":{"id":"","payload":null,"provider_id":"171d5623-e25a-45e5-8e2a-043fc952cbf1","provider_type":"rseries"},"VsphereRequest":null}},"stage":"Discovery","state":"discoveryDone","status":"completed","task_type":"instance_creation","updated":"2024-07-16T17:25:01.919956Z"}`)
+ })
+
+ mux.HandleFunc("/api/device/v1/inventory", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{"_embedded":{"devices":[{"_links":{"self":{"href":"/v1/inventory?filter=hostname+eq+demovm01-ravi-r10800/6cdf38ed-a258-4d92-a64d-972238b27400'"}},"address":"10.144.10.182","certificate_validated":"2024-07-16T17:24:12.848618Z","certificate_validity":false,"hostname":"demovm01-ravi-r10800","id":"6cdf38ed-a258-4d92-a64d-972238b27400","mode":"STANDALONE","platform_name":"R10K","platform_type":"APPLIANCE","port":5443,"short_id":"bcpED8hJ","version":"20.2.1-2.430.2+0.0.48"}]},"_links":{"self":{"href":"/v1/inventory?filter=hostname+eq+demovm01-ravi-r10800"}},"count":1,"total":1}`)
+ })
+ // mux.HandleFunc("/api/device/v1/inventory?filter=hostname+eq+'demovm01-ravi-r10800'", func(w http.ResponseWriter, r *http.Request) {
+ // w.WriteHeader(http.StatusOK)
+ // _, _ = fmt.Fprintf(w, `{"_embedded":{"devices":[{"_links":{"self":{"href":"/v1/inventory?filter=hostname+eq+demovm01-ravi-r10800/6cdf38ed-a258-4d92-a64d-972238b27400'"}},"address":"10.144.10.182","certificate_validated":"2024-07-16T17:24:12.848618Z","certificate_validity":false,"hostname":"demovm01-ravi-r10800","id":"6cdf38ed-a258-4d92-a64d-972238b27400","mode":"STANDALONE","platform_name":"R10K","platform_type":"APPLIANCE","port":5443,"short_id":"bcpED8hJ","version":"20.2.1-2.430.2+0.0.48"}]},"_links":{"self":{"href":"/v1/inventory?filter=hostname+eq+demovm01-ravi-r10800"}},"count":1,"total":1}`)
+ // })
+ mux.HandleFunc("/api/v1/spaces/default/instances/6cdf38ed-a258-4d92-a64d-972238b27400", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ if r.Method == http.MethodDelete {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{"_links":{"self":{"href":"/api/v1/spaces/default/instances/deletion-tasks/837120e1-7420-4e86-afc5-213dd2b07f26"}},"path":"/api/v1/spaces/default/instances/deletion-tasks/837120e1-7420-4e86-afc5-213dd2b07f26"}`)
+ } else {
+ _, _ = fmt.Fprintf(w, `{"_embedded":{"devices":[{"_links":{"self":{"href":"/v1/inventory?filter=hostname+eq+demovm01-ravi-r10800/6cdf38ed-a258-4d92-a64d-972238b27400'"}},"address":"10.144.10.182","certificate_validated":"2024-07-16T17:24:12.848618Z","certificate_validity":false,"hostname":"demovm01-ravi-r10800","id":"6cdf38ed-a258-4d92-a64d-972238b27400","mode":"STANDALONE","platform_name":"R10K","platform_type":"APPLIANCE","port":5443,"short_id":"bcpED8hJ","version":"20.2.1-2.430.2+0.0.48"}]},"_links":{"self":{"href":"/v1/inventory?filter=hostname+eq+demovm01-ravi-r10800"}},"count":1,"total":1}`)
+ }
+ })
+ // mux.HandleFunc("/api/v1/spaces/default/instances/6cdf38ed-a258-4d92-a64d-972238b27400", func(w http.ResponseWriter, r *http.Request) {
+ //
+ // })
+ mux.HandleFunc("/api/device/v1/deletion-tasks/837120e1-7420-4e86-afc5-213dd2b07f26", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{"_links":{"self":{"href":"/v1/deletion-tasks/837120e1-7420-4e86-afc5-213dd2b07f26"}},"address":"10.144.10.182","completed":"2024-07-16T17:35:42.811049Z","created":"2024-07-16T17:32:36.411802Z","device_id":"6cdf38ed-a258-4d92-a64d-972238b27400","failure_reason":"","id":"837120e1-7420-4e86-afc5-213dd2b07f26","state":"instanceRemovalDone","status":"completed"}`)
+ })
+ defer teardown()
+ resource.Test(t, resource.TestCase{
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testAccNextDeployF5OSResourceTC1Config,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ // ImportState testing
+ {
+ ResourceName: "bigipnext_cm_deploy_f5os.rseries01",
+ ImportState: true,
+ ImportStateVerify: false,
+ },
+ },
+ })
+}
+
+func TestUnitNextDeployF5OSResourceTC2(t *testing.T) {
+ testAccPreUnitCheck(t)
+ // count := 0
+ mux.HandleFunc("/api/login", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{
+ "token": "eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.eyJhbGciOiJIUzM4NCIsImtpZCI6IjJiMGE4MjEwLWJhYmQtNDRhZi04MmMyLTI2YWE4Yjk3OWYwMCIsInR5cCI6IkpXVCJ9.AbY1hUw8wHO8Vt1qxRd5xQj_21EQ1iaH6q9Z2XgRwQl98M7aCpyjiF2J16S4HrZ-",
+ "tokenType": "Bearer",
+ "expiresIn": 3600,
+ "refreshToken": "ODA0MmQzZTctZTk1Mi00OTk1LWJmMjUtZWZmMjc1NDE3YzliOt4bKlRr6g7RdTtnBKhm2vzkgJeWqfvow68gyxTipleCq4AjR4nxZDBYKQaWyCWGeA",
+ "refreshExpiresIn": 1209600
+ }`)
+ })
+ mux.HandleFunc("/api/v1/spaces/default/providers", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `[{"instances":[],"provider_host":"10.144.10.146:443","provider_id":"171d5623-e25a-45e5-8e2a-043fc952cbf1","provider_name":"myvelos","provider_type":"VELOS","provider_username":"admin","updated":"2024-07-16T17:16:42.638833Z"}]`)
+ })
+ mux.HandleFunc("/api/device/v1/instances", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{"_links":{"self":{"href":"/v1/instances/tasks/7597ff87-d26d-4154-b03d-9e7999d24f0e"}},"path":"/v1/instances/tasks/7597ff87-d26d-4154-b03d-9e7999d24f0e"}`)
+ })
+
+ mux.HandleFunc("/api/device/v1/instances/tasks/7597ff87-d26d-4154-b03d-9e7999d24f0e", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{"_links":{"self":{"href":"/v1/instances/tasks/7597ff87-d26d-4154-b03d-9e7999d24f0e"}},"completed":"2024-07-16T17:25:01.919956Z","created":"2024-07-16T17:16:46.036781Z","failure_reason":"","id":"7597ff87-d26d-4154-b03d-9e7999d24f0e","name":"instance creation","payload":{"discovery":{"port":5443,"address":"10.144.10.182","device_user":"admin","device_password":"*****","management_user":"admin-cm","management_password":"*****"},"onboarding":{"mode":"STANDALONE","nodes":[{"password":"*****","username":"admin","managementAddress":"10.144.10.182"}],"platformType":"RSERIES"},"instantiation":{"Request":{"F5osRequest":{"provider_id":"171d5623-e25a-45e5-8e2a-043fc952cbf1","provider_type":"rseries","next_instances":[{"nodes":[1],"vlans":[444,555],"mgmt_ip":"10.144.10.182","timeout":600,"hostname":"demovm01-ravi-r10800","cpu_cores":4,"disk_size":30,"mgmt_prefix":24,"mgmt_gateway":"10.144.10.254","admin_password":"*****","tenant_image_name":"BIG-IP-Next-20.2.1-2.430.2+0.0.48","tenant_deployment_file":"BIG-IP-Next-20.2.1-2.430.2+0.0.48.yaml"}]},"VsphereRequest":null},"BaseTask":{"id":"","payload":null,"provider_id":"171d5623-e25a-45e5-8e2a-043fc952cbf1","provider_type":"rseries"},"VsphereRequest":null}},"stage":"Discovery","state":"discoveryDone","status":"completed","task_type":"instance_creation","updated":"2024-07-16T17:25:01.919956Z"}`)
+ })
+
+ mux.HandleFunc("/api/device/v1/inventory", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{"_embedded":{"devices":[{"_links":{"self":{"href":"/v1/inventory?filter=hostname+eq+demovm01-ravi-r10800/6cdf38ed-a258-4d92-a64d-972238b27400'"}},"address":"10.144.10.182","certificate_validated":"2024-07-16T17:24:12.848618Z","certificate_validity":false,"hostname":"demovm01-ravi-r10800","id":"6cdf38ed-a258-4d92-a64d-972238b27400","mode":"STANDALONE","platform_name":"R10K","platform_type":"APPLIANCE","port":5443,"short_id":"bcpED8hJ","version":"20.2.1-2.430.2+0.0.48"}]},"_links":{"self":{"href":"/v1/inventory?filter=hostname+eq+demovm01-ravi-r10800"}},"count":1,"total":1}`)
+ })
+ // mux.HandleFunc("/api/device/v1/inventory?filter=hostname+eq+'demovm01-ravi-r10800'", func(w http.ResponseWriter, r *http.Request) {
+ // w.WriteHeader(http.StatusOK)
+ // _, _ = fmt.Fprintf(w, `{"_embedded":{"devices":[{"_links":{"self":{"href":"/v1/inventory?filter=hostname+eq+demovm01-ravi-r10800/6cdf38ed-a258-4d92-a64d-972238b27400'"}},"address":"10.144.10.182","certificate_validated":"2024-07-16T17:24:12.848618Z","certificate_validity":false,"hostname":"demovm01-ravi-r10800","id":"6cdf38ed-a258-4d92-a64d-972238b27400","mode":"STANDALONE","platform_name":"R10K","platform_type":"APPLIANCE","port":5443,"short_id":"bcpED8hJ","version":"20.2.1-2.430.2+0.0.48"}]},"_links":{"self":{"href":"/v1/inventory?filter=hostname+eq+demovm01-ravi-r10800"}},"count":1,"total":1}`)
+ // })
+ mux.HandleFunc("/api/v1/spaces/default/instances/6cdf38ed-a258-4d92-a64d-972238b27400", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ if r.Method == http.MethodDelete {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{"_links":{"self":{"href":"/api/v1/spaces/default/instances/deletion-tasks/837120e1-7420-4e86-afc5-213dd2b07f26"}},"path":"/api/v1/spaces/default/instances/deletion-tasks/837120e1-7420-4e86-afc5-213dd2b07f26"}`)
+ } else {
+ _, _ = fmt.Fprintf(w, `{"_embedded":{"devices":[{"_links":{"self":{"href":"/v1/inventory?filter=hostname+eq+demovm01-ravi-r10800/6cdf38ed-a258-4d92-a64d-972238b27400'"}},"address":"10.144.10.182","certificate_validated":"2024-07-16T17:24:12.848618Z","certificate_validity":false,"hostname":"demovm01-ravi-r10800","id":"6cdf38ed-a258-4d92-a64d-972238b27400","mode":"STANDALONE","platform_name":"R10K","platform_type":"APPLIANCE","port":5443,"short_id":"bcpED8hJ","version":"20.2.1-2.430.2+0.0.48"}]},"_links":{"self":{"href":"/v1/inventory?filter=hostname+eq+demovm01-ravi-r10800"}},"count":1,"total":1}`)
+ }
+ })
+ // mux.HandleFunc("/api/v1/spaces/default/instances/6cdf38ed-a258-4d92-a64d-972238b27400", func(w http.ResponseWriter, r *http.Request) {
+ //
+ // })
+ mux.HandleFunc("/api/device/v1/deletion-tasks/837120e1-7420-4e86-afc5-213dd2b07f26", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = fmt.Fprintf(w, `{"_links":{"self":{"href":"/v1/deletion-tasks/837120e1-7420-4e86-afc5-213dd2b07f26"}},"address":"10.144.10.182","completed":"2024-07-16T17:35:42.811049Z","created":"2024-07-16T17:32:36.411802Z","device_id":"6cdf38ed-a258-4d92-a64d-972238b27400","failure_reason":"","id":"837120e1-7420-4e86-afc5-213dd2b07f26","state":"instanceRemovalDone","status":"completed"}`)
+ })
+ defer teardown()
+ resource.Test(t, resource.TestCase{
+ IsUnitTest: true,
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ // Read testing
+ {
+ Config: testAccNextDeployF5OSResourceTC2Config,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ {
+ Config: testAccNextDeployF5OSResourceTC2UpdateConfig,
+ Check: resource.ComposeAggregateTestCheckFunc(),
+ },
+ },
+ })
+}
+
func TestAccNextDeployF5OSResourceTC1(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
@@ -48,6 +190,48 @@ resource "bigipnext_cm_deploy_f5os" "rseries01" {
management_user = "admin-cm"
management_password = "F5Twist@123"
vlan_ids = [27, 28, 29]
+ slot_ids = [1]
+ tenant_deployment_file = "BIG-IP-Next-20.1.0-2.279.0+0.0.75.yaml"
+ tenant_image_name = "BIG-IP-Next-20.1.0-2.279.0+0.0.75"
+ }
+}
+`
+const testAccNextDeployF5OSResourceTC2Config = `
+resource "bigipnext_cm_deploy_f5os" "velos01" {
+ f5os_provider = {
+ provider_name = "myvelos"
+ provider_type = "velos"
+ }
+ instance = {
+ instance_hostname = "rseriesravitest04"
+ management_address = "10.144.140.81"
+ management_prefix = 24
+ management_gateway = "10.144.140.254"
+ management_user = "admin-cm"
+ management_password = "F5Twist@123"
+ vlan_ids = [27, 28, 29]
+ slot_ids = [2]
+ tenant_deployment_file = "BIG-IP-Next-20.1.0-2.279.0+0.0.75.yaml"
+ tenant_image_name = "BIG-IP-Next-20.1.0-2.279.0+0.0.75"
+ }
+}
+`
+
+const testAccNextDeployF5OSResourceTC2UpdateConfig = `
+resource "bigipnext_cm_deploy_f5os" "velos01" {
+ f5os_provider = {
+ provider_name = "myvelos"
+ provider_type = "velos"
+ }
+ instance = {
+ instance_hostname = "rseriesravitest04"
+ management_address = "10.144.140.82"
+ management_prefix = 24
+ management_gateway = "10.144.140.254"
+ management_user = "admin-cm"
+ management_password = "F5Twist@123"
+ vlan_ids = [27, 28, 29]
+ slot_ids = [2]
tenant_deployment_file = "BIG-IP-Next-20.1.0-2.279.0+0.0.75.yaml"
tenant_image_name = "BIG-IP-Next-20.1.0-2.279.0+0.0.75"
}
diff --git a/internal/provider/next_deploy_vmware_resource.go b/internal/provider/next_deploy_vmware_resource.go
index 736147e..3cc71ce 100644
--- a/internal/provider/next_deploy_vmware_resource.go
+++ b/internal/provider/next_deploy_vmware_resource.go
@@ -255,21 +255,21 @@ func (r *NextDeployVmwareResource) Configure(ctx context.Context, req resource.C
func (r *NextDeployVmwareResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var resCfg *NextDeployVmwareResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
var providerModel VsphereProviderModel
diag := resCfg.VsphereProvider.As(ctx, &providerModel, basetypes.ObjectAsOptions{})
- if diag.HasError() {
+ if diag.HasError() { // coverage-ignore
return
}
var instanceModel InstanceModel
diag = resCfg.Instance.As(ctx, &instanceModel, basetypes.ObjectAsOptions{})
- if diag.HasError() {
+ if diag.HasError() { // coverage-ignore
return
}
providerID, err := r.client.GetDeviceProviderIDByHostname(providerModel.ProviderName.ValueString())
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to get provider ID:, got error: %s", err))
return
}
@@ -277,13 +277,13 @@ func (r *NextDeployVmwareResource) Create(ctx context.Context, req resource.Crea
providerConfig := instanceConfig(ctx, resCfg)
tflog.Info(ctx, fmt.Sprintf("[CREATE] Deploy Next Instance:%+v\n", providerConfig.Parameters.Hostname))
respData, err := r.client.PostDeviceInstance(providerConfig, int(resCfg.Timeout.ValueInt64()))
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Deploy Instance, got error: %s", err))
return
}
tflog.Info(ctx, fmt.Sprintf("[CREATE] respData ID:%+v\n", respData))
deviceDetails, err := r.client.GetDeviceIdByHostname(providerConfig.Parameters.Hostname)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Read Device Info, got error: %s", err))
return
}
@@ -295,14 +295,14 @@ func (r *NextDeployVmwareResource) Create(ctx context.Context, req resource.Crea
func (r *NextDeployVmwareResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var stateCfg *NextDeployVmwareResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
id := stateCfg.Id.ValueString()
tflog.Info(ctx, fmt.Sprintf("Reading Device info for : %+v", id))
deviceDetails, err := r.client.GetDeviceIdByHostname(stateCfg.Id.ValueString())
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Read Device Info, got error: %s", err))
return
}
@@ -314,7 +314,7 @@ func (r *NextDeployVmwareResource) Update(ctx context.Context, req resource.Upda
var resCfg *NextDeployVmwareResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &resCfg)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
providerConfig := instanceConfig(ctx, resCfg)
@@ -325,7 +325,7 @@ func (r *NextDeployVmwareResource) Update(ctx context.Context, req resource.Upda
func (r *NextDeployVmwareResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var stateCfg *NextDeployVmwareResourceModel
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
resp.Diagnostics.Append(req.State.Get(ctx, &stateCfg)...)
@@ -333,14 +333,14 @@ func (r *NextDeployVmwareResource) Delete(ctx context.Context, req resource.Dele
tflog.Info(ctx, fmt.Sprintf("[DELETE] Deleting Instance from CM : %s", id))
deviceDetails, err := r.client.GetDeviceIdByHostname(stateCfg.Id.ValueString())
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Failed to Read Device Info, got error: %s", err))
return
}
tflog.Info(ctx, fmt.Sprintf("Device Info : %+v", *deviceDetails))
err = r.client.DeleteDevice(*deviceDetails)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to Delete Instance, got error:%s", err))
return
}
@@ -356,12 +356,12 @@ func instanceConfig(ctx context.Context, data *NextDeployVmwareResourceModel) *b
deployConfig.TemplateName = "default-standalone-ve"
var providerModel VsphereProviderModel
diag := data.VsphereProvider.As(ctx, &providerModel, basetypes.ObjectAsOptions{})
- if diag.HasError() {
+ if diag.HasError() { // coverage-ignore
tflog.Error(ctx, fmt.Sprintf("VsphereProviderModel diag Error: %+v", diag.Errors()))
}
var instanceModel InstanceModel
diag = data.Instance.As(ctx, &instanceModel, basetypes.ObjectAsOptions{})
- if diag.HasError() {
+ if diag.HasError() { // coverage-ignore
tflog.Error(ctx, fmt.Sprintf("InstanceModel diag Error: %+v", diag.Errors()))
}
var cmReqDeviceInstance bigipnextsdk.CMReqDeviceInstance
@@ -409,7 +409,7 @@ func instanceConfig(ctx context.Context, data *NextDeployVmwareResourceModel) *b
l1Networks.Vlans[index].Tag = int(vlan.VlanTag.ValueInt64())
elements := make([]types.String, 0, len(vlan.SelfIps.Elements()))
diags := vlan.SelfIps.ElementsAs(ctx, &elements, false)
- if diags.HasError() {
+ if diags.HasError() { // coverage-ignore
tflog.Error(ctx, fmt.Sprintf("SelfIps diag Error: %+v", diags.Errors()))
}
l1Networks.Vlans[index].SelfIps = make([]bigipnextsdk.CMReqSelfIps, len(elements))
diff --git a/internal/provider/next_deploy_vmware_resource_test.go b/internal/provider/next_deploy_vmware_resource_test.go
index 2be9c0b..efcb719 100644
--- a/internal/provider/next_deploy_vmware_resource_test.go
+++ b/internal/provider/next_deploy_vmware_resource_test.go
@@ -51,7 +51,7 @@ func TestUnitNextDeployVmwareResourceTC1(t *testing.T) {
"refreshExpiresIn": 1209600
}`)
})
- mux.HandleFunc("/device/v1/providers?filter=name+eq+'myvsphere03'", func(w http.ResponseWriter, r *http.Request) {
+ mux.HandleFunc("/api/v1/spaces/default/providers?filter=name+eq+'myvsphere03'", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = fmt.Fprintf(w, `{"_links":{"self":{"href":"/api/v1/spaces/default/certificates/create"}},"path":"/v1/certificates/43b7bd5b-5b61-4a64-8fe4-68ef8ed910f2"}`)
})
@@ -82,7 +82,7 @@ func TestUnitNextDeployVmwareResourceTC2(t *testing.T) {
"refreshExpiresIn": 1209600
}`)
})
- mux.HandleFunc("/api/device/v1/providers", func(w http.ResponseWriter, r *http.Request) {
+ mux.HandleFunc("/api/v1/spaces/default/providers", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = fmt.Fprintf(w, `[{"instances":[{"provider_id":"9945d9cd-9f13-438f-8b97-f0cb1745d32b"},{"provider_id":"9945d9cd-9f13-438f-8b97-f0cb1745d32b"},{"provider_id":"9945d9cd-9f13-438f-8b97-f0cb1745d32b"}],"provider_host":"mbip-70-vcenter.pdsea.f5net.com","provider_id":"9945d9cd-9f13-438f-8b97-f0cb1745d32b","provider_name":"myvsphere03","provider_type":"VSPHERE","provider_username":"r.chinthalapalli@f5.com","updated":"2023-12-12T11:53:58.614102Z"}]`)
})
@@ -117,7 +117,7 @@ func TestUnitNextDeployVmwareResourceTC3(t *testing.T) {
"refreshExpiresIn": 1209600
}`)
})
- mux.HandleFunc("/api/device/v1/providers", func(w http.ResponseWriter, r *http.Request) {
+ mux.HandleFunc("/api/v1/spaces/default/providers", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = fmt.Fprintf(w, `[{"instances":[{"provider_id":"9945d9cd-9f13-438f-8b97-f0cb1745d32b"},{"provider_id":"9945d9cd-9f13-438f-8b97-f0cb1745d32b"},{"provider_id":"9945d9cd-9f13-438f-8b97-f0cb1745d32b"}],"provider_host":"mbip-70-vcenter.pdsea.f5net.com","provider_id":"9945d9cd-9f13-438f-8b97-f0cb1745d32b","provider_name":"myvsphere03","provider_type":"VSPHERE","provider_username":"r.chinthalapalli@f5.com","updated":"2023-12-12T11:53:58.614102Z"}]`)
})
@@ -161,7 +161,7 @@ func TestUnitNextDeployVmwareResourceTC3(t *testing.T) {
// "refreshExpiresIn": 1209600
// }`)
// })
-// mux.HandleFunc("/api/device/v1/providers", func(w http.ResponseWriter, r *http.Request) {
+// mux.HandleFunc("/api/v1/spaces/default/providers", func(w http.ResponseWriter, r *http.Request) {
// w.WriteHeader(http.StatusOK)
// _, _ = fmt.Fprintf(w, `[{"instances":[{"provider_id":"9945d9cd-9f13-438f-8b97-f0cb1745d32b"},{"provider_id":"9945d9cd-9f13-438f-8b97-f0cb1745d32b"},{"provider_id":"9945d9cd-9f13-438f-8b97-f0cb1745d32b"}],"provider_host":"mbip-70-vcenter.pdsea.f5net.com","provider_id":"9945d9cd-9f13-438f-8b97-f0cb1745d32b","provider_name":"myvsphere03","provider_type":"VSPHERE","provider_username":"r.chinthalapalli@f5.com","updated":"2023-12-12T11:53:58.614102Z"}]`)
// })
@@ -209,7 +209,7 @@ func TestUnitNextDeployVmwareResourceTC5(t *testing.T) {
"refreshExpiresIn": 1209600
}`)
})
- mux.HandleFunc("/api/device/v1/providers", func(w http.ResponseWriter, r *http.Request) {
+ mux.HandleFunc("/api/v1/spaces/default/providers", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = fmt.Fprintf(w, `[{"instances":[{"provider_id":"9945d9cd-9f13-438f-8b97-f0cb1745d32b"},{"provider_id":"9945d9cd-9f13-438f-8b97-f0cb1745d32b"},{"provider_id":"9945d9cd-9f13-438f-8b97-f0cb1745d32b"}],"provider_host":"mbip-70-vcenter.pdsea.f5net.com","provider_id":"9945d9cd-9f13-438f-8b97-f0cb1745d32b","provider_name":"myvsphere03","provider_type":"VSPHERE","provider_username":"r.chinthalapalli@f5.com","updated":"2023-12-12T11:53:58.614102Z"}]`)
})
@@ -274,6 +274,13 @@ resource "bigipnext_cm_deploy_vmware" "vmware" {
internal_network_name = "LocalTestVLAN-114"
ha_data_plane_network_name = "LocalTestVLAN-116"
}
+ l1_networks = [{
+ name = "demonetwork1"
+ vlans = [{
+ vlan_tag = 115
+ vlan_name = "vlan-115"
+ self_ips=["10.101.10.10/24","10.101.10.11/24"]}]
+ }]
ntp_servers = ["0.us.pool.ntp.org"]
dns_servers = ["8.8.8.8"]
timeout = 1200
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index 045e3b2..4b989cf 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -80,7 +80,7 @@ func (p *BigipNextCMProvider) Configure(ctx context.Context, req provider.Config
var config BigipNextCMProviderModel
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
- if resp.Diagnostics.HasError() {
+ if resp.Diagnostics.HasError() { // coverage-ignore
return
}
@@ -90,15 +90,15 @@ func (p *BigipNextCMProvider) Configure(ctx context.Context, req provider.Config
username := os.Getenv("BIGIPNEXT_USERNAME")
password := os.Getenv("BIGIPNEXT_PASSWORD")
- if !config.Host.IsNull() {
+ if !config.Host.IsNull() { // coverage-ignore
host = config.Host.ValueString()
}
- if !config.Username.IsNull() {
+ if !config.Username.IsNull() { // coverage-ignore
username = config.Username.ValueString()
}
- if !config.Password.IsNull() {
+ if !config.Password.IsNull() { // coverage-ignore
password = config.Password.ValueString()
}
ctx = tflog.SetField(ctx, "bigipnext_host", host)
@@ -113,7 +113,7 @@ func (p *BigipNextCMProvider) Configure(ctx context.Context, req provider.Config
}
tflog.Debug(ctx, fmt.Sprintf("bigipnextCmConfig client:%+v", bigipnextCmConfig))
client, err := bigipnextsdk.CmNewSession(bigipnextCmConfig)
- if err != nil {
+ if err != nil { // coverage-ignore
resp.Diagnostics.AddError(
"Unable to Create bigipnext CM Client",
"An unexpected error occurred when creating the bigipnext client. "+
@@ -178,7 +178,9 @@ func (p *BigipNextCMProvider) Configure(ctx context.Context, req provider.Config
func (p *BigipNextCMProvider) Resources(ctx context.Context) []func() resource.Resource {
return []func() resource.Resource{
NewNextCMAS3DeployResource,
+ // NewNextCMFastHttpResource,
NewNextCMBackupRestoreResource,
+ // NewNextCMFastTemplateResource,
NewNextCMCertificateResource,
NewNextCMImportCertificateResource,
NewNextCMDeviceProviderResource,
@@ -191,6 +193,9 @@ func (p *BigipNextCMProvider) Resources(ctx context.Context) []func() resource.R
NewNextCMWAFPolicyResource,
NewNextCMWAFPolicyImportResource,
NewNextCMHAClusterResource,
+ NewCMNextJwtTokenResource,
+ NewCMNextLicenseActivateResource,
+ NewCMNextBootstrapResource,
}
}
@@ -219,7 +224,7 @@ func toBigipNextCMProvider(in any) (*bigipnextsdk.BigipNextCM, diag.Diagnostics)
p, ok := in.(*bigipnextsdk.BigipNextCM)
- if !ok {
+ if !ok { // coverage-ignore
diags.AddError(
"Unexpected Provider Instance Type",
fmt.Sprintf("While creating the data source or resource, an unexpected provider type (%T) was received. "+
diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go
index 9b2e072..72eade9 100644
--- a/internal/provider/provider_test.go
+++ b/internal/provider/provider_test.go
@@ -71,16 +71,16 @@ func teardown() {
server.Close()
}
-// // loadFixtureBytes returns the entire contents of the given file as a byte slice
-// func loadFixtureBytes(path string) []byte {
-// contents, err := os.ReadFile(path)
-// if err != nil {
-// panic(err)
-// }
-// return contents
-// }
+// loadFixtureBytes returns the entire contents of the given file as a byte slice
+func loadFixtureBytes(path string) []byte {
+ contents, err := os.ReadFile(path)
+ if err != nil {
+ panic(err)
+ }
+ return contents
+}
-// // loadFixtureString returns the entire contents of the given file as a string
-// func loadFixtureString(path string) string {
-// return string(loadFixtureBytes(path))
-// }
+// loadFixtureString returns the entire contents of the given file as a string
+func loadFixtureString(path string) string {
+ return string(loadFixtureBytes(path))
+}
diff --git a/internal/provider/providerplanmodifier.go b/internal/provider/providerplanmodifier.go
index e3cfa02..5e4dbba 100644
--- a/internal/provider/providerplanmodifier.go
+++ b/internal/provider/providerplanmodifier.go
@@ -1,12 +1,15 @@
+//go:build !test
+
package provider
import (
"context"
"encoding/json"
"fmt"
+ "reflect"
+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
- "reflect"
)
// Int64DefaultValue is assign default values for Int Type
diff --git a/vendor/gitswarm.f5net.com/terraform-providers/bigipnext/bigipnextcm.go b/vendor/gitswarm.f5net.com/terraform-providers/bigipnext/bigipnextcm.go
index ae81cfc..15ad847 100644
--- a/vendor/gitswarm.f5net.com/terraform-providers/bigipnext/bigipnextcm.go
+++ b/vendor/gitswarm.f5net.com/terraform-providers/bigipnext/bigipnextcm.go
@@ -32,14 +32,12 @@ const (
uriCMFileUpload = "/system/v1/files"
uriFast = "/mgmt/shared/fast"
uriOpenAPI = "/openapi"
- uriInventory = "/device/v1/inventory"
uriBackups = "/device/v1/backups"
uriBackupTasks = "/device/v1/backup-tasks"
uriRestoreTasks = "/device/v1/restore-tasks"
uriCertificate = "/api/v1/spaces/default/certificates"
+ uriLicenseToken = "/api/v1/spaces/default/license/tokens"
uriCMUpgradeTask = "/upgrade-manager/v1/upgrade-tasks"
- uriAS3Root = "/api/v1/spaces/default/appsvcs"
- uriDiscoverInstance = "/v1/spaces/default/instances"
// uriCertificateUpdate = "/api/certificate/v1/certificates"
uriGlobalResiliency = "/api/v1/spaces/default/gslb/gr-groups"
uriGetGlobalResiliency = "/v1/spaces/default/gslb/gr-groups"
@@ -92,30 +90,6 @@ type CMError struct {
Code int
}
-type DeviceInventoryList struct {
- Embedded struct {
- Devices []struct {
- Links struct {
- Self struct {
- Href string `json:"href"`
- } `json:"self"`
- } `json:"_links"`
- Address string `json:"address"`
- CertificateValidated time.Time `json:"certificate_validated"`
- CertificateValidationError string `json:"certificate_validation_error"`
- CertificateValidity bool `json:"certificate_validity"`
- Hostname string `json:"hostname"`
- Id string `json:"id"`
- Mode string `json:"mode"`
- PlatformType string `json:"platform_type"`
- Port int `json:"port"`
- Version string `json:"version"`
- } `json:"devices"`
- } `json:"_embedded"`
- Count int `json:"count"`
- Total int `json:"total"`
-}
-
// CmNewSession sets up connection to the BIG-IP Next CM system.
func CmNewSession(bigipNextCmObj *BigipNextCMReqConfig) (*BigipNextCM, error) {
@@ -723,6 +697,111 @@ func (p *BigipNextCM) DeleteNextCMCertificate(id string) error {
return nil
}
+type JWTRequestDraft struct {
+ NickName string `json:"nickName,omitempty"`
+ JWT string `json:"jwt,omitempty"`
+}
+
+// https://clouddocs.f5.com/api/v1/spaces/default/license/tokens
+func (p *BigipNextCM) PostLicenseToken(config *JWTRequestDraft) ([]byte, error) {
+ licenseURL := fmt.Sprintf("%s%s", p.Host, uriLicenseToken)
+ f5osLogger.Info("[PostLicenseToken]", "URI Path", licenseURL)
+ body, err := json.Marshal(config)
+ if err != nil {
+ return nil, err
+ }
+ respData, err := p.doCMRequest("POST", licenseURL, body)
+ if err != nil {
+ return nil, err
+ }
+ mapResp := make(map[string]interface{})
+ err = json.Unmarshal(respData, &mapResp)
+ if err != nil {
+ return nil, err
+ }
+ var tokenID string
+ f5osLogger.Info("[PostLicenseToken]", "Token Resp::", hclog.Fmt("%+v", string(respData)))
+ f5osLogger.Info("[PostLicenseToken]", "NewToken", mapResp["NewToken"])
+ if mapResp["NewToken"].(map[string]interface{})["nickName"] == config.NickName {
+ tokenID = mapResp["NewToken"].(map[string]interface{})["id"].(string)
+ return []byte(tokenID), nil
+ }
+ f5osLogger.Info("[PostLicenseToken]", "tokenID", tokenID)
+
+ return nil, nil
+}
+
+// https://clouddocs.f5.com/api/v1/spaces/default/license/tokens/verify
+func (p *BigipNextCM) PostLicenseTokenVerify(config *JWTRequestDraft) ([]byte, error) {
+ licenseURL := fmt.Sprintf("%s%s%s", p.Host, uriLicenseToken, "/verify")
+ f5osLogger.Info("[PostLicenseTokenVerify]", "URI Path", licenseURL)
+ jwtMap := make(map[string]interface{})
+ // map[string]interface{}
+ jwtMap["jwt"] = config.JWT
+ body, err := json.Marshal(jwtMap)
+ if err != nil {
+ return nil, err
+ }
+ respData, err := p.doCMRequest("POST", licenseURL, body)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Info("[PostLicenseTokenVerify]", "Data::", hclog.Fmt("%+v", string(respData)))
+ return respData, nil
+}
+
+// api/v1/spaces/default/license/tokens
+func (p *BigipNextCM) GetLicenseTokens() ([]byte, error) {
+ // fileUrl := fmt.Sprintf("%s?filter=file_name+eq+'%s'", uriCMFileUpload, fileName)
+ licenseURL := fmt.Sprintf("%s%s", p.Host, uriLicenseToken)
+ f5osLogger.Info("[GetLicenseTokens]", "URI Path", licenseURL)
+ respData, err := p.doCMRequest("GET", licenseURL, nil)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Info("[GetLicenseTokens]", "Data::", hclog.Fmt("%+v", string(respData)))
+ return respData, nil
+}
+
+// https://clouddocs.f5.com/api/v1/spaces/default/license/tokens/{token_id}
+func (p *BigipNextCM) GetLicenseToken(tokenID string) (interface{}, error) {
+ licenseURL := fmt.Sprintf("%s%s/%s", p.Host, uriLicenseToken, tokenID)
+ f5osLogger.Info("[GetLicenseToken]", "URI Path", licenseURL)
+ respData, err := p.doCMRequest("GET", licenseURL, nil)
+ if err != nil {
+ return nil, err
+ }
+ // {
+ // "entitlement": "{\"compliance\":{\"digitalAssetComplianceStatus\":\"\",\"digitalAssetDaysRemainingInState\":0,\"digitalAssetExpiringSoon\":false,\"digitalAssetOutOfComplianceDate\":\"\",\"entitlementCheckStatus\":\"\",\"entitlementExpiryStatus\":\"\",\"telemetryStatus\":\"\",\"usageExceededStatus\":\"\"},\"documentType\":\"BIG-IP Next License\",\"documentVersion\":\"1\",\"digitalAsset\":{\"digitalAssetId\":\"\",\"digitalAssetName\":\"\",\"digitalAssetVersion\":\"\",\"telemetryId\":\"\"},\"entitlementMetadata\":{\"complianceEnforcements\":null,\"complianceStates\":null,\"enforcementBehavior\":\"\",\"enforcementPeriodDays\":0,\"entitlementModel\":\"\",\"expiringSoonNotificationDays\":0,\"entitlementExpiryDate\":\"0001-01-01T00:00:00Z\",\"gracePeriodDays\":0,\"nonContactPeriodHours\":0,\"nonFunctionalPeriodDays\":0,\"orderSubType\":\"\",\"orderType\":\"\"},\"subscriptionMetadata\":{\"programName\":\"big_ip_next_internal\",\"programTypeDescription\":\"big_ip_next_internal\",\"subscriptionId\":\"A-S00019374\",\"subscriptionExpiryDate\":\"2024-12-07T00:00:00.000Z\",\"subscriptionNotifyDays\":\"\"},\"RepositoryCertificateMetadata\":{\"sslCertificate\":\"\",\"privateKey\":\"\"}}",
+ // "id": "69609dcd-b2d4-480e-bf06-6848556a1e59",
+ // "nickName": "paid_test_jwt",
+ // "orderSubType": "internal",
+ // "orderType": "paid",
+ // "subscriptionExpiry": "2024-12-07T00:00:00Z"
+ // }
+ // create map
+ var respMap map[string]interface{}
+ err = json.Unmarshal(respData, &respMap)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Info("[GetLicenseToken]", "Data::", hclog.Fmt("%+v", respMap))
+ return respMap, nil
+}
+
+// https://clouddocs.f5.com/api/v1/spaces/default/license/tokens/{token_id}
+// delete request to delete license token
+func (p *BigipNextCM) DeleteLicenseToken(tokenID string) error {
+ licenseURL := fmt.Sprintf("%s%s/%s", p.Host, uriLicenseToken, tokenID)
+ f5osLogger.Info("[DeleteLicenseToken]", "URI Path", licenseURL)
+ respData, err := p.doCMRequest("DELETE", licenseURL, nil)
+ if err != nil {
+ return err
+ }
+ f5osLogger.Info("[DeleteLicenseToken]", "Data::", hclog.Fmt("%+v", string(respData)))
+ return nil
+}
+
type ImportCertificateRequestDraft struct {
Name string `json:"name,omitempty"`
KeyPassphrase string `json:"key_passphrase,omitempty"`
@@ -1288,155 +1367,6 @@ func (p *BigipNextCM) ProxyFileUpload(proxyID, filePath string) ([]byte, error)
return nil, nil
}
-// /api/v1/spaces/default/appsvcs/documents
-func (p *BigipNextCM) PostAS3DraftDocument(config string) (string, error) {
- as3DraftURL := fmt.Sprintf("%s%s%s", p.Host, uriAS3Root, "/documents")
- f5osLogger.Info("[PostAS3DraftDocument]", "URI Path", as3DraftURL)
- f5osLogger.Info("[PostAS3DraftDocument]", "Config", hclog.Fmt("%+v", config))
- respData, err := p.doCMRequest("POST", as3DraftURL, []byte(config))
- if err != nil {
- return "", err
- }
- f5osLogger.Info("[PostAS3DraftDocument]", "Data::", hclog.Fmt("%+v", string(respData)))
- //{"Message":"Application service created successfully","_links":{"self":{"href":"/api/v1/spaces/default/appsvcs/documents/3a220683-6527-4443-8da7-279680c21ac5"}},"id":"3a220683-6527-4443-8da7-279680c21ac5"}
- respString := make(map[string]interface{})
- err = json.Unmarshal(respData, &respString)
- if err != nil {
- return "", err
- }
- f5osLogger.Info("[PostAS3DraftDocument]", "Document Drart", hclog.Fmt("%+v", respString["id"].(string)))
- return respString["id"].(string), nil
-}
-
-// /api/v1/spaces/default/appsvcs/documents/3a220683-6527-4443-8da7-279680c21ac5
-func (p *BigipNextCM) GetAS3DraftDocument(docID string) ([]byte, error) {
- as3DraftURL := fmt.Sprintf("%s%s%s/%s", p.Host, uriAS3Root, "/documents", docID)
- f5osLogger.Info("[GetAS3DraftDocument]", "URI Path", as3DraftURL)
- respData, err := p.doCMRequest("GET", as3DraftURL, nil)
- if err != nil {
- return []byte(""), err
- }
- f5osLogger.Info("[GetAS3DraftDocument]", "Data::", hclog.Fmt("%+v", string(respData)))
- return respData, nil
-}
-
-func (p *BigipNextCM) PutAS3DraftDocument(docID, config string) error {
- as3DraftURL := fmt.Sprintf("%s%s%s/%s", p.Host, uriAS3Root, "/documents", docID)
- f5osLogger.Info("[PutAS3DraftDocument]", "URI Path", as3DraftURL)
- f5osLogger.Info("[PutAS3DraftDocument]", "Config", hclog.Fmt("%+v", config))
- respData, err := p.doCMRequest("PUT", as3DraftURL, []byte(config))
- if err != nil {
- return err
- }
- f5osLogger.Info("[PutAS3DraftDocument]", "Data::", hclog.Fmt("%+v", string(respData)))
- return nil
-}
-
-// /api/v1/spaces/default/appsvcs/documents/3a220683-6527-4443-8da7-279680c21ac5
-func (p *BigipNextCM) DeleteAS3DraftDocument(docID string) error {
- as3DraftURL := fmt.Sprintf("%s%s%s/%s", p.Host, uriAS3Root, "/documents", docID)
- f5osLogger.Info("[DeleteAS3DraftDocument]", "URI Path", as3DraftURL)
- respData, err := p.doCMRequest("DELETE", as3DraftURL, nil)
- if err != nil {
- return err
- }
- f5osLogger.Info("[DeleteAS3DraftDocument]", "Data::", hclog.Fmt("%+v", string(respData)))
- return nil
-}
-
-// https://clouddocs.f5.com/api/v1/spaces/default/appsvcs/documents/{document-id}/deployments
-func (p *BigipNextCM) CMAS3DeployNext(draftID, target string, timeOut int) (string, error) {
- as3DeployUrl := fmt.Sprintf("%s%s%s/%s/%s", p.Host, uriAS3Root, "/documents", draftID, "deployments")
- f5osLogger.Info("[CMAS3DeployNext]", "URI Path", as3DeployUrl)
- as3Json := make(map[string]interface{})
- as3Json["target"] = target
- as3data, err := json.Marshal(as3Json)
- if err != nil {
- return "", err
- }
- f5osLogger.Info("[CMAS3DeployNext]", "Data::", hclog.Fmt("%+v", string(as3data)))
- respData, err := p.doCMRequest("POST", as3DeployUrl, as3data)
- if err != nil {
- return "", err
- }
- f5osLogger.Info("[CMAS3DeployNext]", "Data::", hclog.Fmt("%+v", string(respData)))
- //{ "Message": "Deployment task created successfully", "_links": { "self": { "href": "/declare/1a5a6049-8220-483a-8cbc-275a4b190d35/deployments/2ceb048a-0ee6-4a2d-8952-cd15583bb5e8" } }, "id": "2ceb048a-0ee6-4a2d-8952-cd15583bb5e8" }
- respString := make(map[string]interface{})
- err = json.Unmarshal(respData, &respString)
- if err != nil {
- return "", err
- }
- f5osLogger.Info("[CMAS3DeployNext]", "Deployment Task", hclog.Fmt("%+v", respString["id"].(string)))
- _, err = p.getAS3DeploymentTaskStatus(draftID, respString["id"].(string), timeOut)
- if err != nil {
- return "", err
- }
- return respString["id"].(string), nil
-}
-
-// https://clouddocs.f5.com/api/v1/spaces/default/appsvcs/documents/{document-id}/deployments/{deployment-id}
-func (p *BigipNextCM) GetAS3DeploymentTaskStatus(docID, deployID string) (interface{}, error) {
- as3DeployUrl := fmt.Sprintf("%s%s%s/%s/%s/%s", p.Host, uriAS3Root, "/documents", docID, "deployments", deployID)
- f5osLogger.Info("[GetAS3DeploymentTaskStatus]", "URI Path", as3DeployUrl)
- return p.getAS3DeploymentTaskStatus(docID, deployID, 60)
-}
-
-// https://clouddocs.f5.com/api/v1/spaces/default/appsvcs/documents/{document-id}/deployments/{deployment-id}
-func (p *BigipNextCM) getAS3DeploymentTaskStatus(docID, deployID string, timeOut int) (interface{}, error) {
- as3DeployUrl := fmt.Sprintf("%s%s%s/%s/%s/%s", p.Host, uriAS3Root, "/documents", docID, "deployments", deployID)
- f5osLogger.Info("[getAS3DeploymentTaskStatus]", "URI Path", as3DeployUrl)
- responseData := make(map[string]interface{})
- timeout := time.Duration(timeOut) * time.Second
- endtime := time.Now().Add(timeout)
-outerfor:
- for time.Now().Before(endtime) {
- respData, err := p.doCMRequest("GET", as3DeployUrl, nil)
- if err != nil {
- return nil, err
- }
- err = json.Unmarshal(respData, &responseData)
- if err != nil {
- return nil, err
- }
- f5osLogger.Info("[getAS3DeploymentTaskStatus]", "Status:", hclog.Fmt("%+v", responseData["records"].([]interface{})[0].(map[string]interface{})["status"].(string)))
- for _, v := range responseData["records"].([]interface{}) {
- if v.(map[string]interface{})["status"].(string) == "failed" {
- return nil, fmt.Errorf("%v", v.(map[string]interface{})["failure_reason"].(string))
- }
- if v.(map[string]interface{})["status"].(string) != "completed" {
- time.Sleep(5 * time.Second)
- continue
- } else {
- break outerfor
- }
- }
- }
- f5osLogger.Info("[getAS3DeploymentTaskStatus]", "Response Result:", hclog.Fmt("%+v", responseData["response"]))
- // .(map[string]interface{})["results"].([]interface{})[0].(map[string]interface{})["status"].(string)))
- // if responseData["records"].([]interface{})[0].(map[string]interface{})["status"].(string) != "completed" {
- // return nil, fmt.Errorf("AS3 service deployment failed with :%+v", responseData["records"].([]interface{})[0].(map[string]interface{})["status"].(string))
- // }
- byteData, err := json.Marshal(responseData["app_data"].(map[string]interface{}))
- if err != nil {
- return nil, err
- }
- // appData := strings.Join([]string{strings.TrimSpace(string(byteData))}, "")
- return string(byteData), nil
-}
-
-// /api/v1/spaces/default/appsvcs/documents/83ff823d-477c-4666-a4c7-6b0563bb7be6/deployments/f1f55f4b-5bad-4f67-8ac2-83551502a7c8
-func (p *BigipNextCM) DeleteAS3DeploymentTask(docID string) error {
- // as3DeployUrl := fmt.Sprintf("%s%s%s/%s/%s/%s", p.Host, uriAS3Root, "/documents", docID, "deployments", deployID)
- as3DeployUrl := fmt.Sprintf("%s%s%s/%s", p.Host, uriAS3Root, "/documents", docID)
- f5osLogger.Info("[DeleteAS3DeploymentTask]", "URI Path", as3DeployUrl)
- respData, err := p.doCMRequest("DELETE", as3DeployUrl, nil)
- if err != nil {
- return err
- }
- f5osLogger.Info("[DeleteAS3DeploymentTask]", "Data::", hclog.Fmt("%+v", string(respData)))
- return nil
-}
-
type DiscoverInstanceRequest struct {
Address string `json:"address,omitempty"`
Port int `json:"port,omitempty"`
@@ -2398,145 +2328,6 @@ type TenantBackupRestoreTaskStatus struct {
Status string `json:"status,omitempty"`
}
-// /device/v1/inventory?filter=address+eq+'10.10.10.10'
-
-func (p *BigipNextCM) GetDeviceIdByIp(deviceIp string) (deviceId *string, err error) {
- deviceUrl := fmt.Sprintf("%s?filter=address+eq+'%s'", uriInventory, deviceIp)
- f5osLogger.Debug("[GetDeviceInventory]", "URI Path", deviceUrl)
- bigipNextDevice := &DeviceInventoryList{}
- respData, err := p.GetCMRequest(deviceUrl)
- if err != nil {
- return nil, err
- }
- f5osLogger.Debug("[GetDeviceIdByIp]", "Requested BIG-IP Next:", hclog.Fmt("%+v", string(respData)))
- json.Unmarshal(respData, bigipNextDevice)
- if bigipNextDevice.Count == 1 {
- deviceId := bigipNextDevice.Embedded.Devices[0].Id
- return &deviceId, nil
- }
- return nil, fmt.Errorf("the requested device:%s, was not found", deviceIp)
-}
-
-func (p *BigipNextCM) GetDeviceInfoByIp(deviceIp string) (deviceInfo interface{}, err error) {
- deviceUrl := fmt.Sprintf("%s?filter=address+eq+'%s'", uriInventory, deviceIp)
- f5osLogger.Debug("[GetDeviceInfoByIp]", "URI Path", deviceUrl)
- respData, err := p.GetCMRequest(deviceUrl)
- if err != nil {
- return nil, err
- }
- f5osLogger.Debug("[GetDeviceInfoByIp]", "Requested BIG-IP Next:", hclog.Fmt("%+v", string(respData)))
- deviceList := make(map[string]interface{})
- json.Unmarshal(respData, &deviceList)
- if len(deviceList["_embedded"].(map[string]interface{})["devices"].([]interface{})) == 1 {
- deviceInfo := deviceList["_embedded"].(map[string]interface{})["devices"].([]interface{})[0]
- return deviceInfo, nil
- }
- return nil, fmt.Errorf("the requested device:%s, was not found", deviceIp)
-}
-
-func (p *BigipNextCM) GetDeviceIdByHostname(deviceHostname string) (deviceId *string, err error) {
- deviceUrl := fmt.Sprintf("%s?filter=hostname+eq+'%s'", uriInventory, deviceHostname)
- f5osLogger.Info("[GetDeviceIdByHostname]", "URI Path", deviceUrl)
- bigipNextDevice := &DeviceInventoryList{}
- respData, err := p.GetCMRequest(deviceUrl)
- if err != nil {
- return nil, err
- }
- f5osLogger.Info("[GetDeviceIdByHostname]", "Resp BIG-IP Next:", hclog.Fmt("%+v", string(respData)))
- err = json.Unmarshal(respData, &bigipNextDevice)
- if err != nil {
- return nil, err
- }
-
- if bigipNextDevice.Count == 1 {
- deviceId := bigipNextDevice.Embedded.Devices[0].Id
- return &deviceId, nil
- }
- return nil, fmt.Errorf("the requested device:%s, was not found", deviceHostname)
-}
-
-func (p *BigipNextCM) GetDeviceInfoByID(deviceId string) (interface{}, error) {
- // deviceUrl := fmt.Sprintf("%s/%s", uriInventory, deviceId)
- deviceUrl := fmt.Sprintf("%s/%s", uriDiscoverInstance, deviceId)
- url := fmt.Sprintf("%s%s%s", p.Host, uriCMRoot, deviceUrl)
- f5osLogger.Info("[GetDeviceInfoByID]", "Request path", hclog.Fmt("%+v", url))
- dataResource, err := p.doCMRequest("GET", url, nil)
- if err != nil {
- return nil, err
- }
- f5osLogger.Info("[GetDeviceInfoByID]", "Data::", hclog.Fmt("%+v", string(dataResource)))
- var deviceInfo interface{}
- err = json.Unmarshal(dataResource, &deviceInfo)
- if err != nil {
- return nil, err
- }
- return deviceInfo, nil
-}
-
-// delete device from CM
-func (p *BigipNextCM) DeleteDevice(deviceId string) error {
- // deviceUrl := fmt.Sprintf("%s/%s", uriInventory, deviceId)
- deviceUrl := fmt.Sprintf("%s/%s", uriDiscoverInstance, deviceId)
- url := fmt.Sprintf("%s%s%s", p.Host, uriCMRoot, deviceUrl)
- f5osLogger.Info("[DeleteDevice]", "Request path", hclog.Fmt("%+v", url))
- //{"save_backup":false}
- var data = []byte(`{"save_backup":false}`)
- respData, err := p.doCMRequest("DELETE", url, data)
- // respData, err := p.DeleteCMRequest("DELETE", deviceUrl, data)
- if err != nil {
- return err
- }
- // {"_links":{"self":{"href":"/v1/deletion-tasks/02752890-5660-450c-ace9-b8e0a86a15ad"}},"path":"/v1/deletion-tasks/02752890-5660-450c-ace9-b8e0a86a15ad"}
- respString := make(map[string]interface{})
- err = json.Unmarshal(respData, &respString)
- if err != nil {
- return err
- }
- f5osLogger.Info("[DeleteDevice]", "Task Path", hclog.Fmt("%+v", respString["path"].(string)))
- //get task id from path
- pathList := strings.Split(respString["path"].(string), "/")
- taskId := pathList[len(pathList)-1]
- f5osLogger.Info("[DeleteDevice]", "Task Id", hclog.Fmt("%+v", taskId))
- err = p.deleteTaskStatus(taskId)
- if err != nil {
- return err
- }
- f5osLogger.Info("[DeleteDevice]", "Data::", hclog.Fmt("%+v", string(respData)))
- return nil
-}
-
-// https://10.10.10.10/api/device/v1/deletion-tasks/02752890-5660-450c-ace9-b8e0a86a15ad
-// verify device deletion task status
-func (p *BigipNextCM) deleteTaskStatus(taskID string) error {
- deviceUrl := fmt.Sprintf("%s/%s", "/device/v1/deletion-tasks", taskID)
- url := fmt.Sprintf("%s%s%s", p.Host, uriCMRoot, deviceUrl)
- f5osLogger.Info("[deleteTaskStatus]", "Request path", hclog.Fmt("%+v", url))
- timeout := 360 * time.Second
- endtime := time.Now().Add(timeout)
- respString := make(map[string]interface{})
- for time.Now().Before(endtime) {
- respData, err := p.doCMRequest("GET", url, nil)
- if err != nil {
- return err
- }
- f5osLogger.Debug("[deleteTaskStatus]", "Data::", hclog.Fmt("%+v", string(respData)))
- // {"_links":{"self":{"href":"/v1/deletion-tasks/642d5964-8cd9-4881-9086-1ed5ca682101"}},"address":"10.146.168.20","created":"2023-11-28T07:55:50.924918Z","device_id":"8d6c8c85-1738-4a34-b57b-d3644a2ecfcc","id":"642d5964-8cd9-4881-9086-1ed5ca682101","state":"factoryResetInstance","status":"running"}
- err = json.Unmarshal(respData, &respString)
- if err != nil {
- return err
- }
- f5osLogger.Info("[deleteTaskStatus]", "Task Status", hclog.Fmt("%+v", respString["status"].(string)))
- if respString["status"].(string) == "completed" {
- return nil
- }
- if respString["status"].(string) == "failed" {
- return fmt.Errorf("%s", respString)
- }
- time.Sleep(10 * time.Second)
- }
- return fmt.Errorf("%s", respString)
-}
-
func (p *BigipNextCM) backupTenantTaskStatus(taskidPath string, timeOut int) (*TenantBackupRestoreTaskStatus, error) {
taskData := &TenantBackupRestoreTaskStatus{}
backupUrl := fmt.Sprintf("%s%s", "/device", taskidPath)
@@ -2671,12 +2462,8 @@ func (p *BigipNextCM) DeleteBackupFile(fileName *string) error {
return nil
}
-// https://10.192.75.131/api/device/v1/providers
-// https://10.145.75.237
-
func (p *BigipNextCM) GetDeviceProviders() ([]byte, error) {
- uriProviders := "/device/v1/providers"
- // providerUrl := fmt.Sprintf("%s", uriProviders)
+ // uriProviders := "/device/v1/providers"
f5osLogger.Debug("[GetDeviceProviders]", "URI Path", uriProviders)
respData, err := p.GetCMRequest(uriProviders)
if err != nil {
@@ -2699,115 +2486,6 @@ type DeviceProviderReq struct {
CertFingerprint string `json:"cert_fingerprint,omitempty"`
} `json:"connection,omitempty"`
}
-type DeviceProviderResponse struct {
- Connection struct {
- Authentication struct {
- Type string `json:"type,omitempty"`
- Username string `json:"username,omitempty"`
- } `json:"authentication,omitempty"`
- Host string `json:"host,omitempty"`
- } `json:"connection,omitempty"`
- Id string `json:"id,omitempty"`
- Name string `json:"name,omitempty"`
- Type string `json:"type,omitempty"`
-}
-
-// https://10.145.75.237/api/device/v1/providers/vsphere
-// Create POST call to create device provider
-func (p *BigipNextCM) PostDeviceProvider(config interface{}) (*DeviceProviderResponse, error) {
- uriProviders := "/device/v1/providers/vsphere"
- if config.(*DeviceProviderReq).Type == "VELOS" || config.(*DeviceProviderReq).Type == "RSERIES" {
- uriProviders = "/device/v1/providers/f5os"
- //uriProviders = "/v1/spaces/default/providers/f5os"
- }
- providerUrl := fmt.Sprintf("%s", uriProviders)
- f5osLogger.Debug("[PostDeviceProvider]", "URI Path", providerUrl)
- f5osLogger.Debug("[PostDeviceProvider]", "Config", hclog.Fmt("%+v", config))
- body, err := json.Marshal(config)
- if err != nil {
- return nil, err
- }
- respData, err := p.PostCMRequest(providerUrl, body)
- if err != nil {
- if strings.Contains(err.Error(), "cert_fingerprint") {
- config.(*DeviceProviderReq).Connection.CertFingerprint = strings.ReplaceAll(strings.Split(string(strings.Split(err.Error(), ",")[1]), ":")[2], "\"", "")
- return p.PostDeviceProvider(config)
- }
- return nil, err
- }
- f5osLogger.Debug("[PostDeviceProvider]", "Resp::", hclog.Fmt("%+v", string(respData)))
- var providerResp DeviceProviderResponse
- err = json.Unmarshal(respData, &providerResp)
- if err != nil {
- return nil, err
- }
- return &providerResp, nil
-}
-
-func (p *BigipNextCM) UpdateDeviceProvider(providerId string, config interface{}) (*DeviceProviderResponse, error) {
- uriProviders := "/device/v1/providers/vsphere"
- if config.(*DeviceProviderReq).Type == "VELOS" || config.(*DeviceProviderReq).Type == "RSERIES" {
- uriProviders = "/device/v1/providers/f5os"
- //uriProviders = "/v1/spaces/default/providers/f5os"
- }
- providerUrl := fmt.Sprintf("%s/%s", uriProviders, providerId)
- f5osLogger.Debug("[UpdateDeviceProvider]", "URI Path", providerUrl)
- f5osLogger.Debug("[UpdateDeviceProvider]", "Config", hclog.Fmt("%+v", config))
- body, err := json.Marshal(config)
- if err != nil {
- return nil, err
- }
- respData, err := p.PutCMRequest(providerUrl, body)
- if err != nil {
- return nil, err
- }
- f5osLogger.Debug("[UpdateDeviceProvider]", "Resp::", hclog.Fmt("%+v", string(respData)))
- var providerResp DeviceProviderResponse
- err = json.Unmarshal(respData, &providerResp)
- if err != nil {
- return nil, err
- }
- return &providerResp, nil
-}
-
-func (p *BigipNextCM) GetDeviceProvider(providerId, providerType string) (*DeviceProviderResponse, error) {
- uriProviders := "/device/v1/providers/vsphere"
- if stringToUppercase(providerType) == "VELOS" || stringToUppercase(providerType) == "RSERIES" {
- uriProviders = "/device/v1/providers/f5os"
- //uriProviders = "/v1/spaces/default/providers/f5os"
- }
- providerUrl := fmt.Sprintf("%s/%s", uriProviders, providerId)
- f5osLogger.Debug("[GetDeviceProvider]", "URI Path", providerUrl)
- respData, err := p.GetCMRequest(providerUrl)
- if err != nil {
- return nil, err
- }
- f5osLogger.Info("[GetDeviceProvider]", "Data::", hclog.Fmt("%+v", string(respData)))
- var providerResp DeviceProviderResponse
- err = json.Unmarshal(respData, &providerResp)
- if err != nil {
- return nil, err
- }
- return &providerResp, nil
-}
-
-// https://10.145.75.237/api/device/v1/providers/vsphere/85bc71c3-0bfc-4b28-bb86-13f7e1c1d7af
-// Create function to delete device provider using provider id
-func (p *BigipNextCM) DeleteDeviceProvider(providerId, providerType string) ([]byte, error) {
- uriProviders := "/device/v1/providers/vsphere"
- if stringToUppercase(providerType) == "VELOS" || stringToUppercase(providerType) == "RSERIES" {
- uriProviders = "/device/v1/providers/f5os"
- //uriProviders = "/v1/spaces/default/providers/f5os"
- }
- providerUrl := fmt.Sprintf("%s/%s", uriProviders, providerId)
- f5osLogger.Debug("[DeleteDeviceProvider]", "URI Path", providerUrl)
- respData, err := p.DeleteCMRequest(providerUrl)
- if err != nil {
- return nil, err
- }
- f5osLogger.Info("[DeleteDeviceProvider]", "Data::", hclog.Fmt("%+v", string(respData)))
- return respData, nil
-}
func stringToUppercase(str string) string {
return strings.ToUpper(str)
@@ -2958,254 +2636,22 @@ func stringToUppercase(str string) string {
// return &cmReqDeviceInstance, nil
// }
-type CMReqRseriesProperties struct {
- TenantImageName string `json:"tenant_image_name"`
- TenantDeploymentFile string `json:"tenant_deployment_file"`
- VlanIds []int `json:"vlan_ids"`
- DiskSize int `json:"disk_size"`
- CpuCores int `json:"cpu_cores"`
- // ManagementAddress string `json:"management_address"`
- // ManagementNetworkWidth int `json:"management_network_width"`
- // L1Networks []string `json:"l1Networks"`
- // ManagementCredentials struct {
- // Username string `json:"username"`
- // Password string `json:"password"`
- // } `json:"management_credentials"`
- // InstanceOneTimePassword string `json:"instance_one_time_password"`
- // Hostname string `json:"hostname"`
-}
-
-type CMReqVelosProperties struct {
- TenantImageName string `json:"tenant_image_name"`
- TenantDeploymentFile string `json:"tenant_deployment_file"`
- VlanIds []int `json:"vlan_ids"`
- SlotIds []int `json:"slot_ids"`
- DiskSize int `json:"disk_size"`
- CpuCores int `json:"cpu_cores"`
-}
-
-type CMReqDeviceInstance struct {
- TemplateName string `json:"template_name,omitempty"`
- Parameters struct {
- InstantiationProvider []CMReqInstantiationProvider `json:"instantiation_provider,omitempty"`
- VSphereProperties []CMReqVsphereProperties `json:"vSphere_properties,omitempty"`
- VsphereNetworkAdapterSettings []CMReqVsphereNetworkAdapterSettings `json:"vsphere_network_adapter_settings,omitempty"`
- RseriesProperties []CMReqRseriesProperties `json:"rseries_properties,omitempty"`
- VelosProperties []CMReqVelosProperties `json:"velos_properties,omitempty"`
- DnsServers []string `json:"dns_servers,omitempty"`
- NtpServers []string `json:"ntp_servers,omitempty"`
- ManagementAddress string `json:"management_address,omitempty"`
- ManagementNetworkWidth int `json:"management_network_width,omitempty"`
- DefaultGateway string `json:"default_gateway,omitempty"`
- L1Networks []CMReqL1Networks `json:"l1Networks,omitempty"`
- ManagementCredentialsUsername string `json:"management_credentials_username,omitempty"`
- ManagementCredentialsPassword string `json:"management_credentials_password,omitempty"`
- InstanceOneTimePassword string `json:"instance_one_time_password,omitempty"`
- Hostname string `json:"hostname,omitempty"`
- } `json:"parameters,omitempty"`
-}
-
-type CMReqInstantiationProvider struct {
- Id string `json:"id,omitempty"`
- Name string `json:"name,omitempty"`
- Type string `json:"type,omitempty"`
-}
-type CMReqVsphereProperties struct {
- NumCpus int `json:"num_cpus,omitempty"`
- Memory int `json:"memory,omitempty"`
- DatacenterName string `json:"datacenter_name,omitempty"`
- ClusterName string `json:"cluster_name,omitempty"`
- DatastoreName string `json:"datastore_name,omitempty"`
- ResourcePoolName string `json:"resource_pool_name,omitempty"`
- VsphereContentLibrary string `json:"vsphere_content_library,omitempty"`
- VmTemplateName string `json:"vm_template_name,omitempty"`
-}
-type CMReqVsphereNetworkAdapterSettings struct {
- InternalNetworkName string `json:"internal_network_name,omitempty"`
- HaDataPlaneNetworkName string `json:"ha_data_plane_network_name,omitempty"`
- HaControlPlaneNetworkName string `json:"ha_control_plane_network_name,omitempty"`
- MgmtNetworkName string `json:"mgmt_network_name,omitempty"`
- ExternalNetworkName string `json:"external_network_name,omitempty"`
-}
-
-type CMReqSelfIps struct {
- Address string `json:"address,omitempty"`
- DeviceName string `json:"deviceName,omitempty"`
-}
-
-type CMReqVlans struct {
- SelfIps []CMReqSelfIps `json:"selfIps,omitempty"`
- Name string `json:"name,omitempty"`
- Tag int `json:"tag,omitempty"`
- DefaultVrf bool `json:"defaultVrf,omitempty"`
-}
-
-type CMReqL1Networks struct {
- Vlans []CMReqVlans `json:"vlans,omitempty"`
- L1Link struct {
- LinkType string `json:"linkType,omitempty"`
- Name string `json:"name,omitempty"`
- } `json:"l1Link,omitempty"`
- Name string `json:"name,omitempty"`
-}
-
-type CMReqDeviceInstanceBackup struct {
- TemplateName string `json:"template_name,omitempty"`
- Parameters struct {
- InstantiationProvider []CMReqInstantiationProvider `json:"instantiation_provider,omitempty"`
- VSphereProperties []CMReqVsphereProperties `json:"vSphere_properties,omitempty"`
- VsphereNetworkAdapterSettings []CMReqVsphereNetworkAdapterSettings `json:"vsphere_network_adapter_settings,omitempty"`
- DnsServers []string `json:"dns_servers,omitempty"`
- NtpServers []string `json:"ntp_servers,omitempty"`
- ManagementAddress string `json:"management_address,omitempty"`
- ManagementNetworkWidth int `json:"management_network_width,omitempty"`
- DefaultGateway string `json:"default_gateway,omitempty"`
- L1Networks []CMReqL1Networks `json:"l1Networks,omitempty"`
- ManagementCredentialsUsername string `json:"management_credentials_username,omitempty"`
- ManagementCredentialsPassword string `json:"management_credentials_password,omitempty"`
- InstanceOneTimePassword string `json:"instance_one_time_password,omitempty"`
- Hostname string `json:"hostname,omitempty"`
- } `json:"parameters,omitempty"`
-}
-
-func (p *BigipNextCM) PostDeviceInstance(config *CMReqDeviceInstance, timeout int) ([]byte, error) {
- uriInstances := "/device/v1/instances"
- instanceUrl := fmt.Sprintf("%s", uriInstances)
- f5osLogger.Debug("[PostDeviceInstance]", "URI Path", instanceUrl)
- f5osLogger.Debug("[PostDeviceInstance]", "Config", hclog.Fmt("%+v", config))
- body, err := json.Marshal(config)
- if err != nil {
- return nil, err
- }
- respData, err := p.PostCMRequest(instanceUrl, body)
- if err != nil {
- return nil, err
- }
- f5osLogger.Debug("[PostDeviceInstance]", "Data::", hclog.Fmt("%+v", string(respData)))
- // {"_links":{"self":{"href":"/v1/instances/tasks/deacca61-3162-4672-aac8-2d6bd2b69438"}},"path":"/v1/instances/tasks/deacca61-3162-4672-aac8-2d6bd2b69438"}
- respString := make(map[string]interface{})
- err = json.Unmarshal(respData, &respString)
- if err != nil {
- return nil, err
- }
- f5osLogger.Debug("[PostDeviceInstance]", "Task Path", hclog.Fmt("%+v", respString["path"].(string)))
- // split path string to get task id
- taskId := strings.Split(respString["path"].(string), "/")
- f5osLogger.Info("[PostDeviceInstance]", "Task Id", hclog.Fmt("%+v", taskId[len(taskId)-1]))
- // get task status
- taskData, err := p.GetDeviceInstanceTaskStatus(taskId[len(taskId)-1], timeout)
- if err != nil {
- return nil, err
- }
- f5osLogger.Info("[PostDeviceInstance]", "Task Status", hclog.Fmt("%+v", taskData))
- return respData, nil
-}
+// [
+// {
+// "digitalAssetId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
+// "jwtId": "d390f1ee-6c54-4b01-90e6-d701748f0851"
+// }
+// ]
-// /v1/instances/tasks/deacca61-3162-4672-aac8-2d6bd2b69438
-// get device instance task status
-func (p *BigipNextCM) GetDeviceInstanceTaskStatus(taskID string, timeOut int) (map[string]interface{}, error) {
- // taskData := &DeviceInstanceTaskStatus{}
- taskData := make(map[string]interface{})
- instanceUrl := fmt.Sprintf("%s%s", "/device/v1/instances/tasks/", taskID)
- f5osLogger.Debug("[GetDeviceInstanceTaskStatus]", "URI Path", instanceUrl)
- // var timeout time.Duration
- timeout := time.Duration(timeOut) * time.Second
- endtime := time.Now().Add(timeout)
- for time.Now().Before(endtime) {
- respData, err := p.GetCMRequest(instanceUrl)
- if err != nil {
- return nil, err
- }
- f5osLogger.Info("[GetDeviceInstanceTaskStatus]", "Task Status:\t", hclog.Fmt("%+v", string(respData)))
- err = json.Unmarshal(respData, &taskData)
- if err != nil {
- return nil, err
- }
- if taskData["status"] == "completed" {
- return taskData, nil
+func Contains[T comparable](s []T, e T) bool {
+ for _, v := range s {
+ if v == e {
+ return true
}
- if taskData["status"] == "failed" {
- return nil, fmt.Errorf("%s", taskData["failure_reason"])
- }
- inVal := timeOut / 10
- time.Sleep(time.Duration(inVal) * time.Second)
}
- return nil, fmt.Errorf("task Status is still in :%+v within timeout period of:%+v", taskData["status"], timeout)
-}
-
-// // convert a string to byte array
-// func stringToByteArray(str string) []byte {
-// return []byte(str)
-// }
-
-func (p *BigipNextCM) GetDeviceProviderIDByHostname(hostname string) (interface{}, error) {
- uriProviders := "/device/v1/providers"
- providerUrl := fmt.Sprintf("%s?filter=name+eq+'%s'", uriProviders, hostname)
- f5osLogger.Info("[GetDeviceProviderIDByHostname]", "URI Path", providerUrl)
- respData, err := p.GetCMRequest(providerUrl)
- if err != nil {
- return nil, err
- }
- f5osLogger.Info("[GetDeviceProviderIDByHostname]", "Requested Providers:", hclog.Fmt("%+v", string(respData)))
- var providerResp []interface{}
- err = json.Unmarshal(respData, &providerResp)
- if err != nil {
- return nil, err
- }
- if len(providerResp) == 1 && providerResp[0].(map[string]interface{})["provider_name"].(string) == hostname {
- return providerResp[0].(map[string]interface{})["provider_id"].(string), nil
- }
- return nil, fmt.Errorf("failed to get ID for provider: %+v", hostname)
-}
-
-// https://10.145.75.237/api/llm/license/a2064013-659d-4de0-8c22-773d21414885/status
-// get device license status
-func (p *BigipNextCM) GetDeviceLicenseStatus(deviceId *string) ([]byte, error) {
- uriLicense := "/llm/license"
- licenseUrl := fmt.Sprintf("%s/%s/status", uriLicense, *deviceId)
- f5osLogger.Debug("[GetDeviceLicenseStatus]", "URI Path", licenseUrl)
- respData, err := p.GetCMRequest(licenseUrl)
- if err != nil {
- return nil, err
- }
- f5osLogger.Debug("[GetDeviceLicenseStatus]", "Requested License Status:", hclog.Fmt("%+v", string(respData)))
- return respData, nil
-}
-
-func encodeUrl(urlName string) string {
- // Encode the urlName
- urlNameEncoded := url.QueryEscape(urlName)
- return urlNameEncoded
+ return false
}
-// ####################
-// POST
-// https://10.145.75.237/api/llm/tasks/token/verify
-// create post call to token verify
-
-// func (p *BigipNextCM) PostTokenVerify(config *TokenVerify) ([]byte, error) {
-// uriToken := "/llm/tasks/token/verify"
-// tokenUrl := fmt.Sprintf("%s", uriToken)
-// f5osLogger.Debug("[PostTokenVerify]", "URI Path", tokenUrl)
-// f5osLogger.Debug("[PostTokenVerify]", "Config", hclog.Fmt("%+v", config))
-// body, err := json.Marshal(config)
-// if err != nil {
-// return nil, err
-// }
-// respData, err := p.PostCMRequest(tokenUrl, body)
-// if err != nil {
-// return nil, err
-// }
-// f5osLogger.Debug("[PostTokenVerify]", "Data::", hclog.Fmt("%+v", string(respData)))
-// return respData, nil
-// }
-
-// create TokenVerify struct with below payload
-//{"jwt":"eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6InYxIiwiamt1IjoiaHR0cHM6Ly9wcm9kdWN0LmFwaXMuZjUuY29tL2VlL3Y.eyJzdWIiOiJGTkktNzYyNmVmM2QtNTc4ZC00MGU1LWI5YjYtZDI3ZmRkZTRlODBkIiwiaWF0IjoxNjQ3NDQ1NjMxLCJpc3MiOiJGNSBJbmMuIiwiYXVkIjoidXJuOmY1OnRlZW0iLCJqdGkiOiI1N2VmM2ZmMC1hNTQwLTExZWMtYjE3Ny1lYmRiMzNmYmNjZmYiLCJmNV9vcmRlcl90eXBlIjoiZXZhbCIsImY1X29yZGVyX3N1YnR5cGUiOiJ0cmlhbCJ9.cBfrqxn09rTGiSKpIu6PpDZoCKOY2BRtm6Q9xfAf0iv6IdY3YZn3iqSR1Qrl5Wgwx1uEDsNasFELdvynAQ1vDTG0QNFgSR5HKC9rFS_QBXK8G2XZuJr_XLQxKeOztzbYTn1V2aoVBeZXawcQG9YVu_MXdkDG2LL7LhWgXWVyckuF99cW1ndwsbucx2nXW7-fcU_TsDnTryt8nwQi0hiw-0DlYXEVYfHxndg_JNRlNtKL8aAgf5rUACrhQTVag7in_UuGV7jhKIk5SjVR2-lUnKA2w3Oo6WCeJv9DyIULWfkJwasBlyF9hiYiMUiTyaW7MK-Kx0w9IamlYy0KBzepFvUsUfYIsRJUnqjFHn_S1Rcg7cGiJyl4XUtVP0LKB80xfxYN2ThAiW7usNSAchepSbUXHatxyWWZavxTu1B48tQmiwBb6_OFSxw_GP1SOlE5v539uObPsJ7cTA-OiWby3VgaU4SgHuLg_ITlwcSc3FSZnQY4qYcu9k8nbhbx-2UmN6C0lkaW5ha2xe08kJWXdPzQQ3Y1bJb9T5IXWeGdGb_ppqHsV7LzuEVZJUACOVFvqXDnJPXggLnI8G_w1aCWLWpxZeRpY7iqWjVGzD5cD_eAwLYoSEUtSyG83dbRSZeDXFQSkZ6ZuLz94iySLZPR98Mi0rLfwpRlkIXBXZ_ZMDs"}
-
-// OUTPUT: {"isValid":true}
-// ####################
-
// ####################
// POST
// https://10.145.75.237/api/llm/token
@@ -3758,6 +3204,116 @@ func (p *BigipNextCM) DeleteCMHANodes(deleteNodes []string) {
}
}
+type CMExternalStorageUser struct {
+ Username string `json:"username,omitempty"`
+ Password string `json:"password,omitempty"`
+}
+
+type CMExternalStorage struct {
+ StorageType string `json:"storage_type,omitempty"`
+ StorageAddress string `json:"storage_address,omitempty"`
+ StorageSharePath string `json:"storage_share_path,omitempty"`
+ StorageShareDir string `json:"storage_share_dir"`
+ StorageUser *CMExternalStorageUser `json:"storage_user,omitempty"`
+}
+
+type CMExternalStorageStatus struct {
+ Setup string `json:"setup,omitempty"`
+ FailureMessage string `json:"failure_message,omitempty"`
+}
+
+type CMExternalStorageResp struct {
+ Spec CMExternalStorage `json:"spec,omitempty"`
+ Status CMExternalStorageStatus `json:"status,omitempty"`
+}
+
+type BootstrapCMResp struct {
+ Created string `json:"created,omitempty"`
+ Status string `json:"status,omitempty"`
+ Step string `json:"step,omitempty"`
+ Updated string `json:"updated,omitempty"`
+}
+
+func (p *BigipNextCM) AddExternalStorage(extStorage *CMExternalStorage) (string, error) {
+ uriStorage := "/v1/system/infra/external-storage"
+
+ payload, err := json.Marshal(extStorage)
+
+ if err != nil {
+ f5osLogger.Error("[AddExternalStorage]", "Error", err)
+ return "", err
+ }
+
+ resp, err := p.PostCMRequest(uriStorage, payload)
+
+ return string(resp), err
+}
+
+func (p *BigipNextCM) BootstrapCM(timeout int64) (string, error) {
+ uriBootstrap := "/v1/system/infra/bootstrap"
+ var res BootstrapCMResp
+
+ resp, err := p.PostCMRequest(uriBootstrap, nil)
+
+ if err != nil {
+ f5osLogger.Error("[BootstrapCM]", "Error", err)
+ return "", err
+ }
+
+ json.Unmarshal(resp, &res)
+
+ start := time.Now()
+
+ for res.Status == "RUNNING" && time.Since(start) < (time.Second*time.Duration(timeout)) {
+ resp, err = p.GetCMRequest(uriBootstrap)
+
+ if err != nil {
+ if strings.HasPrefix(err.Error(), `{"code":50`) {
+ time.Sleep(3 * time.Second)
+ continue
+ }
+
+ f5osLogger.Error("[BootstrapCM]", "Error", err)
+ return "", err
+ }
+
+ json.Unmarshal(resp, &res)
+
+ if res.Status == "COMPLETED" {
+ break
+ }
+
+ if res.Status == "FAILED" {
+ return "", fmt.Errorf("bootstrap failed: %v", res.Step)
+ }
+
+ f5osLogger.Info("[BootstrapCM]", "Info", fmt.Sprintf("CM Bootstrap status: %v", res.Step))
+ time.Sleep(5 * time.Second)
+ }
+
+ return string(resp), err
+}
+
+func (p *BigipNextCM) GetCMBootstrap() (string, error) {
+ uriBootstrap := "/v1/system/infra/bootstrap"
+
+ resp, err := p.GetCMRequest(uriBootstrap)
+
+ if err != nil {
+ return "", err
+ }
+
+ return string(resp), nil
+}
+
+func (p *BigipNextCM) GetCMExternalStorage() (string, error) {
+ uriStorage := "/v1/system/infra/external-storage"
+
+ resp, err := p.GetCMRequest(uriStorage)
+
+ return string(resp), err
+}
+
// https://10.144.73.240/api/device/v1/instances
// Req:
diff --git a/vendor/gitswarm.f5net.com/terraform-providers/bigipnext/cmappmgr.go b/vendor/gitswarm.f5net.com/terraform-providers/bigipnext/cmappmgr.go
new file mode 100644
index 0000000..c6e8d1b
--- /dev/null
+++ b/vendor/gitswarm.f5net.com/terraform-providers/bigipnext/cmappmgr.go
@@ -0,0 +1,175 @@
+/*
+Copyright 2023 F5 Networks Inc.
+This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+// Package bigipnext interacts with BIGIP-NEXT/CM systems using the OPEN API.
+package bigipnext
+
+import (
+ "encoding/json"
+ "fmt"
+ "time"
+
+ "github.com/hashicorp/go-hclog"
+)
+
+const (
+ uriAS3Root = "/api/v1/spaces/default/appsvcs"
+)
+
+// /api/v1/spaces/default/appsvcs/documents
+func (p *BigipNextCM) PostAS3DraftDocument(config string) (string, error) {
+ as3DraftURL := fmt.Sprintf("%s%s%s", p.Host, uriAS3Root, "/documents")
+ f5osLogger.Info("[PostAS3DraftDocument]", "URI Path", as3DraftURL)
+ f5osLogger.Info("[PostAS3DraftDocument]", "Config", hclog.Fmt("%+v", config))
+ respData, err := p.doCMRequest("POST", as3DraftURL, []byte(config))
+ if err != nil {
+ return "", err
+ }
+ f5osLogger.Info("[PostAS3DraftDocument]", "Data::", hclog.Fmt("%+v", string(respData)))
+ //{"Message":"Application service created successfully","_links":{"self":{"href":"/api/v1/spaces/default/appsvcs/documents/3a220683-6527-4443-8da7-279680c21ac5"}},"id":"3a220683-6527-4443-8da7-279680c21ac5"}
+ respString := make(map[string]interface{})
+ err = json.Unmarshal(respData, &respString)
+ if err != nil {
+ return "", err
+ }
+ f5osLogger.Info("[PostAS3DraftDocument]", "Document Drart", hclog.Fmt("%+v", respString["id"].(string)))
+ return respString["id"].(string), nil
+}
+
+// /api/v1/spaces/default/appsvcs/documents/3a220683-6527-4443-8da7-279680c21ac5
+func (p *BigipNextCM) GetAS3DraftDocument(docID string) ([]byte, error) {
+ as3DraftURL := fmt.Sprintf("%s%s%s/%s", p.Host, uriAS3Root, "/documents", docID)
+ f5osLogger.Info("[GetAS3DraftDocument]", "URI Path", as3DraftURL)
+ respData, err := p.doCMRequest("GET", as3DraftURL, nil)
+ if err != nil {
+ return []byte(""), err
+ }
+ f5osLogger.Info("[GetAS3DraftDocument]", "Data::", hclog.Fmt("%+v", string(respData)))
+ return respData, nil
+}
+
+func (p *BigipNextCM) PutAS3DraftDocument(docID, config string) error {
+ as3DraftURL := fmt.Sprintf("%s%s%s/%s", p.Host, uriAS3Root, "/documents", docID)
+ f5osLogger.Info("[PutAS3DraftDocument]", "URI Path", as3DraftURL)
+ f5osLogger.Info("[PutAS3DraftDocument]", "Config", hclog.Fmt("%+v", config))
+ respData, err := p.doCMRequest("PUT", as3DraftURL, []byte(config))
+ if err != nil {
+ return err
+ }
+ f5osLogger.Info("[PutAS3DraftDocument]", "Data::", hclog.Fmt("%+v", string(respData)))
+ return nil
+}
+
+// /api/v1/spaces/default/appsvcs/documents/3a220683-6527-4443-8da7-279680c21ac5
+func (p *BigipNextCM) DeleteAS3DraftDocument(docID string) error {
+ as3DraftURL := fmt.Sprintf("%s%s%s/%s", p.Host, uriAS3Root, "/documents", docID)
+ f5osLogger.Info("[DeleteAS3DraftDocument]", "URI Path", as3DraftURL)
+ respData, err := p.doCMRequest("DELETE", as3DraftURL, nil)
+ if err != nil {
+ return err
+ }
+ f5osLogger.Info("[DeleteAS3DraftDocument]", "Data::", hclog.Fmt("%+v", string(respData)))
+ return nil
+}
+
+// https://clouddocs.f5.com/api/v1/spaces/default/appsvcs/documents/{document-id}/deployments
+func (p *BigipNextCM) CMAS3DeployNext(draftID, target string, timeOut int) (string, error) {
+ as3DeployUrl := fmt.Sprintf("%s%s%s/%s/%s", p.Host, uriAS3Root, "/documents", draftID, "deployments")
+ f5osLogger.Info("[CMAS3DeployNext]", "URI Path", as3DeployUrl)
+ as3Json := make(map[string]interface{})
+ as3Json["target"] = target
+ as3data, err := json.Marshal(as3Json)
+ if err != nil {
+ return "", err
+ }
+ f5osLogger.Info("[CMAS3DeployNext]", "Data::", hclog.Fmt("%+v", string(as3data)))
+ respData, err := p.doCMRequest("POST", as3DeployUrl, as3data)
+ if err != nil {
+ return "", err
+ }
+ f5osLogger.Info("[CMAS3DeployNext]", "Data::", hclog.Fmt("%+v", string(respData)))
+ //{ "Message": "Deployment task created successfully", "_links": { "self": { "href": "/declare/1a5a6049-8220-483a-8cbc-275a4b190d35/deployments/2ceb048a-0ee6-4a2d-8952-cd15583bb5e8" } }, "id": "2ceb048a-0ee6-4a2d-8952-cd15583bb5e8" }
+ respString := make(map[string]interface{})
+ err = json.Unmarshal(respData, &respString)
+ if err != nil {
+ return "", err
+ }
+ f5osLogger.Info("[CMAS3DeployNext]", "Deployment Task", hclog.Fmt("%+v", respString["id"].(string)))
+ _, err = p.getAS3DeploymentTaskStatus(draftID, respString["id"].(string), timeOut)
+ if err != nil {
+ return "", err
+ }
+ return respString["id"].(string), nil
+}
+
+// https://clouddocs.f5.com/api/v1/spaces/default/appsvcs/documents/{document-id}/deployments/{deployment-id}
+func (p *BigipNextCM) GetAS3DeploymentTaskStatus(docID, deployID string) (interface{}, error) {
+ as3DeployUrl := fmt.Sprintf("%s%s%s/%s/%s/%s", p.Host, uriAS3Root, "/documents", docID, "deployments", deployID)
+ f5osLogger.Info("[GetAS3DeploymentTaskStatus]", "URI Path", as3DeployUrl)
+ return p.getAS3DeploymentTaskStatus(docID, deployID, 60)
+}
+
+// https://clouddocs.f5.com/api/v1/spaces/default/appsvcs/documents/{document-id}/deployments/{deployment-id}
+func (p *BigipNextCM) getAS3DeploymentTaskStatus(docID, deployID string, timeOut int) (interface{}, error) {
+ as3DeployUrl := fmt.Sprintf("%s%s%s/%s/%s/%s", p.Host, uriAS3Root, "/documents", docID, "deployments", deployID)
+ f5osLogger.Info("[getAS3DeploymentTaskStatus]", "URI Path", as3DeployUrl)
+ responseData := make(map[string]interface{})
+ timeout := time.Duration(timeOut) * time.Second
+ endtime := time.Now().Add(timeout)
+outerfor:
+ for time.Now().Before(endtime) {
+ respData, err := p.doCMRequest("GET", as3DeployUrl, nil)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Info("[getAS3DeploymentTaskStatus]", "respData:", hclog.Fmt("%+v", string(respData)))
+ err = json.Unmarshal(respData, &responseData)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Info("[getAS3DeploymentTaskStatus]", "Status:", hclog.Fmt("%+v", responseData["records"].([]interface{})[0].(map[string]interface{})["status"].(string)))
+ for _, v := range responseData["records"].([]interface{}) {
+ if v.(map[string]interface{})["status"].(string) == "failed" {
+ return nil, fmt.Errorf("%v", v.(map[string]interface{})["failure_reason"].(string))
+ }
+ if v.(map[string]interface{})["status"].(string) != "completed" {
+ time.Sleep(5 * time.Second)
+ continue
+ } else {
+ break outerfor
+ }
+ }
+ }
+ for _, v := range responseData["response"].(map[string]interface{})["results"].([]interface{}) {
+ if v.(map[string]interface{})["message"].(string) == "failed" {
+ tenantName := v.(map[string]interface{})["tenant"].(string)
+ return nil, fmt.Errorf("%v deployment failed", tenantName)
+ }
+ }
+ f5osLogger.Info("[getAS3DeploymentTaskStatus]", "Response Result:", hclog.Fmt("%+v", responseData["response"]))
+ // .(map[string]interface{})["results"].([]interface{})[0].(map[string]interface{})["status"].(string)))
+ // if responseData["records"].([]interface{})[0].(map[string]interface{})["status"].(string) != "completed" {
+ // return nil, fmt.Errorf("AS3 service deployment failed with :%+v", responseData["records"].([]interface{})[0].(map[string]interface{})["status"].(string))
+ // }
+ byteData, err := json.Marshal(responseData["request"].(map[string]interface{}))
+ if err != nil {
+ return nil, err
+ }
+ // appData := strings.Join([]string{strings.TrimSpace(string(byteData))}, "")
+ return string(byteData), nil
+}
+
+// /api/v1/spaces/default/appsvcs/documents/83ff823d-477c-4666-a4c7-6b0563bb7be6/deployments/f1f55f4b-5bad-4f67-8ac2-83551502a7c8
+func (p *BigipNextCM) DeleteAS3DeploymentTask(docID string) error {
+ // as3DeployUrl := fmt.Sprintf("%s%s%s/%s/%s/%s", p.Host, uriAS3Root, "/documents", docID, "deployments", deployID)
+ as3DeployUrl := fmt.Sprintf("%s%s%s/%s", p.Host, uriAS3Root, "/documents", docID)
+ f5osLogger.Info("[DeleteAS3DeploymentTask]", "URI Path", as3DeployUrl)
+ respData, err := p.doCMRequest("DELETE", as3DeployUrl, nil)
+ if err != nil {
+ return err
+ }
+ f5osLogger.Info("[DeleteAS3DeploymentTask]", "Data::", hclog.Fmt("%+v", string(respData)))
+ return nil
+}
diff --git a/vendor/gitswarm.f5net.com/terraform-providers/bigipnext/cminstance.go b/vendor/gitswarm.f5net.com/terraform-providers/bigipnext/cminstance.go
new file mode 100644
index 0000000..4efdb5f
--- /dev/null
+++ b/vendor/gitswarm.f5net.com/terraform-providers/bigipnext/cminstance.go
@@ -0,0 +1,708 @@
+/*
+Copyright 2024 F5 Networks Inc.
+This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
+If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
+*/
+// Package bigipnext interacts with BIGIP-NEXT/CM systems using the OPEN API.
+package bigipnext
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/url"
+ "strings"
+ "time"
+
+ "github.com/hashicorp/go-hclog"
+)
+
+const (
+ uriInventory = "/device/v1/inventory"
+ uriProviders = "/v1/spaces/default/providers"
+ uriDiscoverInstance = "/v1/spaces/default/instances"
+ uriLicense = "/v1/spaces/default/instances/license"
+ // uriLicenseActivate = "/v1/spaces/default/instances/license/activate"
+)
+
+type DeviceInventoryList struct {
+ Embedded struct {
+ Devices []struct {
+ Links struct {
+ Self struct {
+ Href string `json:"href"`
+ } `json:"self"`
+ } `json:"_links"`
+ Address string `json:"address"`
+ CertificateValidated time.Time `json:"certificate_validated"`
+ CertificateValidationError string `json:"certificate_validation_error"`
+ CertificateValidity bool `json:"certificate_validity"`
+ Hostname string `json:"hostname"`
+ Id string `json:"id"`
+ Mode string `json:"mode"`
+ PlatformType string `json:"platform_type"`
+ Port int `json:"port"`
+ Version string `json:"version"`
+ } `json:"devices"`
+ } `json:"_embedded"`
+ Count int `json:"count"`
+ Total int `json:"total"`
+}
+
+type CMReqRseriesProperties struct {
+ TenantImageName string `json:"tenant_image_name"`
+ TenantDeploymentFile string `json:"tenant_deployment_file"`
+ VlanIds []int `json:"vlan_ids"`
+ DiskSize int `json:"disk_size"`
+ CpuCores int `json:"cpu_cores"`
+ // ManagementAddress string `json:"management_address"`
+ // ManagementNetworkWidth int `json:"management_network_width"`
+ // L1Networks []string `json:"l1Networks"`
+ // ManagementCredentials struct {
+ // Username string `json:"username"`
+ // Password string `json:"password"`
+ // } `json:"management_credentials"`
+ // InstanceOneTimePassword string `json:"instance_one_time_password"`
+ // Hostname string `json:"hostname"`
+}
+
+type CMReqVelosProperties struct {
+ TenantImageName string `json:"tenant_image_name"`
+ TenantDeploymentFile string `json:"tenant_deployment_file"`
+ VlanIds []int `json:"vlan_ids"`
+ SlotIds []int `json:"slot_ids"`
+ DiskSize int `json:"disk_size"`
+ CpuCores int `json:"cpu_cores"`
+}
+
+type CMReqInstantiationProvider struct {
+ Id string `json:"id,omitempty"`
+ Name string `json:"name,omitempty"`
+ Type string `json:"type,omitempty"`
+}
+type CMReqVsphereProperties struct {
+ NumCpus int `json:"num_cpus,omitempty"`
+ Memory int `json:"memory,omitempty"`
+ DatacenterName string `json:"datacenter_name,omitempty"`
+ ClusterName string `json:"cluster_name,omitempty"`
+ DatastoreName string `json:"datastore_name,omitempty"`
+ ResourcePoolName string `json:"resource_pool_name,omitempty"`
+ VsphereContentLibrary string `json:"vsphere_content_library,omitempty"`
+ VmTemplateName string `json:"vm_template_name,omitempty"`
+}
+type CMReqVsphereNetworkAdapterSettings struct {
+ InternalNetworkName string `json:"internal_network_name,omitempty"`
+ HaDataPlaneNetworkName string `json:"ha_data_plane_network_name,omitempty"`
+ HaControlPlaneNetworkName string `json:"ha_control_plane_network_name,omitempty"`
+ MgmtNetworkName string `json:"mgmt_network_name,omitempty"`
+ ExternalNetworkName string `json:"external_network_name,omitempty"`
+}
+
+type CMReqSelfIps struct {
+ Address string `json:"address,omitempty"`
+ DeviceName string `json:"deviceName,omitempty"`
+}
+
+type CMReqVlans struct {
+ SelfIps []CMReqSelfIps `json:"selfIps,omitempty"`
+ Name string `json:"name,omitempty"`
+ Tag int `json:"tag,omitempty"`
+ DefaultVrf bool `json:"defaultVrf,omitempty"`
+}
+
+type CMReqL1Networks struct {
+ Vlans []CMReqVlans `json:"vlans,omitempty"`
+ L1Link struct {
+ LinkType string `json:"linkType,omitempty"`
+ Name string `json:"name,omitempty"`
+ } `json:"l1Link,omitempty"`
+ Name string `json:"name,omitempty"`
+}
+
+type CMReqDeviceInstance struct {
+ TemplateName string `json:"template_name,omitempty"`
+ Parameters struct {
+ InstantiationProvider []CMReqInstantiationProvider `json:"instantiation_provider,omitempty"`
+ VSphereProperties []CMReqVsphereProperties `json:"vSphere_properties,omitempty"`
+ VsphereNetworkAdapterSettings []CMReqVsphereNetworkAdapterSettings `json:"vsphere_network_adapter_settings,omitempty"`
+ RseriesProperties []CMReqRseriesProperties `json:"rseries_properties,omitempty"`
+ VelosProperties []CMReqVelosProperties `json:"velos_properties,omitempty"`
+ DnsServers []string `json:"dns_servers,omitempty"`
+ NtpServers []string `json:"ntp_servers,omitempty"`
+ ManagementAddress string `json:"management_address,omitempty"`
+ ManagementNetworkWidth int `json:"management_network_width,omitempty"`
+ DefaultGateway string `json:"default_gateway,omitempty"`
+ L1Networks []CMReqL1Networks `json:"l1Networks,omitempty"`
+ ManagementCredentialsUsername string `json:"management_credentials_username,omitempty"`
+ ManagementCredentialsPassword string `json:"management_credentials_password,omitempty"`
+ InstanceOneTimePassword string `json:"instance_one_time_password,omitempty"`
+ Hostname string `json:"hostname,omitempty"`
+ } `json:"parameters,omitempty"`
+}
+
+type CMReqDeviceInstanceBackup struct {
+ TemplateName string `json:"template_name,omitempty"`
+ Parameters struct {
+ InstantiationProvider []CMReqInstantiationProvider `json:"instantiation_provider,omitempty"`
+ VSphereProperties []CMReqVsphereProperties `json:"vSphere_properties,omitempty"`
+ VsphereNetworkAdapterSettings []CMReqVsphereNetworkAdapterSettings `json:"vsphere_network_adapter_settings,omitempty"`
+ DnsServers []string `json:"dns_servers,omitempty"`
+ NtpServers []string `json:"ntp_servers,omitempty"`
+ ManagementAddress string `json:"management_address,omitempty"`
+ ManagementNetworkWidth int `json:"management_network_width,omitempty"`
+ DefaultGateway string `json:"default_gateway,omitempty"`
+ L1Networks []CMReqL1Networks `json:"l1Networks,omitempty"`
+ ManagementCredentialsUsername string `json:"management_credentials_username,omitempty"`
+ ManagementCredentialsPassword string `json:"management_credentials_password,omitempty"`
+ InstanceOneTimePassword string `json:"instance_one_time_password,omitempty"`
+ Hostname string `json:"hostname,omitempty"`
+ } `json:"parameters,omitempty"`
+}
+
+type DeviceProviderResponse struct {
+ Connection struct {
+ Authentication struct {
+ Type string `json:"type,omitempty"`
+ Username string `json:"username,omitempty"`
+ } `json:"authentication,omitempty"`
+ Host string `json:"host,omitempty"`
+ } `json:"connection,omitempty"`
+ Id string `json:"id,omitempty"`
+ Name string `json:"name,omitempty"`
+ Type string `json:"type,omitempty"`
+}
+
+// /device/v1/inventory?filter=address+eq+'10.10.10.10'
+func (p *BigipNextCM) GetDeviceIdByIp(deviceIp string) (deviceId *string, err error) {
+ deviceUrl := fmt.Sprintf("%s?filter=address+eq+'%s'", uriInventory, deviceIp)
+ f5osLogger.Debug("[GetDeviceInventory]", "URI Path", deviceUrl)
+ bigipNextDevice := &DeviceInventoryList{}
+ respData, err := p.GetCMRequest(deviceUrl)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Debug("[GetDeviceIdByIp]", "Requested BIG-IP Next:", hclog.Fmt("%+v", string(respData)))
+ json.Unmarshal(respData, bigipNextDevice)
+ if bigipNextDevice.Count == 1 {
+ deviceId := bigipNextDevice.Embedded.Devices[0].Id
+ return &deviceId, nil
+ }
+ return nil, fmt.Errorf("the requested device:%s, was not found", deviceIp)
+}
+
+func (p *BigipNextCM) GetDeviceInfoByIp(deviceIp string) (deviceInfo interface{}, err error) {
+ deviceUrl := fmt.Sprintf("%s?filter=address+eq+'%s'", uriInventory, deviceIp)
+ f5osLogger.Debug("[GetDeviceInfoByIp]", "URI Path", deviceUrl)
+ respData, err := p.GetCMRequest(deviceUrl)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Debug("[GetDeviceInfoByIp]", "Requested BIG-IP Next:", hclog.Fmt("%+v", string(respData)))
+ deviceList := make(map[string]interface{})
+ json.Unmarshal(respData, &deviceList)
+ if len(deviceList["_embedded"].(map[string]interface{})["devices"].([]interface{})) == 1 {
+ deviceInfo := deviceList["_embedded"].(map[string]interface{})["devices"].([]interface{})[0]
+ return deviceInfo, nil
+ }
+ return nil, fmt.Errorf("the requested device:%s, was not found", deviceIp)
+}
+
+func (p *BigipNextCM) GetDeviceInfoByID(deviceId string) (interface{}, error) {
+ // deviceUrl := fmt.Sprintf("%s/%s", uriInventory, deviceId)
+ deviceUrl := fmt.Sprintf("%s/%s", uriDiscoverInstance, deviceId)
+ url := fmt.Sprintf("%s%s%s", p.Host, uriCMRoot, deviceUrl)
+ f5osLogger.Info("[GetDeviceInfoByID]", "Request path", hclog.Fmt("%+v", url))
+ dataResource, err := p.doCMRequest("GET", url, nil)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Info("[GetDeviceInfoByID]", "Data::", hclog.Fmt("%+v", string(dataResource)))
+ var deviceInfo interface{}
+ err = json.Unmarshal(dataResource, &deviceInfo)
+ if err != nil {
+ return nil, err
+ }
+ return deviceInfo, nil
+}
+
+// delete device from CM
+func (p *BigipNextCM) DeleteDevice(deviceId string) error {
+ // deviceUrl := fmt.Sprintf("%s/%s", uriInventory, deviceId)
+ deviceUrl := fmt.Sprintf("%s/%s", uriDiscoverInstance, deviceId)
+ url := fmt.Sprintf("%s%s%s", p.Host, uriCMRoot, deviceUrl)
+ f5osLogger.Info("[DeleteDevice]", "Request path", hclog.Fmt("%+v", url))
+ //{"save_backup":false}
+ var data = []byte(`{"save_backup":false}`)
+ respData, err := p.doCMRequest("DELETE", url, data)
+ // respData, err := p.DeleteCMRequest("DELETE", deviceUrl, data)
+ if err != nil {
+ return err
+ }
+ // {"_links":{"self":{"href":"/v1/deletion-tasks/02752890-5660-450c-ace9-b8e0a86a15ad"}},"path":"/v1/deletion-tasks/02752890-5660-450c-ace9-b8e0a86a15ad"}
+ respString := make(map[string]interface{})
+ err = json.Unmarshal(respData, &respString)
+ if err != nil {
+ return err
+ }
+ f5osLogger.Info("[DeleteDevice]", "Task Path", hclog.Fmt("%+v", respString["path"].(string)))
+ //get task id from path
+ pathList := strings.Split(respString["path"].(string), "/")
+ taskId := pathList[len(pathList)-1]
+ f5osLogger.Info("[DeleteDevice]", "Task Id", hclog.Fmt("%+v", taskId))
+ err = p.deleteTaskStatus(taskId)
+ if err != nil {
+ return err
+ }
+ f5osLogger.Info("[DeleteDevice]", "Data::", hclog.Fmt("%+v", string(respData)))
+ return nil
+}
+
+// https://10.10.10.10/api/device/v1/deletion-tasks/02752890-5660-450c-ace9-b8e0a86a15ad
+// verify device deletion task status
+func (p *BigipNextCM) deleteTaskStatus(taskID string) error {
+ deviceUrl := fmt.Sprintf("%s/%s", "/device/v1/deletion-tasks", taskID)
+ url := fmt.Sprintf("%s%s%s", p.Host, uriCMRoot, deviceUrl)
+ f5osLogger.Info("[deleteTaskStatus]", "Request path", hclog.Fmt("%+v", url))
+ timeout := 360 * time.Second
+ endtime := time.Now().Add(timeout)
+ respString := make(map[string]interface{})
+ for time.Now().Before(endtime) {
+ respData, err := p.doCMRequest("GET", url, nil)
+ if err != nil {
+ return err
+ }
+ f5osLogger.Debug("[deleteTaskStatus]", "Data::", hclog.Fmt("%+v", string(respData)))
+ // {"_links":{"self":{"href":"/v1/deletion-tasks/642d5964-8cd9-4881-9086-1ed5ca682101"}},"address":"10.146.168.20","created":"2023-11-28T07:55:50.924918Z","device_id":"8d6c8c85-1738-4a34-b57b-d3644a2ecfcc","id":"642d5964-8cd9-4881-9086-1ed5ca682101","state":"factoryResetInstance","status":"running"}
+ err = json.Unmarshal(respData, &respString)
+ if err != nil {
+ return err
+ }
+ f5osLogger.Info("[deleteTaskStatus]", "Task Status", hclog.Fmt("%+v", respString["status"].(string)))
+ if respString["status"].(string) == "completed" {
+ return nil
+ }
+ if respString["status"].(string) == "failed" {
+ return fmt.Errorf("%s", respString)
+ }
+ time.Sleep(10 * time.Second)
+ }
+ return fmt.Errorf("%s", respString)
+}
+
+func (p *BigipNextCM) PostDeviceProvider(config interface{}) (*DeviceProviderResponse, error) {
+ providerUrl := fmt.Sprintf("%s/vsphere", uriProviders)
+ if config.(*DeviceProviderReq).Type == "VELOS" || config.(*DeviceProviderReq).Type == "RSERIES" {
+ providerUrl = fmt.Sprintf("%s/f5os", uriProviders)
+ }
+ f5osLogger.Debug("[PostDeviceProvider]", "URI Path", providerUrl)
+ f5osLogger.Debug("[PostDeviceProvider]", "Config", hclog.Fmt("%+v", config))
+ body, err := json.Marshal(config)
+ if err != nil {
+ return nil, err
+ }
+ respData, err := p.PostCMRequest(providerUrl, body)
+ if err != nil {
+ if strings.Contains(err.Error(), "cert_fingerprint") {
+ config.(*DeviceProviderReq).Connection.CertFingerprint = strings.ReplaceAll(strings.Split(string(strings.Split(err.Error(), ",")[1]), ":")[2], "\"", "")
+ return p.PostDeviceProvider(config)
+ }
+ return nil, err
+ }
+ f5osLogger.Debug("[PostDeviceProvider]", "Resp::", hclog.Fmt("%+v", string(respData)))
+ var providerResp DeviceProviderResponse
+ err = json.Unmarshal(respData, &providerResp)
+ if err != nil {
+ return nil, err
+ }
+ return &providerResp, nil
+}
+
+func (p *BigipNextCM) UpdateDeviceProvider(providerId string, config interface{}) (*DeviceProviderResponse, error) {
+ providerUrl := fmt.Sprintf("%s/vsphere", uriProviders)
+ if config.(*DeviceProviderReq).Type == "VELOS" || config.(*DeviceProviderReq).Type == "RSERIES" {
+ providerUrl = fmt.Sprintf("%s/f5os", uriProviders)
+ }
+ providerUrl = fmt.Sprintf("%s/%s", providerUrl, providerId)
+ f5osLogger.Debug("[UpdateDeviceProvider]", "URI Path", providerUrl)
+ f5osLogger.Debug("[UpdateDeviceProvider]", "Config", hclog.Fmt("%+v", config))
+ body, err := json.Marshal(config)
+ if err != nil {
+ return nil, err
+ }
+ respData, err := p.PutCMRequest(providerUrl, body)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Debug("[UpdateDeviceProvider]", "Resp::", hclog.Fmt("%+v", string(respData)))
+ var providerResp DeviceProviderResponse
+ err = json.Unmarshal(respData, &providerResp)
+ if err != nil {
+ return nil, err
+ }
+ return &providerResp, nil
+}
+
+func (p *BigipNextCM) GetDeviceProvider(providerId, providerType string) (*DeviceProviderResponse, error) {
+ providerUrl := fmt.Sprintf("%s/vsphere", uriProviders)
+ if stringToUppercase(providerType) == "VELOS" || stringToUppercase(providerType) == "RSERIES" {
+ providerUrl = fmt.Sprintf("%s/f5os", uriProviders)
+ }
+ providerUrl = fmt.Sprintf("%s/%s", providerUrl, providerId)
+ f5osLogger.Debug("[GetDeviceProvider]", "URI Path", providerUrl)
+ respData, err := p.GetCMRequest(providerUrl)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Info("[GetDeviceProvider]", "\n--------Resp--------\n", hclog.Fmt("%+v", string(respData)))
+ var providerResp DeviceProviderResponse
+ err = json.Unmarshal(respData, &providerResp)
+ if err != nil {
+ return nil, err
+ }
+ return &providerResp, nil
+}
+
+func (p *BigipNextCM) DeleteDeviceProvider(providerId, providerType string) ([]byte, error) {
+ providerUrl := fmt.Sprintf("%s/vsphere", uriProviders)
+ if stringToUppercase(providerType) == "VELOS" || stringToUppercase(providerType) == "RSERIES" {
+ providerUrl = fmt.Sprintf("%s/f5os", uriProviders)
+ }
+ providerUrl = fmt.Sprintf("%s/%s", providerUrl, providerId)
+ f5osLogger.Debug("[DeleteDeviceProvider]", "URI Path", providerUrl)
+ respData, err := p.DeleteCMRequest(providerUrl)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Info("[DeleteDeviceProvider]", "Data::", hclog.Fmt("%+v", string(respData)))
+ return respData, nil
+}
+
+func (p *BigipNextCM) GetDeviceProviderIDByHostname(hostname string) (interface{}, error) {
+ providerUrl := fmt.Sprintf("%s?filter=name+eq+'%s'", uriProviders, hostname)
+ f5osLogger.Info("[GetDeviceProviderIDByHostname]", "URI Path", providerUrl)
+ respData, err := p.GetCMRequest(providerUrl)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Info("[GetDeviceProviderIDByHostname]", "provider query response:", hclog.Fmt("%+v", string(respData)))
+ var providerResp []interface{}
+ err = json.Unmarshal(respData, &providerResp)
+ if err != nil {
+ return nil, err
+ }
+ if len(providerResp) == 1 && providerResp[0].(map[string]interface{})["provider_name"].(string) == hostname {
+ return providerResp[0].(map[string]interface{})["provider_id"].(string), nil
+ }
+ return nil, fmt.Errorf("failed to get ID for provider: %+v", hostname)
+}
+
+func (p *BigipNextCM) GetDeviceIdByHostname(deviceHostname string) (deviceId *string, err error) {
+ deviceUrl := fmt.Sprintf("%s?filter=hostname+eq+'%s'", uriInventory, deviceHostname)
+ f5osLogger.Info("[GetDeviceIdByHostname]", "URI Path", deviceUrl)
+ bigipNextDevice := &DeviceInventoryList{}
+ respData, err := p.GetCMRequest(deviceUrl)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Info("[GetDeviceIdByHostname]", "Resp BIG-IP Next:", hclog.Fmt("%+v", string(respData)))
+ err = json.Unmarshal(respData, &bigipNextDevice)
+ if err != nil {
+ return nil, err
+ }
+
+ if bigipNextDevice.Count == 1 {
+ deviceId := bigipNextDevice.Embedded.Devices[0].Id
+ return &deviceId, nil
+ }
+ return nil, fmt.Errorf("the requested device:%s, was not found", deviceHostname)
+}
+
+func (p *BigipNextCM) PostDeviceInstance(config *CMReqDeviceInstance, timeout int) ([]byte, error) {
+ uriInstances := "/device/v1/instances"
+ instanceUrl := fmt.Sprintf("%s", uriInstances)
+ f5osLogger.Debug("[PostDeviceInstance]", "URI Path", instanceUrl)
+ f5osLogger.Debug("[PostDeviceInstance]", "Config", hclog.Fmt("%+v", config))
+ body, err := json.Marshal(config)
+ if err != nil {
+ return nil, err
+ }
+ respData, err := p.PostCMRequest(instanceUrl, body)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Debug("[PostDeviceInstance]", "Data::", hclog.Fmt("%+v", string(respData)))
+ // {"_links":{"self":{"href":"/v1/instances/tasks/deacca61-3162-4672-aac8-2d6bd2b69438"}},"path":"/v1/instances/tasks/deacca61-3162-4672-aac8-2d6bd2b69438"}
+ respString := make(map[string]interface{})
+ err = json.Unmarshal(respData, &respString)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Debug("[PostDeviceInstance]", "Task Path", hclog.Fmt("%+v", respString["path"].(string)))
+ // split path string to get task id
+ taskId := strings.Split(respString["path"].(string), "/")
+ f5osLogger.Info("[PostDeviceInstance]", "Task Id", hclog.Fmt("%+v", taskId[len(taskId)-1]))
+ // get task status
+ taskData, err := p.GetDeviceInstanceTaskStatus(taskId[len(taskId)-1], timeout)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Info("[PostDeviceInstance]", "Task Status", hclog.Fmt("%+v", taskData))
+ return respData, nil
+}
+
+// /v1/instances/tasks/deacca61-3162-4672-aac8-2d6bd2b69438
+// get device instance task status
+func (p *BigipNextCM) GetDeviceInstanceTaskStatus(taskID string, timeOut int) (map[string]interface{}, error) {
+ // taskData := &DeviceInstanceTaskStatus{}
+ taskData := make(map[string]interface{})
+ instanceUrl := fmt.Sprintf("%s%s", "/device/v1/instances/tasks/", taskID)
+ f5osLogger.Debug("[GetDeviceInstanceTaskStatus]", "URI Path", instanceUrl)
+ // var timeout time.Duration
+ timeout := time.Duration(timeOut) * time.Second
+ endtime := time.Now().Add(timeout)
+ for time.Now().Before(endtime) {
+ respData, err := p.GetCMRequest(instanceUrl)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Info("[GetDeviceInstanceTaskStatus]", "Task Status:\t", hclog.Fmt("%+v", string(respData)))
+ err = json.Unmarshal(respData, &taskData)
+ if err != nil {
+ return nil, err
+ }
+ if taskData["status"] == "completed" {
+ return taskData, nil
+ }
+ if taskData["status"] == "failed" {
+ return nil, fmt.Errorf("%s", taskData["failure_reason"])
+ }
+ inVal := timeOut / 10
+ time.Sleep(time.Duration(inVal) * time.Second)
+ }
+ return nil, fmt.Errorf("task Status is still in :%+v within timeout period of:%+v", taskData["status"], timeout)
+}
+
+type LicenseReq struct {
+ DigitalAssetId string `json:"digitalAssetId,omitempty"`
+ JwtId string `json:"jwtId,omitempty"`
+}
+
+// https://clouddocs.f5.com/api/v1/spaces/default/instances/license/activate
+// Activate License Post Req
+func (p *BigipNextCM) PostActivateLicense(config interface{}) (interface{}, error) {
+ uriLicenseActivate := fmt.Sprintf("%s%s", uriLicense, "/activate")
+ f5osLogger.Debug("[PostActivateLicense]", "URI Path", uriLicenseActivate)
+ body, err := json.Marshal(config)
+ if err != nil {
+ return nil, err
+ }
+ respData, err := p.PostCMRequest(uriLicenseActivate, body)
+ if err != nil {
+ return nil, err
+ }
+
+ // {
+ // "422b0cec-03b9-4499-a26e-c88f57869637": {
+ // "_links": {
+ // "self": {
+ // "href": "/license-task/41e49d68-d146-4e16-b286-7b57731fe14d"
+ // }
+ // },
+ // "accepted": true,
+ // "deviceId": "422b0cec-03b9-4499-a26e-c88f57869637",
+ // "reason": "",
+ // "taskId": "41e49d68-d146-4e16-b286-7b57731fe14d"
+ // },
+ // "bf89ae4b-c8f1-4c93-b47e-f2051513ad2f": {
+ // "_links": {
+ // "self": {
+ // "href": "/license-task/10786da5-a6a0-45fd-83d3-9db89a8f0a33"
+ // }
+ // },
+ // "accepted": true,
+ // "deviceId": "bf89ae4b-c8f1-4c93-b47e-f2051513ad2f",
+ // "reason": "",
+ // "taskId": "10786da5-a6a0-45fd-83d3-9db89a8f0a33"
+ // }
+ // }
+ // get taskid
+
+ respMap := make(map[string]interface{})
+ err = json.Unmarshal(respData, &respMap)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Debug("[PostActivateLicense]", "Task Path", hclog.Fmt("%+v", respMap))
+ // get task id from respMap for each device
+ var taskIds []string
+ for _, v := range respMap {
+ f5osLogger.Info("[PostActivateLicense]", "Task Id", hclog.Fmt("%+v", v.(map[string]interface{})["taskId"].(string)))
+ taskIds = append(taskIds, v.(map[string]interface{})["taskId"].(string))
+ }
+ f5osLogger.Debug("[PostActivateLicense]", "taskIds:", hclog.Fmt("%+v", taskIds))
+ lictskReq := &LicenseTaskReq{}
+ lictskReq.LicenseTaskIds = taskIds
+ return p.PostLicenseTaskStatus(lictskReq)
+ // return taskIds, nil
+}
+
+// {
+// "licenseTaskIds": [
+// "d290f1ee-6c54-4b01-90e6-d701748f0851",
+// "d290f1ee-6c54-4b01-90e6-d701748f0852",
+// "d290f1ee-6c54-4b01-90e6-d701748f0853"
+// ]
+// }
+
+type LicenseTaskReq struct {
+ LicenseTaskIds []string `json:"licenseTaskIds,omitempty"`
+}
+
+// https://clouddocs.f5.com/api/v1/spaces/default/license/tasks
+// Create POST call to get license task status
+func (p *BigipNextCM) PostLicenseTaskStatus(config interface{}) (interface{}, error) {
+ uriLicenseTasks := "/v1/spaces/default/license/tasks"
+ f5osLogger.Debug("[PostLicenseTaskStatus]", "URI Path", uriLicenseTasks)
+ body, err := json.Marshal(config)
+ if err != nil {
+ return nil, err
+ }
+ respData, err := p.PostCMRequest(uriLicenseTasks, body)
+ if err != nil {
+ return nil, err
+ }
+
+ // {
+ // "3e45e2bd-4e01-4926-8794-67bf8ceb4f61": {
+ // "_links": {
+ // "self": {
+ // "href": "/license-task/3e45e2bd-4e01-4926-8794-67bf8ceb4f61"
+ // }
+ // },
+ // "taskExecutionStatus": {
+ // "created": "2024-06-27T15:59:25.928845Z",
+ // "failureReason": "",
+ // "status": "completed",
+ // "subStatus": "TERMINATE_ACK_VERIFICATION_COMPLETE",
+ // "taskType": "deactivate"
+ // }
+ // },
+ // "dfeb50ae-c664-4b76-ac29-540f5e5178ab": {
+ // "_links": {
+ // "self": {
+ // "href": "/license-task/dfeb50ae-c664-4b76-ac29-540f5e5178ab"
+ // }
+ // },
+ // "taskExecutionStatus": {
+ // "created": "2024-06-27T15:59:25.914384Z",
+ // "failureReason": "",
+ // "status": "completed",
+ // "subStatus": "TERMINATE_ACK_VERIFICATION_COMPLETE",
+ // "taskType": "deactivate"
+ // }
+ // }
+ // }
+
+ respMap := make(map[string]interface{})
+ err = json.Unmarshal(respData, &respMap)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Debug("[PostLicenseTaskStatus]", "Task Path", hclog.Fmt("%+v", respMap))
+ // verify taskExecutionStatus
+ count := 0
+ for k, v := range respMap {
+ f5osLogger.Info("[PostLicenseTaskStatus]", "Task Id", hclog.Fmt("%+v", k))
+ if v.(map[string]interface{})["taskExecutionStatus"].(map[string]interface{})["status"].(string) == "completed" {
+ count++
+ } else if v.(map[string]interface{})["taskExecutionStatus"].(map[string]interface{})["status"].(string) == "failed" {
+ return nil, fmt.Errorf("%s", v.(map[string]interface{})["taskExecutionStatus"].(map[string]interface{})["failureReason"].(string))
+ } else {
+ time.Sleep(30 * time.Second)
+ return p.PostLicenseTaskStatus(config)
+ }
+ }
+ if count == len(respMap) {
+ return respMap, nil
+ }
+ return respMap, nil
+}
+
+// https://clouddocs.f5.com/api/v1/spaces/default/instances/license/license-info
+// create POST call to get license info
+func (p *BigipNextCM) PostLicenseInfo(config interface{}) (interface{}, error) {
+ uriLicenseInfo := fmt.Sprintf("%s%s", uriLicense, "/license-info")
+ // uriLicenseInfo := "/v1/spaces/default/instances/license/license-info"
+ f5osLogger.Debug("[PostLicenseInfo]", "URI Path", uriLicenseInfo)
+ body, err := json.Marshal(config)
+ if err != nil {
+ return nil, err
+ }
+ respData, err := p.PostCMRequest(uriLicenseInfo, body)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Debug("[PostLicenseInfo]", "Data::", hclog.Fmt("%+v", string(respData)))
+ //conver to map
+ respMap := make(map[string]interface{})
+ err = json.Unmarshal(respData, &respMap)
+ if err != nil {
+ return nil, err
+ }
+ return respMap, nil
+}
+
+type LicenseDeactivaeReq struct {
+ DigitalAssetIds []string `json:"digitalAssetIds,omitempty"`
+}
+
+// https://clouddocs.f5.com/api/v1/spaces/default/instances/license/deactivate
+func (p *BigipNextCM) PostDeactivateLicense(config interface{}) (interface{}, error) {
+ uriLicenseDeactivate := fmt.Sprintf("%s%s", uriLicense, "/deactivate")
+ // uriLicenseDeactivate := "/v1/spaces/default/instances/license/deactivate"
+ f5osLogger.Debug("[PostDeactivateLicense]", "URI Path", uriLicenseDeactivate)
+ body, err := json.Marshal(config)
+ if err != nil {
+ return nil, err
+ }
+ respData, err := p.PostCMRequest(uriLicenseDeactivate, body)
+ if err != nil {
+ return nil, err
+ }
+ respMap := make(map[string]interface{})
+ err = json.Unmarshal(respData, &respMap)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Debug("[PostDeactivateLicense]", "Task Path", hclog.Fmt("%+v", respMap))
+ // get task id from respMap for each device
+ var taskIds []string
+ for _, v := range respMap {
+ f5osLogger.Info("[PostDeactivateLicense]", "Task Id", hclog.Fmt("%+v", v.(map[string]interface{})["taskId"].(string)))
+ taskIds = append(taskIds, v.(map[string]interface{})["taskId"].(string))
+ }
+ lictskReq := &LicenseTaskReq{}
+ lictskReq.LicenseTaskIds = taskIds
+ return p.PostLicenseTaskStatus(lictskReq)
+ // f5osLogger.Debug("[PostDeactivateLicense]", "taskIds:", hclog.Fmt("%+v", taskIds))
+ // return taskIds, nil
+}
+
+// https://10.145.75.237/api/llm/license/a2064013-659d-4de0-8c22-773d21414885/status
+// get device license status
+func (p *BigipNextCM) GetDeviceLicenseStatus(deviceId *string) ([]byte, error) {
+ uriLicense := "/llm/license"
+ licenseUrl := fmt.Sprintf("%s/%s/status", uriLicense, *deviceId)
+ f5osLogger.Debug("[GetDeviceLicenseStatus]", "URI Path", licenseUrl)
+ respData, err := p.GetCMRequest(licenseUrl)
+ if err != nil {
+ return nil, err
+ }
+ f5osLogger.Debug("[GetDeviceLicenseStatus]", "Requested License Status:", hclog.Fmt("%+v", string(respData)))
+ return respData, nil
+}
+
+func encodeUrl(urlName string) string {
+ // Encode the urlName
+ urlNameEncoded := url.QueryEscape(urlName)
+ return urlNameEncoded
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 842e979..a927e2f 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -364,7 +364,7 @@ github.com/zclconf/go-cty/cty/function/stdlib
github.com/zclconf/go-cty/cty/gocty
github.com/zclconf/go-cty/cty/json
github.com/zclconf/go-cty/cty/set
-# gitswarm.f5net.com/terraform-providers/bigipnext v0.0.0-20240620103831-5476a6be942d
+# gitswarm.f5net.com/terraform-providers/bigipnext v0.0.2
## explicit; go 1.19
gitswarm.f5net.com/terraform-providers/bigipnext
# golang.org/x/crypto v0.21.0