Skip to content

Commit

Permalink
feat: configure default cas backend size (#1655)
Browse files Browse the repository at this point in the history
Signed-off-by: Miguel Martinez <miguel@chainloop.dev>
  • Loading branch information
migmartri authored Dec 14, 2024
1 parent f857add commit 82d8a6a
Show file tree
Hide file tree
Showing 14 changed files with 326 additions and 176 deletions.
8 changes: 6 additions & 2 deletions app/controlplane/cmd/wire_gen.go

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

2 changes: 1 addition & 1 deletion app/controlplane/configs/config.devel.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ cas_server:
addr: 0.0.0.0:9001
insecure: true
download_url: http://0.0.0.0:8001/download

default_entry_max_size: 300MB
credentials_service:
vault:
address: ${VAULT_ADDRESS:http://0.0.0.0:8200}
Expand Down
1 change: 1 addition & 0 deletions app/controlplane/configs/samples/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ cas_server:
addr: 0.0.0.0:9001
# Where to redirect the user to download artifacts from the CAS
download_url: http://0.0.0.0:8001/download
default_entry_max_size: 1GB

# nats endpoint where to send events
nats_server:
Expand Down
336 changes: 175 additions & 161 deletions app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ message Bootstrap {
// In the form of [scheme]://[host]/path i.e https://cas.chainloop.dev/download
// https://github.com/chainloop-dev/chainloop/blob/126f47b6c0803eac844b8e3e1a21d582f00e4dc6/app/artifact-cas/internal/service/download.go#L34
string download_url = 3;

// Default max size for each entry in the CAS backend
// the format is a number followed by a unit, like 100MB, 1GB, etc
// Default is 100MB
string default_entry_max_size = 4;
}

// Configuration for onboarding users in organizations with specific roles
Expand Down
27 changes: 19 additions & 8 deletions app/controlplane/pkg/biz/casbackend.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
"io"
"time"

"code.cloudfoundry.org/bytefmt"
conf "github.com/chainloop-dev/chainloop/app/controlplane/internal/conf/controlplane/config/v1"
backend "github.com/chainloop-dev/chainloop/pkg/blobmanager"
"github.com/chainloop-dev/chainloop/pkg/blobmanager/azureblob"
"github.com/chainloop-dev/chainloop/pkg/blobmanager/oci"
Expand All @@ -36,7 +38,6 @@ import (
type CASBackendProvider string

const (
CASBackendDefaultMaxBytes int64 = 100 * 1024 * 1024 // 100MB
// Inline, embedded CAS backend
CASBackendInline CASBackendProvider = "INLINE"
CASBackendInlineDefaultMaxBytes int64 = 500 * 1024 // 500KB
Expand Down Expand Up @@ -111,18 +112,28 @@ type CASBackendReader interface {
}

type CASBackendUseCase struct {
repo CASBackendRepo
logger *log.Helper
credsRW credentials.ReaderWriter
providers backend.Providers
repo CASBackendRepo
logger *log.Helper
credsRW credentials.ReaderWriter
providers backend.Providers
MaxBytesDefault int64
}

func NewCASBackendUseCase(repo CASBackendRepo, credsRW credentials.ReaderWriter, providers backend.Providers, l log.Logger) *CASBackendUseCase {
func NewCASBackendUseCase(repo CASBackendRepo, credsRW credentials.ReaderWriter, providers backend.Providers, c *conf.Bootstrap_CASServer, l log.Logger) (*CASBackendUseCase, error) {
if l == nil {
l = log.NewStdLogger(io.Discard)
}

return &CASBackendUseCase{repo, servicelogger.ScopedHelper(l, "biz/CASBackend"), credsRW, providers}
var maxBytesDefault uint64 = 100 * 1024 * 1024 // 100MB
if c.GetDefaultEntryMaxSize() != "" {
var err error
maxBytesDefault, err = bytefmt.ToBytes(c.DefaultEntryMaxSize)
if err != nil {
return nil, fmt.Errorf("invalid CAS backend default max bytes: %w", err)
}
}

return &CASBackendUseCase{repo, servicelogger.ScopedHelper(l, "biz/CASBackend"), credsRW, providers, int64(maxBytesDefault)}, nil
}

func (uc *CASBackendUseCase) List(ctx context.Context, orgID string) ([]*CASBackend, error) {
Expand Down Expand Up @@ -253,7 +264,7 @@ func (uc *CASBackendUseCase) Create(ctx context.Context, orgID, name, location,
}

backend, err := uc.repo.Create(ctx, &CASBackendCreateOpts{
MaxBytes: CASBackendDefaultMaxBytes,
MaxBytes: uc.MaxBytesDefault,
Name: name,
CASBackendOpts: &CASBackendOpts{
Location: location, SecretName: secretName, Provider: provider, Default: defaultB,
Expand Down
100 changes: 98 additions & 2 deletions app/controlplane/pkg/biz/casbackend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"errors"
"testing"

conf "github.com/chainloop-dev/chainloop/app/controlplane/internal/conf/controlplane/config/v1"
"github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz"
bizMocks "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz/mocks"
backends "github.com/chainloop-dev/chainloop/pkg/blobmanager"
Expand Down Expand Up @@ -171,6 +172,99 @@ func (s *casBackendTestSuite) TestPerformValidation() {
})
}

func (s *casBackendTestSuite) TestNewCASBackendUseCase() {
assert := assert.New(s.T())
const defaultErrorMsg = "byte quantity must be a positive integer with a unit of measurement like M, MB, MiB, G, GiB, or GB"

tests := []struct {
name string
config *conf.Bootstrap_CASServer
expectError bool
errorMsg string
wantSize int64 // Expected size in bytes after parsing
}{
{
name: "nil config uses default",
config: nil,
expectError: false,
wantSize: 100 * 1024 * 1024, // 100MB default
},
{
name: "valid size - megabytes",
config: &conf.Bootstrap_CASServer{
DefaultEntryMaxSize: "100MB",
},
expectError: false,
wantSize: 100 * 1024 * 1024,
},
{
name: "valid size - gigabytes",
config: &conf.Bootstrap_CASServer{
DefaultEntryMaxSize: "2GB",
},
expectError: false,
wantSize: 2 * 1024 * 1024 * 1024,
},
{
name: "invalid size format",
config: &conf.Bootstrap_CASServer{
DefaultEntryMaxSize: "invalid",
},
expectError: true,
errorMsg: defaultErrorMsg,
wantSize: 0,
},
{
name: "negative size",
config: &conf.Bootstrap_CASServer{
DefaultEntryMaxSize: "-100MB",
},
expectError: true,
errorMsg: defaultErrorMsg,
wantSize: 0,
},
{
name: "zero size",
config: &conf.Bootstrap_CASServer{
DefaultEntryMaxSize: "0",
},
expectError: true,
errorMsg: defaultErrorMsg,
wantSize: 0,
},
{
name: "missing unit",
config: &conf.Bootstrap_CASServer{
DefaultEntryMaxSize: "100",
},
expectError: true,
errorMsg: defaultErrorMsg,
wantSize: 0,
},
}

for _, tc := range tests {
s.Run(tc.name, func() {
useCase, err := biz.NewCASBackendUseCase(s.repo, s.credsRW,
backends.Providers{
"OCI": s.backendProvider,
}, tc.config, nil)

if tc.expectError {
assert.Error(err)
if tc.errorMsg != "" {
assert.Contains(err.Error(), tc.errorMsg)
}
assert.Nil(useCase)
} else {
assert.NoError(err)
assert.NotNil(useCase)
assert.Equal(tc.wantSize, useCase.MaxBytesDefault)
}
})
}
}

// Run all the tests
func TestCASBackend(t *testing.T) {
suite.Run(t, new(casBackendTestSuite))
Expand All @@ -188,9 +282,11 @@ func (s *casBackendTestSuite) SetupTest() {
s.repo = bizMocks.NewCASBackendRepo(s.T())
s.credsRW = credentialsM.NewReaderWriter(s.T())
s.backendProvider = blobM.NewProvider(s.T())
s.useCase = biz.NewCASBackendUseCase(s.repo, s.credsRW,
var err error
s.useCase, err = biz.NewCASBackendUseCase(s.repo, s.credsRW,
backends.Providers{
"OCI": s.backendProvider,
}, nil,
}, nil, nil,
)
s.Require().NoError(err)
}
6 changes: 6 additions & 0 deletions app/controlplane/pkg/biz/testhelpers/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,12 @@ func NewConfData(db *TestDatabase, t *testing.T) *conf.Data {
}
}

func NewCASBackendConfig() *conf.Bootstrap_CASServer {
return &conf.Bootstrap_CASServer{
DefaultEntryMaxSize: "100MB",
}
}

func NewPromSpec() []*conf.PrometheusIntegrationSpec {
return []*conf.PrometheusIntegrationSpec{}
}
Expand Down
1 change: 1 addition & 0 deletions app/controlplane/pkg/biz/testhelpers/wire.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func WireTestData(*TestDatabase, *testing.T, log.Logger, credentials.ReaderWrite
wire.FieldsOf(new(*conf.Data), "Database"),
newNatsConnection,
auditor.NewAuditLogPublisher,
NewCASBackendConfig,
),
)
}
Expand Down
7 changes: 6 additions & 1 deletion app/controlplane/pkg/biz/testhelpers/wire_gen.go

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

2 changes: 1 addition & 1 deletion deployment/chainloop/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: Chainloop is an open source software supply chain control plane, a

type: application
# Bump the patch (not minor, not major) version on each change in the Chart Source code
version: 1.157.0
version: 1.157.1
# Do not update appVersion, this is handled automatically by the release process
appVersion: v0.139.0

Expand Down
1 change: 1 addition & 0 deletions deployment/chainloop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,7 @@ chainloop config save \
| Name | Description | Value |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
| `cas.replicaCount` | Number of replicas | `2` |
| `cas.defaultMaxEntrySize` | Maximum size for each entry in the CAS backend, default 100MB | |
| `cas.image.registry` | Image registry | `REGISTRY_NAME` |
| `cas.image.repository` | Image repository | `REPOSITORY_NAME` |
| `cas.containerPorts.http` | controlplane HTTP container port | `8000` |
Expand Down
3 changes: 3 additions & 0 deletions deployment/chainloop/templates/controlplane/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ data:
addr: {{ printf "%s-api:%.0f" (include "chainloop.cas.fullname" .) (coalesce .Values.cas.serviceAPI.port .Values.cas.serviceAPI.ports.http) }}
insecure: {{ empty (include "controlplane.tls-secret-name" .) }}
download_url: {{ include "chainloop.cas.external_url" . }}/download
{{- if .Values.cas.defaultMaxEntrySize }}
default_entry_max_size: {{ .Values.cas.defaultMaxEntrySize | quote }}
{{- end }}
plugins_dir: {{ .Values.controlplane.pluginsDir }}
referrer_shared_index:
{{- toYaml .Values.controlplane.referrerSharedIndex | nindent 6 }}
Expand Down
3 changes: 3 additions & 0 deletions deployment/chainloop/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,9 @@ cas:
## @param cas.replicaCount Number of replicas
replicaCount: 2

## @extra cas.defaultMaxEntrySize Maximum size for each entry in the CAS backend, default 100MB
# defaultMaxEntrySize: 100MB

## @param cas.image.registry [default: REGISTRY_NAME] Image registry
## @param cas.image.repository [default: REPOSITORY_NAME] Image repository
## @skip cas.image.tag
Expand Down

0 comments on commit 82d8a6a

Please sign in to comment.