Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Terrarium - Providers]: Implementation of the provider registry protocol v1 #66

Merged
merged 11 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ RUN apt-get update && \
apt-get install -y ca-certificates

FROM scratch
COPY --from=build /workspace/providers.json /
COPY --from=build /workspace/terrarium /
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
ENTRYPOINT [ "/terrarium" ]
38 changes: 38 additions & 0 deletions cmd/rest_providers_v1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package cmd

import (
providersv1 "github.com/terrariumcloud/terrarium/internal/restapi/providers/v1"

"github.com/terrariumcloud/terrarium/internal/provider/services"

"github.com/spf13/cobra"
)

var mountPathProviders string

var providersV1Cmd = &cobra.Command{
Use: "providers.v1",
Short: "Starts the Terrarium REST API service implementing a read only version of the provider.v1 registry protocol",
Long: "Runs the Terrarium REST server for the implementation of the provider.v1 protocol",
Run: runRESTProvidersV1Server,
}

func init() {
providersV1Cmd.Flags().StringVarP(
&mountPathProviders,
"mount-path",
"m",
"providers",
"Mount path for the rest API server used to process request relative to a particular URL in a reverse proxy type setup",
)
rootCmd.AddCommand(providersV1Cmd)
}

func runRESTProvidersV1Server(cmd *cobra.Command, args []string) {
vm, err := services.NewJSONFileProviderVersionManager()
if err != nil {
panic(err)
}
restAPIServer := providersv1.New(vm)
startRESTAPIService("rest-providers-v1", mountPathProviders, restAPIServer)
}
180 changes: 180 additions & 0 deletions internal/provider/services/jsonDataLoader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
package services

import (
"encoding/json"
"fmt"
"log"
"os"

"gopkg.in/errgo.v2/errors"
)

type ProviderVersionManager interface {
ListProviderVersions(providerName string) (*ProviderVersionsResponse, error)
GetVersionData(providerName string, version string, os string, arch string) (*PlatformMetadataResponse, error)
}

// Structs to load data into (from a JSON file for now, will be from DB later)
type GPGPublicKey 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"`
}

type SigningKeys struct {
GPGPublicKeys []GPGPublicKey `json:"gpg_public_keys"`
}

type ProviderMetadata struct {
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 SigningKeys `json:"signing_keys"`
}

type VersionData struct {
Protocols []string `json:"protocols"`
Platforms []ProviderMetadata `json:"platforms"`
}

type ProviderData map[string]VersionData

type JSONFileProviderVersionManager struct {
data map[string]ProviderData
}

// Structs to load response into (for listing versions for a specific provider)

type Platform struct {
OS string `json:"os"`
Arch string `json:"arch"`
}

type VersionItem struct {
Version string `json:"version"`
Protocols []string `json:"protocols"`
Platforms []Platform `json:"platforms"`
}

type ProviderVersionsResponse struct {
Versions []VersionItem `json:"versions"`
}

// Structs to load response into (for a provider's metadata)

type PlatformMetadataResponse 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"`
ShasumsSigURL string `json:"shasums_signature_url"`
Shasum string `json:"shasum"`
SigningKeys SigningKeys `json:"signing_keys"`
}

var providerObj map[string]ProviderData

func LoadData() (map[string]ProviderData, error) {
anjanikshree12 marked this conversation as resolved.
Show resolved Hide resolved
log.Printf("loadJSONDataIntoStructs")

filePath := "./providers.json"

data, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}

if err := json.Unmarshal(data, &providerObj); err != nil {
return nil, err
}
return providerObj, nil
}

func NewJSONFileProviderVersionManager() (ProviderVersionManager, error) {
if data, err := LoadData(); err == nil {
return &JSONFileProviderVersionManager{data: data}, nil
} else {
return nil, err
}
}

func (vm *JSONFileProviderVersionManager) ListProviderVersions(providerName string) (*ProviderVersionsResponse, error) {

var providerVersions ProviderVersionsResponse
var platform Platform

// Check if the provider ID exists
if providerData, exists := providerObj[providerName]; exists {
// Add the matched provider's version details to the ProviderVersionsResponse
for version, versionMetadata := range providerData {
var versionItem VersionItem
versionItem.Version = version
versionItem.Protocols = versionMetadata.Protocols
for _, versionPlatforms := range versionMetadata.Platforms {
platform.OS = versionPlatforms.OS
platform.Arch = versionPlatforms.Arch
versionItem.Platforms = append(versionItem.Platforms, platform)
}
providerVersions.Versions = append(providerVersions.Versions, versionItem)
}

} else {
errMsg := fmt.Sprintf("failed to retrieve the list of versions for %s", providerName)
return nil, errors.New(errMsg)
}

return &providerVersions, nil
}

