Skip to content

Commit

Permalink
Merge pull request konflux-ci#14 from redhat-appstudio/hacbs1835
Browse files Browse the repository at this point in the history
feat(HACBS-1835): add support for workspaces
  • Loading branch information
davidmogar authored Feb 27, 2023
2 parents a045654 + 06a3f84 commit 739e4af
Show file tree
Hide file tree
Showing 16 changed files with 688 additions and 259 deletions.
6 changes: 3 additions & 3 deletions api/v1alpha1/internalrequest_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import (
"time"
)

// HandlingReason represents a reason for the release "InternalRequestSucceeded" condition.
// HandlingReason represents a reason for the InternalRequest "InternalRequestSucceeded" condition.
type HandlingReason string

const (
Expand Down Expand Up @@ -61,11 +61,11 @@ type InternalRequestSpec struct {

// InternalRequestStatus defines the observed state of InternalRequest.
type InternalRequestStatus struct {
// StartTime is the time when the Release PipelineRun was created and set to run
// StartTime is the time when the InternalRequest PipelineRun was created and set to run
// +optional
StartTime *metav1.Time `json:"startTime,omitempty"`

// CompletionTime is the time the Release PipelineRun completed
// CompletionTime is the time the InternalRequest PipelineRun completed
// +optional
CompletionTime *metav1.Time `json:"completionTime,omitempty"`

Expand Down
22 changes: 14 additions & 8 deletions api/v1alpha1/internalservicesconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,26 @@ type InternalServicesConfigSpec struct {
// +required
AllowList []string `json:"allowList,omitempty"`

// Catalog holds the information about the Tekton catalog
// Debug sets the operator to run in debug mode. In this mode, PipelineRuns and PVCs will not be removed
// +optional
Catalog Catalog `json:"catalog,omitempty"`
Debug bool `json:"debug,omitempty"`

// VolumeClaim holds information about the volume to request for Pipelines requiring a workspace
// +kubebuilder:default={name:"workspace", size:"1Gi"}
VolumeClaim VolumeClaim `json:"volumeClaim,omitempty"`
}

type Catalog struct {
// Namespace where to find the Tekton Pipelines
type VolumeClaim struct {
// Name is the workspace name
// +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
// +kubebuilder:default="workspace"
// +optional
Namespace string `json:"namespace,omitempty"`
Name string `json:"name,omitempty"`

// Bundle where to find the Tekton Pipelines
// +optional
Bundle string `json:"bundle,omitempty"`
// Size is the size that will be requested when a workspace is required by a Pipeline
// +kubebuilder:validation:Pattern=^[1-9][0-9]*(K|M|G)i$
// +kubebuilder:default="1Gi"
Size string `json:"size,omitempty"`
}

// InternalServicesConfigStatus defines the observed state of InternalServicesConfig.
Expand Down
32 changes: 16 additions & 16 deletions api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions config/crd/bases/appstudio.redhat.com_internalrequests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ spec:
description: InternalRequestStatus defines the observed state of InternalRequest.
properties:
completionTime:
description: CompletionTime is the time the Release PipelineRun completed
description: CompletionTime is the time the InternalRequest PipelineRun
completed
format: date-time
type: string
conditions:
Expand Down Expand Up @@ -140,8 +141,8 @@ spec:
Tekton PipelineRun kubebuilder:pruning:PreserveUnknownFields
type: object
startTime:
description: StartTime is the time when the Release PipelineRun was
created and set to run
description: StartTime is the time when the InternalRequest PipelineRun
was created and set to run
format: date-time
type: string
type: object
Expand Down
26 changes: 19 additions & 7 deletions config/crd/bases/appstudio.redhat.com_internalservicesconfigs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,28 @@ spec:
items:
type: string
type: array
catalog:
description: Catalog holds the information about the Tekton catalog
debug:
description: Debug sets the operator to run in debug mode. In this
mode, PipelineRuns and PVCs will not be removed
type: boolean
volumeClaim:
default:
name: workspace
size: 1Gi
description: VolumeClaim holds information about the volume to request
for Pipelines requiring a workspace
properties:
bundle:
description: Bundle where to find the Tekton Pipelines
type: string
namespace:
description: Namespace where to find the Tekton Pipelines
name:
default: workspace
description: Name is the workspace name
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
type: string
size:
default: 1Gi
description: Size is the size that will be requested when a workspace
is required by a Pipeline
pattern: ^[1-9][0-9]*(K|M|G)i$
type: string
type: object
type: object
status:
Expand Down
94 changes: 70 additions & 24 deletions controllers/internalrequest/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"context"
"fmt"
"github.com/go-logr/logr"
libhandler "github.com/operator-framework/operator-lib/handler"
"github.com/redhat-appstudio/internal-services/api/v1alpha1"
"github.com/redhat-appstudio/internal-services/loader"
"github.com/redhat-appstudio/internal-services/tekton"
Expand All @@ -31,18 +30,18 @@ import (
"knative.dev/pkg/apis"
"os"
"sigs.k8s.io/controller-runtime/pkg/client"
"strings"
)

// Adapter holds the objects needed to reconcile an InternalRequest.
type Adapter struct {
client client.Client
internalServicesConfig *v1alpha1.InternalServicesConfig
ctx context.Context
internalClient client.Client
internalRequest *v1alpha1.InternalRequest
loader loader.ObjectLoader
logger logr.Logger
client client.Client
internalServicesConfig *v1alpha1.InternalServicesConfig
ctx context.Context
internalClient client.Client
internalRequest *v1alpha1.InternalRequest
internalRequestPipeline *v1beta1.Pipeline
loader loader.ObjectLoader
logger logr.Logger
}

// NewAdapter creates and returns an Adapter instance.
Expand All @@ -59,6 +58,8 @@ func NewAdapter(ctx context.Context, client, internalClient client.Client, inter

// EnsureConfigIsLoaded is an operation that will load the service InternalServicesConfig from the manager namespace. If not found,
// a new InternalServicesConfig resource will be generated and attached to the adapter.
//
// Note: This operation sets values in the adapter to be used by other operations, so it should be always enabled.
func (a *Adapter) EnsureConfigIsLoaded() (reconciler.OperationResult, error) {
namespace := os.Getenv("SERVICE_NAMESPACE")
if namespace == "" {
Expand All @@ -78,6 +79,25 @@ func (a *Adapter) EnsureConfigIsLoaded() (reconciler.OperationResult, error) {
return reconciler.ContinueProcessing()
}

// EnsurePipelineExists is an operation that will ensure the Pipeline referenced by the InternalRequest exists and add it
// to the adapter, so it can be used in other operations. If the Pipeline doesn't exist, the InternalRequest will be
// marked as failed.
//
// Note: This operation sets values in the adapter to be used by other operations, so it should be always enabled.
func (a *Adapter) EnsurePipelineExists() (reconciler.OperationResult, error) {
var err error
a.internalRequestPipeline, err = a.loader.GetInternalRequestPipeline(a.ctx, a.internalClient,
a.internalRequest.Spec.Request, a.internalServicesConfig.Namespace)

if err != nil {
patch := client.MergeFrom(a.internalRequest.DeepCopy())
a.internalRequest.MarkFailed(fmt.Sprintf("No endpoint to handle '%s' requests", a.internalRequest.Spec.Request))
return reconciler.RequeueOnErrorOrStop(a.client.Status().Patch(a.ctx, a.internalRequest, patch))
}

return reconciler.ContinueProcessing()
}

// EnsurePipelineRunIsCreated is an operation that will ensure that the InternalRequest is handled by creating a new
// PipelineRun for the Pipeline referenced in the Request field.
func (a *Adapter) EnsurePipelineRunIsCreated() (reconciler.OperationResult, error) {
Expand All @@ -88,14 +108,7 @@ func (a *Adapter) EnsurePipelineRunIsCreated() (reconciler.OperationResult, erro

if pipelineRun == nil || !a.internalRequest.HasStarted() {
if pipelineRun == nil {
pipelineRun = tekton.NewPipelineRun(a.internalRequest, a.internalServicesConfig)

err = libhandler.SetOwnerAnnotations(a.internalRequest, pipelineRun)
if err != nil {
return reconciler.RequeueWithError(err)
}

err = a.internalClient.Create(a.ctx, pipelineRun)
pipelineRun, err = a.createInternalRequestPipelineRun()
if err != nil {
return reconciler.RequeueWithError(err)
}
Expand All @@ -110,6 +123,27 @@ func (a *Adapter) EnsurePipelineRunIsCreated() (reconciler.OperationResult, erro
return reconciler.ContinueProcessing()
}

// EnsurePipelineRunIsDeleted is an operation that will ensure that the PipelineRun created to handle the InternalRequest
// is deleted once it finishes.
func (a *Adapter) EnsurePipelineRunIsDeleted() (reconciler.OperationResult, error) {
if !a.internalRequest.HasCompleted() {
return reconciler.ContinueProcessing()
}

if a.internalServicesConfig.Spec.Debug {
a.logger.Info("Running in debug mode. Skipping PipelineRun deletion")

return reconciler.ContinueProcessing()
}

pipelineRun, err := a.loader.GetInternalRequestPipelineRun(a.ctx, a.internalClient, a.internalRequest)
if err != nil {
return reconciler.RequeueWithError(err)
}

return reconciler.RequeueOnErrorOrContinue(a.internalClient.Delete(a.ctx, pipelineRun))
}

// EnsureRequestIsAllowed is an operation that will ensure that the request is coming from a namespace allowed
// to execute InternalRequests. If the InternalServicesConfig spec.allowList is empty, any request will be allowed regardless of the
// remote namespace.
Expand All @@ -126,7 +160,7 @@ func (a *Adapter) EnsureRequestIsAllowed() (reconciler.OperationResult, error) {
return reconciler.RequeueOnErrorOrStop(a.client.Status().Patch(a.ctx, a.internalRequest, patch))
}

// EnsureStatusIsTracked is an operation that will ensure that the release PipelineRun status is tracked
// EnsureStatusIsTracked is an operation that will ensure that the InternalRequest PipelineRun status is tracked
// in the InternalRequest being processed.
func (a *Adapter) EnsureStatusIsTracked() (reconciler.OperationResult, error) {
pipelineRun, err := a.loader.GetInternalRequestPipelineRun(a.ctx, a.internalClient, a.internalRequest)
Expand All @@ -141,6 +175,24 @@ func (a *Adapter) EnsureStatusIsTracked() (reconciler.OperationResult, error) {
return reconciler.ContinueProcessing()
}

// createInternalRequestPipelineRun creates and returns a new InternalRequest PipelineRun. The new PipelineRun will
// include owner annotations, so it triggers InternalRequest reconciles whenever it changes. The Pipeline information
// and its parameters will be extracted from the InternalRequest.
func (a *Adapter) createInternalRequestPipelineRun() (*v1beta1.PipelineRun, error) {
pipelineRun := tekton.NewInternalRequestPipelineRun(a.internalServicesConfig).
WithInternalRequest(a.internalRequest).
WithOwner(a.internalRequest).
WithPipeline(a.internalRequestPipeline, a.internalServicesConfig).
AsPipelineRun()

err := a.internalClient.Create(a.ctx, pipelineRun)
if err != nil {
return nil, err
}

return pipelineRun, nil
}

// getDefaultInternalServicesConfig creates and returns a InternalServicesConfig resource in the given namespace with default values.
func (a *Adapter) getDefaultInternalServicesConfig(namespace string) *v1alpha1.InternalServicesConfig {
return &v1alpha1.InternalServicesConfig{
Expand Down Expand Up @@ -176,12 +228,6 @@ func (a *Adapter) registerInternalRequestPipelineRunStatus(pipelineRun *v1beta1.
if condition.IsTrue() {
a.internalRequest.Status.Results = tekton.GetResultsFromPipelineRun(pipelineRun)
a.internalRequest.MarkSucceeded()
} else if strings.Contains(condition.Message, "not found") {
var endpoint string
if pipelineRun.Spec.PipelineRef != nil {
endpoint = pipelineRun.Spec.PipelineRef.Name
}
a.internalRequest.MarkFailed(fmt.Sprintf("No endpoint to handle '%s' requests", endpoint))
} else {
a.internalRequest.MarkFailed(condition.Message)
}
Expand Down
Loading

0 comments on commit 739e4af

Please sign in to comment.