Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Support for 4 new cloudflare_teams_* resources and additional README.md Improvements #669

Merged
merged 14 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,10 @@

# Output of the go coverage tool, specifically when used with LiteIDE
*.out
.idea/
.idea/

*.terraform
*.terraform.lock.hcl

# ignore for testing locally
main.tf
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ CLOUDFLARE_ZONE_ID ?= 00deadb33f000000000000000000000000000
CLOUDFLARE_ACCOUNT_ID ?= 00deadb33f000000000000000000000000000
VERSION ?= $$(git describe --tags --abbrev=0)-dev+$$(git rev-parse --short=12 HEAD)
ROOT_DIR = $$PWD
CLOUDFLARE_TERRAFORM_INSTALL_PATH=$$PWD

HASHICORP_CHECKPOINT_TIMEMOUT ?= 30000

Expand All @@ -20,6 +21,7 @@ test:
@CI=true \
USE_STATIC_RESOURCE_IDS=true \
CHECKPOINT_TIMEOUT=$(HASHICORP_CHECKPOINT_TIMEMOUT) \
CLOUDFLARE_TERRAFORM_INSTALL_PATH=$(CLOUDFLARE_TERRAFORM_INSTALL_PATH) \
CLOUDFLARE_EMAIL="$(CLOUDFLARE_EMAIL)" \
CLOUDFLARE_API_KEY="$(CLOUDFLARE_API_KEY)" \
CLOUDFLARE_ZONE_ID="$(CLOUDFLARE_ZONE_ID)" \
Expand Down
43 changes: 41 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,10 @@ Any resources not listed are currently not supported.
| [cloudflare_ruleset](https://www.terraform.io/docs/providers/cloudflare/r/ruleset) | Account or Zone | ✅ | ✅ |
| [cloudflare_spectrum_application](https://www.terraform.io/docs/providers/cloudflare/r/spectrum_application) | Zone | ✅ | ✅ |
| [cloudflare_tiered_cache](https://www.terraform.io/docs/providers/cloudflare/r/tiered_cache) | Zone | ✅ | ❌ |
| [cloudflare_teams_list](https://www.terraform.io/docs/providers/cloudflare/r/teams_list) | Account | ✅ | ✅ |
| [cloudflare_teams_location](https://www.terraform.io/docs/providers/cloudflare/r/teams_location) | Account | ✅ | ✅ |
| [cloudflare_teams_proxy_endpoint](https://www.terraform.io/docs/providers/cloudflare/r/teams_proxy_endpoint) | Account | ✅ | ✅ |
| [cloudflare_teams_rule](https://www.terraform.io/docs/providers/cloudflare/r/teams_rule) | Account | ✅ | ✅ |
| [cloudflare_tunnel](https://www.terraform.io/docs/providers/cloudflare/r/tunnel) | Account | ✅ | ✅ |
| [cloudflare_turnstile_widget](https://registry.terraform.io/providers/cloudflare/cloudflare/latest/docs/resources/turnstile_widget) | Account | ✅ | ✅ |
| [cloudflare_url_normalization_settings](https://www.terraform.io/docs/providers/cloudflare/r/url_normalization_settings) | Zone | ✅ | ❌ |
Expand Down Expand Up @@ -275,6 +279,41 @@ test. The Terraform files then allow us to build what the resource structure is
expected to look like and once the tool parses the API response, we can compare
that to the static file.

Suggested local testing steps:

1. Create a file with the basic provider configuration (do not commit this file)

```bash
cat > main.tf <<EOF
terraform {
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4"
}
}
}
EOF
```

2. Initialize terraform

```bash
terraform init
```

3. Run tests (Cloudflare Install path should be path to repository)
devinbfergy marked this conversation as resolved.
Show resolved Hide resolved

```bash
make test
```

If you want to run a specific test case you can do so with the TESTARGS variable and -run flag

```bash
TESTARGS="-run '^TestResourceGeneration/cloudflare_teams_list'" make test
```

## Updating VCR cassettes

Periodically, it is a good idea to recreate the VCR cassettes used in our
Expand All @@ -289,12 +328,12 @@ will need to:
(`CLOUDFLARE_EMAIL`, `CLOUDFLARE_KEY`, `CLOUDFLARE_API_TOKEN`) and the test
you want to update.
Example of updating the DNS CAA record test with a zone I own:
```bash
```bash
OVERWRITE_VCR_CASSETTES=true \
CLOUDFLARE_DOMAIN="terraform.cfapi.net" \
CLOUDFLARE_EMAIL="jb@example.com" \
CLOUDFLARE_API_KEY="..." \
TESTARGS="-run '^TestResourceGeneration/cloudflare_record_caa'" \
make test
```
```
- Commit your changes and push them via a Pull Request.
81 changes: 79 additions & 2 deletions internal/app/cf-terraforming/cmd/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -879,11 +879,88 @@ func generateResources() func(cmd *cobra.Command, args []string) {
if err != nil {
log.Fatal(err)
}
case "cloudflare_teams_list":
jsonPayload, _, err := api.ListTeamsLists(context.Background(), identifier, cloudflare.ListTeamListsParams{})
if err != nil {
log.Fatal(err)
}
// get items for the lists and add it the specific list struct
for i, TeamsList := range jsonPayload {
items_struct, _, err := api.ListTeamsListItems(
context.Background(),
identifier,
cloudflare.ListTeamsListItemsParams{ListID: TeamsList.ID})
if err != nil {
log.Fatal(err)
}
TeamsList.Items = append(TeamsList.Items, items_struct...)
jsonPayload[i] = TeamsList
}
m, err := json.Marshal(jsonPayload)
if err != nil {
log.Fatal(err)
}
err = json.Unmarshal(m, &jsonStructData)
if err != nil {
log.Fatal(err)
}
resourceCount = len(jsonPayload)

// converting the items to value field and not the otherway around
for i := 0; i < resourceCount; i++ {
if jsonStructData[i].(map[string]interface{})["items"] != nil && len(jsonStructData[i].(map[string]interface{})["items"].([]interface{})) > 0 {
// new interface for storing data
var newItems []interface{}
for _, item := range jsonStructData[i].(map[string]interface{})["items"].([]interface{}) {
newItems = append(newItems, item.(map[string]interface{})["value"])
}
jsonStructData[i].(map[string]interface{})["items"] = newItems
}
}
case "cloudflare_teams_location":
jsonPayload, _, err := api.TeamsLocations(context.Background(), accountID)
if err != nil {
log.Fatal(err)
}
resourceCount = len(jsonPayload)
m, _ := json.Marshal(jsonPayload)
err = json.Unmarshal(m, &jsonStructData)
if err != nil {
log.Fatal(err)
}
case "cloudflare_teams_proxy_endpoint":
jsonPayload, _, err := api.TeamsProxyEndpoints(context.Background(), accountID)
if err != nil {
log.Fatal(err)
}
resourceCount = len(jsonPayload)
m, _ := json.Marshal(jsonPayload)
err = json.Unmarshal(m, &jsonStructData)
if err != nil {
log.Fatal(err)
}
case "cloudflare_teams_rule":
jsonPayload, err := api.TeamsRules(context.Background(), accountID)
if err != nil {
log.Fatal(err)
}
resourceCount = len(jsonPayload)
m, _ := json.Marshal(jsonPayload)
err = json.Unmarshal(m, &jsonStructData)
if err != nil {
log.Fatal(err)
}
// check for empty descriptions
for i := 0; i < resourceCount; i++ {
if jsonStructData[i].(map[string]interface{})["description"] == "" {
jsonStructData[i].(map[string]interface{})["description"] = "default"
}
}
case "cloudflare_tunnel":
log.Debug("only requesting the first 1000 active Cloudflare Tunnels due to the service not providing correct pagination responses")
jsonPayload, _, err := api.ListTunnels(
context.Background(),
cloudflare.AccountIdentifier(accountID),
identifier,
cloudflare.TunnelListParams{
IsDeleted: cloudflare.BoolPtr(false),
ResultInfo: cloudflare.ResultInfo{
Expand All @@ -905,7 +982,7 @@ func generateResources() func(cmd *cobra.Command, args []string) {
for i := 0; i < resourceCount; i++ {
secret, err := api.GetTunnelToken(
context.Background(),
cloudflare.AccountIdentifier(accountID),
identifier,
jsonStructData[i].(map[string]interface{})["id"].(string),
)
if err != nil {
Expand Down
4 changes: 4 additions & 0 deletions internal/app/cf-terraforming/cmd/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ func TestResourceGeneration(t *testing.T) {
"cloudflare ruleset (rewrite to empty query string)": {identiferType: "zone", resourceType: "cloudflare_ruleset", testdataFilename: "cloudflare_ruleset_zone_rewrite_to_empty_query_parameter"},
"cloudflare ruleset": {identiferType: "zone", resourceType: "cloudflare_ruleset", testdataFilename: "cloudflare_ruleset_zone"},
"cloudflare spectrum application": {identiferType: "zone", resourceType: "cloudflare_spectrum_application", testdataFilename: "cloudflare_spectrum_application"},
"cloudflare teams list": {identiferType: "account", resourceType: "cloudflare_teams_list", testdataFilename: "cloudflare_teams_list"},
"cloudflare teams location": {identiferType: "account", resourceType: "cloudflare_teams_location", testdataFilename: "cloudflare_teams_location"},
"cloudflare teams proxy endpoint": {identiferType: "account", resourceType: "cloudflare_teams_proxy_endpoint", testdataFilename: "cloudflare_teams_proxy_endpoint"},
"cloudflare teams rule": {identiferType: "account", resourceType: "cloudflare_teams_rule", testdataFilename: "cloudflare_teams_rule"},
"cloudflare tunnel": {identiferType: "account", resourceType: "cloudflare_tunnel", testdataFilename: "cloudflare_tunnel"},
"cloudflare turnstile_widget": {identiferType: "account", resourceType: "cloudflare_turnstile_widget", testdataFilename: "cloudflare_turnstile_widget"},
"cloudflare turnstile_widget_no_domains": {identiferType: "account", resourceType: "cloudflare_turnstile_widget", testdataFilename: "cloudflare_turnstile_widget_no_domains"},
Expand Down
48 changes: 48 additions & 0 deletions internal/app/cf-terraforming/cmd/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ var resourceImportStringFormats = map[string]string{
"cloudflare_record": ":zone_id/:id",
"cloudflare_ruleset": ":identifier_type/:identifier_value/:id",
"cloudflare_spectrum_application": ":zone_id/:id",
"cloudflare_teams_list": ":account_id/:id",
"cloudflare_teams_location": ":account_id/:id",
"cloudflare_teams_proxy_endpoint": ":account_id/:id",
"cloudflare_teams_rule": ":account_id/:id",
"cloudflare_tunnel": ":account_id/:id",
"cloudflare_turnstile_widget": ":account_id/:id",
"cloudflare_waf_override": ":zone_id/:id",
Expand Down Expand Up @@ -368,6 +372,50 @@ func runImport() func(cmd *cobra.Command, args []string) {
log.Fatal(err)
}

m, _ := json.Marshal(jsonPayload)
err = json.Unmarshal(m, &jsonStructData)
if err != nil {
log.Fatal(err)
}
case "cloudflare_teams_list":
jsonPayload, _, err := api.ListTeamsLists(context.Background(), identifier, cloudflare.ListTeamListsParams{})
if err != nil {
log.Fatal(err)
}

m, _ := json.Marshal(jsonPayload)
err = json.Unmarshal(m, &jsonStructData)
if err != nil {
log.Fatal(err)
}
case "cloudflare_teams_location":
jsonPayload, _, err := api.TeamsLocations(context.Background(), accountID)
if err != nil {
log.Fatal(err)
}

m, _ := json.Marshal(jsonPayload)
err = json.Unmarshal(m, &jsonStructData)
if err != nil {
log.Fatal(err)
}
case "cloudflare_teams_proxy_endpoint":
jsonPayload, _, err := api.TeamsProxyEndpoints(context.Background(), accountID)
if err != nil {
log.Fatal(err)
}

m, _ := json.Marshal(jsonPayload)
err = json.Unmarshal(m, &jsonStructData)
if err != nil {
log.Fatal(err)
}
case "cloudflare_teams_rule":
jsonPayload, err := api.TeamsRules(context.Background(), accountID)
if err != nil {
log.Fatal(err)
}

m, _ := json.Marshal(jsonPayload)
err = json.Unmarshal(m, &jsonStructData)
if err != nil {
Expand Down
79 changes: 79 additions & 0 deletions testdata/cloudflare/cloudflare_teams_list.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
---
version: 1
interactions:
- request:
body: ""
form: {}
headers:
Content-Type:
- application/json
url: https://api.cloudflare.com/client/v4/accounts/f037e56e89293a057740de681ac9abbe/gateway/lists
method: GET
response:
body: |
{
"errors": [],
"messages": [],
"result": [
{
"count": 1,
"created_at": "2014-01-01T05:20:00.12345Z",
"description": "we like domains here",
"id": "971fc4e8-388e-4ab9-b377-16430c0fc018",
"name": "STUFF TO DO WITH DOMAINS",
"type": "DOMAIN",
"updated_at": "2014-01-01T05:20:00.12345Z"
}
],
"success": true,
"result_info": {
"count": 1,
"page": 1,
"per_page": 20,
"total_count": 2000
}
}
headers:
Content-Type:
- application/json
Vary:
- Accept-Encoding
status: 200 OK
code: 200
duration: ""
- request:
body: ""
form: {}
headers:
Content-Type:
- application/json
url: https://api.cloudflare.com/client/v4/accounts/f037e56e89293a057740de681ac9abbe/gateway/lists/971fc4e8-388e-4ab9-b377-16430c0fc018/items?page=1&per_page=50
method: GET
response:
body: |
{
"result": [
{
"value": "example.com",
"created_at": "2024-01-11T22:57:26Z"
}
],
"success": true,
"errors": [],
"messages": [],
"result_info": {
"page": 1,
"per_page": 50,
"count": 15,
"total_count": 15,
"total_pages": 1
}
}
headers:
Content-Type:
- application/json
Vary:
- Accept-Encoding
status: 200 OK
code: 200
duration: ""
Loading
Loading