Skip to content

Commit

Permalink
Another version for file mounts
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaszo committed Dec 6, 2024
1 parent de12226 commit 7a523f6
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 68 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/gofrs/uuid v4.3.0+incompatible
github.com/gorilla/websocket v1.5.0
github.com/iancoleman/strcase v0.2.0
github.com/koyeb/koyeb-api-client-go v0.0.0-20241129081540-9cecbc45397f
github.com/koyeb/koyeb-api-client-go v0.0.0-20241206143543-39fbd0d0bf5e
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/manifoldco/promptui v0.9.0
github.com/mitchellh/go-homedir v1.1.0
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,12 @@ github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLf
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/koyeb/koyeb-api-client-go v0.0.0-20241127113640-742236b17b87 h1:VkwuM05Wszx/dwLrJm48AkTg13Pmq7TFzwUpiFBOgxo=
github.com/koyeb/koyeb-api-client-go v0.0.0-20241127113640-742236b17b87/go.mod h1:+oQfFj2WL3gi9Pb+UHbob4D7xaT52mPfKyH1UvWa4PQ=
github.com/koyeb/koyeb-api-client-go v0.0.0-20241129081540-9cecbc45397f h1:jzyPhhyZgLKA3FXMNxyEZiETROBEde4uI4qwHsliBrk=
github.com/koyeb/koyeb-api-client-go v0.0.0-20241129081540-9cecbc45397f/go.mod h1:+oQfFj2WL3gi9Pb+UHbob4D7xaT52mPfKyH1UvWa4PQ=
github.com/koyeb/koyeb-api-client-go v0.0.0-20241206143120-7817d20778fd h1:krjNLKRYbBEExAIEI1maqyo9P3oF1cKevQXiVedTX18=
github.com/koyeb/koyeb-api-client-go v0.0.0-20241206143120-7817d20778fd/go.mod h1:+oQfFj2WL3gi9Pb+UHbob4D7xaT52mPfKyH1UvWa4PQ=
github.com/koyeb/koyeb-api-client-go v0.0.0-20241206143543-39fbd0d0bf5e h1:/pSEDHiuCglPMooi0kcQay0ZmJ1fZys8qre6Jz2iQ7Q=
github.com/koyeb/koyeb-api-client-go v0.0.0-20241206143543-39fbd0d0bf5e/go.mod h1:+oQfFj2WL3gi9Pb+UHbob4D7xaT52mPfKyH1UvWa4PQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
Expand Down
102 changes: 44 additions & 58 deletions pkg/koyeb/flags_list/file_mounts.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package flags_list

