driftctl/pkg/terraform/provider_downloader.go

88 lines
1.9 KiB
Go

package terraform
import (
"context"
"fmt"
"io/ioutil"
"net/http"
"os"
"runtime"
"github.com/hashicorp/go-getter"
"github.com/sirupsen/logrus"
)
type ProviderDownloaderInterface interface {
Download(url, path string) error
GetProviderUrl(name, version string) string
}
type ProviderDownloader struct {
httpclient *http.Client
unzip getter.ZipDecompressor
context context.Context
}
func NewProviderDownloader() *ProviderDownloader {
return &ProviderDownloader{
httpclient: http.DefaultClient,
unzip: getter.ZipDecompressor{},
context: context.Background(),
}
}
func (p *ProviderDownloader) GetProviderUrl(name, version string) string {
return fmt.Sprintf(
"https://releases.hashicorp.com/terraform-provider-%s/%s/terraform-provider-%s_%s_%s_%s.zip",
name,
version,
name,
version,
runtime.GOOS,
runtime.GOARCH,
)
}
func (p *ProviderDownloader) Download(url, path string) error {
logrus.WithFields(logrus.Fields{
"url": url,
"path": path,
}).Debug("Downloading provider")
req, err := http.NewRequestWithContext(p.context, "GET", url, nil)
if err != nil {
return err
}
resp, err := p.httpclient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unsuccessful request to %s: %s", url, resp.Status)
}
f, err := ioutil.TempFile("", "terraform-provider")
if err != nil {
return fmt.Errorf("failed to open temporary file to download from %s", url)
}
defer f.Close()
defer os.Remove(f.Name())
n, err := getter.Copy(p.context, f, resp.Body)
if err == nil && n < resp.ContentLength {
err = fmt.Errorf("incorrect response size: expected %d bytes, but got %d bytes", resp.ContentLength, n)
}
if err != nil {
return err
}
logrus.WithFields(logrus.Fields{
"src": f.Name(),
"dst": path,
}).Debug("Decompressing archive")
err = p.unzip.Decompress(path, f.Name(), true, 0)
if err != nil {
return err
}
return nil
}