Skip to content

Commit

Permalink
Add debug option for TaskRuns
Browse files Browse the repository at this point in the history
.spec.debug bool, is added to TaskRun API which enables
debug mode for the particular TaskRun.

Co-authored-by: Vibhav Bobade <vbobade@redhat.com>
Co-authored-by: Nikhil Thomas <nikthoma@redhat.com>
  • Loading branch information
3 people committed Apr 5, 2020
1 parent e9f0454 commit f4862cd
Show file tree
Hide file tree
Showing 9 changed files with 265 additions and 29 deletions.
2 changes: 2 additions & 0 deletions pkg/apis/pipeline/v1alpha1/taskrun_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func (source *TaskRunSpec) ConvertTo(ctx context.Context, sink *v1beta1.TaskRunS
sink.Workspaces = source.Workspaces
sink.Params = source.Params
sink.Resources = source.Resources
sink.Debug = source.Debug
// Deprecated fields
if source.Inputs != nil {
if len(source.Inputs.Params) > 0 && len(source.Params) > 0 {
Expand Down Expand Up @@ -144,5 +145,6 @@ func (sink *TaskRunSpec) ConvertFrom(ctx context.Context, source *v1beta1.TaskRu
sink.Workspaces = source.Workspaces
sink.Params = source.Params
sink.Resources = source.Resources
sink.Debug = source.Debug
return nil
}
3 changes: 3 additions & 0 deletions pkg/apis/pipeline/v1alpha1/taskrun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ type TaskRunSpec struct {
// Workspaces is a list of WorkspaceBindings from volumes to workspaces.
// +optional
Workspaces []WorkspaceBinding `json:"workspaces,omitempty"`
// Debug specifies if the TaskRun has to be run in DebugMode
// +optional
Debug bool `json:"debug"`
// From v1beta1
// +optional
Params []Param `json:"params,omitempty"`
Expand Down
6 changes: 6 additions & 0 deletions pkg/apis/pipeline/v1beta1/taskrun_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import (

// TaskRunSpec defines the desired state of TaskRun
type TaskRunSpec struct {
// +optional
Debug bool `json:"debug"`
// +optional
Params []Param `json:"params,omitempty"`
// +optional
Expand Down Expand Up @@ -152,6 +154,10 @@ type TaskRunStatusFields struct {
// The list has one entry per sidecar in the manifest. Each entry is
// represents the imageid of the corresponding sidecar.
Sidecars []SidecarState `json:"sidecars,omitempty"`

// Debug shows if debugMode has been enabled for the TaskRun
// +optional
Debug bool `json:"debug"`
}

// TaskRunResult used to describe the results of a task
Expand Down
2 changes: 1 addition & 1 deletion pkg/pod/creds_init.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ var credsInitHomeVolumeMount = corev1.VolumeMount{
//
// If it finds secrets, it also returns a set of Volumes to attach to the Pod
// to provide those secrets to this initialization.
func credsInit(credsImage string, serviceAccountName, namespace string, kubeclient kubernetes.Interface, volumeMounts []corev1.VolumeMount, implicitEnvVars []corev1.EnvVar) (*corev1.Container, []corev1.Volume, error) {
func credsInit(credsImage, serviceAccountName, namespace string, kubeclient kubernetes.Interface, volumeMounts []corev1.VolumeMount, implicitEnvVars []corev1.EnvVar) (*corev1.Container, []corev1.Volume, error) {
if serviceAccountName == "" {
serviceAccountName = "default"
}
Expand Down
59 changes: 46 additions & 13 deletions pkg/pod/entrypoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,18 @@ import (
)

const (
toolsVolumeName = "tekton-internal-tools"
mountPoint = "/tekton/tools"
entrypointBinary = mountPoint + "/entrypoint"
toolsVolumeName = "tekton-internal-tools"
mountPoint = "/tekton/tools"
debugToolsVolumeName = "tekton-debug-internal-tools"
debugMountPoint = "/tekton/debug/tools"
entrypointBinary = mountPoint + "/entrypoint"

downwardVolumeName = "tekton-internal-downward"
downwardMountPoint = "/tekton/downward"
terminationPath = "/tekton/termination"
downwardMountReadyFile = "ready"
readyAnnotation = "tekton.dev/ready"
readyAnnotationValue = "READY"
downwardVolumeName = "tekton-internal-downward"
downwardMountPoint = "/tekton/downward"
terminationPath = "/tekton/termination"
readyFile = "ready"
readyAnnotation = "tekton.dev/ready"
readyAnnotationValue = "READY"

stepPrefix = "step-"
sidecarPrefix = "sidecar-"
Expand All @@ -55,14 +57,23 @@ var (
VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}},
}

debugToolsMount = corev1.VolumeMount{
Name: debugToolsVolumeName,
MountPath: debugMountPoint,
}
debugToolsVolume = corev1.Volume{
Name: debugToolsVolumeName,
VolumeSource: corev1.VolumeSource{EmptyDir: &corev1.EmptyDirVolumeSource{}},
}

// TODO(#1605): Signal sidecar readiness by injecting entrypoint,
// remove dependency on Downward API.
downwardVolume = corev1.Volume{
Name: downwardVolumeName,
VolumeSource: corev1.VolumeSource{
DownwardAPI: &corev1.DownwardAPIVolumeSource{
Items: []corev1.DownwardAPIVolumeFile{{
Path: downwardMountReadyFile,
Path: readyFile,
FieldRef: &corev1.ObjectFieldSelector{
FieldPath: fmt.Sprintf("metadata.annotations['%s']", readyAnnotation),
},
Expand All @@ -86,12 +97,17 @@ var (
// method, using entrypoint_lookup.go.
//
// TODO(#1605): Also use entrypoint injection to order sidecar start/stop.
func orderContainers(entrypointImage string, steps []corev1.Container, results []v1alpha1.TaskResult) (corev1.Container, []corev1.Container, error) {
func orderContainers(entrypointImage string, steps []corev1.Container, results []v1alpha1.TaskResult, debugMode bool) (corev1.Container, []corev1.Container, error) {

volumeMounts := []corev1.VolumeMount{toolsMount}
if debugMode {
volumeMounts = append(volumeMounts, debugToolsMount, debugScriptsMount)
}
initContainer := corev1.Container{
Name: "place-tools",
Image: entrypointImage,
Command: []string{"cp", "/ko-app/entrypoint", entrypointBinary},
VolumeMounts: []corev1.VolumeMount{toolsMount},
VolumeMounts: volumeMounts,
}

if len(steps) == 0 {
Expand All @@ -104,19 +120,36 @@ func orderContainers(entrypointImage string, steps []corev1.Container, results [
case 0:
argsForEntrypoint = []string{
// First step waits for the Downward volume file.
"-wait_file", filepath.Join(downwardMountPoint, downwardMountReadyFile),
"-wait_file", filepath.Join(downwardMountPoint, readyFile),
"-wait_file_content", // Wait for file contents, not just an empty file.
// Start next step.
"-post_file", filepath.Join(mountPoint, fmt.Sprintf("%d", i)),
"-termination_path", terminationPath,
}
if debugMode {
argsForEntrypoint = []string{
// First step waits for the Downward volume file.
"-wait_file", filepath.Join(debugMountPoint, readyFile),
"-wait_file_content", // Wait for file contents, not just an empty file.
// Start next step.
"-post_file", filepath.Join(debugMountPoint, fmt.Sprintf("debug-%d", i)),
"-termination_path", terminationPath,
}
}
default:
// All other steps wait for previous file, write next file.
argsForEntrypoint = []string{
"-wait_file", filepath.Join(mountPoint, fmt.Sprintf("%d", i-1)),
"-post_file", filepath.Join(mountPoint, fmt.Sprintf("%d", i)),
"-termination_path", terminationPath,
}
if debugMode {
argsForEntrypoint = []string{
"-wait_file", filepath.Join(mountPoint, fmt.Sprintf("%d", i-1)),
"-post_file", filepath.Join(debugMountPoint, fmt.Sprintf("debug-%d", i)),
"-termination_path", terminationPath,
}
}
}
argsForEntrypoint = append(argsForEntrypoint, resultArgument(steps, results)...)

Expand Down
78 changes: 78 additions & 0 deletions pkg/pod/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
Copyright 2020 The Tekton Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package pod

import (
"path/filepath"

corev1 "k8s.io/api/core/v1"
)

var (
debugEntrypointPath = filepath.Join(debugScriptsDebugDir, "debug")
superEntrypointPath = filepath.Join(scriptsDir, "super")
superExitFilePath = filepath.Join(mountPoint, "super-exit")
)

func createHelperContainers(entrypointImage string, debugMode bool) (corev1.Container, corev1.Container) {
var superContainer, debugContainer corev1.Container
volumeMounts := append(implicitVolumeMounts, scriptsVolumeMount, toolsMount)
if debugMode {
volumeMounts = append(volumeMounts, debugScriptsMount, debugToolsMount)
debugContainer = createDebugContainer(entrypointImage, volumeMounts)
}

argsForEntrypoint := []string{
"-wait_file", superExitFilePath,
"-termination_path", terminationPath,
"-entrypoint", superEntrypointPath,
"--",
}

superContainer = corev1.Container{
Name: "super",
Image: entrypointImage,
Command: []string{entrypointBinary},
Args: argsForEntrypoint,
TTY: true,
VolumeMounts: volumeMounts,
}

return superContainer, debugContainer

}

func createDebugContainer(entrypointImage string, volumeMounts []corev1.VolumeMount) corev1.Container {
argsForEntrypoint := []string{
"-wait_file", filepath.Join(downwardMountPoint, readyFile),
"-post_file", filepath.Join(debugMountPoint, readyFile),
"-termination_path", terminationPath,
"-entrypoint", "exit",
"--",
}

debugContainer := corev1.Container{
Name: "debug",
Image: entrypointImage,
Command: []string{entrypointBinary},
Args: argsForEntrypoint,
VolumeMounts: volumeMounts,
TerminationMessagePath: terminationPath,
}

return debugContainer
}
27 changes: 23 additions & 4 deletions pkg/pod/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,11 @@ var (
// by the supplied CRD.
func MakePod(images pipeline.Images, taskRun *v1alpha1.TaskRun, taskSpec v1alpha1.TaskSpec, kubeclient kubernetes.Interface, entrypointCache EntrypointCache, overrideHomeEnv bool) (*corev1.Pod, error) {
var initContainers []corev1.Container
var helperContainers []corev1.Container
var volumes []corev1.Volume
var volumeMounts []corev1.VolumeMount
implicitEnvVars := []corev1.EnvVar{}

debugMode := taskRun.Status.Debug
// Add our implicit volumes first, so they can be overridden by the user if they prefer.
volumes = append(volumes, implicitVolumes...)
volumeMounts = append(volumeMounts, implicitVolumeMounts...)
Expand Down Expand Up @@ -119,10 +120,13 @@ func MakePod(images pipeline.Images, taskRun *v1alpha1.TaskRun, taskSpec v1alpha

// Convert any steps with Script to command+args.
// If any are found, append an init container to initialize scripts.
scriptsInit, stepContainers, sidecarContainers := convertScripts(images.ShellImage, steps, taskSpec.Sidecars)
scriptsInit, stepContainers, sidecarContainers := convertScripts(images.ShellImage, steps, taskSpec.Sidecars, debugMode)
if scriptsInit != nil {
initContainers = append(initContainers, *scriptsInit)
volumes = append(volumes, scriptsVolume)
if debugMode {
volumes = append(volumes, debugScriptsVolume)
}
}

// Initialize any workingDirs under /workspace.
Expand All @@ -138,12 +142,15 @@ func MakePod(images pipeline.Images, taskRun *v1alpha1.TaskRun, taskSpec v1alpha

// Rewrite steps with entrypoint binary. Append the entrypoint init
// container to place the entrypoint binary.
entrypointInit, stepContainers, err := orderContainers(images.EntrypointImage, stepContainers, taskSpec.Results)
entrypointInit, stepContainers, err := orderContainers(images.EntrypointImage, stepContainers, taskSpec.Results, debugMode)
if err != nil {
return nil, err
}
initContainers = append(initContainers, entrypointInit)
volumes = append(volumes, toolsVolume, downwardVolume)
if debugMode {
volumes = append(volumes, debugToolsVolume)
}

limitRangeMin, err := getLimitRangeMinimum(taskRun.Namespace, kubeclient)
if err != nil {
Expand Down Expand Up @@ -175,6 +182,9 @@ func MakePod(images pipeline.Images, taskRun *v1alpha1.TaskRun, taskSpec v1alpha
}
}
vms := append(s.VolumeMounts, toAdd...)
if debugMode {
vms = append(vms, debugToolsMount)
}
stepContainers[i].VolumeMounts = vms
}

Expand Down Expand Up @@ -210,7 +220,16 @@ func MakePod(images pipeline.Images, taskRun *v1alpha1.TaskRun, taskSpec v1alpha
return nil, err
}

mergedPodContainers := stepContainers
// Create Helper Containers (especially the Super Container which will act a bastion post for
// carrying out operations like debugging)
superContainer, debugContainer := createHelperContainers(images.EntrypointImage, debugMode)
helperContainers = []corev1.Container{superContainer}
if debugMode {
helperContainers = append(helperContainers, debugContainer)
}

// Aggregate all containers to be added to the Pod.
mergedPodContainers := append(helperContainers, stepContainers...)

// Merge sidecar containers with step containers.
for _, sc := range sidecarContainers {
Expand Down
Loading

0 comments on commit f4862cd

Please sign in to comment.