import (
"encoding/base64"
"errors"
"fmt"
"os"
Expand All @@ -13,17 +12,14 @@ import (

type FlagFileMount struct {
BaseFlag
raw *string
secret *string
path string
permissions string
content string
}

// Parse the list of values in the form path:secret:name or path:file:<path>
// The function is wrapped in another function to allow the caller to provide a function to resolve the volume ID from its name.
func GetNewFileMountListFromFlags() func(values []string) ([]Flag[koyeb.DeploymentFileMount], error) {
return func(values []string) ([]Flag[koyeb.DeploymentFileMount], error) {
ret := make([]Flag[koyeb.DeploymentFileMount], 0, len(values))
func GetNewFileMountListFromFlags() func(values []string) ([]Flag[koyeb.FileMount], error) {
return func(values []string) ([]Flag[koyeb.FileMount], error) {
ret := make([]Flag[koyeb.FileMount], 0, len(values))

for _, value := range values {
hc := &FlagFileMount{BaseFlag: BaseFlag{cliValue: value}}
Expand All @@ -35,7 +31,7 @@ func GetNewFileMountListFromFlags() func(values []string) ([]Flag[koyeb.Deployme
What: "Error while configuring the service",
Why: fmt.Sprintf("unable to parse the file mount\"%s\"", hc.cliValue),
Additional: []string{
"To remove a file mount from the service, prefix the path with '!', e.g. '!path'",
"To remove a mounted file from the service, prefix the path with '!', e.g. '!path'",
"The source should not be specified to remove it from the service",
},
Orig: nil,
Expand All @@ -45,93 +41,83 @@ func GetNewFileMountListFromFlags() func(values []string) ([]Flag[koyeb.Deployme
hc.markedForDeletion = true
hc.path = components[0][1:]
} else {
if len(components) != 4 {
if len(components) != 2 && len(components) != 3 {
return nil, &kerrors.CLIError{
What: "Error while configuring the service",
Why: fmt.Sprintf("unable to parse the file mount\"%s\"", hc.cliValue),
Additional: []string{
"File mounts must be specified as PATH:SOURCE:DATA:PERMISSIONS",
"To remove a file mount from the service, prefix it with '!', e.g. '!path'",
"File mount must be specified as SOURCE:PATH[:PERMISSIONS]",
"To remove a mounted file from the service, prefix the path with '!', e.g. '!path'",
},
Orig: nil,
Solution: "Fix the file mount and try again",
}
}
hc.path = components[0]
source := components[1]
source = strings.ToLower(source)
switch source {
case "secret":
hc.secret = &components[2]
case "file":
path := components[2]
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
return nil, &kerrors.CLIError{
What: "Error while configuring the service",
Why: fmt.Sprintf("unable to parse the file mount\"%s\"", hc.cliValue),
Additional: []string{
"File mounts must be specified as PATH:SOURCE:DATA:PERMISSIONS",
"To remove a file mount from the service, prefix it with '!', e.g. '!path'",
},
Orig: nil,
Solution: "Fix the file mount and try again",
}
hc.path = components[1]
path := components[0]
if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) {
return nil, &kerrors.CLIError{
What: "Error while configuring the service",
Why: fmt.Sprintf("unable to parse the file mount \"%s\"", hc.cliValue),
Additional: []string{
"File mount must be specified as SOURCE:PATH[:PERMISSIONS]",
"To remove a file mount from the service, prefix it with '!', e.g. '!path'",
},
Orig: nil,
Solution: "Fix the file mount and try again",
}
data, err := os.ReadFile(components[2])
if err != nil {
return nil, &kerrors.CLIError{
What: "Error while configuring the service",
Why: fmt.Sprintf("unable to parse the file mount\"%s\"", hc.cliValue),
Additional: []string{
"File mounts must be specified as PATH:SOURCE:DATA:PERMISSIONS",
"To remove a file mount from the service, prefix it with '!', e.g. '!path'",
},
Orig: nil,
Solution: "Fix the file mount and try again",
}
}
data, err := os.ReadFile(path)
if err != nil {
return nil, &kerrors.CLIError{
What: "Error while configuring the service",
Why: fmt.Sprintf("unable to read the file mount\"%s\"", hc.cliValue),
Additional: []string{
"File mount must be specified as SOURCE:PATH[:PERMISSIONS]",
"To remove a file mount from the service, prefix it with '!', e.g. '!path'",
},
Orig: nil,
Solution: "Fix the file mount and try again",
}
encoded := base64.URLEncoding.EncodeToString([]byte(data))
hc.raw = &encoded
}
hc.content = string(data)

permissions := "0644"
if len(components) == 3 {
permissions = components[2]
}
permissions := components[3]
if len(permissions) != 4 {
return nil, &kerrors.CLIError{
What: "Error while configuring the service",
Why: fmt.Sprintf("unable to parse the file mount\"%s\"", hc.cliValue),
Additional: []string{
"File mounts must be specified as PATH:SOURCE:DATA:PERMISSIONS",
"File mount permission must be specified as SOURCE:PATH:PERMISSIONS",
"To remove a file mount from the service, prefix it with '!', e.g. '!path'",
},
Orig: nil,
Solution: "Fix the permissions in file mount and try again",
}
}
hc.permissions = permissions
ret = append(ret, hc)
}
ret = append(ret, hc)
}
return ret, nil
}
}

func (f *FlagFileMount) IsEqualTo(hc koyeb.DeploymentFileMount) bool {
func (f *FlagFileMount) IsEqualTo(hc koyeb.FileMount) bool {
return hc.GetPath() == f.path
}

func (f *FlagFileMount) UpdateItem(hc *koyeb.DeploymentFileMount) {
if f.secret != nil {
hc.Secret = &koyeb.SecretSource{Name: f.secret}
}
if f.raw != nil {
hc.Raw = &koyeb.RawSource{Content: f.raw}
}
func (f *FlagFileMount) UpdateItem(hc *koyeb.FileMount) {
hc.Content = &f.content
hc.Path = &f.path
hc.Permissions = &f.permissions
}

func (f *FlagFileMount) CreateNewItem() *koyeb.DeploymentFileMount {
item := koyeb.NewDeploymentFileMountWithDefaults()
func (f *FlagFileMount) CreateNewItem() *koyeb.FileMount {
item := koyeb.NewFileMountWithDefaults()
f.UpdateItem(item)
return item
}
13 changes: 6 additions & 7 deletions pkg/koyeb/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -378,10 +378,10 @@ func (h *ServiceHandler) addServiceDefinitionFlagsForAllSources(flags *pflag.Fla
"To delete a volume, use !VOLUME, for example --volume '!myvolume'\n",
)
flags.StringSlice(
"file-mounts",
"mount-config-file",
nil,
"Mount a secret or file in the service container using the format PATH:SECRET:NAME, PATH:FILE:<local_path>, for example --file-mount /data:secret:mysecret.\n"+
"To delete a file mount, use !PATH, for example\n",
"Mount a copy of local file as a file in the service container using the format LOCAL_FILE:PATH:[PERMISSIONS] for example --mount-file /etc/data.yaml:/etc/data.yaml:0644\n"+
"To delete a file mount, use !PATH, for example --mount-file !/etc/data.yaml\n",
)

// Configure aliases: for example, allow user to use --port instead of --ports
Expand Down Expand Up @@ -414,7 +414,6 @@ func (h *ServiceHandler) addServiceDefinitionFlagsForAllSources(flags *pflag.Fla
"git-docker-arg": "git-docker-args",
"docker-arg": "docker-args",
"archive-docker-arg": "archive-docker-args",
"file-mount": "file-mounts",
}
alias, exists := aliases[name]
if exists {
Expand Down Expand Up @@ -1755,9 +1754,9 @@ func (h *ServiceHandler) parseVolumes(ctx *CLIContext, flags *pflag.FlagSet, cur
return parseListFlags("volumes", flags_list.GetNewVolumeListFromFlags(wrappedResolveVolumeId), flags, currentVolumes)
}

// Parse --file-mounts
func (h *ServiceHandler) parseFileMounts(ctx *CLIContext, flags *pflag.FlagSet, currentFileMounts []koyeb.DeploymentFileMount) ([]koyeb.DeploymentFileMount, error) {
return parseListFlags("file-mounts", flags_list.GetNewFileMountListFromFlags(), flags, currentFileMounts)
// Parse --mount-config-file
func (h *ServiceHandler) parseFileMounts(ctx *CLIContext, flags *pflag.FlagSet, currentFileMounts []koyeb.FileMount) ([]koyeb.FileMount, error) {
return parseListFlags("mount-config-file", flags_list.GetNewFileMountListFromFlags(), flags, currentFileMounts)
}

// DeploymentStrategy is a type alias for koyeb.DeploymentStrategyType which implements the pflag.Value interface.
Expand Down

0 comments on commit 7a523f6

Please sign in to comment.