Skip to content

Commit

Permalink
Added support for container build args and run options
Browse files Browse the repository at this point in the history
  • Loading branch information
akclace committed Aug 16, 2024
1 parent 72a24d6 commit 6037be9
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 30 deletions.
47 changes: 39 additions & 8 deletions cmd/clace/app_cmds.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ func appCreateCommand(commonFlags []cli.Flag, clientConfig *types.ClientConfig)
Aliases: []string{"p"},
Usage: "Set a parameter value. Format is paramName=paramValue",
})
flags = append(flags,
&cli.StringSliceFlag{
Name: "container-options",
Aliases: []string{"copt"},
Usage: "Set a container option. Format is opt[=optValue]",
})
flags = append(flags,
&cli.StringSliceFlag{
Name: "container-args",
Aliases: []string{"carg"},
Usage: "Set an argument for building the container image. Format is argKey=argValue",
})

flags = append(flags, dryRunFlag())

Expand Down Expand Up @@ -114,15 +126,34 @@ Examples:
paramValues[key] = value
}

containerOptions := cCtx.StringSlice("container-options")
coptMap := make(map[string]string)
for _, param := range containerOptions {
key, value, _ := strings.Cut(param, "=")
coptMap[key] = value // value can be empty string
}

containerArgs := cCtx.StringSlice("container-args")
cargMap := make(map[string]string)
for _, param := range containerArgs {
key, value, ok := strings.Cut(param, "=")
if !ok {
return fmt.Errorf("invalid container arg format: %s", param)
}
cargMap[key] = value
}

body := types.CreateAppRequest{
SourceUrl: cCtx.Args().Get(0),
IsDev: cCtx.Bool("dev"),
AppAuthn: types.AppAuthnType(cCtx.String("auth")),
GitBranch: cCtx.String("branch"),
GitCommit: cCtx.String("commit"),
GitAuthName: cCtx.String("git-auth"),
Spec: types.AppSpec(cCtx.String("spec")),
ParamValues: paramValues,
SourceUrl: cCtx.Args().Get(0),
IsDev: cCtx.Bool("dev"),
AppAuthn: types.AppAuthnType(cCtx.String("auth")),
GitBranch: cCtx.String("branch"),
GitCommit: cCtx.String("commit"),
GitAuthName: cCtx.String("git-auth"),
Spec: types.AppSpec(cCtx.String("spec")),
ParamValues: paramValues,
ContainerOptions: coptMap,
ContainerArgs: cargMap,
}
var createResult types.AppCreateResponse
err := client.Post("/_clace/app", values, body, &createResult)
Expand Down
26 changes: 23 additions & 3 deletions internal/app/container/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,18 @@ func (c ContainerCommand) RemoveImage(config *types.SystemConfig, name ImageName
return nil
}

