fix: refactor publish command #14
8 changed files with 650 additions and 425 deletions
149
cmd/cmd/publish/architecture.go
Normal file
149
cmd/cmd/publish/architecture.go
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
package publish
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Architecture struct {
|
||||||
|
Protocols []string `json:"protocols"`
|
||||||
|
OS string `json:"os"`
|
||||||
|
Arch string `json:"arch"`
|
||||||
|
FileName string `json:"filename"`
|
||||||
|
DownloadUrl string `json:"download_url"`
|
||||||
|
ShaSumsUrl string `json:"shasums_url"`
|
||||||
|
ShaSumsSignatureUrl string `json:"shasums_signature_url"`
|
||||||
|
ShaSum string `json:"shasum"`
|
||||||
|
SigningKeys []SigningKey `json:"signing_keys"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SigningKey struct {
|
||||||
|
KeyId string `json:"key_id"`
|
||||||
|
AsciiArmor string `json:"ascii_armor"`
|
||||||
|
TrustSignature string `json:"trust_signature"`
|
||||||
|
Source string `json:"source"`
|
||||||
|
SourceUrl string `json:"source_url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) CreateArchitectureFiles() error {
|
||||||
|
// var namespace, provider, distPath, repoName, version, gpgFingerprint, gpgPubKeyFile, domain string
|
||||||
|
|
||||||
|
log.Println("* Creating architecture files in target directories")
|
||||||
|
|
||||||
|
// filename = terraform-provider-[provider]_0.0.1_darwin_amd64.zip - provider_name + version + target + architecture + .zip
|
||||||
|
// prefix := fmt.Sprintf("v1/providers/%s/%s/%s/", namespace, provider, version)
|
||||||
|
prefix := path.Join("v1", "providers", p.Namespace, p.Provider, p.Version)
|
||||||
|
|
||||||
|
// pathPrefix := fmt.Sprintf("release/%s", prefix)
|
||||||
|
pathPrefix := path.Join("release", prefix)
|
||||||
|
|
||||||
|
// urlPrefix := fmt.Sprintf("https://%s/%s", domain, prefix)
|
||||||
|
urlPrefix := path.Join("https://", p.Domain, prefix)
|
||||||
|
|
||||||
|
// download url = https://example.com/v1/providers/namespace/provider/0.0.1/download/terraform-provider_0.0.1_darwin_amd64.zip
|
||||||
|
downloadUrlPrefix := path.Join(urlPrefix, "download")
|
||||||
|
downloadPathPrefix := path.Join(pathPrefix, "download")
|
||||||
|
|
||||||
|
// shasums url = https://example.com/v1/providers/namespace/provider/0.0.1/terraform-provider_0.0.1_SHA256SUMS
|
||||||
|
shasumsUrl := path.Join(urlPrefix, fmt.Sprintf("%s_%s_SHA256SUMS", p.RepoName, p.Version))
|
||||||
|
// shasums_signature_url = https://example.com/v1/providers/namespace/provider/0.0.1/terraform-provider_0.0.1_SHA256SUMS.sig
|
||||||
|
shasumsSigUrl := shasumsUrl + ".sig"
|
||||||
|
|
||||||
|
gpgAsciiPub, err := p.ReadGpgFile()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
shaSums, err := p.GetShaSums()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, sum := range shaSums {
|
||||||
|
downloadUrl := path.Join(downloadUrlPrefix, sum.Path)
|
||||||
|
|
||||||
|
// get os and arch from filename
|
||||||
|
removeFileExtension := strings.Split(sum.Path, ".zip")
|
||||||
|
fileNameSplit := strings.Split(removeFileExtension[0], "_")
|
||||||
|
|
||||||
|
// Get build target and architecture from the zip file name
|
||||||
|
target := fileNameSplit[2]
|
||||||
|
arch := fileNameSplit[3]
|
||||||
|
|
||||||
|
// build filepath
|
||||||
|
archFileName := path.Join(downloadPathPrefix, target, arch)
|
||||||
|
|
||||||
|
a := Architecture{
|
||||||
|
Protocols: []string{"5.1"},
|
||||||
|
OS: target,
|
||||||
|
Arch: arch,
|
||||||
|
FileName: sum.Path,
|
||||||
|
DownloadUrl: downloadUrl,
|
||||||
|
ShaSumsUrl: shasumsUrl,
|
||||||
|
ShaSumsSignatureUrl: shasumsSigUrl,
|
||||||
|
ShaSum: sum.Sum,
|
||||||
|
SigningKeys: []SigningKey{
|
||||||
|
{
|
||||||
|
KeyId: p.GpgFingerprint,
|
||||||
|
AsciiArmor: gpgAsciiPub,
|
||||||
|
TrustSignature: "",
|
||||||
|
Source: "",
|
||||||
|
SourceUrl: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// var architectureTemplate = []byte(fmt.Sprintf(`
|
||||||
|
//{
|
||||||
|
// "protocols": [
|
||||||
|
// "4.0",
|
||||||
|
// "5.1",
|
||||||
|
// "6.0"
|
||||||
|
// ],
|
||||||
|
// "os": "%s",
|
||||||
|
// "arch": "%s",
|
||||||
|
// "filename": "%s",
|
||||||
|
// "download_url": "%s",
|
||||||
|
// "shasums_url": "%s",
|
||||||
|
// "shasums_signature_url": "%s",
|
||||||
|
// "shasum": "%s",
|
||||||
|
// "signing_keys": {
|
||||||
|
// "gpg_public_keys": [
|
||||||
|
// {
|
||||||
|
// "key_id": "%s",
|
||||||
|
// "ascii_armor": "%s",
|
||||||
|
// "trust_signature": "",
|
||||||
|
// "source": "",
|
||||||
|
// "source_url": ""
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//`, target, arch, fileName, downloadUrl, shasumsUrl, shasumsSigUrl, shasum, gpgFingerprint, gpgAsciiPub))
|
||||||
|
|
||||||
|
log.Printf(" - Arch file: %s", archFileName)
|
||||||
|
|
||||||
|
err := WriteArchitectureFile(archFileName, a)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteArchitectureFile(filePath string, arch Architecture) error {
|
||||||
|
jsonString, err := json.Marshal(arch)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error encoding data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(filePath, jsonString, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error writing data: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
20
cmd/cmd/publish/gpg.go
Normal file
20
cmd/cmd/publish/gpg.go
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
package publish
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *Provider) ReadGpgFile() (string, error) {
|
||||||
|
// Get contents of GPG key
|
||||||
|
gpgFile, err := ReadFile(p.GpgPubKeyFile)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error reading '%s' file: %w", p.GpgPubKeyFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop through every line and stick with \\n
|
||||||
|
gpgAsciiPub := ""
|
||||||
|
for _, line := range gpgFile {
|
||||||
|
gpgAsciiPub = gpgAsciiPub + line + "\\n"
|
||||||
|
}
|
||||||
|
return gpgAsciiPub, nil
|
||||||
|
}
|
||||||
233
cmd/cmd/publish/provider.go
Normal file
233
cmd/cmd/publish/provider.go
Normal file
|
|
@ -0,0 +1,233 @@
|
||||||
|
package publish
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/fs"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Provider struct {
|
||||||
|
Namespace string
|
||||||
|
Provider string
|
||||||
|
DistPath string
|
||||||
|
RepoName string
|
||||||
|
Version string
|
||||||
|
GpgFingerprint string
|
||||||
|
GpgPubKeyFile string
|
||||||
|
Domain string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) CreateV1Dir() error {
|
||||||
|
// Path to semantic version dir
|
||||||
|
versionPath := p.providerDirs()
|
||||||
|
|
||||||
|
// Files to create under v1/providers/[namespace]/[provider_name]
|
||||||
|
err := p.createVersionsFile()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("[CreateV1Dir] - create versions file:%w", err)
|
||||||
|
} // Creates version file one above download, which is why downloadPath isn't used
|
||||||
|
|
||||||
|
// Files/Directories to create under v1/providers/[namespace]/[provider_name]/[version]
|
||||||
|
err = p.copyShaFiles(versionPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("[CreateV1Dir] - copy sha files: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("* Creating download/ in %s directory", versionPath)
|
||||||
|
downloadsPath := path.Join(versionPath, "download")
|
||||||
|
err = CreateDir(downloadsPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create darwin, freebsd, linux, windows dirs
|
||||||
|
for _, v := range [4]string{"darwin", "freebsd", "linux", "windows"} {
|
||||||
|
err = CreateDir(path.Join(downloadsPath, v))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error creating dir '%s': %w", path.Join(downloadsPath, v), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy all zips
|
||||||
|
err = p.copyBuildZips(downloadsPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create all individual files for build targets and each architecture for the build targets
|
||||||
|
err = p.CreateArchitectureFiles()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) copyBuildZips(destPath string) error {
|
||||||
|
log.Println("* Copying build zips")
|
||||||
|
|
||||||
|
shaSums, err := p.GetShaSums()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through and copy each
|
||||||
|
for _, sum := range shaSums {
|
||||||
|
zipSrcPath := path.Join(p.DistPath, sum.Path)
|
||||||
|
zipDestPath := path.Join(destPath, sum.Path)
|
||||||
|
|
||||||
|
log.Printf(" - Zip Source: %s", zipSrcPath)
|
||||||
|
log.Printf(" - Zip Dest: %s", zipDestPath)
|
||||||
|
|
||||||
|
// Copy the zip
|
||||||
|
_, err = CopyFile(zipSrcPath, zipDestPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error copying file '%s': %w", zipSrcPath, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) copyShaFiles(destPath string) error {
|
||||||
|
log.Printf("* Copying SHA files in %s directory", p.DistPath)
|
||||||
|
|
||||||
|
// Copy files from srcPath
|
||||||
|
shaSum := p.RepoName + "_" + p.Version + "_SHA256SUMS"
|
||||||
|
shaSumPath := path.Join(p.DistPath, shaSum)
|
||||||
|
|
||||||
|
// _SHA256SUMS file
|
||||||
|
_, err := CopyFile(shaSumPath, path.Join(destPath, shaSum))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// _SHA256SUMS.sig file
|
||||||
|
_, err = CopyFile(shaSumPath+".sig", path.Join(destPath, shaSum+".sig"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) createVersionsFile() error {
|
||||||
|
log.Println("* Writing to release/v1/providers/[namespace]/[repo]/versions file")
|
||||||
|
|
||||||
|
versionPath := path.Join("release", "v1", "providers", p.Namespace, p.Provider, "versions")
|
||||||
|
|
||||||
|
shasums, err := p.GetShaSums()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error getting sha sums: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the versions file...
|
||||||
|
version := Version{}
|
||||||
|
for _, sum := range shasums {
|
||||||
|
// get os and arch from filename
|
||||||
|
removeFileExtension := strings.Split(sum.Path, ".zip")
|
||||||
|
fileNameSplit := strings.Split(removeFileExtension[0], "_")
|
||||||
|
|
||||||
|
// Get build target and architecture from the zip file name
|
||||||
|
target := fileNameSplit[2]
|
||||||
|
arch := fileNameSplit[3]
|
||||||
|
|
||||||
|
version.Platforms = append(version.Platforms, Platform{
|
||||||
|
OS: target,
|
||||||
|
Arch: arch,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
data := Data{}
|
||||||
|
|
||||||
|
downloadPath := path.Join(p.Domain, "v1", "providers", p.Namespace, p.Provider, "versions")
|
||||||
|
err = data.LoadFromUrl(fmt.Sprintf("https://%s", downloadPath))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error getting existing versions file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = data.AddVersion(version)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error appending version: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = data.WriteToFile(versionPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error saving file '%s':%w", versionPath, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Provider) providerDirs() string {
|
||||||
|
log.Println("* Creating release/v1/providers/[namespace]/[repo]/[version] directories")
|
||||||
|
|
||||||
|
target := path.Join("release", "v1", "providers", p.Namespace, p.RepoName, p.Version)
|
||||||
|
|
||||||
|
err := CreateDir(target)
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
func CreateDir(path string) error {
|
||||||
|
log.Printf("* Creating %s directory", path)
|
||||||
|
err := os.MkdirAll(path, os.ModePerm)
|
||||||
|
if errors.Is(err, fs.ErrExist) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadFile(filePath string) ([]string, error) {
|
||||||
|
rFile, err := os.Open(filePath)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
fileScanner := bufio.NewScanner(rFile)
|
||||||
|
fileScanner.Split(bufio.ScanLines)
|
||||||
|
var fileLines []string
|
||||||
|
|
||||||
|
for fileScanner.Scan() {
|
||||||
|
fileLines = append(fileLines, fileScanner.Text())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = rFile.Close()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileLines, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CopyFile(src, dst string) (int64, error) {
|
||||||
|
sourceFileStat, err := os.Stat(src)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !sourceFileStat.Mode().IsRegular() {
|
||||||
|
return 0, fmt.Errorf("%s is not a regular file", src)
|
||||||
|
}
|
||||||
|
|
||||||
|
source, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer source.Close()
|
||||||
|
|
||||||
|
destination, err := os.Create(dst)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
defer destination.Close()
|
||||||
|
nBytes, err := io.Copy(destination, source)
|
||||||
|
return nBytes, err
|
||||||
|
}
|
||||||
39
cmd/cmd/publish/shasums.go
Normal file
39
cmd/cmd/publish/shasums.go
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
package publish
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *Provider) GetShaSums() (ShaSums, error) {
|
||||||
|
return GetShaSumContents(p.DistPath, p.RepoName, p.Version)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ShaSums []ShaSum
|
||||||
|
type ShaSum struct {
|
||||||
|
Sum string
|
||||||
|
Path string
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetShaSumContents(distPath, repoName, version string) (ShaSums, error) {
|
||||||
|
shaSumFileName := repoName + "_" + version + "_SHA256SUMS"
|
||||||
|
shaSumPath := path.Join(distPath, shaSumFileName)
|
||||||
|
|
||||||
|
shaSumLine, err := ReadFile(shaSumPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
regEx := regexp.MustCompile(`([0-9a-fA-F]+)\s+(.+)`)
|
||||||
|
shaSums := ShaSums{}
|
||||||
|
for _, line := range shaSumLine {
|
||||||
|
matches := regEx.FindAllStringSubmatch(line, -1)
|
||||||
|
if len(matches) < 1 {
|
||||||
|
slog.Warn("unable to parse SHA sum line", "line", line)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
shaSums = append(shaSums, ShaSum{Sum: matches[0][0], Path: matches[0][1]})
|
||||||
|
}
|
||||||
|
return shaSums, nil
|
||||||
|
}
|
||||||
143
cmd/cmd/publish/versions.go
Normal file
143
cmd/cmd/publish/versions.go
Normal file
|
|
@ -0,0 +1,143 @@
|
||||||
|
package publish
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Version struct {
|
||||||
|
Version string `json:"version"`
|
||||||
|
Protocols []string `json:"protocols"`
|
||||||
|
Platforms []Platform `json:"platforms"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Platform struct {
|
||||||
|
OS string `json:"os" yaml:"os"`
|
||||||
|
Arch string `json:"arch" yaml:"arch"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Data struct {
|
||||||
|
Versions []Version `json:"versions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Data) WriteToFile(filePath string) error {
|
||||||
|
//file, err := os.OpenFile(filePath, os.O_CREATE, os.ModePerm)
|
||||||
|
//if err != nil {
|
||||||
|
// return fmt.Errorf("error creating file: %w", err)
|
||||||
|
//}
|
||||||
|
//defer file.Close()
|
||||||
|
//
|
||||||
|
jsonString, err := json.Marshal(d)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error encoding data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.WriteFile(filePath, jsonString, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error writing data: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Data) AddVersion(v Version) error {
|
||||||
|
d.Versions = append(d.Versions, v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Data) Validate() error {
|
||||||
|
for _, v := range d.Versions {
|
||||||
|
err := v.Validate()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Data) LoadFromFile(filePath string) error {
|
||||||
|
plan, err := os.ReadFile(filePath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(plan, &d)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Data) LoadFromUrl(uri string) error {
|
||||||
|
u, err := url.ParseRequestURI(uri)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.CreateTemp("", "versions.*.json")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer os.Remove(file.Name()) // Clean up
|
||||||
|
|
||||||
|
err = DownloadFile(
|
||||||
|
u.String(),
|
||||||
|
file.Name(),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return d.LoadFromFile(file.Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Version) Validate() error {
|
||||||
|
slog.Warn("validation needs to be implemented")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Version) AddPlatform(p Platform) error {
|
||||||
|
if p.OS == "" || p.Arch == "" {
|
||||||
|
return fmt.Errorf("OS and Arch MUST NOT be empty")
|
||||||
|
}
|
||||||
|
v.Platforms = append(v.Platforms, p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Version) AddProtocol(p string) error {
|
||||||
|
if p == "" {
|
||||||
|
return fmt.Errorf("protocol MUST NOT be empty")
|
||||||
|
}
|
||||||
|
v.Protocols = append(v.Protocols, p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DownloadFile will download a url and store it in local filepath.
|
||||||
|
// It writes to the destination file as it downloads it, without
|
||||||
|
// loading the entire file into memory.
|
||||||
|
func DownloadFile(url string, filepath string) error {
|
||||||
|
// Create the file
|
||||||
|
out, err := os.Create(filepath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer out.Close()
|
||||||
|
|
||||||
|
// Get the data
|
||||||
|
resp, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// Write the body to file
|
||||||
|
_, err = io.Copy(out, resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -1,17 +1,14 @@
|
||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
|
|
||||||
|
publish2 "github.com/mhenselin/terraform-provider-stackitprivatepreview/cmd/cmd/publish"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -26,7 +23,7 @@ var (
|
||||||
gpgPubKeyFile string
|
gpgPubKeyFile string
|
||||||
)
|
)
|
||||||
|
|
||||||
var rootCmd = &cobra.Command{
|
var publishCmd = &cobra.Command{
|
||||||
Use: "publish",
|
Use: "publish",
|
||||||
Short: "Publish terraform provider",
|
Short: "Publish terraform provider",
|
||||||
Long: `...`,
|
Long: `...`,
|
||||||
|
|
@ -36,66 +33,75 @@ var rootCmd = &cobra.Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { // nolint: gochecknoinits
|
func init() { // nolint: gochecknoinits
|
||||||
rootCmd.Flags().StringVarP(&namespace, "namespace", "n", "", "Namespace for the Terraform registry.")
|
publishCmd.Flags().StringVarP(&namespace, "namespace", "n", "", "Namespace for the Terraform registry.")
|
||||||
rootCmd.Flags().StringVarP(&domain, "domain", "d", "", "Domain for the Terraform registry.")
|
publishCmd.Flags().StringVarP(&domain, "domain", "d", "", "Domain for the Terraform registry.")
|
||||||
rootCmd.Flags().StringVarP(&providerName, "providerName", "p", "", "ProviderName for the Terraform registry.")
|
publishCmd.Flags().StringVarP(&providerName, "providerName", "p", "", "ProviderName for the Terraform registry.")
|
||||||
rootCmd.Flags().StringVarP(&distPath, "distPath", "x", "dist", "Dist Path for the Terraform registry.")
|
publishCmd.Flags().StringVarP(&distPath, "distPath", "x", "dist", "Dist Path for the Terraform registry.")
|
||||||
rootCmd.Flags().StringVarP(&repoName, "repoName", "r", "", "RepoName for the Terraform registry.")
|
publishCmd.Flags().StringVarP(&repoName, "repoName", "r", "", "RepoName for the Terraform registry.")
|
||||||
rootCmd.Flags().StringVarP(&version, "version", "v", "", "Version for the Terraform registry.")
|
publishCmd.Flags().StringVarP(&version, "version", "v", "", "Version for the Terraform registry.")
|
||||||
rootCmd.Flags().StringVarP(&gpgFingerprint, "gpgFingerprint", "f", "", "GPG Fingerprint for the Terraform registry.")
|
publishCmd.Flags().StringVarP(&gpgFingerprint, "gpgFingerprint", "f", "", "GPG Fingerprint for the Terraform registry.")
|
||||||
rootCmd.Flags().StringVarP(&gpgPubKeyFile, "gpgPubKeyFile", "k", "", "GPG PubKey file name for the Terraform registry.")
|
publishCmd.Flags().StringVarP(&gpgPubKeyFile, "gpgPubKeyFile", "k", "", "GPG PubKey file name for the Terraform registry.")
|
||||||
|
|
||||||
err := rootCmd.MarkFlagRequired("namespace")
|
err := publishCmd.MarkFlagRequired("namespace")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = rootCmd.MarkFlagRequired("domain")
|
err = publishCmd.MarkFlagRequired("domain")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = rootCmd.MarkFlagRequired("providerName")
|
err = publishCmd.MarkFlagRequired("providerName")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = rootCmd.MarkFlagRequired("gpgFingerprint")
|
err = publishCmd.MarkFlagRequired("gpgFingerprint")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = rootCmd.MarkFlagRequired("gpgPubKeyFile")
|
err = publishCmd.MarkFlagRequired("gpgPubKeyFile")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = rootCmd.MarkFlagRequired("repoName")
|
err = publishCmd.MarkFlagRequired("repoName")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = rootCmd.MarkFlagRequired("version")
|
err = publishCmd.MarkFlagRequired("version")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = rootCmd.MarkFlagRequired("gpgFingerprint")
|
err = publishCmd.MarkFlagRequired("gpgFingerprint")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = rootCmd.MarkFlagRequired("gpgPubKeyFile")
|
err = publishCmd.MarkFlagRequired("gpgPubKeyFile")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPublishCmd() *cobra.Command {
|
func NewPublishCmd() *cobra.Command {
|
||||||
return rootCmd
|
return publishCmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func publish() error {
|
func publish() error {
|
||||||
log.Println("📦 Packaging Terraform Provider for private registry...")
|
log.Println("📦 Packaging Terraform Provider for private registry...")
|
||||||
|
p := publish2.Provider{
|
||||||
distPath = filepath.Clean(distPath) + "/"
|
Namespace: namespace,
|
||||||
|
Provider: providerName,
|
||||||
|
DistPath: filepath.Clean(distPath) + "/",
|
||||||
|
RepoName: repoName,
|
||||||
|
Version: version,
|
||||||
|
GpgFingerprint: gpgFingerprint,
|
||||||
|
GpgPubKeyFile: gpgPubKeyFile,
|
||||||
|
Domain: domain,
|
||||||
|
}
|
||||||
|
|
||||||
// Create release dir - only the contents of this need to be uploaded to S3
|
// Create release dir - only the contents of this need to be uploaded to S3
|
||||||
err := createDir("release")
|
log.Printf("* Creating reelase directory")
|
||||||
if err != nil {
|
err := os.Mkdir("release", os.ModePerm)
|
||||||
return fmt.Errorf("error creating 'release' dir: %s", err)
|
if !errors.Is(err, fs.ErrExist) {
|
||||||
|
return fmt.Errorf("error creating 'release' dir: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create .wellKnown directory and terraform.json file
|
// Create .wellKnown directory and terraform.json file
|
||||||
|
|
@ -104,8 +110,7 @@ func publish() error {
|
||||||
return fmt.Errorf("error creating '.wellKnown' dir: %s", err)
|
return fmt.Errorf("error creating '.wellKnown' dir: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create v1 directory
|
err = p.CreateV1Dir()
|
||||||
err = provider(namespace, providerName, distPath, repoName, version, gpgFingerprint, gpgPubKeyFile, domain)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error creating 'v1' dir: %s", err)
|
return fmt.Errorf("error creating 'v1' dir: %s", err)
|
||||||
}
|
}
|
||||||
|
|
@ -118,385 +123,20 @@ func publish() error {
|
||||||
func wellKnown() error {
|
func wellKnown() error {
|
||||||
log.Println("* Creating .well-known directory")
|
log.Println("* Creating .well-known directory")
|
||||||
|
|
||||||
err := createDir("release/.well-known")
|
err := os.Mkdir("release/.well-known", os.ModePerm)
|
||||||
if err != nil {
|
if !errors.Is(err, fs.ErrExist) {
|
||||||
return err
|
return fmt.Errorf("error creating 'release' dir: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
terraformJson := []byte(`{"providers.v1": "/v1/providers/"}`)
|
|
||||||
|
|
||||||
log.Println(" - Writing to .well-known/terraform.json file")
|
log.Println(" - Writing to .well-known/terraform.json file")
|
||||||
err = writeFile("release/.well-known/terraform.json", terraformJson)
|
err = os.WriteFile(
|
||||||
|
"release/.well-known/terraform.json",
|
||||||
|
[]byte(`{"providers.v1": "/v1/providers/"}`),
|
||||||
|
0644,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// provider is the Terraform name
|
|
||||||
// repoName is the Repository name
|
|
||||||
func provider(namespace, provider, distPath, repoName, version, gpgFingerprint, gpgPubKeyFile, domain string) error {
|
|
||||||
// Path to semantic version dir
|
|
||||||
versionPath := providerDirs(namespace, provider, version)
|
|
||||||
|
|
||||||
// Files to create under v1/providers/[namespace]/[provider_name]
|
|
||||||
err := createVersionsFile(namespace, provider, distPath, repoName, version)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} // Creates version file one above download, which is why downloadPath isn't used
|
|
||||||
|
|
||||||
// Files/Directories to create under v1/providers/[namespace]/[provider_name]/[version]
|
|
||||||
copyShaFiles(versionPath, distPath, repoName, version)
|
|
||||||
downloadPath, err := createDownloadsDir(versionPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create darwin, freebsd, linux, windows dirs
|
|
||||||
err = createTargetDirs(*downloadPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy all zips
|
|
||||||
err = copyBuildZips(*downloadPath, distPath, repoName, version)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create all individual files for build targets and each architecture for the build targets
|
|
||||||
err = createArchitectureFiles(namespace, provider, distPath, repoName, version, gpgFingerprint, gpgPubKeyFile, domain)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the directories with a path format v1/providers/[namespace]/[provider_name]/[version]
|
|
||||||
func providerDirs(namespace, repoName, version string) string {
|
|
||||||
log.Println("* Creating release/v1/providers/[namespace]/[repo]/[version] directories")
|
|
||||||
|
|
||||||
providerPathArr := [6]string{"release", "v1", "providers", namespace, repoName, version}
|
|
||||||
|
|
||||||
var currentPath string
|
|
||||||
for _, v := range providerPathArr {
|
|
||||||
currentPath = currentPath + v + "/"
|
|
||||||
err := createDir(currentPath)
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentPath
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the versions file under v1/providers/[namespace]/[provider_name]
|
|
||||||
func createVersionsFile(namespace, provider, distPath, repoName, version string) error {
|
|
||||||
log.Println("* Writing to release/v1/providers/[namespace]/[repo]/versions file")
|
|
||||||
|
|
||||||
versionPath := fmt.Sprintf("release/v1/providers/%s/%s/versions", namespace, provider)
|
|
||||||
|
|
||||||
shaSumContents, err := getShaSumContents(distPath, repoName, version)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the versions file...
|
|
||||||
platforms := ""
|
|
||||||
for _, line := range shaSumContents {
|
|
||||||
fileName := line[1] // zip file name
|
|
||||||
|
|
||||||
// get os and arch from filename
|
|
||||||
removeFileExtension := strings.Split(fileName, ".zip")
|
|
||||||
fileNameSplit := strings.Split(removeFileExtension[0], "_")
|
|
||||||
|
|
||||||
// Get build target and architecture from the zip file name
|
|
||||||
target := fileNameSplit[2]
|
|
||||||
arch := fileNameSplit[3]
|
|
||||||
|
|
||||||
platforms += "{"
|
|
||||||
platforms += fmt.Sprintf(`"os": "%s",`, target)
|
|
||||||
platforms += fmt.Sprintf(`"arch": "%s"`, arch)
|
|
||||||
platforms += "}"
|
|
||||||
platforms += ","
|
|
||||||
}
|
|
||||||
platforms = strings.TrimRight(platforms, ",") // remove trailing comma, json does not allow
|
|
||||||
|
|
||||||
var versions = []byte(fmt.Sprintf(`
|
|
||||||
{
|
|
||||||
"versions": [
|
|
||||||
{
|
|
||||||
"version": "%s",
|
|
||||||
"protocols": [
|
|
||||||
"4.0",
|
|
||||||
"5.1",
|
|
||||||
"6.0"
|
|
||||||
],
|
|
||||||
"platform": [
|
|
||||||
%s
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
`, version, platforms))
|
|
||||||
|
|
||||||
err = writeFile(versionPath, versions)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyShaFiles(destPath, srcPath, repoName, version string) {
|
|
||||||
log.Printf("* Copying SHA files in %s directory", srcPath)
|
|
||||||
|
|
||||||
// Copy files from srcPath
|
|
||||||
shaSum := repoName + "_" + version + "_SHA256SUMS"
|
|
||||||
shaSumPath := path.Join(srcPath, shaSum)
|
|
||||||
|
|
||||||
// _SHA256SUMS file
|
|
||||||
_, err := copyFile(shaSumPath, path.Join(destPath, shaSum))
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// _SHA256SUMS.sig file
|
|
||||||
_, err = copyFile(shaSumPath+".sig", path.Join(destPath, shaSum+".sig"))
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createDownloadsDir(destPath string) (*string, error) {
|
|
||||||
log.Printf("* Creating download/ in %s directory", destPath)
|
|
||||||
|
|
||||||
downloadPath := path.Join(destPath, "download")
|
|
||||||
|
|
||||||
err := createDir(downloadPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &downloadPath, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createTargetDirs(destPath string) error {
|
|
||||||
log.Printf("* Creating target dirs in %s directory", destPath)
|
|
||||||
|
|
||||||
targets := [4]string{"darwin", "freebsd", "linux", "windows"}
|
|
||||||
|
|
||||||
for _, v := range targets {
|
|
||||||
err := createDir(destPath + v)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
err = createDir(path.Join(destPath, v))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyBuildZips(destPath, distPath, repoName, version string) error {
|
|
||||||
log.Println("* Copying build zips")
|
|
||||||
|
|
||||||
shaSumContents, err := getShaSumContents(distPath, repoName, version)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop through and copy each
|
|
||||||
for _, v := range shaSumContents {
|
|
||||||
zipName := v[1]
|
|
||||||
zipSrcPath := path.Join(distPath, zipName)
|
|
||||||
zipDestPath := path.Join(destPath, zipName)
|
|
||||||
|
|
||||||
log.Printf(" - Zip Source: %s", zipSrcPath)
|
|
||||||
log.Printf(" - Zip Dest: %s", zipDestPath)
|
|
||||||
|
|
||||||
// Copy the zip
|
|
||||||
_, err := copyFile(zipSrcPath, zipDestPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getShaSumContents(distPath, repoName, version string) ([][]string, error) {
|
|
||||||
shaSumFileName := repoName + "_" + version + "_SHA256SUMS"
|
|
||||||
shaSumPath := distPath + "/" + shaSumFileName
|
|
||||||
|
|
||||||
shaSumLine, err := readFile(shaSumPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
buildsAndShaSums := [][]string{}
|
|
||||||
|
|
||||||
for _, line := range shaSumLine {
|
|
||||||
lineSplit := strings.Split(line, " ")
|
|
||||||
|
|
||||||
row := []string{lineSplit[0], lineSplit[1]}
|
|
||||||
buildsAndShaSums = append(buildsAndShaSums, row)
|
|
||||||
}
|
|
||||||
|
|
||||||
// log.Println(buildsAndShaSums)
|
|
||||||
|
|
||||||
return buildsAndShaSums, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create architecture files for each build target
|
|
||||||
func createArchitectureFiles(namespace, provider, distPath, repoName, version, gpgFingerprint, gpgPubKeyFile, domain string) error {
|
|
||||||
log.Println("* Creating architecture files in target directories")
|
|
||||||
|
|
||||||
// filename = terraform-provider-[provider]_0.0.1_darwin_amd64.zip - provider_name + version + target + architecture + .zip
|
|
||||||
prefix := fmt.Sprintf("v1/providers/%s/%s/%s/", namespace, provider, version)
|
|
||||||
pathPrefix := fmt.Sprintf("release/%s", prefix)
|
|
||||||
urlPrefix := fmt.Sprintf("https://%s/%s", domain, prefix)
|
|
||||||
|
|
||||||
// download url = https://example.com/v1/providers/namespace/provider/0.0.1/download/terraform-provider_0.0.1_darwin_amd64.zip
|
|
||||||
downloadUrlPrefix := urlPrefix + "download/"
|
|
||||||
downloadPathPrefix := pathPrefix + "download/"
|
|
||||||
|
|
||||||
// shasums url = https://example.com/v1/providers/namespace/provider/0.0.1/terraform-provider_0.0.1_SHA256SUMS
|
|
||||||
shasumsUrl := urlPrefix + fmt.Sprintf("%s_%s_SHA256SUMS", repoName, version)
|
|
||||||
// shasums_signature_url = https://example.com/v1/providers/namespace/provider/0.0.1/terraform-provider_0.0.1_SHA256SUMS.sig
|
|
||||||
shasumsSigUrl := shasumsUrl + ".sig"
|
|
||||||
|
|
||||||
shaSumContents, err := getShaSumContents(distPath, repoName, version)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get contents of GPG key
|
|
||||||
gpgFile, err := readFile(gpgPubKeyFile)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error reading '%s' file: %s", gpgPubKeyFile, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// loop through every line and stick with \\n
|
|
||||||
gpgAsciiPub := ""
|
|
||||||
for _, line := range gpgFile {
|
|
||||||
gpgAsciiPub = gpgAsciiPub + line + "\\n"
|
|
||||||
}
|
|
||||||
// log.Println(gpgAsciiPub)
|
|
||||||
|
|
||||||
for _, line := range shaSumContents {
|
|
||||||
shasum := line[0] // shasum of the zip
|
|
||||||
fileName := line[1] // zip file name
|
|
||||||
|
|
||||||
downloadUrl := downloadUrlPrefix + fileName
|
|
||||||
|
|
||||||
// get os and arch from filename
|
|
||||||
removeFileExtension := strings.Split(fileName, ".zip")
|
|
||||||
fileNameSplit := strings.Split(removeFileExtension[0], "_")
|
|
||||||
|
|
||||||
// Get build target and architecture from the zip file name
|
|
||||||
target := fileNameSplit[2]
|
|
||||||
arch := fileNameSplit[3]
|
|
||||||
|
|
||||||
// build filepath
|
|
||||||
archFileName := downloadPathPrefix + target + "/" + arch
|
|
||||||
|
|
||||||
var architectureTemplate = []byte(fmt.Sprintf(`
|
|
||||||
{
|
|
||||||
"protocols": [
|
|
||||||
"4.0",
|
|
||||||
"5.1",
|
|
||||||
"6.0"
|
|
||||||
],
|
|
||||||
"os": "%s",
|
|
||||||
"arch": "%s",
|
|
||||||
"filename": "%s",
|
|
||||||
"download_url": "%s",
|
|
||||||
"shasums_url": "%s",
|
|
||||||
"shasums_signature_url": "%s",
|
|
||||||
"shasum": "%s",
|
|
||||||
"signing_keys": {
|
|
||||||
"gpg_public_keys": [
|
|
||||||
{
|
|
||||||
"key_id": "%s",
|
|
||||||
"ascii_armor": "%s",
|
|
||||||
"trust_signature": "",
|
|
||||||
"source": "",
|
|
||||||
"source_url": ""
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`, target, arch, fileName, downloadUrl, shasumsUrl, shasumsSigUrl, shasum, gpgFingerprint, gpgAsciiPub))
|
|
||||||
|
|
||||||
log.Printf(" - Arch file: %s", archFileName)
|
|
||||||
|
|
||||||
err := writeFile(archFileName, architectureTemplate)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createDir(path string) error {
|
|
||||||
log.Printf("* Creating %s directory", path)
|
|
||||||
err := os.Mkdir(path, os.ModePerm)
|
|
||||||
if errors.Is(err, fs.ErrExist) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyFile(src, dst string) (int64, error) {
|
|
||||||
sourceFileStat, err := os.Stat(src)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !sourceFileStat.Mode().IsRegular() {
|
|
||||||
return 0, fmt.Errorf("%s is not a regular file", src)
|
|
||||||
}
|
|
||||||
|
|
||||||
source, err := os.Open(src)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
defer source.Close()
|
|
||||||
|
|
||||||
destination, err := os.Create(dst)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
defer destination.Close()
|
|
||||||
nBytes, err := io.Copy(destination, source)
|
|
||||||
return nBytes, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func readFile(filePath string) ([]string, error) {
|
|
||||||
rFile, err := os.Open(filePath)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
fileScanner := bufio.NewScanner(rFile)
|
|
||||||
fileScanner.Split(bufio.ScanLines)
|
|
||||||
var fileLines []string
|
|
||||||
|
|
||||||
for fileScanner.Scan() {
|
|
||||||
fileLines = append(fileLines, fileScanner.Text())
|
|
||||||
}
|
|
||||||
|
|
||||||
rFile.Close()
|
|
||||||
|
|
||||||
return fileLines, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeFile(fileName string, fileContents []byte) error {
|
|
||||||
err := os.WriteFile(fileName, fileContents, 0644)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func mapGetInstanceResponseToModel(ctx context.Context, m *postgresflexalpharesource.InstanceModel, resp *postgresflex.GetInstanceResponse) error {
|
func mapGetInstanceResponseToModel(ctx context.Context, m *postgresflexalpharesource.InstanceModel, resp *postgresflex.GetInstanceResponse) error {
|
||||||
tflog.Info(ctx, ">>>> MSH DEBUG <<<<", map[string]interface{}{
|
tflog.Debug(ctx, ">>>> MSH DEBUG <<<<", map[string]interface{}{
|
||||||
"id": m.Id.ValueString(),
|
"id": m.Id.ValueString(),
|
||||||
"instance_id": m.InstanceId.ValueString(),
|
"instance_id": m.InstanceId.ValueString(),
|
||||||
"backup_schedule": m.BackupSchedule.ValueString(),
|
"backup_schedule": m.BackupSchedule.ValueString(),
|
||||||
|
|
@ -47,17 +47,17 @@ func mapGetInstanceResponseToModel(ctx context.Context, m *postgresflexalphareso
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.ConnectionInfo.Host = types.StringValue(resp.ConnectionInfo.GetHost())
|
||||||
|
m.ConnectionInfo.Port = types.Int64Value(resp.ConnectionInfo.GetPort())
|
||||||
|
|
||||||
m.FlavorId = types.StringValue(resp.GetFlavorId())
|
m.FlavorId = types.StringValue(resp.GetFlavorId())
|
||||||
if m.Id.IsNull() || m.Id.IsUnknown() {
|
if m.Id.IsNull() || m.Id.IsUnknown() {
|
||||||
m.Id = utils.BuildInternalTerraformId(m.ProjectId.ValueString(), m.Region.ValueString(), m.InstanceId.ValueString())
|
m.Id = utils.BuildInternalTerraformId(m.ProjectId.ValueString(), m.Region.ValueString(), m.InstanceId.ValueString())
|
||||||
}
|
}
|
||||||
m.InstanceId = types.StringPointerValue(resp.Id)
|
m.InstanceId = types.StringPointerValue(resp.Id)
|
||||||
|
|
||||||
//m.IsDeletable = types.BoolUnknown()
|
|
||||||
//if isDel, ok := resp.GetIsDeletableOk(); ok {
|
|
||||||
// m.IsDeletable = types.BoolValue(isDel)
|
|
||||||
m.IsDeletable = types.BoolValue(resp.GetIsDeletable())
|
m.IsDeletable = types.BoolValue(resp.GetIsDeletable())
|
||||||
//}
|
|
||||||
|
|
||||||
netAcl, diags := types.ListValueFrom(ctx, types.StringType, resp.Network.GetAcl())
|
netAcl, diags := types.ListValueFrom(ctx, types.StringType, resp.Network.GetAcl())
|
||||||
if diags.HasError() {
|
if diags.HasError() {
|
||||||
|
|
@ -93,10 +93,6 @@ func mapGetInstanceResponseToModel(ctx context.Context, m *postgresflexalphareso
|
||||||
|
|
||||||
m.Name = types.StringValue(resp.GetName())
|
m.Name = types.StringValue(resp.GetName())
|
||||||
|
|
||||||
//m.Status = types.StringUnknown()
|
|
||||||
//if status, ok := resp.GetStatusOk(); ok {
|
|
||||||
// m.Status = types.StringValue(string(status))
|
|
||||||
//}
|
|
||||||
m.Status = types.StringValue(string(resp.GetStatus()))
|
m.Status = types.StringValue(string(resp.GetStatus()))
|
||||||
|
|
||||||
storage, diags := postgresflexalpharesource.NewStorageValue(
|
storage, diags := postgresflexalpharesource.NewStorageValue(
|
||||||
|
|
@ -117,13 +113,14 @@ func mapGetInstanceResponseToModel(ctx context.Context, m *postgresflexalphareso
|
||||||
|
|
||||||
func mapGetDataInstanceResponseToModel(ctx context.Context, m *postgresflexalphadatasource.InstanceModel, resp *postgresflex.GetInstanceResponse) error {
|
func mapGetDataInstanceResponseToModel(ctx context.Context, m *postgresflexalphadatasource.InstanceModel, resp *postgresflex.GetInstanceResponse) error {
|
||||||
m.BackupSchedule = types.StringValue(resp.GetBackupSchedule())
|
m.BackupSchedule = types.StringValue(resp.GetBackupSchedule())
|
||||||
//nolint:gocritic
|
m.Encryption = postgresflexalphadatasource.EncryptionValue{
|
||||||
// m.Encryption = postgresflexalpharesource.EncryptionValue{
|
KekKeyId: types.StringValue(resp.Encryption.GetKekKeyId()),
|
||||||
// KekKeyId: types.StringValue(resp.Encryption.GetKekKeyId()),
|
KekKeyRingId: types.StringValue(resp.Encryption.GetKekKeyRingId()),
|
||||||
// KekKeyRingId: types.StringValue(resp.Encryption.GetKekKeyRingId()),
|
KekKeyVersion: types.StringValue(resp.Encryption.GetKekKeyVersion()),
|
||||||
// KekKeyVersion: types.StringValue(resp.Encryption.GetKekKeyVersion()),
|
ServiceAccount: types.StringValue(resp.Encryption.GetServiceAccount()),
|
||||||
// ServiceAccount: types.StringValue(resp.Encryption.GetServiceAccount()),
|
}
|
||||||
// }
|
m.ConnectionInfo.Host = types.StringValue(resp.ConnectionInfo.GetHost())
|
||||||
|
m.ConnectionInfo.Port = types.Int64Value(resp.ConnectionInfo.GetPort())
|
||||||
m.FlavorId = types.StringValue(resp.GetFlavorId())
|
m.FlavorId = types.StringValue(resp.GetFlavorId())
|
||||||
m.Id = utils.BuildInternalTerraformId(m.ProjectId.ValueString(), m.Region.ValueString(), m.InstanceId.ValueString())
|
m.Id = utils.BuildInternalTerraformId(m.ProjectId.ValueString(), m.Region.ValueString(), m.InstanceId.ValueString())
|
||||||
m.InstanceId = types.StringPointerValue(resp.Id)
|
m.InstanceId = types.StringPointerValue(resp.Id)
|
||||||
|
|
|
||||||
|
|
@ -247,16 +247,20 @@ func (r *instanceResource) Create(
|
||||||
}
|
}
|
||||||
|
|
||||||
func modelToCreateInstancePayload(netAcl []string, model postgresflexalpha.InstanceModel, replVal int32) postgresflex.CreateInstanceRequestPayload {
|
func modelToCreateInstancePayload(netAcl []string, model postgresflexalpha.InstanceModel, replVal int32) postgresflex.CreateInstanceRequestPayload {
|
||||||
payload := postgresflex.CreateInstanceRequestPayload{
|
var enc postgresflex.InstanceEncryption
|
||||||
BackupSchedule: model.BackupSchedule.ValueStringPointer(),
|
if !model.Encryption.IsNull() && !model.Encryption.IsUnknown() {
|
||||||
Encryption: &postgresflex.InstanceEncryption{
|
enc = postgresflex.InstanceEncryption{
|
||||||
KekKeyId: model.Encryption.KekKeyId.ValueStringPointer(),
|
KekKeyId: model.Encryption.KekKeyId.ValueStringPointer(),
|
||||||
KekKeyRingId: model.Encryption.KekKeyRingId.ValueStringPointer(),
|
KekKeyRingId: model.Encryption.KekKeyRingId.ValueStringPointer(),
|
||||||
KekKeyVersion: model.Encryption.KekKeyVersion.ValueStringPointer(),
|
KekKeyVersion: model.Encryption.KekKeyVersion.ValueStringPointer(),
|
||||||
ServiceAccount: model.Encryption.ServiceAccount.ValueStringPointer(),
|
ServiceAccount: model.Encryption.ServiceAccount.ValueStringPointer(),
|
||||||
},
|
}
|
||||||
FlavorId: model.FlavorId.ValueStringPointer(),
|
}
|
||||||
Name: model.Name.ValueStringPointer(),
|
payload := postgresflex.CreateInstanceRequestPayload{
|
||||||
|
BackupSchedule: model.BackupSchedule.ValueStringPointer(),
|
||||||
|
Encryption: &enc,
|
||||||
|
FlavorId: model.FlavorId.ValueStringPointer(),
|
||||||
|
Name: model.Name.ValueStringPointer(),
|
||||||
Network: &postgresflex.InstanceNetwork{
|
Network: &postgresflex.InstanceNetwork{
|
||||||
AccessScope: postgresflex.InstanceNetworkGetAccessScopeAttributeType(
|
AccessScope: postgresflex.InstanceNetworkGetAccessScopeAttributeType(
|
||||||
model.Network.AccessScope.ValueStringPointer(),
|
model.Network.AccessScope.ValueStringPointer(),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue