DownloadTFProviders ensures Terraform providers are downloaded and cached locally in a unique directory for the test. Uses `terraform init` then `mirror` to populate the cache if needed. Returns the cache directory path.
(t *testing.T, rootDir string, testName string, templateFiles map[string]string)
| 114 | // Uses `terraform init` then `mirror` to populate the cache if needed. |
| 115 | // Returns the cache directory path. |
| 116 | func DownloadTFProviders(t *testing.T, rootDir string, testName string, templateFiles map[string]string) string { |
| 117 | t.Helper() |
| 118 | |
| 119 | dir := GetTestTFCacheDir(t, rootDir, testName, templateFiles) |
| 120 | if _, err := os.Stat(dir); err == nil { |
| 121 | t.Logf("%s: using cached terraform providers", testName) |
| 122 | return dir |
| 123 | } |
| 124 | filesDir := filepath.Join(dir, cacheTemplateFilesDirName) |
| 125 | defer func() { |
| 126 | // The files dir will contain a copy of terraform providers generated |
| 127 | // by the terraform init command. We don't want to persist them since |
| 128 | // we already have a registry mirror in the providers dir. |
| 129 | if err := os.RemoveAll(filesDir); err != nil { |
| 130 | t.Logf("failed to remove files dir %s: %s", filesDir, err) |
| 131 | } |
| 132 | if !t.Failed() { |
| 133 | return |
| 134 | } |
| 135 | // If `DownloadTFProviders` function failed, clean up the cache dir. |
| 136 | // We don't want to leave it around because it may be incomplete or corrupted. |
| 137 | if err := os.RemoveAll(dir); err != nil { |
| 138 | t.Logf("failed to remove dir %s: %s", dir, err) |
| 139 | } |
| 140 | }() |
| 141 | |
| 142 | require.NoError(t, os.MkdirAll(filesDir, 0o700)) |
| 143 | |
| 144 | for fileName, file := range templateFiles { |
| 145 | filePath := filepath.Join(filesDir, fileName) |
| 146 | require.NoError(t, os.MkdirAll(filepath.Dir(filePath), 0o700)) |
| 147 | require.NoError(t, os.WriteFile(filePath, []byte(file), 0o600)) |
| 148 | } |
| 149 | |
| 150 | providersDir := filepath.Join(dir, cacheProvidersDirName) |
| 151 | require.NoError(t, os.MkdirAll(providersDir, 0o700)) |
| 152 | |
| 153 | // We need to run init because if a test uses modules in its template, |
| 154 | // the mirror command will fail without it. |
| 155 | runCmd(t, filesDir, "terraform", "init") |
| 156 | // Now, mirror the providers into `providersDir`. We use this explicit mirror |
| 157 | // instead of relying only on the standard Terraform plugin cache. |
| 158 | // |
| 159 | // Why? Because this mirror, when used with the CLI config from `WriteCliConfig`, |
| 160 | // prevents Terraform from hitting the network registry during `plan`. This cuts |
| 161 | // down on network calls, making CI tests less flaky. |
| 162 | // |
| 163 | // In contrast, the standard cache *still* contacts the registry for metadata |
| 164 | // during `init`, even if the plugins are already cached locally - see link below. |
| 165 | // |
| 166 | // Ref: https://developer.hashicorp.com/terraform/cli/config/config-file#provider-plugin-cache |
| 167 | // > When a plugin cache directory is enabled, the terraform init command will |
| 168 | // > still use the configured or implied installation methods to obtain metadata |
| 169 | // > about which plugins are available |
| 170 | runCmd(t, filesDir, "terraform", "providers", "mirror", providersDir) |
| 171 | |
| 172 | return dir |
| 173 | } |
no test coverage detected