From 6e68af006959da478a4cf1af1ef0b663347852c5 Mon Sep 17 00:00:00 2001 From: Adam Bozanich Date: Tue, 23 Apr 2024 05:28:04 -0700 Subject: [PATCH] feat(private-containers): private registries (#1941) refs akash-network/support#54 Signed-off-by: Adam Bozanich --- sdl/_testdata/v2.1-credentials-error.yaml | 48 ++++++++++++++++++++++ sdl/_testdata/v2.1-credentials.yaml | 49 +++++++++++++++++++++++ sdl/groupBuilder_v2.go | 8 ++++ sdl/groupBuilder_v2_1.go | 10 +++++ sdl/v2.go | 49 ++++++++++++++++++++--- sdl/v2_1.go | 12 ++++++ sdl/v2_1_test.go | 32 +++++++++++++++ 7 files changed, 202 insertions(+), 6 deletions(-) create mode 100644 sdl/_testdata/v2.1-credentials-error.yaml create mode 100644 sdl/_testdata/v2.1-credentials.yaml diff --git a/sdl/_testdata/v2.1-credentials-error.yaml b/sdl/_testdata/v2.1-credentials-error.yaml new file mode 100644 index 0000000000..83e3fc24df --- /dev/null +++ b/sdl/_testdata/v2.1-credentials-error.yaml @@ -0,0 +1,48 @@ +--- +version: "2.1" +services: + web: + image: nginx + expose: + - port: 80 + accept: + - ahostname.com + to: + - global: true + - port: 12345 + to: + - global: true + proto: udp + credentials: + username: "foo" + password: "foo" +profiles: + compute: + web: + resources: + cpu: + units: "100m" + memory: + size: "128Mi" + storage: + size: "1Gi" + placement: + westcoast: + attributes: + region: us-west + signedBy: + anyOf: + - 1 + - 2 + allOf: + - 3 + - 4 + pricing: + web: + denom: uakt + amount: 50 +deployment: + web: + westcoast: + profile: web + count: 2 diff --git a/sdl/_testdata/v2.1-credentials.yaml b/sdl/_testdata/v2.1-credentials.yaml new file mode 100644 index 0000000000..63622b0a61 --- /dev/null +++ b/sdl/_testdata/v2.1-credentials.yaml @@ -0,0 +1,49 @@ +--- +version: "2.1" +services: + web: + image: nginx + expose: + - port: 80 + accept: + - ahostname.com + to: + - global: true + - port: 12345 + to: + - global: true + proto: udp + credentials: + host: "https://test.com/v1" + username: "foo" + password: "foo" +profiles: + compute: + web: + resources: + cpu: + units: "100m" + memory: + size: "128Mi" + storage: + size: "1Gi" + placement: + westcoast: + attributes: + region: us-west + signedBy: + anyOf: + - 1 + - 2 + allOf: + - 3 + - 4 + pricing: + web: + denom: uakt + amount: 50 +deployment: + web: + westcoast: + profile: web + count: 2 diff --git a/sdl/groupBuilder_v2.go b/sdl/groupBuilder_v2.go index 4e124c0b43..3d9911ed46 100644 --- a/sdl/groupBuilder_v2.go +++ b/sdl/groupBuilder_v2.go @@ -114,6 +114,14 @@ func (sdl *v2) buildGroups() error { msvc.Params = params } + if svc.Credentials != nil { + msvc.Credentials = &manifest.ServiceImageCredentials{ + Host: svc.Credentials.Host, + Username: svc.Credentials.Username, + Password: svc.Credentials.Password, + } + } + group.mgroup.Services = append(group.mgroup.Services, msvc) } } diff --git a/sdl/groupBuilder_v2_1.go b/sdl/groupBuilder_v2_1.go index 7e14642c03..e39143449e 100644 --- a/sdl/groupBuilder_v2_1.go +++ b/sdl/groupBuilder_v2_1.go @@ -2,6 +2,7 @@ package sdl import ( "sort" + "strings" manifest "github.com/akash-network/akash-api/go/manifest/v2beta2" dtypes "github.com/akash-network/akash-api/go/node/deployment/v1beta3" @@ -123,6 +124,15 @@ func (sdl *v2_1) buildGroups() error { msvc.Params = params } + if svc.Credentials != nil { + msvc.Credentials = &manifest.ServiceImageCredentials{ + Host: strings.TrimSpace(svc.Credentials.Host), + Email: strings.TrimSpace(svc.Credentials.Email), + Username: strings.TrimSpace(svc.Credentials.Username), + Password: strings.TrimSpace(svc.Credentials.Password), + } + } + group.mgroup.Services = append(group.mgroup.Services, msvc) } } diff --git a/sdl/v2.go b/sdl/v2.go index 40030b226a..d5f8078f72 100644 --- a/sdl/v2.go +++ b/sdl/v2.go @@ -7,6 +7,7 @@ import ( "regexp" "sort" "strconv" + "strings" "gopkg.in/yaml.v3" @@ -42,6 +43,9 @@ var ( errUnknownNextCase = errors.New("next case is unknown") errHTTPOptionNotAllowed = errors.New("http option not allowed") errSDLInvalid = errors.New("SDL invalid") + errCredentialNoHost = errors.New("Service Credentials missing Host") + errCredentialNoUsername = errors.New("Service Credentials missing Username") + errCredentialNoPassword = errors.New("Service Credentials missing Password") ) var endpointNameValidationRegex = regexp.MustCompile(`^[[:lower:]]+[[:lower:]-_\d]+$`) @@ -167,12 +171,33 @@ type v2ServiceParams struct { type v2Service struct { Image string - Command []string `yaml:",omitempty"` - Args []string `yaml:",omitempty"` - Env []string `yaml:",omitempty"` - Expose v2Exposes `yaml:",omitempty"` - Dependencies []v2Dependency `yaml:",omitempty"` - Params *v2ServiceParams `yaml:",omitempty"` + Command []string `yaml:",omitempty"` + Args []string `yaml:",omitempty"` + Env []string `yaml:",omitempty"` + Expose v2Exposes `yaml:",omitempty"` + Dependencies []v2Dependency `yaml:",omitempty"` + Params *v2ServiceParams `yaml:",omitempty"` + Credentials *v2ServiceCredentials `yaml:",omitempty"` +} + +type v2ServiceCredentials struct { + Host string `yaml:",omitempty"` + Email string `yaml:",omitempty"` + Username string `yaml:",omitempty"` + Password string `yaml:",omitempty"` +} + +func (c v2ServiceCredentials) validate() error { + if strings.TrimSpace(c.Host) == "" { + return errCredentialNoHost + } + if strings.TrimSpace(c.Username) == "" { + return errCredentialNoUsername + } + if strings.TrimSpace(c.Password) == "" { + return errCredentialNoPassword + } + return nil } type v2ServiceDeployment struct { @@ -328,6 +353,18 @@ func (sdl *v2) validate() error { ) } + if svc.Credentials != nil { + if err := svc.Credentials.validate(); err != nil { + return fmt.Errorf( + "%w: %v.%v: %v", + errSDLInvalid, + svcName, + placementName, + err, + ) + } + } + for _, serviceExpose := range svc.Expose { for _, to := range serviceExpose.To { // Check to see if an IP endpoint is also specified diff --git a/sdl/v2_1.go b/sdl/v2_1.go index 33a5b0e68a..98fcdec844 100644 --- a/sdl/v2_1.go +++ b/sdl/v2_1.go @@ -155,6 +155,18 @@ func (sdl *v2_1) validate() error { ) } + if svc.Credentials != nil { + if err := svc.Credentials.validate(); err != nil { + return fmt.Errorf( + "%w: %v.%v: %v", + errSDLInvalid, + svcName, + placementName, + err, + ) + } + } + for _, serviceExpose := range svc.Expose { for _, to := range serviceExpose.To { // Check to see if an IP endpoint is also specified diff --git a/sdl/v2_1_test.go b/sdl/v2_1_test.go index b867d710c6..6e67f0d05e 100644 --- a/sdl/v2_1_test.go +++ b/sdl/v2_1_test.go @@ -330,6 +330,38 @@ func Test_V2_1_Parse_simple(t *testing.T) { }, }, }, mani.GetGroups()[0]) + + assert.Nil(t, mani.GetGroups()[0].Services[0].Credentials) + +} + +func Test_V2_1_Parse_credentials(t *testing.T) { + sdl, err := ReadFile("./_testdata/v2.1-credentials.yaml") + require.NoError(t, err) + + mani, err := sdl.Manifest() + require.NoError(t, err) + + assert.Len(t, mani.GetGroups(), 1) + + grp := mani.GetGroups()[0] + assert.Len(t, grp.Services, 1) + + svc := grp.Services[0] + + assert.NotNil(t, svc) + + creds := svc.Credentials + assert.NotNil(t, creds) + + assert.Equal(t, "https://test.com/v1", creds.Host) + assert.Equal(t, "foo", creds.Username) + assert.Equal(t, "foo", creds.Password) +} + +func Test_V2_1_Parse_credentials_error(t *testing.T) { + _, err := ReadFile("./_testdata/v2.1-credentials-error.yaml") + require.Error(t, err) } func Test_v2_1_Parse_ProfileNameNotServiceName(t *testing.T) {