Commit 56efef02 authored by Alessio Caiazza's avatar Alessio Caiazza

Merge branch '3755-gitlab-runner-helper-image-feature-flag' into 'master'

Deprecate helper image commands

See merge request gitlab-org/gitlab-runner!1218
parents 62745eed 09cc6ffb
Pipeline #50386955 passed with stages
in 48 minutes and 38 seconds
......@@ -62,6 +62,10 @@ const (
BuildStageUploadOnFailureArtifacts BuildStage = "upload_artifacts_on_failure"
)
const (
FFDockerHelperImageV2 string = "FF_DOCKER_HELPER_IMAGE_V2"
)
type Build struct {
JobResponse `yaml:",inline"`
......
......@@ -29,5 +29,6 @@ change hidden behind the feature flag disabled a corresponding environment varia
| Feature flag | Default value | Deprecated | To be removed with | Description |
|--------------------------------------|---------------|------------|--------------------|-------------|
| `FF_K8S_USE_ENTRYPOINT_OVER_COMMAND` | `true` | ✓ | 12.0 | Enables [the fix][mr-1010] for entrypoint configuration when `kubernetes` executor is used. |
| `FF_DOCKER_HELPER_IMAGE_V2` | `false` | ✓ | 12.0 | Enable the helper image to use the new commands when [helper_image](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnersdocker-section) is specified. This will start using the new API that will be used in 12.0 and stop showing the warning message in the build log. |
[mr-1010]: https://gitlab.com/gitlab-org/gitlab-runner/merge_requests/1010
......@@ -291,6 +291,10 @@ func (e *executor) getPrebuiltImage() (*types.ImageInspect, error) {
imageNameFromConfig = common.AppVersion.Variables().ExpandValue(imageNameFromConfig)
e.Debugln("Pull configured helper_image for predefined container instead of import bundled image", imageNameFromConfig, "...")
if !e.Build.IsFeatureFlagOn(common.FFDockerHelperImageV2) {
e.Warningln("DEPRECATION: With gitlab-runner 12.0 we will change some tools inside the helper image, please make sure your image is compliant with the new API. https://gitlab.com/gitlab-org/gitlab-runner/issues/4013")
}
return e.getDockerImage(imageNameFromConfig)
}
......@@ -380,17 +384,21 @@ func (e *executor) getLabels(containerType string, otherLabels ...string) map[st
// createCacheVolume returns the id of the created container, or an error
func (e *executor) createCacheVolume(containerName, containerPath string) (string, error) {
// get busybox image
cacheImage, err := e.getPrebuiltImage()
if err != nil {
return "", err
}
cmd := []string{"gitlab-runner-helper", "cache-init", containerPath}
// TODO: Remove in 12.0 to start using the command from `gitlab-runner-helper`
if e.checkOutdatedHelperImage() {
e.Debugln(common.FFDockerHelperImageV2, "is not set, falling back to old command")
cmd = []string{"gitlab-runner-cache", containerPath}
}
config := &container.Config{
Image: cacheImage.ID,
Cmd: []string{
"gitlab-runner-cache", containerPath,
},
Cmd: cmd,
Volumes: map[string]struct{}{
containerPath: {},
},
......@@ -1299,8 +1307,15 @@ func (e *executor) runServiceHealthCheckContainer(service *types.Container, time
containerName := service.Names[0] + "-wait-for-service"
cmd := []string{"gitlab-runner-helper", "health-check"}
// TODO: Remove in 12.0 to start using the command from `gitlab-runner-helper`
if e.checkOutdatedHelperImage() {
e.Debugln(common.FFDockerHelperImageV2, "is not set, falling back to old command")
cmd = []string{"gitlab-runner-service"}
}
config := &container.Config{
Cmd: []string{"gitlab-runner-service"},
Cmd: cmd,
Image: waitImage.ID,
Labels: e.getLabels("wait", "wait="+service.ID),
}
......@@ -1399,3 +1414,7 @@ func (e *executor) readContainerLogs(containerID string) string {
containerLog := containerBuffer.String()
return strings.TrimSpace(containerLog)
}
func (e *executor) checkOutdatedHelperImage() bool {
return !e.Build.IsFeatureFlagOn(common.FFDockerHelperImageV2) && e.Config.Docker.HelperImage != ""
}
......@@ -22,6 +22,7 @@ import (
"github.com/stretchr/testify/require"
"gitlab.com/gitlab-org/gitlab-runner/common"
"gitlab.com/gitlab-org/gitlab-runner/executors"
"gitlab.com/gitlab-org/gitlab-runner/helpers"
"gitlab.com/gitlab-org/gitlab-runner/helpers/docker"
)
......@@ -321,6 +322,11 @@ func TestHelperImageWithVariable(t *testing.T) {
Once()
e := executor{
AbstractExecutor: executors.AbstractExecutor{
Build: &common.Build{
JobResponse: common.JobResponse{},
},
},
client: c,
}
......@@ -1156,6 +1162,201 @@ func TestDockerSysctlsSetting(t *testing.T) {
testDockerConfigurationWithJobContainer(t, dockerConfig, cce)
}
// TODO: Remove in 12.0
func TestCreateCacheVolumeFeatureFlag(t *testing.T) {
cacheDir := "/cache"
cases := []struct {
name string
variables common.JobVariables
helperImage string
expectedCmd []string
}{
{
name: "Helper image is not specified",
variables: common.JobVariables{},
helperImage: "",
expectedCmd: []string{"gitlab-runner-helper", "cache-init", cacheDir},
},
{
name: "Helper image is not specified and FF still turned on",
variables: common.JobVariables{
common.JobVariable{Key: common.FFDockerHelperImageV2, Value: "true"},
},
helperImage: "",
expectedCmd: []string{"gitlab-runner-helper", "cache-init", cacheDir},
},
{
name: "Helper image is specified",
variables: common.JobVariables{},
helperImage: "gitlab/gitlab-runner-helper:x86_64-latest",
expectedCmd: []string{"gitlab-runner-cache", cacheDir},
},
{
name: "Helper image is specified & FF variable is set to true",
variables: common.JobVariables{
common.JobVariable{Key: common.FFDockerHelperImageV2, Value: "true"},
},
helperImage: "gitlab/gitlab-runner-helper:x86_64-latest",
expectedCmd: []string{"gitlab-runner-helper", "cache-init", cacheDir},
},
}
for _, testCase := range cases {
t.Run(testCase.name, func(t *testing.T) {
helperImageID := fmt.Sprintf("%s-helperImage-%d", t.Name(), time.Now().Unix())
cacheContainerID := fmt.Sprintf("%s-cacheContainer-%d", t.Name(), time.Now().Unix())
containerName := fmt.Sprintf("%s-cacheContainerName-%d", t.Name(), time.Now().Unix())
mClient := docker_helpers.MockClient{}
defer mClient.AssertExpectations(t)
mClient.On("ImageInspectWithRaw", mock.Anything, mock.Anything).
Return(types.ImageInspect{ID: helperImageID}, nil, nil)
mClient.On("ContainerStart", mock.Anything, cacheContainerID, mock.Anything).Return(nil).Once()
mClient.On("ContainerInspect", mock.Anything, cacheContainerID).Return(types.ContainerJSON{
ContainerJSONBase: &types.ContainerJSONBase{
State: &types.ContainerState{
ExitCode: 0,
},
},
}, nil).Once()
if testCase.helperImage != "" {
mClient.On("ImagePullBlocking", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
}
executor := setUpExecutorForFeatureFlag(testCase.variables, testCase.helperImage, &mClient)
expectedConfig := &container.Config{
Image: helperImageID,
Cmd: testCase.expectedCmd,
Volumes: map[string]struct{}{
cacheDir: {},
},
Labels: executor.getLabels("cache", "cache.dir="+cacheDir),
}
mClient.On("ContainerCreate", mock.Anything, expectedConfig, mock.Anything, mock.Anything, containerName).
Return(container.ContainerCreateCreatedBody{ID: cacheContainerID}, nil).
Once()
_, err := executor.createCacheVolume(containerName, cacheDir)
assert.NoError(t, err)
})
}
}
// TODO: Remove in 12.0
func TestRunServiceHealthCheckContainerFeatureFlag(t *testing.T) {
var cases = []struct {
name string
variables common.JobVariables
helperImage string
expectedCmd []string
}{
{
name: "Helper image is not specified",
variables: common.JobVariables{},
helperImage: "",
expectedCmd: []string{"gitlab-runner-helper", "health-check"},
},
{
name: "Helper image is not specified and FF still turned on",
variables: common.JobVariables{
common.JobVariable{Key: common.FFDockerHelperImageV2, Value: "true"},
},
helperImage: "",
expectedCmd: []string{"gitlab-runner-helper", "health-check"},
},
{
name: "Helper image is specified",
variables: common.JobVariables{},
helperImage: "gitlab/gitlab-runner-helper:x86_64-latest",
expectedCmd: []string{"gitlab-runner-service"},
},
{
name: "Helper image is specified & FF variable is set to true",
variables: common.JobVariables{
common.JobVariable{Key: common.FFDockerHelperImageV2, Value: "true"},
},
helperImage: "gitlab/gitlab-runner-helper:x86_64-latest",
expectedCmd: []string{"gitlab-runner-helper", "health-check"},
},
}
for _, testCase := range cases {
t.Run(testCase.name, func(t *testing.T) {
helperImageID := fmt.Sprintf("%s-helperImage-%d", t.Name(), time.Now().Unix())
containerID := fmt.Sprintf("%s-%d", t.Name(), time.Now().Unix())
serviceContainerID := fmt.Sprintf("%s-wait-for-service", containerID)
mClient := docker_helpers.MockClient{}
defer mClient.AssertExpectations(t)
mClient.On("ImageInspectWithRaw", mock.Anything, mock.Anything).
Return(types.ImageInspect{ID: helperImageID}, nil, nil)
mClient.On("ContainerStart", mock.Anything, serviceContainerID, mock.Anything).Return(nil).Once()
mClient.On("ContainerInspect", mock.Anything, serviceContainerID).Return(types.ContainerJSON{
ContainerJSONBase: &types.ContainerJSONBase{
State: &types.ContainerState{
ExitCode: 0,
},
},
}, nil).Once()
mClient.On("NetworkList", mock.Anything, mock.Anything).Return([]types.NetworkResource{}, nil).Once()
mClient.On("ContainerRemove", mock.Anything, serviceContainerID, mock.Anything).Return(nil).Once()
if testCase.helperImage != "" {
mClient.On("ImagePullBlocking", mock.Anything, mock.Anything, mock.Anything).Return(nil).Maybe()
}
executor := setUpExecutorForFeatureFlag(testCase.variables, testCase.helperImage, &mClient)
service := &types.Container{
ID: containerID,
Names: []string{containerID},
}
expectedConfig := &container.Config{
Cmd: testCase.expectedCmd,
Image: helperImageID,
Labels: executor.getLabels("wait", "wait="+service.ID),
}
mClient.On("ContainerCreate", mock.Anything, expectedConfig, mock.Anything, mock.Anything, serviceContainerID).
Return(container.ContainerCreateCreatedBody{ID: serviceContainerID}, nil).
Once()
err := executor.runServiceHealthCheckContainer(service, time.Minute)
assert.NoError(t, err)
})
}
}
// TODO: Remove in 12.0
func setUpExecutorForFeatureFlag(variables common.JobVariables, helperImage string, client docker_helpers.Client) executor {
return executor{
AbstractExecutor: executors.AbstractExecutor{
Config: common.RunnerConfig{
RunnerSettings: common.RunnerSettings{
Docker: &common.DockerConfig{
HelperImage: helperImage,
},
},
},
Build: &common.Build{
JobResponse: common.JobResponse{
Variables: variables,
},
Runner: &common.RunnerConfig{
RunnerCredentials: common.RunnerCredentials{
Token: "xxxxx",
},
},
},
Context: context.Background(),
},
client: client,
}
}
func init() {
docker_helpers.HomeDirectory = ""
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment