Skip to content

Commit 4ede90f

Browse files
feat(api): add spec.setup to Workspace for pre-agent init containers (#87)
* feat(api): add spec.setup to Workspace for pre-agent init containers * fix: review comments
1 parent 11b27b8 commit 4ede90f

6 files changed

Lines changed: 609 additions & 4 deletions

File tree

api/v1alpha1/workspace_types.go

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,39 @@ type WorkspaceFile struct {
2929
Content string `json:"content"`
3030
}
3131

32+
// SetupContainer defines an init container that runs after git clone but
33+
// before the agent container starts. Setup containers receive the workspace
34+
// volume mount (at /workspace) and any user-defined workspace volumes.
35+
type SetupContainer struct {
36+
// Name is the init container name (must be unique across setup containers).
37+
// +kubebuilder:validation:MinLength=1
38+
Name string `json:"name"`
39+
40+
// Image is the container image to run.
41+
// +kubebuilder:validation:MinLength=1
42+
Image string `json:"image"`
43+
44+
// Command is the entrypoint array (passed to the container as the command).
45+
// +kubebuilder:validation:MinItems=1
46+
Command []string `json:"command"`
47+
48+
// Env are additional environment variables for the container.
49+
// +optional
50+
Env []EnvVar `json:"env,omitempty"`
51+
}
52+
53+
// EnvVar represents an environment variable present in a container.
54+
type EnvVar struct {
55+
// Name of the environment variable.
56+
// +kubebuilder:validation:MinLength=1
57+
Name string `json:"name"`
58+
59+
// Value of the environment variable.
60+
Value string `json:"value"`
61+
}
62+
3263
// WorkspaceVolume defines an additional volume to mount into the agent
33-
// container (and setup containers, once supported).
64+
// container and setup containers.
3465
type WorkspaceVolume struct {
3566
// Name is the volume name (must be unique across workspace volumes).
3667
// +kubebuilder:validation:MinLength=1
@@ -107,6 +138,15 @@ type WorkspaceSpec struct {
107138
// +kubebuilder:validation:XValidation:rule="self.map(v, v.name).size() == self.size()",message="volume names must be unique"
108139
// +kubebuilder:validation:XValidation:rule="self.all(v, v.name != 'workspace' && v.name != 'kelos-plugin')",message="volume names 'workspace' and 'kelos-plugin' are reserved"
109140
Volumes []WorkspaceVolume `json:"volumes,omitempty"`
141+
142+
// Setup are init containers that run after git clone (and file injection)
143+
// but before the agent container starts. Each container receives the
144+
// workspace volume and any user-defined volumes. Use this for dependency
145+
// installation, code generation, or other pre-agent setup steps.
146+
// +optional
147+
// +kubebuilder:validation:XValidation:rule="self.map(sc, sc.name).size() == self.size()",message="setup container names must be unique"
148+
// +kubebuilder:validation:XValidation:rule="self.all(sc, !['git-clone','remote-setup','branch-setup','workspace-files','plugin-setup','skills-install'].exists(r, r == sc.name))",message="setup container names 'git-clone', 'remote-setup', 'branch-setup', 'workspace-files', 'plugin-setup', and 'skills-install' are reserved"
149+
Setup []SetupContainer `json:"setup,omitempty"`
110150
}
111151

112152
// +genclient

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 47 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/controller/job_builder.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,15 +515,47 @@ func (b *JobBuilder) buildAgentJob(task *kelosv1alpha1.Task, workspace *kelosv1a
515515
mainContainer.VolumeMounts = []corev1.VolumeMount{volumeMount}
516516

517517
// Append user-defined workspace volumes to the pod and agent container.
518+
var userVolumeMounts []corev1.VolumeMount
518519
for _, wv := range workspace.Volumes {
519520
volumes = append(volumes, corev1.Volume{
520521
Name: wv.Name,
521522
VolumeSource: wv.Source,
522523
})
523-
mainContainer.VolumeMounts = append(mainContainer.VolumeMounts, corev1.VolumeMount{
524+
vm := corev1.VolumeMount{
524525
Name: wv.Name,
525526
MountPath: wv.MountPath,
526527
ReadOnly: wv.ReadOnly,
528+
}
529+
userVolumeMounts = append(userVolumeMounts, vm)
530+
mainContainer.VolumeMounts = append(mainContainer.VolumeMounts, vm)
531+
}
532+
533+
// Append user-defined setup init containers. They run after git clone
534+
// and file injection but before the agent, and receive both the workspace
535+
// volume and any user-defined volumes.
536+
for _, sc := range workspace.Setup {
537+
mounts := make([]corev1.VolumeMount, 0, 1+len(userVolumeMounts))
538+
mounts = append(mounts, volumeMount)
539+
mounts = append(mounts, userVolumeMounts...)
540+
541+
var setupEnvVars []corev1.EnvVar
542+
for _, e := range sc.Env {
543+
setupEnvVars = append(setupEnvVars, corev1.EnvVar{
544+
Name: e.Name,
545+
Value: e.Value,
546+
})
547+
}
548+
549+
initContainers = append(initContainers, corev1.Container{
550+
Name: sc.Name,
551+
Image: sc.Image,
552+
Command: sc.Command,
553+
Env: setupEnvVars,
554+
VolumeMounts: mounts,
555+
WorkingDir: WorkspaceMountPath + "/repo",
556+
SecurityContext: &corev1.SecurityContext{
557+
RunAsUser: &agentUID,
558+
},
527559
})
528560
}
529561

0 commit comments

Comments
 (0)