forked from atlassian/terraform-provider-artifactory
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
edfaff3
commit b0dfd46
Showing
3 changed files
with
297 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,202 @@ | ||
package artifactory | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"github.com/atlassian/go-artifactory/v2/artifactory" | ||
"github.com/atlassian/go-artifactory/v2/artifactory/v1" | ||
"github.com/hashicorp/terraform/helper/schema" | ||
"os" | ||
"io" | ||
"crypto/sha256" | ||
"encoding/hex" | ||
) | ||
|
||
func datasourceArtifactoryFile() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: nil, | ||
Read: resourceArtifactRead, | ||
Update: nil, | ||
Delete: nil, | ||
|
||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"repository": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
"path": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
"created": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"created_by": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"last_modified": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"modified_by": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"last_updated": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"download_uri": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"mimetype": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"size": { | ||
Type: schema.TypeInt, | ||
Computed: true, | ||
}, | ||
"md5": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"sha1": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"sha256": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"output_path": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
}, | ||
"force_overwrite": { | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
Default: false, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceArtifactRead(d *schema.ResourceData, m interface{}) error { | ||
c := m.(*artifactory.Artifactory) | ||
|
||
repository := d.Get("repository").(string) | ||
path := d.Get("path").(string) | ||
outputPath := d.Get("output_path").(string) | ||
forceOverwrite := d.Get("force_overwrite").(bool) | ||
|
||
fileInfo, _, err := c.V1.Artifacts.FileInfo(context.Background(), repository, path) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
skip, err := SkipDownload(fileInfo, outputPath) | ||
if err != nil && !forceOverwrite { | ||
return err | ||
} | ||
|
||
if !skip { | ||
outFile, err := os.Create(outputPath) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
defer outFile.Close() | ||
|
||
fileInfo, _, err = c.V1.Artifacts.FileContents(context.Background(), repository, path, outFile) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return packFileInfo(fileInfo, d) | ||
} | ||
|
||
func SkipDownload(fileInfo *v1.FileInfo, path string) (bool, error) { | ||
const skip = true | ||
const dontSkip = false | ||
|
||
if path == "" { | ||
// no path specified, nothing to download | ||
return skip, nil | ||
} | ||
|
||
if FileExists(path) { | ||
chks_matches, err := VerifySha256Checksum(path, *fileInfo.Checksums.Sha256) | ||
|
||
if chks_matches { | ||
return skip, nil | ||
} else if err != nil { | ||
return dontSkip, err | ||
} else { | ||
return dontSkip, fmt.Errorf("Local file differs from upstream version") | ||
} | ||
} else { | ||
return dontSkip, nil | ||
} | ||
} | ||
|
||
func FileExists(path string) bool { | ||
if _, err := os.Stat(path); err != nil { | ||
if os.IsNotExist(err) { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
|
||
func VerifySha256Checksum(path string, expectedSha256 string) (bool, error) { | ||
f, err := os.Open(path) | ||
if err != nil { | ||
return false, err | ||
} | ||
defer f.Close() | ||
|
||
hasher := sha256.New() | ||
|
||
if _, err := io.Copy(hasher, f); err != nil { | ||
return false, err | ||
} | ||
|
||
return hex.EncodeToString(hasher.Sum(nil)) == expectedSha256, nil | ||
} | ||
|
||
func packFileInfo(fileInfo *v1.FileInfo, d *schema.ResourceData) error { | ||
hasErr := false | ||
logErr := cascadingErr(&hasErr) | ||
|
||
d.SetId(*fileInfo.DownloadUri) | ||
|
||
logErr(d.Set("created", *fileInfo.Created)) | ||
logErr(d.Set("created_by", *fileInfo.CreatedBy)) | ||
logErr(d.Set("last_modified", *fileInfo.LastModified)) | ||
logErr(d.Set("modified_by", *fileInfo.ModifiedBy)) | ||
logErr(d.Set("last_updated", *fileInfo.LastUpdated)) | ||
logErr(d.Set("download_uri", *fileInfo.DownloadUri)) | ||
logErr(d.Set("mimetype", *fileInfo.MimeType)) | ||
logErr(d.Set("size", *fileInfo.Size)) | ||
|
||
if fileInfo.Checksums != nil { | ||
logErr(d.Set("md5", *fileInfo.Checksums.Md5)) | ||
logErr(d.Set("sha1", *fileInfo.Checksums.Sha1)) | ||
logErr(d.Set("sha256", *fileInfo.Checksums.Sha256)) | ||
} | ||
|
||
if hasErr { | ||
return fmt.Errorf("failed to pack fileInfo") | ||
} | ||
|
||
return 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,91 @@ | ||
package artifactory | ||
|
||
import ( | ||
"testing" | ||
"io/ioutil" | ||
"os" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/atlassian/go-artifactory/v2/artifactory/v1" | ||
"path/filepath" | ||
) | ||
|
||
func TestSkipDownload(t *testing.T) { | ||
const testString = "test content" | ||
const expectedSha256 = "6ae8a75555209fd6c44157c0aed8016e763ff435a19cf186f76863140143ff72" | ||
|
||
file, err := CreateTempFile(testString) | ||
|
||
assert.Nil(t, err) | ||
|
||
defer CloseAndRemove(file) | ||
|
||
existingPath, _ := filepath.Abs(file.Name()) | ||
nonExistingPath := existingPath + "-doesnt-exist" | ||
|
||
sha256 := expectedSha256 | ||
fileInfo := new(v1.FileInfo) | ||
fileInfo.Checksums = new(v1.Checksums) | ||
fileInfo.Checksums.Sha256 = &sha256 | ||
|
||
skip, err := SkipDownload(fileInfo, existingPath) | ||
assert.Equal(t, true, skip) // file exists, checksum matches => skip | ||
assert.Nil(t, err) | ||
|
||
skip, err = SkipDownload(fileInfo, nonExistingPath) | ||
assert.Equal(t, false, skip) // file doesn't exist => dont skip | ||
assert.Nil(t, err) | ||
|
||
sha256 = "6666666666666666666666666666666666666666666666666666666666666666" | ||
fileInfo.Checksums.Sha256 = &sha256 | ||
|
||
skip, err = SkipDownload(fileInfo, existingPath) | ||
assert.Equal(t, false, skip) // file exists, checksum doesnt match => dont skip & err | ||
assert.NotNil(t, err) | ||
} | ||
|
||
func TestFileExists(t *testing.T) { | ||
tmpFile, err := CreateTempFile("test") | ||
|
||
assert.Nil(t, err) | ||
|
||
defer CloseAndRemove(tmpFile) | ||
|
||
existingPath, _ := filepath.Abs(tmpFile.Name()) | ||
nonExistingPath := existingPath + "-doesnt-exist" | ||
|
||
assert.Equal(t, true, FileExists(existingPath)) | ||
assert.Equal(t, false, FileExists(nonExistingPath)) | ||
} | ||
|
||
func TestVerifySha256Checksum(t *testing.T) { | ||
const testString = "test content" | ||
const expectedSha256 = "6ae8a75555209fd6c44157c0aed8016e763ff435a19cf186f76863140143ff72" | ||
|
||
file, err := CreateTempFile(testString) | ||
|
||
assert.Nil(t, err) | ||
|
||
defer CloseAndRemove(file) | ||
|
||
filePath, _ := filepath.Abs(file.Name()) | ||
|
||
sha256Verified, err := VerifySha256Checksum(filePath, expectedSha256) | ||
|
||
assert.Nil(t, err) | ||
assert.Equal(t, true, sha256Verified) | ||
} | ||
|
||
func CreateTempFile(content string) (f *os.File, err error) { | ||
file, err := ioutil.TempFile(os.TempDir(), "terraform-provider-artifactory-") | ||
|
||
if content != "" { | ||
file.WriteString(content) | ||
} | ||
|
||
return file, err | ||
} | ||
|
||
func CloseAndRemove(f *os.File) { | ||
f.Close() | ||
os.Remove(f.Name()) | ||
} |
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