Skip to content

Commit

Permalink
feat: support setting running container as dev container
Browse files Browse the repository at this point in the history
  • Loading branch information
amitds1997 committed Dec 22, 2023
1 parent 96e5d00 commit 5e67472
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 11 deletions.
12 changes: 8 additions & 4 deletions cmd/agent/workspace/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,15 @@ func removeContainer(ctx context.Context, workspaceInfo *provider2.AgentWorkspac
return err
}

err = runner.Delete(ctx)
if err != nil {
return err
if workspaceInfo.Workspace.Source.Container != "" {
log.Infof("Skipping container deletion, since it was not created by DevPod")
} else {
err = runner.Delete(ctx)
if err != nil {
return err
}
log.Debugf("Successfully removed DevPod container from server")
}
log.Debugf("Successfully removed DevPod container from server")

return nil
}
Expand Down
5 changes: 4 additions & 1 deletion cmd/agent/workspace/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,12 @@ func prepareWorkspace(ctx context.Context, workspaceInfo *provider2.AgentWorkspa
} else if workspaceInfo.Workspace.Source.Image != "" {
log.Debugf("Prepare Image")
return PrepareImage(workspaceInfo.ContentFolder, workspaceInfo.Workspace.Source.Image)
} else if workspaceInfo.Workspace.Source.Container != "" {
log.Debugf("Workspace is a container, nothing to do")
return nil
}

return fmt.Errorf("either workspace repository, image or local-folder is required")
return fmt.Errorf("either workspace repository, image, container or local-folder is required")
}

func InitContentFolder(workspaceInfo *provider2.AgentWorkspaceInfo, log log.Logger) (bool, error) {
Expand Down
6 changes: 6 additions & 0 deletions pkg/devcontainer/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type MergedDevContainerConfig struct {
ImageContainer `json:",inline"`
ComposeContainer `json:",inline"`
DockerfileContainer `json:",inline"`
RunningContainer `json:",inline"`

// Origin is the origin from where this config was loaded
Origin string `json:"-"`
Expand All @@ -29,6 +30,7 @@ type DevContainerConfig struct {
ImageContainer `json:",inline"`
ComposeContainer `json:",inline"`
DockerfileContainer `json:",inline"`
RunningContainer `json:",inline"`

// Origin is the origin from where this config was loaded
Origin string `json:"-"`
Expand Down Expand Up @@ -217,6 +219,10 @@ type DockerfileContainer struct {
Build *ConfigBuildOptions `json:"build,omitempty"`
}

type RunningContainer struct {
ContainerID string `json:"containerID,omitempty"`
}

func (d DockerfileContainer) GetDockerfile() string {
if d.Dockerfile != "" {
return d.Dockerfile
Expand Down
3 changes: 3 additions & 0 deletions pkg/devcontainer/config/container_details.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ type ContainerDetails struct {
type ContainerDetailsConfig struct {
Labels map[string]string `json:"Labels,omitempty"`

// WorkingDir specifies default working directory inside the container
WorkingDir string `json:"WorkingDir,omitempty"`

// LegacyUser shouldn't get used anymore and is only there for backwards compatibility, please
// use the label config.UserLabel instead
LegacyUser string `json:"User,omitempty"`
Expand Down
14 changes: 13 additions & 1 deletion pkg/devcontainer/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func (r *runner) Up(ctx context.Context, options UpOptions) (*config.Result, err

// check if its a compose devcontainer.json
var result *config.Result
if isDockerFileConfig(substitutedConfig.Config) || substitutedConfig.Config.Image != "" {
if isDockerFileConfig(substitutedConfig.Config) || substitutedConfig.Config.Image != "" || substitutedConfig.Config.ContainerID != "" {
result, err = r.runSingleContainer(
ctx,
substitutedConfig,
Expand Down Expand Up @@ -165,6 +165,18 @@ func (r *runner) prepare(
} else {
rawParsedConfig.Origin = path.Join(filepath.ToSlash(r.LocalWorkspaceFolder), ".devcontainer.devpod.json")
}
} else if r.WorkspaceConfig.Workspace.Source.Container != "" {
rawParsedConfig = &config.DevContainerConfig{
DevContainerConfigBase: config.DevContainerConfigBase{
// Default workspace directory for containers
// Upon inspecting the container, this would be updated to the correct folder, if found set
WorkspaceFolder: "/",
},
RunningContainer: config.RunningContainer{
ContainerID: r.WorkspaceConfig.Workspace.Source.Container,
},
Origin: "",
}
} else {
var err error

Expand Down
9 changes: 8 additions & 1 deletion pkg/devcontainer/single.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ func (r *runner) runSingleContainer(ctx context.Context, parsedConfig *config.Su
var (
mergedConfig *config.MergedDevContainerConfig
)
if !options.Recreate && containerDetails != nil {
// if options.Recreate is true, and workspace is a running container, we should not rebuild
if options.Recreate && parsedConfig.Config.ContainerID != "" {
return nil, fmt.Errorf("cannot recreate a running container not created by DevPod")
} else if !options.Recreate && containerDetails != nil {
// start container if not running
if strings.ToLower(containerDetails.State.Status) != "running" {
err = r.Driver.StartDevContainer(ctx, r.ID)
Expand All @@ -34,6 +37,10 @@ func (r *runner) runSingleContainer(ctx context.Context, parsedConfig *config.Su
}
}

if parsedConfig.Config.ContainerID != "" && containerDetails.Config.WorkingDir != "" {
substitutionContext.ContainerWorkspaceFolder = containerDetails.Config.WorkingDir
}

imageMetadataConfig, err := metadata.GetImageMetadataFromContainer(containerDetails, substitutionContext, r.Log)
if err != nil {
return nil, err
Expand Down
1 change: 1 addition & 0 deletions pkg/docker/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

type DockerHelper struct {
DockerCommand string
ContainerID string
// allow command to have a custom environment
Environment []string
}
Expand Down
9 changes: 8 additions & 1 deletion pkg/driver/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func NewDockerDriver(workspaceInfo *provider2.AgentWorkspaceInfo, log log.Logger
Docker: &docker.DockerHelper{
DockerCommand: dockerCommand,
Environment: makeEnvironment(workspaceInfo.Agent.Docker.Env, log),
ContainerID: workspaceInfo.Workspace.Source.Container,
},
Log: log,
}
Expand Down Expand Up @@ -151,7 +152,13 @@ func (d *dockerDriver) ComposeHelper() (*compose.ComposeHelper, error) {
}

func (d *dockerDriver) FindDevContainer(ctx context.Context, workspaceId string) (*config.ContainerDetails, error) {
containerDetails, err := d.Docker.FindDevContainer(ctx, []string{config.DockerIDLabel + "=" + workspaceId})
var containerDetails *config.ContainerDetails
var err error
if d.Docker.ContainerID != "" {
containerDetails, err = d.Docker.FindContainerByID(ctx, []string{d.Docker.ContainerID})
} else {
containerDetails, err = d.Docker.FindDevContainer(ctx, []string{config.DockerIDLabel + "=" + workspaceId})
}
if err != nil {
return nil, err
} else if containerDetails == nil {
Expand Down
16 changes: 13 additions & 3 deletions pkg/provider/workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import (
)

var (
WorkspaceSourceGit = "git:"
WorkspaceSourceLocal = "local:"
WorkspaceSourceImage = "image:"
WorkspaceSourceGit = "git:"
WorkspaceSourceLocal = "local:"
WorkspaceSourceImage = "image:"
WorkspaceSourceContainer = "container:"
)

type Workspace struct {
Expand Down Expand Up @@ -108,6 +109,9 @@ type WorkspaceSource struct {

// Image is the docker image to use
Image string `json:"image,omitempty"`

// Container is the container to use
Container string `json:"container,omitempty"`
}

type ContainerWorkspaceInfo struct {
Expand Down Expand Up @@ -203,6 +207,8 @@ func (w WorkspaceSource) String() string {
return WorkspaceSourceLocal + w.LocalFolder
} else if w.Image != "" {
return WorkspaceSourceImage + w.Image
} else if w.Container != "" {
return WorkspaceSourceContainer + w.Container
}

return ""
Expand All @@ -225,6 +231,10 @@ func ParseWorkspaceSource(source string) *WorkspaceSource {
return &WorkspaceSource{
Image: strings.TrimPrefix(source, WorkspaceSourceImage),
}
} else if strings.HasPrefix(source, WorkspaceSourceContainer) {
return &WorkspaceSource{
Container: strings.TrimPrefix(source, WorkspaceSourceContainer),
}
}

return nil
Expand Down
8 changes: 8 additions & 0 deletions pkg/workspace/workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,14 @@ func ResolveWorkspace(
}
}

// configure dev container source
if workspace.Source.Container != "" {
err = provider2.SaveWorkspaceConfig(workspace)
if err != nil {
return nil, errors.Wrap(err, "save workspace")
}
}

// create workspace client
var workspaceClient client.BaseWorkspaceClient
if provider.IsProxyProvider() {
Expand Down

0 comments on commit 5e67472

Please sign in to comment.