func (vm *JSONFileProviderVersionManager) GetVersionData(providerName string, version string, os string, arch string) (*PlatformMetadataResponse, error) {

var providerMetadata PlatformMetadataResponse
var outputExists bool

// Check if the provider ID exists
if providerData, exists := providerObj[providerName]; exists {
// Check if the version exists for the provider
if versionData, exists := providerData[version]; exists {
for _, platform := range versionData.Platforms {
if platform.OS == os && platform.Arch == arch {
outputExists = true
// Add the matched platform details to the providerMetadata
providerMetadata.Protocols = versionData.Protocols
providerMetadata.OS = platform.OS
providerMetadata.Arch = platform.Arch
providerMetadata.Filename = platform.Filename
providerMetadata.DownloadURL = platform.DownloadURL
providerMetadata.ShasumsURL = platform.ShasumsURL
providerMetadata.ShasumsSigURL = platform.ShasumsSignatureURL
providerMetadata.Shasum = platform.Shasum
providerMetadata.SigningKeys = platform.SigningKeys
break
} else {
outputExists = false
}
}
} else {
errMsg := fmt.Sprintf("failed to retrieve version: %s for: %s", version, providerName)
return nil, errors.New(errMsg)
}
} else {
errMsg := fmt.Sprintf("failed to retrieve : %s", providerName)
return nil, errors.New(errMsg)
}

if outputExists {
return &providerMetadata, nil
} else {
errMsg := fmt.Sprintf("failed to retrieve provider %s (version %s) for os: %s and arch: %s", providerName, version, os, arch)
return nil, errors.New(errMsg)
}

}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"modules.v1": "/modules/v1"
"modules.v1": "/modules/v1",
"providers.v1": "/providers/v1/"
}
10 changes: 5 additions & 5 deletions internal/restapi/browse/frontend/build/asset-manifest.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
{
"files": {
"main.css": "/static/css/main.a593e941.css",
"main.js": "/static/js/main.248c1869.js",
"main.js": "/static/js/main.d65f24d1.js",
"static/js/496.c4cdc242.chunk.js": "/static/js/496.c4cdc242.chunk.js",
"static/media/not-found-1.jpg": "/static/media/not-found-1.3eec1753dacc2df2dcac.jpg",
"static/media/providers.svg": "/static/media/providers.6ba0b53e84665662440dd84573d617fb.svg",
"static/media/providers.svg": "/static/media/providers.b23747e853582f7fef85d036a949de8f.svg",
"static/media/server-error-1.jpg": "/static/media/server-error-1.6a4af50aed762b81d561.jpg",
"static/media/release.svg": "/static/media/release.08bd319f2eeb6be6a24e6af1ceb025dd.svg",
"static/media/release.svg": "/static/media/release.75050f51cb3da5cd45e3eb3dba9b8991.svg",
"static/media/modules.png": "/static/media/modules.df4734ecc28bffc1b755.png",
"index.html": "/index.html",
"main.a593e941.css.map": "/static/css/main.a593e941.css.map",
"main.248c1869.js.map": "/static/js/main.248c1869.js.map",
"main.d65f24d1.js.map": "/static/js/main.d65f24d1.js.map",
"496.c4cdc242.chunk.js.map": "/static/js/496.c4cdc242.chunk.js.map"
},
"entrypoints": [
"static/css/main.a593e941.css",
"static/js/main.248c1869.js"
"static/js/main.d65f24d1.js"
]
}
2 changes: 1 addition & 1 deletion internal/restapi/browse/frontend/build/index.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>Terrarium: Synamedia Terraform Registry</title><script defer="defer" src="/static/js/main.248c1869.js"></script><link href="/static/css/main.a593e941.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>Terrarium: Synamedia Terraform Registry</title><script defer="defer" src="/static/js/main.d65f24d1.js"></script><link href="/static/css/main.a593e941.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{
"modules.v1": "/modules/v1"
"modules.v1": "/modules/v1",
"providers.v1": "/providers/v1/"
}
Loading