pipeline/pkg/reconciler/taskrun/resources/input_resources.go
jbarrick@mesosphere.com 04f5b6fc56 Only mount artifact bucket volume once, even with multiple inputs.
This fixes an issue where an artifact bucket secret can be mounted multiple times if there are multiple inputs that copy
from another task.
2019-10-11 09:57:18 -05:00

135 lines
4.8 KiB
Go

/*
Copyright 2019 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 resources
import (
"path/filepath"
"github.com/tektoncd/pipeline/pkg/apis/pipeline"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1"
"github.com/tektoncd/pipeline/pkg/artifacts"
"go.uber.org/zap"
"golang.org/x/xerrors"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes"
)
func getBoundResource(resourceName string, boundResources []v1alpha1.TaskResourceBinding) (*v1alpha1.TaskResourceBinding, error) {
for _, br := range boundResources {
if br.Name == resourceName {
return &br, nil
}
}
return nil, xerrors.Errorf("couldnt find resource named %q in bound resources %v", resourceName, boundResources)
}
// AddInputResource reads the inputs resources and adds the corresponding container steps
// This function reads the `paths` to check if resource copies needs to be fetched from previous tasks output(from PVC)
// 1. If resource has paths declared then serially copies the resource from previous task output paths into current resource destination.
// 2. If resource has custom destination directory using targetPath then that directory is created and resource is fetched / copied
// from previous task
// 3. If resource has paths declared then fresh copy of resource is not fetched
func AddInputResource(
kubeclient kubernetes.Interface,
images pipeline.Images,
taskName string,
taskSpec *v1alpha1.TaskSpec,
taskRun *v1alpha1.TaskRun,
inputResources map[string]v1alpha1.PipelineResourceInterface,
logger *zap.SugaredLogger,
) (*v1alpha1.TaskSpec, error) {
if taskSpec.Inputs == nil {
return taskSpec, nil
}
taskSpec = taskSpec.DeepCopy()
pvcName := taskRun.GetPipelineRunPVCName()
mountPVC := false
mountSecrets := false
prNameFromLabel := taskRun.Labels[pipeline.GroupName+pipeline.PipelineRunLabelKey]
if prNameFromLabel == "" {
prNameFromLabel = pvcName
}
as, err := artifacts.GetArtifactStorage(images, prNameFromLabel, kubeclient, logger)
if err != nil {
return nil, err
}
// Iterate in reverse through the list, each element prepends but we want the first one to remain first.
for i := len(taskSpec.Inputs.Resources) - 1; i >= 0; i-- {
input := taskSpec.Inputs.Resources[i]
boundResource, err := getBoundResource(input.Name, taskRun.Spec.Inputs.Resources)
if err != nil {
return nil, xerrors.Errorf("failed to get bound resource: %w", err)
}
resource, ok := inputResources[boundResource.Name]
if !ok || resource == nil {
return nil, xerrors.Errorf("failed to Get Pipeline Resource for task %s with boundResource %v", taskName, boundResource)
}
var copyStepsFromPrevTasks []v1alpha1.Step
dPath := destinationPath(input.Name, input.TargetPath)
// if taskrun is fetching resource from previous task then execute copy step instead of fetching new copy
// to the desired destination directory, as long as the resource exports output to be copied
if allowedOutputResources[resource.GetType()] && taskRun.HasPipelineRunOwnerReference() {
for _, path := range boundResource.Paths {
cpSteps := as.GetCopyFromStorageToSteps(boundResource.Name, path, dPath)
if as.GetType() == v1alpha1.ArtifactStoragePVCType {
mountPVC = true
for _, s := range cpSteps {
s.VolumeMounts = []corev1.VolumeMount{v1alpha1.GetPvcMount(pvcName)}
copyStepsFromPrevTasks = append(copyStepsFromPrevTasks,
v1alpha1.CreateDirStep(images.BashNoopImage, boundResource.Name, dPath),
s)
}
} else {
// bucket
copyStepsFromPrevTasks = append(copyStepsFromPrevTasks, cpSteps...)
}
}
}
// source is copied from previous task so skip fetching download container definition
if len(copyStepsFromPrevTasks) > 0 {
taskSpec.Steps = append(copyStepsFromPrevTasks, taskSpec.Steps...)
mountSecrets = true
} else {
// Allow the resource to mutate the task.
modifier, err := resource.GetInputTaskModifier(taskSpec, dPath)
if err != nil {
return nil, err
}
v1alpha1.ApplyTaskModifier(taskSpec, modifier)
}
}
if mountPVC {
taskSpec.Volumes = append(taskSpec.Volumes, GetPVCVolume(pvcName))
}
if mountSecrets {
taskSpec.Volumes = append(taskSpec.Volumes, as.GetSecretsVolumes()...)
}
return taskSpec, nil
}
func destinationPath(name, path string) string {
if path == "" {
return filepath.Join(workspaceDir, name)
}
return filepath.Join(workspaceDir, path)
}