Skip to content

Commit

Permalink
Merge branch 'main' into mojtaba/feat-custom-registry
Browse files Browse the repository at this point in the history
  • Loading branch information
mojtaba-esk committed Dec 6, 2024
2 parents 1ccc809 + 21d8b67 commit 62cf6f7
Show file tree
Hide file tree
Showing 10 changed files with 232 additions and 126 deletions.
36 changes: 30 additions & 6 deletions pkg/instance/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package instance
import (
"context"
"fmt"
"os"
"path/filepath"
"sync"

Expand All @@ -14,8 +15,6 @@ import (
"github.com/celestiaorg/knuu/pkg/container"
)

const buildDirBase = "/tmp/knuu"

type build struct {
instance *Instance
imageName string
Expand All @@ -25,6 +24,7 @@ type build struct {
args []string
env map[string]string
imageCache *sync.Map
buildDir string
}

func (i *Instance) Build() *build {
Expand Down Expand Up @@ -53,10 +53,15 @@ func (b *build) SetImage(ctx context.Context, image string, args ...builder.ArgI
return ErrSettingImageNotAllowed.WithParams(b.instance.state.String())
}

buildDir, err := b.getBuildDir()
if err != nil {
return ErrGettingBuildDir.Wrap(err)
}

// Use the builder to build a new image
factory, err := container.NewBuilderFactory(container.BuilderFactoryOptions{
ImageName: image,
BuildContext: b.getBuildDir(),
BuildContext: buildDir,
ImageBuilder: b.instance.ImageBuilder,
Args: args,
Logger: b.instance.Logger,
Expand Down Expand Up @@ -88,9 +93,20 @@ func (b *build) SetGitRepo(ctx context.Context, gitContext builder.GitContext, a
}
b.imageName = resolvedImage.ToString()

buildDir, err := b.getBuildDir()
if err != nil {
return ErrGettingBuildDir.Wrap(err)
}
b.imageName = resolvedImage.ToString()

buildDir, err := b.getBuildDir()
if err != nil {
return ErrGettingBuildDir.Wrap(err)
}

factory, err := container.NewBuilderFactory(container.BuilderFactoryOptions{
ImageName: b.imageName,
BuildContext: b.getBuildDir(),
BuildContext: buildDir,
ImageBuilder: b.instance.ImageBuilder,
Args: args,
Logger: b.instance.Logger,
Expand Down Expand Up @@ -226,8 +242,16 @@ func getImageRegistry(imageName string) (string, error) {
}

// getBuildDir returns the build directory for the instance
func (b *build) getBuildDir() string {
return filepath.Join(buildDirBase, b.instance.name)
func (b *build) getBuildDir() (string, error) {
if b.buildDir != "" {
return b.buildDir, nil
}

tmpDir, err := os.MkdirTemp("", "knuu-build-*")
if err != nil {
return "", err
}
return filepath.Join(tmpDir, b.instance.name), nil
}

// addFileToBuilder adds a file to the builder
Expand Down
7 changes: 7 additions & 0 deletions pkg/instance/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ var (
ErrSettingGitRepo = errors.New("SettingGitRepo", "setting git repo is only allowed in state 'None'. Current state is '%s'")
ErrGettingBuildContext = errors.New("GettingBuildContext", "error getting build context")
ErrGettingImageName = errors.New("GettingImageName", "error getting image name")
ErrGettingBuildDir = errors.New("GettingBuildDir", "error getting build directory")
ErrSettingImageNotAllowedForSidecars = errors.New("SettingImageNotAllowedForSidecars", "setting image is not allowed for sidecars")
ErrSettingCommand = errors.New("SettingCommand", "setting command is only allowed in state 'Preparing' or 'Committed'. Current state is '%s")
ErrSettingArgsNotAllowed = errors.New("SettingArgsNotAllowed", "setting args is only allowed in state 'Preparing' or 'Committed'. Current state is '%s")
Expand All @@ -102,7 +103,9 @@ var (
ErrCreatingDirectory = errors.New("CreatingDirectory", "error creating directory")
ErrFailedToCreateDestFile = errors.New("FailedToCreateDestFile", "failed to create destination file '%s'")
ErrFailedToOpenSrcFile = errors.New("FailedToOpenSrcFile", "failed to open source file '%s'")
ErrFailedToGetSrcFileInfo = errors.New("FailedToGetSrcFileInfo", "failed to get source file info for %s")
ErrFailedToCopyFile = errors.New("FailedToCopyFile", "failed to copy from source '%s' to destination '%s'")
ErrFailedToSetPermissions = errors.New("FailedToSetPermissions", "failed to set permissions for destination file")
ErrSrcDoesNotExistOrIsDirectory = errors.New("SrcDoesNotExistOrIsDirectory", "src '%s' does not exist or is a directory")
ErrInvalidFormat = errors.New("InvalidFormat", "invalid format")
ErrFailedToConvertToInt64 = errors.New("FailedToConvertToInt64", "failed to convert to int64")
Expand Down Expand Up @@ -215,6 +218,7 @@ var (
ErrApplyingFunctionToSidecar = errors.New("ApplyingFunctionToSidecar", "error applying function to sidecar '%s'")
ErrInitializingSidecar = errors.New("InitializingSidecar", "error initializing sidecar for instance '%s'")
ErrSidecarInstanceIsNil = errors.New("SidecarInstanceIsNil", "sidecar instance is nil for instance '%s'")
ErrFailedToCreatePersistentVolumeClaim = errors.New("FailedToCreatePersistentVolumeClaim", "failed to create persistent volume claim")
ErrFailedToDeletePersistentVolumeClaim = errors.New("FailedToDeletePersistentVolumeClaim", "failed to delete persistent volume claim")
ErrUpgradingImageNotAllowed = errors.New("UpgradingImageNotAllowed", "upgrading image is only allowed in state 'Started'. Current state is '%s'")
ErrAddingHostToProxyNotAllowed = errors.New("AddingHostToProxyNotAllowed", "adding host to proxy is only allowed in state 'Started' and 'Preparing'. Current state is '%s'")
Expand All @@ -224,4 +228,7 @@ var (
ErrCannotCloneInstance = errors.New("CannotCloneInstance", "cannot clone instance '%s' in state '%s'")
ErrGettingIPNotAllowed = errors.New("GettingIPNotAllowed", "getting IP is allowed in state 'Started'. Current state is '%s'")
ErrPodIPNotReady = errors.New("PodIPNotReady", "pod IP is not ready for pod '%s'")
ErrFailedToGetFileSize = errors.New("FailedToGetFileSize", "failed to get file size")
ErrFileTooLargeCommitted = errors.New("FileTooLargeCommitted", "file '%s' is too large (max 1MiB) to add after instance is committed")
ErrTotalFilesSizeTooLarge = errors.New("TotalFilesSizeTooLarge", "total files size is too large (max 1MiB)")
)
5 changes: 4 additions & 1 deletion pkg/instance/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,8 @@ func (e *execution) prepareReplicaSetConfig() k8s.ReplicaSetConfig {
StartupProbe: e.instance.monitoring.startupProbe,
Files: e.instance.storage.files,
SecurityContext: e.instance.security.prepareSecurityContext(),
TCPPorts: e.instance.network.portsTCP,
UDPPorts: e.instance.network.portsUDP,
}

sidecarConfigs := make([]k8s.ContainerConfig, 0)
Expand All @@ -404,6 +406,8 @@ func (e *execution) prepareReplicaSetConfig() k8s.ReplicaSetConfig {
StartupProbe: sidecar.Instance().monitoring.startupProbe,
Files: sidecar.Instance().storage.files,
SecurityContext: sidecar.Instance().security.prepareSecurityContext(),
TCPPorts: sidecar.Instance().network.portsTCP,
UDPPorts: sidecar.Instance().network.portsUDP,
})
}

Expand All @@ -412,7 +416,6 @@ func (e *execution) prepareReplicaSetConfig() k8s.ReplicaSetConfig {
Name: e.instance.name,
Labels: e.Labels(),
ServiceAccountName: e.instance.name,
FsGroup: e.instance.storage.fsGroup,
ContainerConfig: containerConfig,
SidecarConfigs: sidecarConfigs,
ImagePullSecrets: []v1.LocalObjectReference{{Name: "registry-cert-secret"}},
Expand Down
2 changes: 1 addition & 1 deletion pkg/instance/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (n *network) AddHost(ctx context.Context, port int) (host string, err error
serviceName = n.instance.parentInstance.name
}

prefix := fmt.Sprintf("%s-%d", serviceName, port)
prefix := fmt.Sprintf("%s-%s-%d", n.instance.Scope, serviceName, port)
if err := n.instance.Proxy.AddHost(ctx, serviceName, prefix, port); err != nil {
return "", ErrAddingToProxy.WithParams(serviceName).Wrap(err)
}
Expand Down
12 changes: 5 additions & 7 deletions pkg/instance/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,12 @@ func (r *resources) deployStorage(ctx context.Context) error {
return ErrDeployingVolumeForInstance.WithParams(r.instance.name).Wrap(err)
}
}
if len(r.instance.storage.files) == 0 {
return nil
if len(r.instance.storage.files) != 0 {
if err := r.instance.storage.deployFiles(ctx); err != nil {
return ErrDeployingFilesForInstance.WithParams(r.instance.name).Wrap(err)
}
}

if err := r.instance.storage.deployFiles(ctx); err != nil {
return ErrDeployingFilesForInstance.WithParams(r.instance.name).Wrap(err)
}
return nil
}

Expand Down Expand Up @@ -123,8 +122,7 @@ func (r *resources) destroyResources(ctx context.Context) error {
}

if len(r.instance.storage.files) != 0 {
err := r.instance.storage.destroyFiles(ctx)
if err != nil {
if err := r.instance.storage.destroyFiles(ctx); err != nil {
return ErrDestroyingFilesForInstance.WithParams(r.instance.name).Wrap(err)
}
}
Expand Down
113 changes: 84 additions & 29 deletions pkg/instance/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@ import (
"github.com/celestiaorg/knuu/pkg/names"
)

const maxTotalFilesBytes = 1024 * 1024

type storage struct {
instance *Instance
volumes []*k8s.Volume
files []*k8s.File
fsGroup int64
}

const defaultFilePermission = 0644

func (i *Instance) Storage() *storage {
return i.storage
}
Expand All @@ -41,7 +44,7 @@ func (s *storage) AddFile(src string, dest string, chown string) error {
return err
}

dstPath, err := s.copyFileToBuildDir(src, dest)
buildDirPath, err := s.copyFileToBuildDir(src, dest)
if err != nil {
return err
}
Expand All @@ -51,14 +54,25 @@ func (s *storage) AddFile(src string, dest string, chown string) error {
s.instance.build.addFileToBuilder(src, dest, chown)
return nil
case StateCommitted, StateStopped:
return s.addFileToInstance(dstPath, dest, chown)
srcInfo, err := os.Stat(src)
if err != nil {
return ErrFailedToGetFileSize.Wrap(err)
}
if srcInfo.Size() > maxTotalFilesBytes {
return ErrFileTooLargeCommitted.WithParams(src)
}
return s.addFileToInstance(buildDirPath, dest, chown)
}

buildDir, err := s.instance.build.getBuildDir()
if err != nil {
return ErrGettingBuildDir.Wrap(err)
}
s.instance.Logger.WithFields(logrus.Fields{
"file": dest,
"instance": s.instance.name,
"state": s.instance.state,
"build_dir": s.instance.build.getBuildDir(),
"build_dir": buildDir,
}).Debug("added file")
return nil
}
Expand Down Expand Up @@ -92,7 +106,11 @@ func (s *storage) AddFolder(src string, dest string, chown string) error {
if err != nil {
return err
}
dstPath := filepath.Join(s.instance.build.getBuildDir(), dest, relPath)
buildDir, err := s.instance.build.getBuildDir()
if err != nil {
return ErrGettingBuildDir.Wrap(err)
}
dstPath := filepath.Join(buildDir, dest, relPath)

if info.IsDir() {
// create directory at destination path
Expand All @@ -106,11 +124,15 @@ func (s *storage) AddFolder(src string, dest string, chown string) error {
return ErrCopyingFolderToInstance.WithParams(src, s.instance.name).Wrap(err)
}

buildDir, err := s.instance.build.getBuildDir()
if err != nil {
return ErrGettingBuildDir.Wrap(err)
}
s.instance.Logger.WithFields(logrus.Fields{
"folder": dest,
"instance": s.instance.name,
"state": s.instance.state,
"build_dir": s.instance.build.getBuildDir(),
"build_dir": buildDir,
}).Debug("added folder")
return nil
}
Expand All @@ -131,6 +153,9 @@ func (s *storage) AddFileBytes(bytes []byte, dest string, chown string) error {
if _, err := tmpfile.Write(bytes); err != nil {
return err
}
if err := tmpfile.Chmod(defaultFilePermission); err != nil {
return err
}
if err := tmpfile.Close(); err != nil {
return err
}
Expand Down Expand Up @@ -240,55 +265,83 @@ func (s *storage) validateFileArgs(src, dest, chown string) error {
if !strings.Contains(chown, ":") || len(strings.Split(chown, ":")) != 2 {
return ErrChownMustBeInFormatUserGroup
}

parts := strings.Split(chown, ":")
for _, part := range parts {
if _, err := strconv.ParseInt(part, 10, 64); err != nil {
return ErrFailedToConvertToInt64.WithParams(part).Wrap(err)
}
}
return nil
}

func (s *storage) copyFileToBuildDir(src, dest string) (string, error) {
dstPath := filepath.Join(s.instance.build.getBuildDir(), dest)
buildDir, err := s.instance.build.getBuildDir()
if err != nil {
return "", ErrGettingBuildDir.Wrap(err)
}
dstPath := filepath.Join(buildDir, dest)
if err := os.MkdirAll(filepath.Dir(dstPath), os.ModePerm); err != nil {
return "", ErrCreatingDirectory.Wrap(err)
}

dst, err := os.Create(dstPath)
if err != nil {
return "", ErrFailedToCreateDestFile.WithParams(dstPath).Wrap(err)
}
defer dst.Close()

srcFile, err := os.Open(src)
if err != nil {
return "", ErrFailedToOpenSrcFile.WithParams(src).Wrap(err)
}
defer srcFile.Close()

srcInfo, err := srcFile.Stat()
if err != nil {
return "", ErrFailedToGetSrcFileInfo.WithParams(src).Wrap(err)
}

dst, err := os.OpenFile(dstPath, os.O_CREATE|os.O_WRONLY, srcInfo.Mode().Perm())
if err != nil {
return "", ErrFailedToCreateDestFile.WithParams(dstPath).Wrap(err)
}
defer dst.Close()

if _, err := io.Copy(dst, srcFile); err != nil {
return "", ErrFailedToCopyFile.WithParams(src, dstPath).Wrap(err)
}

// Ensure the destination file has the same permissions as the source file
if err := os.Chmod(dstPath, srcInfo.Mode().Perm()); err != nil {
return "", ErrFailedToSetPermissions.WithParams(dstPath).Wrap(err)
}

return dstPath, nil
}

func (s *storage) addFileToInstance(dstPath, dest, chown string) error {
srcInfo, err := os.Stat(dstPath)
func (s *storage) addFileToInstance(srcPath, dest, chown string) error {
srcInfo, err := os.Stat(srcPath)
if os.IsNotExist(err) || srcInfo.IsDir() {
return ErrSrcDoesNotExistOrIsDirectory.WithParams(dstPath).Wrap(err)
return ErrSrcDoesNotExistOrIsDirectory.WithParams(srcPath).Wrap(err)
}

file := s.instance.K8sClient.NewFile(dstPath, dest)
parts := strings.Split(chown, ":")
if len(parts) != 2 {
return ErrInvalidFormat
}
// get the permission of the src file
permission := fmt.Sprintf("%o", srcInfo.Mode().Perm())

group, err := strconv.ParseInt(parts[1], 10, 64)
size := int64(0)
for _, file := range s.files {
srcInfo, err := os.Stat(file.Source)
if err != nil {
return ErrFailedToGetFileSize.Wrap(err)
}
size += srcInfo.Size()
}
srcInfo, err = os.Stat(srcPath)
if err != nil {
return ErrFailedToConvertToInt64.Wrap(err)
return ErrFailedToGetFileSize.Wrap(err)
}

if s.fsGroup != 0 && s.fsGroup != group {
return ErrAllFilesMustHaveSameGroup
size += srcInfo.Size()
if size > maxTotalFilesBytes {
return ErrTotalFilesSizeTooLarge.WithParams(srcPath)
}
s.fsGroup = group

file := s.instance.K8sClient.NewFile(srcPath, dest, chown, permission)

s.files = append(s.files, file)
return nil
}
Expand All @@ -307,7 +360,10 @@ func (s *storage) deployVolume(ctx context.Context) error {
for _, volume := range s.volumes {
totalSize.Add(volume.Size)
}
s.instance.K8sClient.CreatePersistentVolumeClaim(ctx, s.instance.name, s.instance.execution.Labels(), totalSize)
err := s.instance.K8sClient.CreatePersistentVolumeClaim(ctx, s.instance.name, s.instance.execution.Labels(), totalSize)
if err != nil {
return ErrFailedToCreatePersistentVolumeClaim.Wrap(err)
}
s.instance.Logger.WithFields(logrus.Fields{
"total_size": totalSize.String(),
"instance": s.instance.name,
Expand Down Expand Up @@ -439,6 +495,5 @@ func (s *storage) clone() *storage {
instance: nil,
volumes: volumesCopy,
files: filesCopy,
fsGroup: s.fsGroup,
}
}
Loading

0 comments on commit 62cf6f7

Please sign in to comment.