Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
71 changes: 51 additions & 20 deletions cmd/appstreamfile/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,76 @@ import (
"github.com/aslamcodes/appstreamfile/internal/validator"
)

type RunOptions struct {
location string
bucket string
key string
versionId string
}

func main() {
source := flag.String("source", "", "The source to pick actions from")
location := flag.String("location", "", "The config file location")
source := flag.String("source", "", "Configuration source: s3 or local")
location := flag.String("location", "", "Local filesystem path to the config file")
bucket := flag.String("bucket", "", "S3 bucket containing the config file")
key := flag.String("key", "", "S3 object key for the config file")
versionId := flag.String("version-id", "", "Optional S3 object version ID")

flag.Parse()

logger.Init()

if err := run(*source, *location); err != nil {
runOptions := &RunOptions{
location: *location,
bucket: *bucket,
key: *key,
versionId: *versionId,
}

if err := run(*source, runOptions); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}

func run(sourceType string, location string) error {
func run(sourceType string, opts *RunOptions) error {
var backendSource backend.BackendSource
var err error

switch sourceType {
case "local":
backend := backend.LocalBackend{
Location: location,
case "local":
if opts.location == "" {
return fmt.Errorf("location of config file must be provided")
}
backendSource, err = backend.NewLocalBackend(opts.location)
case "s3":
if opts.bucket == "" || opts.key == "" {
return fmt.Errorf("missing required S3 options: bucket and key")
}
backendSource, err = backend.NewS3Backend(opts.bucket, opts.key, opts.versionId, "appstream_machine_role")

config, err := backend.GetConfig()

if err != nil {
return fmt.Errorf("failed to fetch config from backend: %w", err)
}
default:
return fmt.Errorf("invalid source provided")
}

if err := validator.ValidateConfig(config); err != nil {
return fmt.Errorf("config file validation failed: %w", err)
}
if err != nil {
return fmt.Errorf("unable to create backend source: %w", err)
}

err = service.ImplementConfig(config)
config, err := backendSource.GetConfig()

if err != nil {
return fmt.Errorf("error setting up config: %w", err)
}
if err != nil {
return fmt.Errorf("failed to fetch config from backend: %w", err)
}

default:
return fmt.Errorf("invalid source provided")
if err := validator.ValidateConfig(config); err != nil {
return fmt.Errorf("config file validation failed: %w", err)
}

err = service.ImplementConfig(config)

if err != nil {
return fmt.Errorf("error setting up config: %w", err)
}

return nil
Expand Down
26 changes: 25 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,28 @@ module github.com/aslamcodes/appstreamfile

go 1.24.1

require github.com/goccy/go-yaml v1.19.0
require (
github.com/aws/aws-sdk-go-v2/config v1.32.5
github.com/aws/aws-sdk-go-v2/service/s3 v1.94.0
github.com/goccy/go-yaml v1.19.0
)

require (
github.com/aws/aws-sdk-go-v2 v1.41.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.19.5 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 // indirect
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 // indirect
github.com/aws/smithy-go v1.24.0 // indirect
)
38 changes: 38 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,40 @@
github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4=
github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4=
github.com/aws/aws-sdk-go-v2/config v1.32.5 h1:pz3duhAfUgnxbtVhIK39PGF/AHYyrzGEyRD9Og0QrE8=
github.com/aws/aws-sdk-go-v2/config v1.32.5/go.mod h1:xmDjzSUs/d0BB7ClzYPAZMmgQdrodNjPPhd6bGASwoE=
github.com/aws/aws-sdk-go-v2/credentials v1.19.5 h1:xMo63RlqP3ZZydpJDMBsH9uJ10hgHYfQFIk1cHDXrR4=
github.com/aws/aws-sdk-go-v2/credentials v1.19.5/go.mod h1:hhbH6oRcou+LpXfA/0vPElh/e0M3aFeOblE1sssAAEk=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16 h1:80+uETIWS1BqjnN9uJ0dBUaETh+P1XwFy5vwHwK5r9k=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.16/go.mod h1:wOOsYuxYuB/7FlnVtzeBYRcjSRtQpAW0hCP7tIULMwo=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 h1:CjMzUs78RDDv4ROu3JnJn/Ig1r6ZD7/T2DXLLRpejic=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16/go.mod h1:uVW4OLBqbJXSHJYA9svT9BluSvvwbzLQ2Crf6UPzR3c=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 h1:DIBqIrJ7hv+e4CmIk2z3pyKT+3B6qVMgRsawHiR3qso=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7/go.mod h1:vLm00xmBke75UmpNvOcZQ/Q30ZFjbczeLFqGx5urmGo=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 h1:NSbvS17MlI2lurYgXnCOLvCFX38sBW4eiVER7+kkgsU=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16/go.mod h1:SwT8Tmqd4sA6G1qaGdzWCJN99bUmPGHfRwwq3G5Qb+A=
github.com/aws/aws-sdk-go-v2/service/s3 v1.94.0 h1:SWTxh/EcUCDVqi/0s26V6pVUq0BBG7kx0tDTmF/hCgA=
github.com/aws/aws-sdk-go-v2/service/s3 v1.94.0/go.mod h1:79S2BdqCJpScXZA2y+cpZuocWsjGjJINyXnOsf5DTz8=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4 h1:HpI7aMmJ+mm1wkSHIA2t5EaFFv5EFYXePW30p1EIrbQ=
github.com/aws/aws-sdk-go-v2/service/signin v1.0.4/go.mod h1:C5RdGMYGlfM0gYq/tifqgn4EbyX99V15P2V3R+VHbQU=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7 h1:eYnlt6QxnFINKzwxP5/Ucs1vkG7VT3Iezmvfgc2waUw=
github.com/aws/aws-sdk-go-v2/service/sso v1.30.7/go.mod h1:+fWt2UHSb4kS7Pu8y+BMBvJF0EWx+4H0hzNwtDNRTrg=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12 h1:AHDr0DaHIAo8c9t1emrzAlVDFp+iMMKnPdYy6XO4MCE=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.12/go.mod h1:GQ73XawFFiWxyWXMHWfhiomvP3tXtdNar/fi8z18sx0=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5 h1:SciGFVNZ4mHdm7gpD1dgZYnCuVdX1s+lFTg4+4DOy70=
github.com/aws/aws-sdk-go-v2/service/sts v1.41.5/go.mod h1:iW40X4QBmUxdP+fZNOpfmkdMZqsovezbAeO+Ubiv2pk=
github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk=
github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
github.com/goccy/go-yaml v1.19.0 h1:EmkZ9RIsX+Uq4DYFowegAuJo8+xdX3T/2dwNPXbxEYE=
github.com/goccy/go-yaml v1.19.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
2 changes: 1 addition & 1 deletion internal/backend/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ package backend
import c "github.com/aslamcodes/appstreamfile/internal/config"

type BackendSource interface {
GetConfig() c.Config
GetConfig() (*c.Config, error)
}
6 changes: 6 additions & 0 deletions internal/backend/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,9 @@ func (lb *LocalBackend) GetConfig() (*config.Config, error) {

return &configData, nil
}

func NewLocalBackend(location string) (BackendSource, error) {
return &LocalBackend{
Location: location,
}, nil
}
58 changes: 55 additions & 3 deletions internal/backend/s3.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,64 @@
package backend

import (
c "github.com/aslamcodes/appstreamfile/internal/config"
"context"
"fmt"
"io"

"github.com/aslamcodes/appstreamfile/internal/config"
"github.com/goccy/go-yaml"
)

type S3Backend struct {
Bucket string
Key string
VersionId string
Client S3Client
}

func (s3 *S3Backend) GetConfig() (*c.Config, error) {
return &c.Config{}, nil
func (s3Backend *S3Backend) GetConfig() (*config.Config, error) {
ctx := context.Background()

if s3Backend.Client == nil {
return nil, fmt.Errorf("client is nil")
}

out, err := s3Backend.Client.GetObject(ctx, s3Backend.Bucket, s3Backend.Key, s3Backend.VersionId)

if err != nil {
return nil, fmt.Errorf("failed to fetch object from s3: %w", err)
}

defer out.Body.Close()

content, err := io.ReadAll(out.Body)

if err != nil {
return nil, fmt.Errorf("error reading config: %w", err)
}

var configData config.Config

if err := yaml.Unmarshal(content, &configData); err != nil {
return nil, fmt.Errorf("failed to parse config data, config data or formatting is invalid: %w", err)
}

fmt.Printf("Builder has successfully parsed the config file from backend\n")

return &configData, nil
}

func NewS3Backend(bucket, key, versionId, profile string) (BackendSource, error) {
client, err := NewS3Client(profile)

if err != nil {
return nil, fmt.Errorf("not able to create s3 client: %w", err)
}

return &S3Backend{
Bucket: bucket,
Key: key,
VersionId: versionId,
Client: client,
}, nil
}
53 changes: 53 additions & 0 deletions internal/backend/s3_client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package backend

import (
"context"
"fmt"

s3Config "github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
)

type S3Client interface {
GetObject(ctx context.Context, bucket string, key string, versionId string) (*s3.GetObjectOutput, error)
}

type S3BackendClient struct {
s3Client *s3.Client
}

func (c *S3BackendClient) GetObject(ctx context.Context, bucket string, key string, versionId string) (*s3.GetObjectOutput, error) {
objectInput := &s3.GetObjectInput{
Bucket: &bucket,
Key: &key,
}

if versionId != "" {
objectInput.VersionId = &versionId
}

return c.s3Client.GetObject(ctx, objectInput)
}

func NewS3Client(profile string) (S3Client, error) {
opts := []func(*s3Config.LoadOptions) error{}

if profile != "" {
opts = append(opts, s3Config.WithSharedConfigProfile(profile))
}

ctx := context.Background()

cfg, err := s3Config.LoadDefaultConfig(ctx, opts...)
if err != nil {
return nil, fmt.Errorf("failed to load SDK configuration: %w", err)
}

client := s3.NewFromConfig(cfg)

backendClient := S3BackendClient{
s3Client: client,
}

return &backendClient, nil
}
88 changes: 88 additions & 0 deletions internal/backend/s3_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package backend_test

import (
"bytes"
"context"
"errors"
"io"
"reflect"
"testing"

"github.com/aslamcodes/appstreamfile/internal/backend"
"github.com/aslamcodes/appstreamfile/internal/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
)

type mockS3Client struct {
Output *s3.GetObjectOutput
Err error
}

func (client *mockS3Client) GetObject(ctx context.Context, bucket string, key string, versionId string) (*s3.GetObjectOutput, error) {
return client.Output, client.Err
}

func TestS3GetConfig(t *testing.T) {
client := &mockS3Client{}

content := `platform: "unix"
installers:
- executable: "bash"
installScript: |
echo "Hello World"`

expected := &config.Config{
Platform: "unix",
Installers: []config.Installer{
{
InstallScript: `echo "Hello World"`,
Executable: "bash",
},
},
}

client.Output = &s3.GetObjectOutput{
Body: io.NopCloser(bytes.NewReader([]byte(content))),
}

backend := &backend.S3Backend{
Bucket: "test",
Key: "test",
VersionId: "",
Client: client,
}

actual, err := backend.GetConfig()

if err != nil {
t.Errorf("error fetching the config: %v", err)
}

if !reflect.DeepEqual(actual, expected) {
t.Errorf("expected %v+,\n actual %v+", expected, actual)
}

}

func TestGetConfigFail(t *testing.T) {
expectedErr := errors.New("boom")

backend := &backend.S3Backend{
Bucket: "test",
Key: "test",
VersionId: "",
Client: &mockS3Client{
Err: expectedErr,
},
}

_, err := backend.GetConfig()

if err == nil {
t.Errorf("expected %v, got nil", expectedErr)
}
if !errors.Is(err, expectedErr) {
t.Errorf("expected %v, got %v", expectedErr, err)
}

}