diff --git a/.gitignore b/.gitignore index 8dab327..587c19f 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ _testmain.go *.test *.prof terraform.tfstate* + +openapi.yaml +spec.json \ No newline at end of file diff --git a/docs/resources/crawler.md b/docs/resources/crawler.md new file mode 100644 index 0000000..a8cda95 --- /dev/null +++ b/docs/resources/crawler.md @@ -0,0 +1,28 @@ +# Crawler Resource + +Provides a crawler resource to manage crawlers in Quant. + +## Example Usage + +```hcl +resource "quant_crawler" "crawler" { + project = quant_project.test.machine_name + name = "test-crawler" + domain = "example.com" + urls = ["/"] + browser_mode = false + exclude = ["/admin"] + headers = { + "X-Header" = "value" + } +} +``` + +## Argument Reference + +- `project` - (Required) The machine name of the project. +- `name` - (Required) The name of the crawler. +- `domain` - (Required) The domain to apply the crawler to. +- `urls` - (Required) The URLs to apply the crawler to. +- `browser_mode` - (Required) Whether to use browser mode. +- `exclude` - (Required) The URLs to exclude from the crawler. diff --git a/docs/resources/crawler_schedule.md b/docs/resources/crawler_schedule.md new file mode 100644 index 0000000..e8e2362 --- /dev/null +++ b/docs/resources/crawler_schedule.md @@ -0,0 +1,28 @@ +# Crawler Schedule Resource + +Manages a Quant crawler schedule. + +## Example Usage + +```hcl +resource "quant_crawler_schedule" "crawler_schedule" { + project = quant_project.test.machine_name + crawler = quant_crawler.crawler.uuid + schedule_cron_string = "0 0 * * *" +} +``` + +## Argument Reference + +- `project` - (Required) The machine name of the project. +- `crawler` - (Required) The UUID of the crawler. +- `schedule_cron_string` - (Required) The cron string to schedule the crawler. + +## Attributes Reference + +- `id` - The ID of the crawler schedule. +- `crawler_config_id` - The ID of the crawler configuration. +- `project_id` - The ID of the project. +- `crawler_last_run_id` - The ID of the last crawler run. +- `schedule_cron_string` - The cron string to schedule the crawler. +- `created_at` - The date and time the crawler schedule was created. diff --git a/docs/resources/rule_proxy.md b/docs/resources/rule_proxy.md index f593b9e..301621c 100644 --- a/docs/resources/rule_proxy.md +++ b/docs/resources/rule_proxy.md @@ -10,10 +10,21 @@ resource "quant_rule_proxy" "test" { project = quant_project.test.machine_name domain = ["any"] url = ["/proxy"] + country = "country_is" + country_is = ["US", "CA"] + method = "method_is" + method_is = ["GET", "POST"] + ip = "ip_is" + ip_is = ["192.168.1.1", "192.168.1.2"] proxy = { to = "https://backend.example.com" host = "backend.example.com" } + failover = { + failover_mode = "true" + failover_lifetime = "1h" + failover_origin_status_codes = ["200", "201"] + } waf_enabled = true waf_config = { mode = "report" @@ -27,9 +38,39 @@ resource "quant_rule_proxy" "test" { enabled = false } } + notify = "slack" + notify_config = { + origin_status_codes = ["200", "201"] + period = "60" + slack_webhook = "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX" + } + thresholds = [{ + cooldown = 60 + hits = 10 + minutes = 1 + mode = "block" + notify_slack = "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX" + rps = 1000 + type = "block" + value = "192.168.1.1" + }] } ``` +## Rule Selection Criteria + +The following parameters are used to inspect the request and determine if the rule should be applied. + +- `country` - Should be `country_is` or `country_is_not`. This tells the rules engine which variable to inspect when applying the rule. +- `country_is` - A list of country codes to match. +- `country_is_not` - A list of country codes to not match. +- `ip` - Should be `ip_is` or `ip_is_not`. This tells the rules engine which variable to inspect when applying the rule. +- `ip_is` - A list of IP addresses to match. +- `ip_is_not` - A list of IP addresses to not match. +- `method` - AnyOf `method_is` or `method_is_not`. This tells the rules engine which variable to inspect when applying the rule. +- `method_is` - A list of HTTP methods to match. +- `method_is_not` - A list of HTTP methods to not match. + ## Argument Reference - `name` - (Required) The name of the rule. diff --git a/go.mod b/go.mod index 8adfc88..8466e42 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/hashicorp/terraform-plugin-go v0.25.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.35.0 github.com/hashicorp/terraform-plugin-testing v1.11.0 - github.com/quantcdn/quant-admin-go v0.0.0-20241115034118-d5bee8cc24e8 + github.com/quantcdn/quant-admin-go v0.0.0-20241213023303-ad9791a191a1 github.com/stretchr/testify v1.9.0 ) @@ -66,5 +66,6 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/grpc v1.67.1 // indirect google.golang.org/protobuf v1.35.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 99b5d10..98b2d02 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,12 @@ github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migc github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/ProtonMail/go-crypto v1.1.0-alpha.2 h1:bkyFVUP+ROOARdgCiJzNQo2V2kiB97LyUpzH9P6Hrlg= github.com/ProtonMail/go-crypto v1.1.0-alpha.2/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk= +github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= +github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= @@ -13,6 +17,8 @@ github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZ github.com/bufbuild/protocompile v0.4.0/go.mod h1:3v93+mbWn/v3xzN+31nwkJfrEpAUwp+BagBSZWx+TP8= github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys= +github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -23,6 +29,8 @@ github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FM github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= @@ -44,6 +52,8 @@ github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -74,10 +84,16 @@ github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVW github.com/hashicorp/terraform-exec v0.21.0/go.mod h1:1PPeMYou+KDUSSeRE9szMZ/oHf4fYUmB923Wzbq1ICg= github.com/hashicorp/terraform-json v0.23.0 h1:sniCkExU4iKtTADReHzACkk8fnpQXrdD2xoR+lppBkI= github.com/hashicorp/terraform-json v0.23.0/go.mod h1:MHdXbBAbSg0GvzuWazEGKAn/cyNfIB7mN6y7KJN6y2c= +github.com/hashicorp/terraform-json v0.24.0 h1:rUiyF+x1kYawXeRth6fKFm/MdfBS6+lW4NbeATsYz8Q= +github.com/hashicorp/terraform-json v0.24.0/go.mod h1:Nfj5ubo9xbu9uiAoZVBsNOjvNKB66Oyrvtit74kC7ow= github.com/hashicorp/terraform-plugin-framework v1.12.0 h1:7HKaueHPaikX5/7cbC1r9d1m12iYHY+FlNZEGxQ42CQ= github.com/hashicorp/terraform-plugin-framework v1.12.0/go.mod h1:N/IOQ2uYjW60Jp39Cp3mw7I/OpC/GfZ0385R0YibmkE= +github.com/hashicorp/terraform-plugin-framework v1.13.0 h1:8OTG4+oZUfKgnfTdPTJwZ532Bh2BobF4H+yBiYJ/scw= +github.com/hashicorp/terraform-plugin-framework v1.13.0/go.mod h1:j64rwMGpgM3NYXTKuxrCnyubQb/4VKldEKlcG8cvmjU= github.com/hashicorp/terraform-plugin-framework-validators v0.13.0 h1:bxZfGo9DIUoLLtHMElsu+zwqI4IsMZQBRRy4iLzZJ8E= github.com/hashicorp/terraform-plugin-framework-validators v0.13.0/go.mod h1:wGeI02gEhj9nPANU62F2jCaHjXulejm/X+af4PdZaNo= +github.com/hashicorp/terraform-plugin-framework-validators v0.16.0 h1:O9QqGoYDzQT7lwTXUsZEtgabeWW96zUBh47Smn2lkFA= +github.com/hashicorp/terraform-plugin-framework-validators v0.16.0/go.mod h1:Bh89/hNmqsEWug4/XWKYBwtnw3tbz5BAy1L1OgvbIaY= github.com/hashicorp/terraform-plugin-go v0.25.0 h1:oi13cx7xXA6QciMcpcFi/rwA974rdTxjqEhXJjbAyks= github.com/hashicorp/terraform-plugin-go v0.25.0/go.mod h1:+SYagMYadJP86Kvn+TGeV+ofr/R3g4/If0O5sO96MVw= github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= @@ -92,6 +108,8 @@ github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= +github.com/hashicorp/yamux v0.1.2 h1:XtB8kyFOyHXYVFnwT5C3+Bdo8gArse7j2AQ0DA0Uey8= +github.com/hashicorp/yamux v0.1.2/go.mod h1:C+zze2n6e/7wshOZep2A70/aQU6QBRWJO/G6FT1wIns= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= @@ -118,18 +136,26 @@ github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJ github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= +github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/quantcdn/quant-admin-go v0.0.0-20241115034118-d5bee8cc24e8 h1:WCqPMWp6RnxsPrIl1cOlGc6tRfVVVMa9jGw9cYjiRGI= github.com/quantcdn/quant-admin-go v0.0.0-20241115034118-d5bee8cc24e8/go.mod h1:JDPQsgcOJGMBj3RnIbqWGHh9w5qZ+/zqrI3S3de9FWY= +github.com/quantcdn/quant-admin-go v0.0.0-20241213014220-d9bb395a27b6 h1:lWQyzMilAR8Fog+IAoHkaBtbLiJnYt+G81G0P3unVp4= +github.com/quantcdn/quant-admin-go v0.0.0-20241213014220-d9bb395a27b6/go.mod h1:JDPQsgcOJGMBj3RnIbqWGHh9w5qZ+/zqrI3S3de9FWY= +github.com/quantcdn/quant-admin-go v0.0.0-20241213023303-ad9791a191a1 h1:RQtT4/S4AHBl7OEDajYj+uuUHpmT5RyUVdS3y7l9b0Y= +github.com/quantcdn/quant-admin-go v0.0.0-20241213023303-ad9791a191a1/go.mod h1:JDPQsgcOJGMBj3RnIbqWGHh9w5qZ+/zqrI3S3de9FWY= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= @@ -138,6 +164,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= @@ -150,26 +178,36 @@ github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zclconf/go-cty v1.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ= github.com/zclconf/go-cty v1.15.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +github.com/zclconf/go-cty v1.15.1 h1:RgQYm4j2EvoBRXOPxhUvxPzRrGDo1eCOhHXuGfrj5S0= +github.com/zclconf/go-cty v1.15.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= +golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -184,6 +222,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -193,11 +233,15 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= +golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -205,16 +249,24 @@ google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAs google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs= google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/grpc v1.69.0 h1:quSiOM1GJPmPH5XtU+BCoVXcDVJJAzNcoyfC2cCjGkI= +google.golang.org/grpc v1.69.0/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= +google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/provider/crawler_resource.go b/internal/provider/crawler_resource.go index 5594c9b..8d89c94 100644 --- a/internal/provider/crawler_resource.go +++ b/internal/provider/crawler_resource.go @@ -6,11 +6,14 @@ import ( "terraform-provider-quant/internal/client" "terraform-provider-quant/internal/resource_crawler" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/types" + "gopkg.in/yaml.v3" + openapi "github.com/quantcdn/quant-admin-go" ) @@ -131,13 +134,23 @@ func callCrawlerCreateAPI(ctx context.Context, r *crawlerResource, crawler *reso req.SetDomain(crawler.Domain.ValueString()) req.SetName(crawler.Name.ValueString()) - urls := make([]string, 0, len(crawler.UrlList.Elements())) - diags.Append(crawler.UrlList.ElementsAs(ctx, &urls, false)...) + if !crawler.Urls.IsNull() { + urls := make([]string, 0, len(crawler.Urls.Elements())) + diags.Append(crawler.Urls.ElementsAs(ctx, &urls, false)...) + req.SetUrls(urls) + } - req.SetUrlList(urls) + if !crawler.Exclude.IsNull() { + exclude := make([]string, 0, len(crawler.Exclude.Elements())) + diags.Append(crawler.Exclude.ElementsAs(ctx, &exclude, false)...) + req.SetExclude(exclude) + } - // @todo: Support custom headers. - // @todo: API to support crawler config overrides. + if !crawler.Headers.IsNull() { + headers := make(map[string]string, len(crawler.Headers.Elements())) + diags.Append(crawler.Headers.ElementsAs(ctx, &headers, false)...) + req.SetHeaders(headers) + } api, _, err := r.client.Instance.CrawlersAPI.CrawlersCreate(r.client.AuthContext, r.client.Organization, crawler.Project.ValueString()).CrawlerRequest(req).Execute() @@ -149,9 +162,9 @@ func callCrawlerCreateAPI(ctx context.Context, r *crawlerResource, crawler *reso return diags } - crawler.Uuid = types.StringValue(api.Uuid) + crawler.Uuid = types.StringValue(api.GetUuid()) - return diags + return callCrawlerReadAPI(ctx, r, crawler) } func callCrawlerReadAPI(ctx context.Context, r *crawlerResource, crawler *resource_crawler.CrawlerModel) (diags diag.Diagnostics) { @@ -161,7 +174,7 @@ func callCrawlerReadAPI(ctx context.Context, r *crawlerResource, crawler *resour "Missing crawler.uuid attribute", "To read crawler information, uuid must be provided.", ) - return + return diags } if crawler.Project.IsNull() || crawler.Project.IsUnknown() { @@ -170,7 +183,7 @@ func callCrawlerReadAPI(ctx context.Context, r *crawlerResource, crawler *resour "Missing crawler.project attribute", "To read crawler information, project must be provided.", ) - return + return diags } org := r.client.Organization @@ -181,17 +194,47 @@ func callCrawlerReadAPI(ctx context.Context, r *crawlerResource, crawler *resour api, _, err := r.client.Instance.CrawlersAPI.CrawlersRead(ctx, org, crawler.Project.ValueString(), crawler.Uuid.ValueString()).Execute() if err != nil { diags.AddError("Unable to load crawler", fmt.Sprintf("Error: %s", err.Error())) - return + return diags } - // @todo API to support browser mode. - // crawler.BrowserMode = types.BoolValue(api.GetBrowserMode()) + var config map[string]interface{} - crawler.CreatedAt = types.StringValue(api.GetCreatedAt()) + if api.Config != "" { + crawler.Config = types.StringValue(api.GetConfig()) + if err := yaml.Unmarshal([]byte(api.GetConfig()), &config); err != nil { + // Continue... + } + } + + crawler.Uuid = types.StringValue(api.GetUuid()) + crawler.Name = types.StringValue(api.GetName()) crawler.Domain = types.StringValue(api.GetDomain()) crawler.DomainVerified = types.Int64Value(int64(api.GetDomainVerified())) + crawler.BrowserMode = types.BoolValue(config["browser_mode"].(bool)) + crawler.CreatedAt = types.StringValue(api.GetCreatedAt()) + crawler.UpdatedAt = types.StringValue(api.GetUpdatedAt()) + + if config["exclude"] != nil { + excludeStrs := config["exclude"].([]interface{}) + excludeVals := make([]attr.Value, len(excludeStrs)) + for i, v := range excludeStrs { + excludeVals[i] = types.StringValue(v.(string)) + } + crawler.Exclude = types.ListValueMust(types.StringType, excludeVals) + } + + if config["headers"] != nil { + headers := config["headers"].(map[string]interface{}) + headersMap := make(map[string]attr.Value) + for k, v := range headers { + headersMap[k] = types.StringValue(v.(string)) + } + crawler.Headers = types.MapValueMust(types.StringType, headersMap) + } + + crawler.UrlsList = types.StringNull() - return + return diags } func callCrawlerDeleteAPI(ctx context.Context, r *crawlerResource, crawler *resource_crawler.CrawlerModel) (diags diag.Diagnostics) { @@ -254,18 +297,24 @@ func callCrawlerUpdateAPI(ctx context.Context, r *crawlerResource, crawler *reso req.SetDomain(crawler.Domain.ValueString()) req.SetBrowserMode(crawler.BrowserMode.ValueBool()) - urls := make([]string, 0, len(crawler.UrlList.Elements())) - diags.Append(crawler.UrlList.ElementsAs(ctx, &urls, false)...) + urls := make([]string, 0, len(crawler.Urls.Elements())) + diags.Append(crawler.Urls.ElementsAs(ctx, &urls, false)...) + + req.SetUrls(urls) + + exclude := make([]string, 0, len(crawler.Exclude.Elements())) + diags.Append(crawler.Exclude.ElementsAs(ctx, &exclude, false)...) + req.SetExclude(exclude) - req.SetUrlList(urls) + headers := make(map[string]string, len(crawler.Headers.Elements())) + diags.Append(crawler.Headers.ElementsAs(ctx, &headers, false)...) + req.SetHeaders(headers) - api, _, err := r.client.Instance.CrawlersAPI.CrawlersUpdate(ctx, org, crawler.Project.ValueString(), crawler.Uuid.ValueString()).CrawlerRequestUpdate(req).Execute() + _, _, err := r.client.Instance.CrawlersAPI.CrawlersUpdate(ctx, org, crawler.Project.ValueString(), crawler.Uuid.ValueString()).CrawlerRequestUpdate(req).Execute() if err != nil { diags.AddError("Unable to update crawler", fmt.Sprintf("Error: %s", err.Error())) return } - crawler.UpdatedAt = types.StringValue(api.GetUpdatedAt()) - - return diags + return callCrawlerReadAPI(ctx, r, crawler) } diff --git a/internal/provider/crawler_schedule_resource.go b/internal/provider/crawler_schedule_resource.go new file mode 100644 index 0000000..8c108a4 --- /dev/null +++ b/internal/provider/crawler_schedule_resource.go @@ -0,0 +1,262 @@ +package provider + +import ( + "context" + "fmt" + "strconv" + "terraform-provider-quant/internal/client" + + "terraform-provider-quant/internal/resource_crawler_schedule" + + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/types" + + openapi "github.com/quantcdn/quant-admin-go" +) + +var ( + _ resource.Resource = (*crawlerScheduleResource)(nil) + _ resource.ResourceWithConfigure = (*crawlerScheduleResource)(nil) +) + +func NewCrawlerScheduleResource() resource.Resource { + return &crawlerScheduleResource{} +} + +type crawlerScheduleResource struct { + client *client.Client +} + +func (r *crawlerScheduleResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_crawler_schedule" +} + +func (r *crawlerScheduleResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = resource_crawler_schedule.CrawlerScheduleResourceSchema(ctx) +} + +func (r *crawlerScheduleResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + if req.ProviderData == nil { + return + } + client, ok := req.ProviderData.(*client.Client) + if !ok { + resp.Diagnostics.AddError( + "Unexpected resource configure type", + fmt.Sprintf("Expected *internal.Client, got: %T. Please report this issue to the provider developers", req.ProviderData), + ) + } + r.client = client +} + +func (r *crawlerScheduleResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var data resource_crawler_schedule.CrawlerScheduleModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(callCrawlerScheduleCreateAPI(ctx, r, &data)...) + if resp.Diagnostics.HasError() { + return + } + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *crawlerScheduleResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var data resource_crawler_schedule.CrawlerScheduleModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(callCrawlerScheduleReadAPI(ctx, r, &data)...) + if resp.Diagnostics.HasError() { + return + } + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *crawlerScheduleResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var data resource_crawler_schedule.CrawlerScheduleModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + // Update the crawler schedule object. + resp.Diagnostics.Append(callCrawlerScheduleUpdateAPI(ctx, r, &data)...) + if resp.Diagnostics.HasError() { + return + } + + // Save updated data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +func (r *crawlerScheduleResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var data resource_crawler_schedule.CrawlerScheduleModel + + // Read Terraform prior state data into the model + resp.Diagnostics.Append(req.State.Get(ctx, &data)...) + + if resp.Diagnostics.HasError() { + return + } + + // Delete API call logic + resp.Diagnostics.Append(callCrawlerScheduleDeleteAPI(ctx, r, &data)...) + if resp.Diagnostics.HasError() { + return + } +} + +func callCrawlerScheduleCreateAPI(ctx context.Context, r *crawlerScheduleResource, schedule *resource_crawler_schedule.CrawlerScheduleModel) (diags diag.Diagnostics) { + req := *openapi.NewCrawlerScheduleRequestWithDefaults() + + req.SetScheduleCronString(schedule.ScheduleCronString.ValueString()) + + api, _, err := r.client.Instance.CrawlerSchedulesAPI.CrawlerSchedulesCreate(r.client.AuthContext, r.client.Organization, schedule.Project.ValueString(), schedule.Crawler.ValueString()).CrawlerScheduleRequest(req).Execute() + + if err != nil { + diags.AddError( + "Unable to create crawler schedule", + fmt.Sprintf("Error: %s", err.Error()), + ) + return diags + } + + schedule.Id = types.Int64Value(int64(api.GetId())) + schedule.CrawlerConfigId = types.Int64Value(int64(api.GetCrawlerConfigId())) + schedule.ProjectId = types.Int64Value(int64(api.GetProjectId())) + schedule.CrawlerLastRunId = types.Int64Value(int64(api.GetCrawlerLastRunId())) + schedule.CreatedAt = types.StringValue(api.GetCreatedAt()) + + return diags +} + +func callCrawlerScheduleReadAPI(ctx context.Context, r *crawlerScheduleResource, schedule *resource_crawler_schedule.CrawlerScheduleModel) (diags diag.Diagnostics) { + if schedule.Id.IsUnknown() || schedule.Id.IsNull() { + diags.AddAttributeError( + path.Root("id"), + "Missing schedule.id attribute", + "To read schedule information, id must be provided.", + ) + return + } + + if schedule.Project.IsNull() || schedule.Project.IsUnknown() { + diags.AddAttributeError( + path.Root("project"), + "Missing schedule.project attribute", + "To read schedule information, project must be provided.", + ) + return + } + + org := r.client.Organization + if !schedule.Organization.IsNull() { + org = schedule.Organization.ValueString() + } + + scheduleId := strconv.FormatInt(schedule.Id.ValueInt64(), 10) + api, _, err := r.client.Instance.CrawlerSchedulesAPI.CrawlerSchedulesRead(ctx, org, schedule.Project.ValueString(), schedule.Crawler.ValueString(), scheduleId).Execute() + if err != nil { + diags.AddError("Unable to load crawler schedule", fmt.Sprintf("Error: %s", err.Error())) + return + } + + schedule.CrawlerConfigId = types.Int64Value(int64(api.GetCrawlerConfigId())) + schedule.ProjectId = types.Int64Value(int64(api.GetProjectId())) + schedule.CrawlerLastRunId = types.Int64Value(int64(api.GetCrawlerLastRunId())) + schedule.ScheduleCronString = types.StringValue(api.GetScheduleCronString()) + schedule.CreatedAt = types.StringValue(api.GetCreatedAt()) + + return +} + +func callCrawlerScheduleDeleteAPI(ctx context.Context, r *crawlerScheduleResource, schedule *resource_crawler_schedule.CrawlerScheduleModel) (diags diag.Diagnostics) { + if schedule.Id.IsUnknown() || schedule.Id.IsNull() { + diags.AddAttributeError( + path.Root("id"), + "Missing schedule.id attribute", + "To delete schedule information the schedule id must be provided", + ) + return + } + + if schedule.Project.IsNull() || schedule.Project.IsUnknown() { + diags.AddAttributeError( + path.Root("project"), + "Missing schedule.project attribute", + "To delete schedule information the schedule project must be provided", + ) + return + } + + org := r.client.Organization + if !schedule.Organization.IsNull() { + org = schedule.Organization.ValueString() + } + + scheduleId := strconv.FormatInt(schedule.Id.ValueInt64(), 10) + _, _, err := r.client.Instance.CrawlerSchedulesAPI.CrawlerSchedulesDelete(ctx, org, schedule.Project.ValueString(), schedule.Crawler.ValueString(), scheduleId).Execute() + if err != nil { + diags.AddError("Unable to delete crawler schedule", fmt.Sprintf("Error: %s", err.Error())) + } + return diags +} + +func callCrawlerScheduleUpdateAPI(ctx context.Context, r *crawlerScheduleResource, schedule *resource_crawler_schedule.CrawlerScheduleModel) (diags diag.Diagnostics) { + if schedule.Id.IsUnknown() || schedule.Id.IsNull() { + diags.AddAttributeError( + path.Root("id"), + "Missing schedule.id attribute", + "To update schedule information the schedule id must be provided", + ) + return + } + + if schedule.Project.IsNull() || schedule.Project.IsUnknown() { + diags.AddAttributeError( + path.Root("project"), + "Missing schedule.project attribute", + "To update schedule information the schedule project must be provided", + ) + return + } + + org := r.client.Organization + if !schedule.Organization.IsNull() { + org = schedule.Organization.ValueString() + } + + req := *openapi.NewCrawlerScheduleRequestUpdateWithDefaults() + req.SetScheduleCronString(schedule.ScheduleCronString.ValueString()) + + scheduleId := strconv.FormatInt(schedule.Id.ValueInt64(), 10) + api, _, err := r.client.Instance.CrawlerSchedulesAPI.CrawlerSchedulesUpdate(ctx, org, schedule.Project.ValueString(), schedule.Crawler.ValueString(), scheduleId).CrawlerScheduleRequestUpdate(req).Execute() + if err != nil { + diags.AddError("Unable to update crawler schedule", fmt.Sprintf("Error: %s", err.Error())) + return + } + + schedule.UpdatedAt = types.StringValue(api.GetUpdatedAt()) + + return diags +} diff --git a/internal/provider/project_resource.go b/internal/provider/project_resource.go index 3181e4a..b9bcf29 100644 --- a/internal/provider/project_resource.go +++ b/internal/provider/project_resource.go @@ -371,7 +371,7 @@ func callProjectDeleteAPI(ctx context.Context, r *projectResource, project *reso } org := r.client.Organization - _, _, err := r.client.Instance.ProjectsAPI.ProjectsDelete(r.client.AuthContext, org, project.MachineName.ValueString()).Execute() + _, err := r.client.Instance.ProjectsAPI.ProjectsDelete(r.client.AuthContext, org, project.MachineName.ValueString()).Execute() if err != nil { diags.AddError( diff --git a/internal/provider/rule_proxy_resource.go b/internal/provider/rule_proxy_resource.go index 70a82e5..632ed3a 100644 --- a/internal/provider/rule_proxy_resource.go +++ b/internal/provider/rule_proxy_resource.go @@ -238,24 +238,15 @@ func callRuleProxyCreateAPI(ctx context.Context, r *ruleProxyResource, data *res req.SetMethodIsNot(methodList) } - // The proxy location. - req.SetTo(data.Proxy.To.ValueString()) - req.SetHost(data.Proxy.Host.ValueString()) - req.SetCacheLifetime(int32(data.Proxy.CacheLifetime.ValueInt64())) + proxy := openapi.NewProxyConfigWithDefaults() + proxy.SetTo(data.Proxy.To.ValueString()) + proxy.SetHost(data.Proxy.Host.ValueString()) + proxy.SetCacheLifetime(int32(data.Proxy.CacheLifetime.ValueInt64())) if data.Proxy.AuthUser.ValueString() != "" && data.Proxy.AuthPass.ValueString() != "" { // Only set basic auth details if we have both. - req.SetAuthUser(data.Proxy.AuthUser.ValueString()) - req.SetAuthPass(data.Proxy.AuthPass.ValueString()) - } - - req.SetDisableSslVerify(data.Proxy.DisableSslVerify.ValueBool()) - req.SetOnlyProxy404(data.Proxy.OnlyProxy404.ValueBool()) - - if data.Failover.FailoverMode.ValueString() == "true" { - req.SetFailoverMode("true") - } else { - req.SetFailoverMode("false") + proxy.SetAuthUser(data.Proxy.AuthUser.ValueString()) + proxy.SetAuthPass(data.Proxy.AuthPass.ValueString()) } // Set strip headers. @@ -263,7 +254,26 @@ func callRuleProxyCreateAPI(ctx context.Context, r *ruleProxyResource, data *res for _, header := range data.Proxy.ProxyStripHeaders.Elements() { stripHeaders = append(stripHeaders, header.String()) } - req.SetProxyStripHeaders(stripHeaders) + proxy.SetProxyStripHeaders(stripHeaders) + + proxy.SetDisableSslVerify(data.Proxy.DisableSslVerify.ValueBool()) + proxy.SetOnlyProxy404(data.Proxy.OnlyProxy404.ValueBool()) + + req.SetProxy(*proxy) + + failover := openapi.NewFailoverConfigWithDefaults() + failover.SetFailoverMode(data.Failover.FailoverMode.ValueString()) + failover.SetFailoverOriginTtfb(data.Failover.FailoverOriginTtfb.ValueString()) + + var statusCodes []string + for _, code := range data.Failover.FailoverOriginStatusCodes.Elements() { + if strVal, ok := code.(types.String); ok { + statusCodes = append(statusCodes, strVal.ValueString()) + } + } + failover.SetFailoverOriginStatusCodes(statusCodes) + + req.SetFailover(*failover) req.SetWafEnabled(data.WafEnabled.ValueBool()) @@ -313,16 +323,6 @@ func callRuleProxyCreateAPI(ctx context.Context, r *ruleProxyResource, data *res } wafConfig.SetBlockReferer(blockReferer) - // httpbl dictionary support. - // httpbl := openapi.NewWAFConfigHttpblWithDefaults() - // httpbl.SetApiKey(data.WafConfig.Httpbl.ApiKey.ValueString()) - // httpbl.SetBlockHarvester(data.WafConfig.Httpbl.BlockHarvester.ValueBool()) - // httpbl.SetBlockSearchEngine(data.WafConfig.Httpbl.BlockSearchEngine.ValueBool()) - // httpbl.SetBlockSpam(data.WafConfig.Httpbl.BlockSpam.ValueBool()) - // httpbl.SetBlockSuspicious(data.WafConfig.Httpbl.BlockSuspicious.ValueBool()) - // httpbl.SetHttpblEnabled(data.WafConfig.Httpbl.Enabled.ValueBool()) - // wafConfig.SetHttpbl(*httpbl) - var emails []string for _, email := range data.WafConfig.NotifyEmail.Elements() { if e, ok := email.(types.String); ok { @@ -340,216 +340,13 @@ func callRuleProxyCreateAPI(ctx context.Context, r *ruleProxyResource, data *res return } - // Set required fields from API response data.Uuid = types.StringValue(api.GetUuid()) - data.RuleId = types.StringValue(api.GetRuleId()) - data.Organization = types.StringValue(r.client.Organization) - data.Action = types.StringValue("proxy") - data.Weight = types.Int64Value(0) - data.Name = types.StringValue(api.GetName()) - data.CookieName = types.StringValue(api.GetOnlyWithCookie()) - data.Rule = types.StringNull() - // Convert API domain list to types.List - domainList, diag := types.ListValueFrom(ctx, types.StringType, api.Domain) - if diag.HasError() { - diags.Append(diag...) - return - } - data.Domain = domainList - - // Convert API URL list to types.List - urlList, diag := types.ListValueFrom(ctx, types.StringType, api.Url) - if diag.HasError() { - diags.Append(diag...) + readDiags := callRuleProxyReadAPI(ctx, r, data) + if readDiags.HasError() { + diags.Append(readDiags...) return } - data.Url = urlList - - // Initialize empty lists for optional fields - emptyStringList, _ := types.ListValueFrom(ctx, types.StringType, []string{}) - - // Handle Method fields - if api.Method != nil && *api.Method != "" { - data.Method = types.StringValue(*api.Method) - if len(api.MethodIs) > 0 { - data.MethodIs, _ = types.ListValueFrom(ctx, types.StringType, api.MethodIs) - } else { - data.MethodIs = emptyStringList - } - if len(api.MethodIsNot) > 0 { - data.MethodIsNot, _ = types.ListValueFrom(ctx, types.StringType, api.MethodIsNot) - } else { - data.MethodIsNot = emptyStringList - } - } else { - data.Method = types.StringNull() - data.MethodIs = emptyStringList - data.MethodIsNot = emptyStringList - } - - // Handle Country fields - if api.Country != nil && *api.Country != "" { - data.Country = types.StringValue(*api.Country) - if len(api.CountryIs) > 0 { - data.CountryIs, _ = types.ListValueFrom(ctx, types.StringType, api.CountryIs) - } else { - data.CountryIs = emptyStringList - } - if len(api.CountryIsNot) > 0 { - data.CountryIsNot, _ = types.ListValueFrom(ctx, types.StringType, api.CountryIsNot) - } else { - data.CountryIsNot = emptyStringList - } - } else { - data.Country = types.StringNull() - data.CountryIs = emptyStringList - data.CountryIsNot = emptyStringList - } - - // Handle IP fields - if api.Ip != nil && *api.Ip != "" { - data.Ip = types.StringValue(*api.Ip) - if len(api.IpIs) > 0 { - data.IpIs, _ = types.ListValueFrom(ctx, types.StringType, api.IpIs) - } else { - data.IpIs = emptyStringList - } - if len(api.IpIsNot) > 0 { - data.IpIsNot, _ = types.ListValueFrom(ctx, types.StringType, api.IpIsNot) - } else { - data.IpIsNot = emptyStringList - } - } else { - data.Ip = types.StringNull() - data.IpIs = emptyStringList - data.IpIsNot = emptyStringList - } - - // Set proxy configuration - data.Proxy.AuthUser = types.StringValue(api.ActionConfig.GetAuthUser()) - data.Proxy.AuthPass = types.StringValue(api.ActionConfig.GetAuthPass()) - data.Proxy.CacheLifetime = types.Int64Value(int64(api.ActionConfig.GetCacheLifetime())) - data.Proxy.DisableSslVerify = types.BoolValue(api.ActionConfig.GetDisableSslVerify()) - data.Proxy.OnlyProxy404 = types.BoolValue(api.ActionConfig.GetOnlyProxy404()) - - // Set WAF configuration - data.WafConfig.NotifySlack = types.StringValue(api.GetActionConfig().WafConfig.GetNotifySlack()) - data.WafConfig.NotifySlackHitsRpm = types.Int64Value(int64(api.GetActionConfig().WafConfig.GetNotifySlackHitsRpm())) - data.WafConfig.NotifySlackRpm = types.Int64Value(int64(api.GetActionConfig().WafConfig.GetNotifySlackRpm())) - data.WafConfig.RequestHeaderName = types.StringValue(api.GetActionConfig().WafConfig.GetRequestHeaderName()) - - if len(api.GetActionConfig().WafConfig.GetThresholds()) > 0 { - thresholdObjType := types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "cooldown": types.Int64Type, - "hits": types.Int64Type, - "minutes": types.Int64Type, - "mode": types.StringType, - "notify_slack": types.StringType, - "rps": types.Int64Type, - "type": types.StringType, - "value": types.StringType, - }, - } - data.WafConfig.Thresholds, _ = types.ListValueFrom(ctx, thresholdObjType, api.GetActionConfig().WafConfig.GetThresholds()) - } else { - data.WafConfig.Thresholds = types.ListNull(types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "cooldown": types.Int64Type, - "hits": types.Int64Type, - "minutes": types.Int64Type, - "mode": types.StringType, - "notify_slack": types.StringType, - "rps": types.Int64Type, - "type": types.StringType, - "value": types.StringType, - }, - }) - } - - if len(api.GetActionConfig().WafConfig.GetBlockIp()) > 0 { - data.WafConfig.BlockIp, _ = types.ListValueFrom(ctx, types.StringType, api.GetActionConfig().WafConfig.GetBlockIp()) - } else { - data.WafConfig.BlockIp = emptyStringList - } - - if len(api.GetActionConfig().WafConfig.GetBlockUa()) > 0 { - data.WafConfig.BlockUa, _ = types.ListValueFrom(ctx, types.StringType, api.GetActionConfig().WafConfig.GetBlockUa()) - } else { - data.WafConfig.BlockUa = emptyStringList - } - - if len(api.GetActionConfig().WafConfig.GetBlockReferer()) > 0 { - data.WafConfig.BlockReferer, _ = types.ListValueFrom(ctx, types.StringType, api.GetActionConfig().WafConfig.GetBlockReferer()) - } else { - data.WafConfig.BlockReferer = emptyStringList - } - - if len(api.GetActionConfig().WafConfig.GetNotifyEmail()) > 0 { - data.WafConfig.NotifyEmail, _ = types.ListValueFrom(ctx, types.StringType, api.GetActionConfig().WafConfig.GetNotifyEmail()) - } else { - data.WafConfig.NotifyEmail = emptyStringList - } - - // Set notification config - if api.GetActionConfig().NotifyConfig != nil { - if len(api.GetActionConfig().NotifyConfig.GetOriginStatusCodes()) > 0 { - data.NotifyConfig.OriginStatusCodes, _ = types.ListValueFrom(ctx, types.StringType, api.GetActionConfig().NotifyConfig.GetOriginStatusCodes()) - } else { - data.NotifyConfig.OriginStatusCodes = emptyStringList - } - data.NotifyConfig.Period = types.StringValue(api.GetActionConfig().NotifyConfig.GetPeriod()) - data.NotifyConfig.SlackWebhook = types.StringValue(api.GetActionConfig().NotifyConfig.GetSlackWebhook()) - } else { - data.NotifyConfig = resource_rule_proxy.NotifyConfigValue{} - data.NotifyConfig.OriginStatusCodes = emptyStringList - data.NotifyConfig.Period = types.StringNull() - data.NotifyConfig.SlackWebhook = types.StringNull() - } - - // Set failover config - if api.GetActionConfig().FailoverMode != nil { - data.Failover.FailoverMode = types.StringValue(fmt.Sprintf("%v", *api.GetActionConfig().FailoverMode)) - data.Failover.FailoverLifetime = types.StringValue(*api.GetActionConfig().FailoverLifetime) - if len(api.GetActionConfig().FailoverOriginStatusCodes) > 0 { - data.Failover.FailoverOriginStatusCodes, _ = types.ListValueFrom(ctx, types.StringType, api.GetActionConfig().FailoverOriginStatusCodes) - } else { - data.Failover.FailoverOriginStatusCodes = emptyStringList - } - } else { - data.Failover = resource_rule_proxy.FailoverValue{} - data.Failover.FailoverMode = types.StringNull() - data.Failover.FailoverLifetime = types.StringNull() - data.Failover.FailoverOriginStatusCodes = emptyStringList - } - - // Initialize empty lists for optional fields - data.Failover = resource_rule_proxy.FailoverValue{ - FailoverMode: types.StringValue("false"), - FailoverLifetime: types.StringValue(""), - FailoverOriginStatusCodes: types.ListValueMust(types.StringType, []attr.Value{}), - } - - data.NotifyConfig = resource_rule_proxy.NotifyConfigValue{ - OriginStatusCodes: types.ListValueMust(types.StringType, []attr.Value{}), - Period: types.StringValue(""), - SlackWebhook: types.StringValue(""), - } - - thresholdObjType := types.ObjectType{ - AttrTypes: map[string]attr.Type{ - "cooldown": types.Int64Type, - "hits": types.Int64Type, - "minutes": types.Int64Type, - "mode": types.StringType, - "notify_slack": types.StringType, - "rps": types.Int64Type, - "type": types.StringType, - "value": types.StringType, - }, - } - data.WafConfig.Thresholds = types.ListValueMust(thresholdObjType, []attr.Value{}) return } @@ -640,31 +437,32 @@ func callRuleProxyUpdateAPI(ctx context.Context, r *ruleProxyResource, data *res } // The proxy location. - req.SetTo(data.Proxy.To.ValueString()) - req.SetHost(data.Proxy.Host.ValueString()) - req.SetCacheLifetime(int32(data.Proxy.CacheLifetime.ValueInt64())) + proxy := openapi.NewProxyConfigUpdateWithDefaults() + proxy.SetTo(data.Proxy.To.ValueString()) + proxy.SetHost(data.Proxy.Host.ValueString()) + proxy.SetCacheLifetime(int32(data.Proxy.CacheLifetime.ValueInt64())) if data.Proxy.AuthUser.ValueString() != "" && data.Proxy.AuthPass.ValueString() != "" { // Only set basic auth details if we have both. - req.SetAuthUser(data.Proxy.AuthUser.ValueString()) - req.SetAuthPass(data.Proxy.AuthPass.ValueString()) + proxy.SetAuthUser(data.Proxy.AuthUser.ValueString()) + proxy.SetAuthPass(data.Proxy.AuthPass.ValueString()) } - req.SetDisableSslVerify(data.Proxy.DisableSslVerify.ValueBool()) - req.SetOnlyProxy404(data.Proxy.OnlyProxy404.ValueBool()) + proxy.SetDisableSslVerify(data.Proxy.DisableSslVerify.ValueBool()) + proxy.SetOnlyProxy404(data.Proxy.OnlyProxy404.ValueBool()) - if data.Failover.FailoverMode.ValueString() == "true" { - req.SetFailoverMode("true") - } else { - req.SetFailoverMode("false") - } + req.SetProxy(*proxy) + failover := openapi.NewFailoverConfigWithDefaults() + failover.SetFailoverMode(data.Failover.FailoverMode.ValueString()) + failover.SetFailoverOriginTtfb(data.Failover.FailoverOriginTtfb.ValueString()) // Set strip headers. var stripHeaders []string for _, header := range data.Proxy.ProxyStripHeaders.Elements() { stripHeaders = append(stripHeaders, header.String()) } - req.SetProxyStripHeaders(stripHeaders) + proxy.SetProxyStripHeaders(stripHeaders) + req.SetFailover(*failover) req.SetWafEnabled(data.WafEnabled.ValueBool()) @@ -714,16 +512,6 @@ func callRuleProxyUpdateAPI(ctx context.Context, r *ruleProxyResource, data *res } wafConfig.SetBlockReferer(blockReferer) - // httpbl dictionary support. - // httpbl := openapi.NewWAFConfigUpdateHttpblWithDefaults() - // httpbl.SetApiKey(data.WafConfig.Httpbl.ApiKey.ValueString()) - // httpbl.SetBlockHarvester(data.WafConfig.Httpbl.BlockHarvester.ValueBool()) - // httpbl.SetBlockSearchEngine(data.WafConfig.Httpbl.BlockSearchEngine.ValueBool()) - // httpbl.SetBlockSpam(data.WafConfig.Httpbl.BlockSpam.ValueBool()) - // httpbl.SetBlockSuspicious(data.WafConfig.Httpbl.BlockSuspicious.ValueBool()) - // httpbl.SetHttpblEnabled(data.WafConfig.Httpbl.Enabled.ValueBool()) - // wafConfig.SetHttpbl(*httpbl) - var emails []string for _, email := range data.WafConfig.NotifyEmail.Elements() { if e, ok := email.(types.String); ok { @@ -761,7 +549,7 @@ func callRuleProxyDeleteAPI(ctx context.Context, r *ruleProxyResource, data *res } org := r.client.Organization - _, _, err := r.client.Instance.RulesProxyAPI.RulesProxyDelete(r.client.AuthContext, org, data.Project.ValueString(), data.RuleId.ValueString()).Execute() + _, err := r.client.Instance.RulesProxyAPI.RulesProxyDelete(r.client.AuthContext, org, data.Project.ValueString(), data.RuleId.ValueString()).Execute() if err != nil { diags.AddError("Failed to delete rule proxy", err.Error()) @@ -877,11 +665,13 @@ func callRuleProxyReadAPI(ctx context.Context, r *ruleProxyResource, data *resou } // Set proxy configuration - data.Proxy.AuthUser = types.StringValue(api.ActionConfig.GetAuthUser()) - data.Proxy.AuthPass = types.StringValue(api.ActionConfig.GetAuthPass()) - data.Proxy.CacheLifetime = types.Int64Value(int64(api.ActionConfig.GetCacheLifetime())) - data.Proxy.DisableSslVerify = types.BoolValue(api.ActionConfig.GetDisableSslVerify()) - data.Proxy.OnlyProxy404 = types.BoolValue(api.ActionConfig.GetOnlyProxy404()) + actionConfig := api.GetActionConfig() + proxy := actionConfig.Proxy + data.Proxy.AuthUser = types.StringValue(proxy.GetAuthUser()) + data.Proxy.AuthPass = types.StringValue(proxy.GetAuthPass()) + data.Proxy.CacheLifetime = types.Int64Value(int64(proxy.GetCacheLifetime())) + data.Proxy.DisableSslVerify = types.BoolValue(proxy.GetDisableSslVerify()) + data.Proxy.OnlyProxy404 = types.BoolValue(proxy.GetOnlyProxy404()) // Set WAF configuration data.WafConfig.NotifySlack = types.StringValue(api.GetActionConfig().WafConfig.GetNotifySlack()) @@ -918,39 +708,39 @@ func callRuleProxyReadAPI(ctx context.Context, r *ruleProxyResource, data *resou }) } - if len(api.GetActionConfig().WafConfig.GetBlockIp()) > 0 { - data.WafConfig.BlockIp, _ = types.ListValueFrom(ctx, types.StringType, api.GetActionConfig().WafConfig.GetBlockIp()) + if len(actionConfig.WafConfig.GetBlockIp()) > 0 { + data.WafConfig.BlockIp, _ = types.ListValueFrom(ctx, types.StringType, actionConfig.WafConfig.GetBlockIp()) } else { data.WafConfig.BlockIp = emptyStringList } - if len(api.GetActionConfig().WafConfig.GetBlockUa()) > 0 { - data.WafConfig.BlockUa, _ = types.ListValueFrom(ctx, types.StringType, api.GetActionConfig().WafConfig.GetBlockUa()) + if len(actionConfig.WafConfig.GetBlockUa()) > 0 { + data.WafConfig.BlockUa, _ = types.ListValueFrom(ctx, types.StringType, actionConfig.WafConfig.GetBlockUa()) } else { data.WafConfig.BlockUa = emptyStringList } - if len(api.GetActionConfig().WafConfig.GetBlockReferer()) > 0 { - data.WafConfig.BlockReferer, _ = types.ListValueFrom(ctx, types.StringType, api.GetActionConfig().WafConfig.GetBlockReferer()) + if len(actionConfig.WafConfig.GetBlockReferer()) > 0 { + data.WafConfig.BlockReferer, _ = types.ListValueFrom(ctx, types.StringType, actionConfig.WafConfig.GetBlockReferer()) } else { data.WafConfig.BlockReferer = emptyStringList } - if len(api.GetActionConfig().WafConfig.GetNotifyEmail()) > 0 { - data.WafConfig.NotifyEmail, _ = types.ListValueFrom(ctx, types.StringType, api.GetActionConfig().WafConfig.GetNotifyEmail()) + if len(actionConfig.WafConfig.GetNotifyEmail()) > 0 { + data.WafConfig.NotifyEmail, _ = types.ListValueFrom(ctx, types.StringType, actionConfig.WafConfig.GetNotifyEmail()) } else { data.WafConfig.NotifyEmail = emptyStringList } // Set notification config - if api.GetActionConfig().NotifyConfig != nil { - if len(api.GetActionConfig().NotifyConfig.GetOriginStatusCodes()) > 0 { - data.NotifyConfig.OriginStatusCodes, _ = types.ListValueFrom(ctx, types.StringType, api.GetActionConfig().NotifyConfig.GetOriginStatusCodes()) + if actionConfig.NotifyConfig != nil { + if len(actionConfig.NotifyConfig.GetOriginStatusCodes()) > 0 { + data.NotifyConfig.OriginStatusCodes, _ = types.ListValueFrom(ctx, types.StringType, actionConfig.NotifyConfig.GetOriginStatusCodes()) } else { data.NotifyConfig.OriginStatusCodes = emptyStringList } - data.NotifyConfig.Period = types.StringValue(api.GetActionConfig().NotifyConfig.GetPeriod()) - data.NotifyConfig.SlackWebhook = types.StringValue(api.GetActionConfig().NotifyConfig.GetSlackWebhook()) + data.NotifyConfig.Period = types.StringValue(actionConfig.NotifyConfig.GetPeriod()) + data.NotifyConfig.SlackWebhook = types.StringValue(actionConfig.NotifyConfig.GetSlackWebhook()) } else { data.NotifyConfig = resource_rule_proxy.NotifyConfigValue{} data.NotifyConfig.OriginStatusCodes = emptyStringList @@ -959,18 +749,13 @@ func callRuleProxyReadAPI(ctx context.Context, r *ruleProxyResource, data *resou } // Set failover config - if api.GetActionConfig().FailoverMode != nil { - data.Failover.FailoverMode = types.StringValue(fmt.Sprintf("%v", *api.GetActionConfig().FailoverMode)) - data.Failover.FailoverLifetime = types.StringValue(*api.GetActionConfig().FailoverLifetime) - if len(api.GetActionConfig().FailoverOriginStatusCodes) > 0 { - data.Failover.FailoverOriginStatusCodes, _ = types.ListValueFrom(ctx, types.StringType, api.GetActionConfig().FailoverOriginStatusCodes) - } else { - data.Failover.FailoverOriginStatusCodes = emptyStringList - } + failover := actionConfig.GetFailover() + + data.Failover.FailoverMode = types.StringValue(fmt.Sprintf("%v", *failover.FailoverMode)) + data.Failover.FailoverLifetime = types.StringValue(*failover.FailoverLifetime) + if len(failover.FailoverOriginStatusCodes) > 0 { + data.Failover.FailoverOriginStatusCodes, _ = types.ListValueFrom(ctx, types.StringType, failover.FailoverOriginStatusCodes) } else { - data.Failover = resource_rule_proxy.FailoverValue{} - data.Failover.FailoverMode = types.StringNull() - data.Failover.FailoverLifetime = types.StringNull() data.Failover.FailoverOriginStatusCodes = emptyStringList } diff --git a/internal/resource_crawler/crawler_resource_gen.go b/internal/resource_crawler/crawler_resource_gen.go index d77e3b9..68f2c15 100644 --- a/internal/resource_crawler/crawler_resource_gen.go +++ b/internal/resource_crawler/crawler_resource_gen.go @@ -4,6 +4,7 @@ package resource_crawler import ( "context" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64default" "github.com/hashicorp/terraform-plugin-framework/types" @@ -16,6 +17,7 @@ func CrawlerResourceSchema(ctx context.Context) schema.Schema { "browser_mode": schema.BoolAttribute{ Optional: true, Computed: true, + Default: booldefault.StaticBool(false), }, "config": schema.StringAttribute{ Computed: true, @@ -37,9 +39,15 @@ func CrawlerResourceSchema(ctx context.Context) schema.Schema { Computed: true, Default: int64default.StaticInt64(0), }, + "exclude": schema.ListAttribute{ + ElementType: types.StringType, + Optional: true, + Computed: true, + }, "headers": schema.MapAttribute{ ElementType: types.StringType, - Required: true, + Optional: true, + Computed: true, }, "id": schema.Int64Attribute{ Computed: true, @@ -62,9 +70,10 @@ func CrawlerResourceSchema(ctx context.Context) schema.Schema { "updated_at": schema.StringAttribute{ Computed: true, }, - "url_list": schema.ListAttribute{ + "urls": schema.ListAttribute{ ElementType: types.StringType, - Required: true, + Optional: true, + Computed: true, }, "urls_list": schema.StringAttribute{ Computed: true, @@ -84,6 +93,7 @@ type CrawlerModel struct { DeletedAt types.String `tfsdk:"deleted_at"` Domain types.String `tfsdk:"domain"` DomainVerified types.Int64 `tfsdk:"domain_verified"` + Exclude types.List `tfsdk:"exclude"` Headers types.Map `tfsdk:"headers"` Id types.Int64 `tfsdk:"id"` Name types.String `tfsdk:"name"` @@ -91,7 +101,7 @@ type CrawlerModel struct { Project types.String `tfsdk:"project"` ProjectId types.Int64 `tfsdk:"project_id"` UpdatedAt types.String `tfsdk:"updated_at"` - UrlList types.List `tfsdk:"url_list"` + Urls types.List `tfsdk:"urls"` UrlsList types.String `tfsdk:"urls_list"` Uuid types.String `tfsdk:"uuid"` } diff --git a/internal/resource_crawler_schedule/crawler_schedule_resource_gen.go b/internal/resource_crawler_schedule/crawler_schedule_resource_gen.go new file mode 100644 index 0000000..3434a74 --- /dev/null +++ b/internal/resource_crawler_schedule/crawler_schedule_resource_gen.go @@ -0,0 +1,72 @@ +// Code generated by terraform-plugin-framework-generator DO NOT EDIT. + +package resource_crawler_schedule + +import ( + "context" + "github.com/hashicorp/terraform-plugin-framework/types" + + "github.com/hashicorp/terraform-plugin-framework/resource/schema" +) + +func CrawlerScheduleResourceSchema(ctx context.Context) schema.Schema { + return schema.Schema{ + Attributes: map[string]schema.Attribute{ + "crawler": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "crawler_config_id": schema.Int64Attribute{ + Computed: true, + }, + "crawler_last_run_id": schema.Int64Attribute{ + Computed: true, + }, + "crawler_schedule": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "created_at": schema.StringAttribute{ + Computed: true, + }, + "deleted_at": schema.StringAttribute{ + Computed: true, + }, + "id": schema.Int64Attribute{ + Computed: true, + }, + "organization": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "project": schema.StringAttribute{ + Optional: true, + Computed: true, + }, + "project_id": schema.Int64Attribute{ + Computed: true, + }, + "schedule_cron_string": schema.StringAttribute{ + Required: true, + }, + "updated_at": schema.StringAttribute{ + Computed: true, + }, + }, + } +} + +type CrawlerScheduleModel struct { + Crawler types.String `tfsdk:"crawler"` + CrawlerConfigId types.Int64 `tfsdk:"crawler_config_id"` + CrawlerLastRunId types.Int64 `tfsdk:"crawler_last_run_id"` + CrawlerSchedule types.String `tfsdk:"crawler_schedule"` + CreatedAt types.String `tfsdk:"created_at"` + DeletedAt types.String `tfsdk:"deleted_at"` + Id types.Int64 `tfsdk:"id"` + Organization types.String `tfsdk:"organization"` + Project types.String `tfsdk:"project"` + ProjectId types.Int64 `tfsdk:"project_id"` + ScheduleCronString types.String `tfsdk:"schedule_cron_string"` + UpdatedAt types.String `tfsdk:"updated_at"` +}