func (c ContainerCommand) BuildImage(config *types.SystemConfig, name ImageName, sourceUrl, containerFile string) error {
func (c ContainerCommand) BuildImage(config *types.SystemConfig, name ImageName, sourceUrl, containerFile string, containerArgs map[string]string) error {
c.Debug().Msgf("Building image %s from %s with %s", name, containerFile, sourceUrl)
cmd := exec.Command(config.ContainerCommand, "build", "-t", string(name), "-f", containerFile, ".")
args := []string{config.ContainerCommand, "build", "-t", string(name), "-f", containerFile}

for k, v := range containerArgs {
args = append(args, "--build-arg", fmt.Sprintf("%s=%s", k, v))
}

args = append(args, ".")
cmd := exec.Command(args[0], args[1:]...)

c.Debug().Msgf("Running command: %s", cmd.String())
cmd.Dir = sourceUrl
output, err := cmd.CombinedOutput()
if err != nil {
Expand Down Expand Up @@ -228,7 +237,8 @@ func (c ContainerCommand) StartContainer(config *types.SystemConfig, name Contai
const LABEL_PREFIX = "io.clace."

func (c ContainerCommand) RunContainer(config *types.SystemConfig, appEntry *types.AppEntry, containerName ContainerName,
imageName ImageName, port int64, envMap map[string]string, mountArgs []string) error {
imageName ImageName, port int64, envMap map[string]string, mountArgs []string,
containerOptions map[string]string) error {
c.Debug().Msgf("Running container %s from image %s with port %d env %+v mountArgs %+v",
containerName, imageName, port, envMap, mountArgs)
publish := fmt.Sprintf("127.0.0.1::%d", port)
Expand All @@ -248,10 +258,20 @@ func (c ContainerCommand) RunContainer(config *types.SystemConfig, appEntry *typ
args = append(args, "--label", LABEL_PREFIX+"git.message="+appEntry.Metadata.VersionMetadata.GitMessage)
}

// Add env args
for k, v := range envMap {
args = append(args, "--env", fmt.Sprintf("%s=%s", k, v))
}

// Add container related args
for k, v := range containerOptions {
if v == "" {
args = append(args, fmt.Sprintf("--%s", k))
} else {
args = append(args, fmt.Sprintf("--%s=%s", k, v))
}
}

args = append(args, string(imageName))

c.Debug().Msgf("Running container with args: %v", args)
Expand Down
10 changes: 6 additions & 4 deletions internal/app/container/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ func (m *Manager) DevReload(dryRun bool) error {
return err
}
buildDir := path.Join(m.appEntry.SourceUrl, m.buildDir)
err = m.command.BuildImage(m.systemConfig, imageName, buildDir, m.containerFile)
err = m.command.BuildImage(m.systemConfig, imageName, buildDir, m.containerFile, m.appEntry.Metadata.ContainerArgs)
if err != nil {
return err
}
Expand All @@ -277,7 +277,8 @@ func (m *Manager) DevReload(dryRun bool) error {
}

envMap, _ := m.GetEnvMap()
err = m.command.RunContainer(m.systemConfig, m.appEntry, containerName, imageName, m.port, envMap, m.getMountArgs())
err = m.command.RunContainer(m.systemConfig, m.appEntry, containerName,
imageName, m.port, envMap, m.getMountArgs(), m.appEntry.Metadata.ContainerOptions)
if err != nil {
return fmt.Errorf("error building image: %w", err)
}
Expand Down Expand Up @@ -391,7 +392,7 @@ func (m *Manager) ProdReload(excludeGlob []string, dryRun bool) error {
return fmt.Errorf("error creating temp source dir: %w", err)
}
buildDir := path.Join(tempDir, m.buildDir)
buildErr := m.command.BuildImage(m.systemConfig, imageName, buildDir, m.containerFile)
buildErr := m.command.BuildImage(m.systemConfig, imageName, buildDir, m.containerFile, m.appEntry.Metadata.ContainerArgs)

// Cleanup temp dir after image has been built (even if build failed)
if err = os.RemoveAll(tempDir); err != nil {
Expand All @@ -410,7 +411,8 @@ func (m *Manager) ProdReload(excludeGlob []string, dryRun bool) error {
}

// Start the container with newly built image
err = m.command.RunContainer(m.systemConfig, m.appEntry, containerName, imageName, m.port, envMap, m.getMountArgs())
err = m.command.RunContainer(m.systemConfig, m.appEntry, containerName,
imageName, m.port, envMap, m.getMountArgs(), m.appEntry.Metadata.ContainerOptions)
if err != nil {
return fmt.Errorf("error building image: %w", err)
}
Expand Down
6 changes: 6 additions & 0 deletions internal/app/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,12 @@ func (a *App) addParams(builtin starlark.StringDict) (starlark.StringDict, error
}

newBuiltins[apptype.PARAM_MODULE] = &paramModule

for k, v := range a.Metadata.ParamValues {
if _, ok := paramDict[k]; !ok {
a.paramMap[k] = v // add additional param values to paramMap
}
}
return newBuiltins, nil
}

Expand Down
2 changes: 2 additions & 0 deletions internal/server/app_apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ func (s *Server) CreateApp(ctx context.Context, appPath string, approve, dryRun

appEntry.Metadata.Spec = appRequest.Spec // validated in createApp
appEntry.Metadata.ParamValues = appRequest.ParamValues
appEntry.Metadata.ContainerOptions = appRequest.ContainerOptions
appEntry.Metadata.ContainerArgs = appRequest.ContainerArgs

auditResult, err := s.createApp(ctx, &appEntry, approve, dryRun, appRequest.GitBranch, appRequest.GitCommit, appRequest.GitAuthName)
if err != nil {
Expand Down
18 changes: 10 additions & 8 deletions internal/types/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ func (r RequestError) Error() string {

// CreateAppRequest is the request body for creating an app
type CreateAppRequest struct {
SourceUrl string `json:"source_url"`
IsDev bool `json:"is_dev"`
AppAuthn AppAuthnType `json:"app_authn"`
GitBranch string `json:"git_branch"`
GitCommit string `json:"git_commit"`
GitAuthName string `json:"git_auth_name"`
Spec AppSpec `json:"spec"`
ParamValues map[string]string `json:"param_values"`
SourceUrl string `json:"source_url"`
IsDev bool `json:"is_dev"`
AppAuthn AppAuthnType `json:"app_authn"`
GitBranch string `json:"git_branch"`
GitCommit string `json:"git_commit"`
GitAuthName string `json:"git_auth_name"`
Spec AppSpec `json:"spec"`
ParamValues map[string]string `json:"param_values"`
ContainerOptions map[string]string `json:"container_options"`
ContainerArgs map[string]string `json:"container_args"`
}

// UpdateAppRequest is the request body for updating an app settings
Expand Down
16 changes: 9 additions & 7 deletions internal/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,13 +259,15 @@ func (ae *AppEntry) AppPathDomain() AppPathDomain {

// AppMetadata contains the configuration for an app. App configurations are version controlled.
type AppMetadata struct {
VersionMetadata VersionMetadata `json:"version_metadata"`
Loads []string `json:"loads"`
Permissions []Permission `json:"permissions"`
Accounts []AccountLink `json:"accounts"`
ParamValues map[string]string `json:"param_values"`
Spec AppSpec `json:"spec"`
SpecFiles *SpecFiles `json:"spec_files"`
VersionMetadata VersionMetadata `json:"version_metadata"`
Loads []string `json:"loads"`
Permissions []Permission `json:"permissions"`
Accounts []AccountLink `json:"accounts"`
ParamValues map[string]string `json:"param_values"`
Spec AppSpec `json:"spec"`
SpecFiles *SpecFiles `json:"spec_files"`
ContainerOptions map[string]string `json:"container_options"`
ContainerArgs map[string]string `json:"container_args"`
}

// AppSettings contains the settings for an app. Settings are not version controlled.
Expand Down

0 comments on commit 6037be9

Please sign in to comment.