-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for go-getter syntax when calling opa.Eval (#1026)
* Add support for go-getter syntax when calling opa.Eval * Update modules/opa/download_policy.go
- Loading branch information
1 parent
cb603f1
commit e19192d
Showing
6 changed files
with
223 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package opa | ||
|
||
import ( | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
"sync" | ||
|
||
getter "github.com/hashicorp/go-getter" | ||
|
||
"github.com/gruntwork-io/terratest/modules/logger" | ||
"github.com/gruntwork-io/terratest/modules/testing" | ||
) | ||
|
||
var ( | ||
// A map that maps the go-getter base URL to the temporary directory where it is downloaded. | ||
policyDirCache sync.Map | ||
) | ||
|
||
// downloadPolicyE takes in a rule path written in go-getter syntax and downloads it to a temporary directory so that it | ||
// can be passed to opa. The temporary directory that is used is cached based on the go-getter base path, and reused | ||
// across calls. | ||
// For example, if you call downloadPolicyE with the go-getter URL multiple times: | ||
// git::https://github.com/gruntwork-io/terratest.git//policies/foo.rego?ref=master | ||
// The first time the gruntwork-io/terratest repo will be downloaded to a new temp directory. All subsequent calls will | ||
// reuse that first temporary dir where the repo was cloned. This is preserved even if a different subdir is requested | ||
// later, e.g.: git::https://github.com/gruntwork-io/terratest.git//examples/bar.rego?ref=master. | ||
// Note that the query parameters are always included in the base URL. This means that if you use a different ref (e.g., | ||
// git::https://github.com/gruntwork-io/terratest.git//examples/bar.rego?ref=v0.39.3), then that will be cloned to a new | ||
// temporary directory rather than the cached dir. | ||
func downloadPolicyE(t testing.TestingT, rulePath string) (string, error) { | ||
cwd, err := os.Getwd() | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
detected, err := getter.Detect(rulePath, cwd, getter.Detectors) | ||
if err != nil { | ||
return "", err | ||
} | ||
|
||
// File getters are assumed to be a local path reference, so pass through the original path. | ||
if strings.HasPrefix(detected, "file") { | ||
return rulePath, nil | ||
} | ||
|
||
// At this point we assume the getter URL is a remote URL, so we start the process of downloading it to a temp dir. | ||
|
||
// First, check if we had already downloaded the source and it is in our cache. | ||
baseDir, subDir := getter.SourceDirSubdir(rulePath) | ||
downloadPath, hasDownloaded := policyDirCache.Load(baseDir) | ||
if hasDownloaded { | ||
logger.Logf(t, "Previously downloaded %s: returning cached path", baseDir) | ||
return filepath.Join(downloadPath.(string), subDir), nil | ||
} | ||
|
||
// Not downloaded, so use go-getter to download the remote source to a temp dir. | ||
tempDir, err := ioutil.TempDir("", "terratest-opa-policy-*") | ||
if err != nil { | ||
return "", err | ||
} | ||
// go-getter doesn't work if you give it a directory that already exists, so we add an additional path in the | ||
// tempDir to make sure we feed a directory that doesn't exist yet. | ||
tempDir = filepath.Join(tempDir, "getter") | ||
|
||
logger.Logf(t, "Downloading %s to temp dir %s", rulePath, tempDir) | ||
if err := getter.GetAny(tempDir, baseDir); err != nil { | ||
return "", err | ||
} | ||
policyDirCache.Store(baseDir, tempDir) | ||
return filepath.Join(tempDir, subDir), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
package opa | ||
|
||
import ( | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/gruntwork-io/terratest/modules/files" | ||
"github.com/gruntwork-io/terratest/modules/git" | ||
) | ||
|
||
// Test to make sure the downloadPolicyE function returns a local path without processing it. | ||
func TestDownloadPolicyReturnsLocalPath(t *testing.T) { | ||
t.Parallel() | ||
|
||
localPath := "../../examples/terraform-opa-example/policy/enforce_source.rego" | ||
path, err := downloadPolicyE(t, localPath) | ||
require.NoError(t, err) | ||
assert.Equal(t, localPath, path) | ||
} | ||
|
||
// Test to make sure the downloadPolicyE function returns a remote path to a temporary directory. | ||
func TestDownloadPolicyDownloadsRemote(t *testing.T) { | ||
t.Parallel() | ||
|
||
curRef := git.GetCurrentGitRef(t) | ||
baseDir := fmt.Sprintf("git::https://github.com/gruntwork-io/terratest.git?ref=%s", curRef) | ||
localPath := "../../examples/terraform-opa-example/policy/enforce_source.rego" | ||
remotePath := fmt.Sprintf("git::https://github.com/gruntwork-io/terratest.git//examples/terraform-opa-example/policy/enforce_source.rego?ref=%s", curRef) | ||
|
||
// Make sure we clean up the downloaded file, while simultaneously asserting that the download dir was stored in the | ||
// cache. | ||
defer func() { | ||
downloadPathRaw, inCache := policyDirCache.Load(baseDir) | ||
require.True(t, inCache) | ||
downloadPath := downloadPathRaw.(string) | ||
if strings.HasSuffix(downloadPath, "/getter") { | ||
downloadPath = filepath.Dir(downloadPath) | ||
} | ||
assert.NoError(t, os.RemoveAll(downloadPath)) | ||
}() | ||
|
||
path, err := downloadPolicyE(t, remotePath) | ||
require.NoError(t, err) | ||
|
||
absPath, err := filepath.Abs(localPath) | ||
require.NoError(t, err) | ||
assert.NotEqual(t, absPath, path) | ||
|
||
localContents, err := ioutil.ReadFile(localPath) | ||
require.NoError(t, err) | ||
remoteContents, err := ioutil.ReadFile(path) | ||
require.NoError(t, err) | ||
assert.Equal(t, localContents, remoteContents) | ||
} | ||
|
||
// Test to make sure the downloadPolicyE function uses the cache if it has already downloaded an existing base path. | ||
func TestDownloadPolicyReusesCachedDir(t *testing.T) { | ||
t.Parallel() | ||
|
||
baseDir := "git::https://github.com/gruntwork-io/terratest.git?ref=master" | ||
remotePath := "git::https://github.com/gruntwork-io/terratest.git//examples/terraform-opa-example/policy/enforce_source.rego?ref=master" | ||
remotePathAltSubPath := "git::https://github.com/gruntwork-io/terratest.git//modules/opa/eval.go?ref=master" | ||
|
||
// Make sure we clean up the downloaded file, while simultaneously asserting that the download dir was stored in the | ||
// cache. | ||
defer func() { | ||
downloadPathRaw, inCache := policyDirCache.Load(baseDir) | ||
require.True(t, inCache) | ||
downloadPath := downloadPathRaw.(string) | ||
|
||
if strings.HasSuffix(downloadPath, "/getter") { | ||
downloadPath = filepath.Dir(downloadPath) | ||
} | ||
assert.NoError(t, os.RemoveAll(downloadPath)) | ||
}() | ||
|
||
path, err := downloadPolicyE(t, remotePath) | ||
require.NoError(t, err) | ||
files.FileExists(path) | ||
|
||
downloadPathRaw, inCache := policyDirCache.Load(baseDir) | ||
require.True(t, inCache) | ||
downloadPath := downloadPathRaw.(string) | ||
|
||
// make sure the second call is exactly equal to the first call | ||
newPath, err := downloadPolicyE(t, remotePath) | ||
require.NoError(t, err) | ||
assert.Equal(t, path, newPath) | ||
|
||
// Also make sure the cache is reused for alternative sub dirs. | ||
newAltPath, err := downloadPolicyE(t, remotePathAltSubPath) | ||
require.NoError(t, err) | ||
assert.True(t, strings.HasPrefix(path, downloadPath)) | ||
assert.True(t, strings.HasPrefix(newAltPath, downloadPath)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters