Skip to content

Commit 8e8b9ea

Browse files
committed
Switch to running without Supervisord as PID 1 in containers
To do this, the idea is to start the container component: 1- using the command/args defined in the Devfile 2- using whatever was defined in the container image if there is no command/args defined in the Devfile Then, once the container is started, we would execute the Devfile commands directly in the container component, just like a simple 'kubectl exec' command would do. Since this is a long-running command (and potentially never ending), we would need to run it in the background, i.e. in a side goroutine. Point 2) above requires implementing a temporary hack (as discussed in [1]), without us having to wait for [2] to be merged on the Devfile side. This temporary hack overrides the container entrypoint with "tail -f /dev/null" if the component defines no command or args (in which case we should have used whatever is defined in the image, per the specification). [1] redhat-developer#5768 (comment) [2] devfile/registry#102
1 parent 0ace5c6 commit 8e8b9ea

File tree

21 files changed

+552
-1333
lines changed

21 files changed

+552
-1333
lines changed

docs/website/versioned_docs/version-3.0.0/command-reference/dev.md

+3
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,9 @@ components:
208208
mountSources: true
209209
```
210210
211+
Note that `odo` will set the container entrypoint to `tail -f /dev/null` if no `command` or `args` fields are explicitly defined for this component in the Devfile.
212+
This is a temporary workaround that allows `odo` to start non-terminating containers in which the Devfile commands will get executed.
213+
211214
### Full Example
212215
213216
```yaml

pkg/devfile/adapters/common/executor.go

-17
This file was deleted.

pkg/devfile/adapters/common/generic.go

-168
This file was deleted.
-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
package common
22

3-
import (
4-
devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
5-
)
6-
73
// ComponentAdapter defines the functions that platform-specific adapters must implement
84
type ComponentAdapter interface {
95
Push(parameters PushParameters) error
10-
CheckSupervisordCommandStatus(command devfilev1.Command) error
116
}

pkg/devfile/adapters/common/utils.go

-139
Original file line numberDiff line numberDiff line change
@@ -1,162 +1,23 @@
11
package common
22

33
import (
4-
"os"
54
"path/filepath"
65
"strings"
76

8-
"k8s.io/klog"
9-
107
devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
11-
parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common"
128
)
139

14-
// PredefinedDevfileCommands encapsulates constants for predefined devfile commands
15-
type PredefinedDevfileCommands string
16-
1710
const (
18-
19-
// DefaultDevfileRunCommand is a predefined devfile command for run
20-
DefaultDevfileRunCommand PredefinedDevfileCommands = "devrun"
21-
22-
// DefaultDevfileDebugCommand is a predefined devfile command for debug
23-
DefaultDevfileDebugCommand PredefinedDevfileCommands = "debugrun"
24-
25-
// SupervisordInitContainerName The init container name for supervisord
26-
SupervisordInitContainerName = "copy-supervisord"
27-
28-
// Default Image that will be used containing the supervisord binary and assembly scripts
29-
// use GetBootstrapperImage() function instead of this variable
30-
defaultBootstrapperImage = "registry.access.redhat.com/ocp-tools-4/odo-init-container-rhel8:1.1.11"
31-
32-
// SupervisordVolumeName Create a custom name and (hope) that users don't use the *exact* same name in their deployment (occlient.go)
33-
SupervisordVolumeName = "odo-supervisord-shared-data"
34-
35-
// SupervisordMountPath The supervisord Mount Path for the container mounting the supervisord volume
36-
SupervisordMountPath = "/opt/odo/"
37-
38-
// SupervisordBinaryPath The supervisord binary path inside the container volume mount
39-
SupervisordBinaryPath = "/opt/odo/bin/supervisord"
40-
41-
// SupervisordConfFile The supervisord configuration file inside the container volume mount
42-
SupervisordConfFile = "/opt/odo/conf/devfile-supervisor.conf"
43-
44-
// OdoInitImageContents The path to the odo init image contents
45-
OdoInitImageContents = "/opt/odo-init/."
46-
47-
// ENV variable to overwrite image used to bootstrap SupervisorD in S2I and Devfile builder Image
48-
bootstrapperImageEnvName = "ODO_BOOTSTRAPPER_IMAGE"
49-
5011
// EnvProjectsRoot is the env defined for project mount in a component container when component's mountSources=true
5112
EnvProjectsRoot = "PROJECTS_ROOT"
5213

53-
// EnvOdoCommandRunWorkingDir is the env defined in the runtime component container which holds the work dir for the run command
54-
EnvOdoCommandRunWorkingDir = "ODO_COMMAND_RUN_WORKING_DIR"
55-
56-
// EnvOdoCommandRun is the env defined in the runtime component container which holds the run command to be executed
57-
EnvOdoCommandRun = "ODO_COMMAND_RUN"
58-
59-
// EnvOdoCommandDebugWorkingDir is the env defined in the runtime component container which holds the work dir for the debug command
60-
EnvOdoCommandDebugWorkingDir = "ODO_COMMAND_DEBUG_WORKING_DIR"
61-
62-
// EnvOdoCommandDebug is the env defined in the runtime component container which holds the debug command to be executed
63-
EnvOdoCommandDebug = "ODO_COMMAND_DEBUG"
64-
6514
// EnvDebugPort is the env defined in the runtime component container which holds the debug port for remote debugging
6615
EnvDebugPort = "DEBUG_PORT"
6716

6817
// ShellExecutable is the shell executable
6918
ShellExecutable = "/bin/sh"
70-
71-
// SupervisordCtlSubCommand is the supervisord sub command ctl
72-
SupervisordCtlSubCommand = "ctl"
7319
)
7420

75-
// GetBootstrapperImage returns the odo-init bootstrapper image
76-
func GetBootstrapperImage() string {
77-
if env, ok := os.LookupEnv(bootstrapperImageEnvName); ok {
78-
return env
79-
}
80-
return defaultBootstrapperImage
81-
}
82-
83-
// getCommandsByGroup gets commands by the group kind
84-
func getCommandsByGroup(commands []devfilev1.Command, groupType devfilev1.CommandGroupKind) []devfilev1.Command {
85-
var filteredCommands []devfilev1.Command
86-
for _, command := range commands {
87-
commandGroup := parsercommon.GetGroup(command)
88-
if commandGroup != nil && commandGroup.Kind == groupType {
89-
filteredCommands = append(filteredCommands, command)
90-
}
91-
}
92-
93-
return filteredCommands
94-
}
95-
96-
// IsRestartRequired checks if restart required for run command
97-
func IsRestartRequired(hotReload bool, runModeChanged bool) bool {
98-
if runModeChanged || !hotReload {
99-
return true
100-
}
101-
102-
return false
103-
}
104-
105-
// IsEnvPresent checks if the env variable is present in an array of env variables
106-
func IsEnvPresent(envVars []devfilev1.EnvVar, envVarName string) bool {
107-
for _, envVar := range envVars {
108-
if envVar.Name == envVarName {
109-
return true
110-
}
111-
}
112-
113-
return false
114-
}
115-
116-
// IsPortPresent checks if the port is present in the endpoints array
117-
func IsPortPresent(endpoints []devfilev1.Endpoint, port int) bool {
118-
for _, endpoint := range endpoints {
119-
if endpoint.TargetPort == port {
120-
return true
121-
}
122-
}
123-
124-
return false
125-
}
126-
127-
// GetComponentEnvVar returns true if a list of env vars contains the specified env var
128-
// If the env exists, it returns the value of it
129-
func GetComponentEnvVar(env string, envs []devfilev1.EnvVar) string {
130-
for _, envVar := range envs {
131-
if envVar.Name == env {
132-
return envVar.Value
133-
}
134-
}
135-
return ""
136-
}
137-
138-
// GetCommandsFromEvent returns the list of commands from the event name.
139-
// If the event is a composite command, it returns the sub-commands from the tree
140-
func GetCommandsFromEvent(commandsMap map[string]devfilev1.Command, eventName string) []string {
141-
var commands []string
142-
143-
if command, ok := commandsMap[eventName]; ok {
144-
if command.Composite != nil {
145-
klog.V(4).Infof("%s is a composite command", command.Id)
146-
for _, compositeSubCmd := range command.Composite.Commands {
147-
klog.V(4).Infof("checking if sub-command %s is either an exec or a composite command ", compositeSubCmd)
148-
subCommands := GetCommandsFromEvent(commandsMap, strings.ToLower(compositeSubCmd))
149-
commands = append(commands, subCommands...)
150-
}
151-
} else {
152-
klog.V(4).Infof("%s is an exec command", command.Id)
153-
commands = append(commands, command.Id)
154-
}
155-
}
156-
157-
return commands
158-
}
159-
16021
// GetCommandsMap returns a map of the command Id to the command
16122
func GetCommandsMap(commands []devfilev1.Command) map[string]devfilev1.Command {
16223
commandMap := make(map[string]devfilev1.Command, len(commands))

0 commit comments

Comments
 (0)