pkg/tektoncd/trigger_template.go (106 lines of code) (raw):
package tektoncd
import (
"bytes"
"context"
"errors"
"fmt"
tektonpipelineApi "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
tektonTriggersApi "github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/client"
codebaseApi "github.com/epam/edp-codebase-operator/v2/api/v1"
)
var ErrEmptyTriggerTemplateResources = fmt.Errorf("trigger template resources is empty")
type TriggerTemplateManager interface {
GetRawResourceFromTriggerTemplate(ctx context.Context, triggerTemplateName, ns string) ([]byte, error)
CreatePipelineRun(ctx context.Context, ns, cdStageDeployName string, rawPipeRun, appPayload, stage, pipeline, clusterSecret []byte) error
CreatePendingPipelineRun(ctx context.Context, ns, cdStageDeployName string, rawPipeRun, appPayload, stage, pipeline, clusterSecret []byte) error
}
var _ TriggerTemplateManager = &TektonTriggerTemplateManager{}
type TektonTriggerTemplateManager struct {
k8sClient client.Client
}
func NewTektonTriggerTemplateManager(k8sClient client.Client) *TektonTriggerTemplateManager {
return &TektonTriggerTemplateManager{k8sClient: k8sClient}
}
func (h *TektonTriggerTemplateManager) GetRawResourceFromTriggerTemplate(ctx context.Context, triggerTemplateName, ns string) ([]byte, error) {
template := &tektonTriggersApi.TriggerTemplate{}
if err := h.k8sClient.Get(ctx, client.ObjectKey{
Namespace: ns,
Name: triggerTemplateName,
}, template); err != nil {
return nil, fmt.Errorf("failed to get TriggerTemplate: %w", err)
}
if len(template.Spec.ResourceTemplates) == 0 {
return nil, ErrEmptyTriggerTemplateResources
}
rawPipeRun := make([]byte, len(template.Spec.ResourceTemplates[0].RawExtension.Raw))
copy(rawPipeRun, template.Spec.ResourceTemplates[0].RawExtension.Raw)
return rawPipeRun, nil
}
func (h *TektonTriggerTemplateManager) CreatePipelineRun(
ctx context.Context,
ns,
cdStageDeployName string,
rawPipeRun,
appPayload,
stage,
pipeline,
clusterSecret []byte,
) error {
data, err := makeUnstructuredPipelineRun(ns, cdStageDeployName, rawPipeRun, appPayload, stage, pipeline, clusterSecret)
if err != nil {
return err
}
if err = h.k8sClient.Create(ctx, data); err != nil {
return fmt.Errorf("failed to create resource: %w", err)
}
return nil
}
func (h *TektonTriggerTemplateManager) CreatePendingPipelineRun(
ctx context.Context,
ns,
cdStageDeployName string,
rawPipeRun,
appPayload,
stage,
pipeline,
clusterSecret []byte,
) error {
data, err := makeUnstructuredPipelineRun(ns, cdStageDeployName, rawPipeRun, appPayload, stage, pipeline, clusterSecret)
if err != nil {
return err
}
spec, ok := data.Object["spec"].(map[string]interface{})
if !ok {
return errors.New("invalid PipelineRun spec")
}
spec["status"] = tektonpipelineApi.PipelineRunSpecStatusPending
if err = h.k8sClient.Create(ctx, data); err != nil {
return fmt.Errorf("failed to create resource: %w", err)
}
return nil
}
func makeUnstructuredPipelineRun(
ns,
cdStageDeployName string,
rawPipeRun []byte,
appPayload []byte,
stage []byte,
pipeline []byte,
clusterSecret []byte,
) (*unstructured.Unstructured, error) {
rawPipeRun = bytes.ReplaceAll(rawPipeRun, []byte("$(tt.params.APPLICATIONS_PAYLOAD)"), bytes.ReplaceAll(appPayload, []byte(`"`), []byte(`\"`)))
rawPipeRun = bytes.ReplaceAll(rawPipeRun, []byte("$(tt.params.CDSTAGE)"), stage)
rawPipeRun = bytes.ReplaceAll(rawPipeRun, []byte("$(tt.params.CDPIPELINE)"), pipeline)
rawPipeRun = bytes.ReplaceAll(rawPipeRun, []byte("$(tt.params.KUBECONFIG_SECRET_NAME)"), clusterSecret)
data := &unstructured.Unstructured{}
if err := data.UnmarshalJSON(rawPipeRun); err != nil {
return nil, fmt.Errorf("couldn't unmarshal json from the TriggerTemplate: %w", err)
}
data.SetNamespace(ns)
labels := data.GetLabels()
labels[codebaseApi.CdStageDeployLabel] = cdStageDeployName
data.SetLabels(labels)
return data, nil
}