-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(STONEINTG-524): report result of handling ITS to github
* Create function to get credential from snapshot * Create function to report for result of handle ITSes for snapshot Signed-off-by: Hongwei Liu <[email protected]>
- Loading branch information
1 parent
12da31d
commit 88fe5b0
Showing
14 changed files
with
1,096 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/* | ||
Copyright 2023. | ||
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 statusreport | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
|
||
applicationapiv1alpha1 "github.com/redhat-appstudio/application-api/api/v1alpha1" | ||
"github.com/redhat-appstudio/integration-service/gitops" | ||
h "github.com/redhat-appstudio/integration-service/helpers" | ||
"github.com/redhat-appstudio/integration-service/status" | ||
|
||
"github.com/redhat-appstudio/integration-service/loader" | ||
"github.com/redhat-appstudio/operator-toolkit/controller" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
) | ||
|
||
// Adapter holds the objects needed to reconcile a snapshot's test status report. | ||
type Adapter struct { | ||
snapshot *applicationapiv1alpha1.Snapshot | ||
application *applicationapiv1alpha1.Application | ||
component *applicationapiv1alpha1.Component | ||
logger h.IntegrationLogger | ||
loader loader.ObjectLoader | ||
client client.Client | ||
context context.Context | ||
status status.Status | ||
} | ||
|
||
// NewAdapter creates and returns an Adapter instance. | ||
func NewAdapter(snapshot *applicationapiv1alpha1.Snapshot, application *applicationapiv1alpha1.Application, component *applicationapiv1alpha1.Component, logger h.IntegrationLogger, loader loader.ObjectLoader, client client.Client, | ||
context context.Context) *Adapter { | ||
return &Adapter{ | ||
snapshot: snapshot, | ||
application: application, | ||
component: component, | ||
logger: logger, | ||
loader: loader, | ||
client: client, | ||
context: context, | ||
status: status.NewAdapter(logger.Logger, client), | ||
} | ||
} | ||
|
||
// EnsureSnapshotTestStatusReported will ensure that integration test status including env provision and snapshotEnvironmentBinding error is reported to the git provider | ||
// which (indirectly) triggered its execution. | ||
func (a *Adapter) EnsureSnapshotTestStatusReported() (controller.OperationResult, error) { | ||
reporters, err := a.status.GetReporters(a.snapshot) | ||
|
||
if err != nil { | ||
return controller.RequeueWithError(err) | ||
} | ||
|
||
for _, reporter := range reporters { | ||
integrationTestStatusDetails, err := getIntegrationScenarioTestStatusFromAnnotation(a.snapshot) | ||
if err != nil { | ||
a.logger.Error(err, "failed to report integration test scenario test status for snapshot %s/%s", a.snapshot.Namespace, a.snapshot.Name) | ||
return controller.RequeueWithError(err) | ||
} | ||
if integrationTestStatusDetails == nil { | ||
a.logger.Info("no snapshot annotation %s defined for snapshot %s/%s, no need to report integration test status", a.snapshot.Namespace, a.snapshot.Name) | ||
return controller.ContinueProcessing() | ||
} | ||
|
||
if err := reporter.ReportStatusForSnapshot(a.client, a.context, a.snapshot, integrationTestStatusDetails); err != nil { | ||
return controller.RequeueWithError(err) | ||
} | ||
} | ||
|
||
return controller.ContinueProcessing() | ||
} | ||
|
||
func getIntegrationScenarioTestStatusFromAnnotation(snapshot *applicationapiv1alpha1.Snapshot) (*[]gitops.IntegrationTestStatusDetail, error) { | ||
statusAnnotation, ok := snapshot.GetAnnotations()[gitops.SnapshotTestsStatusAnnotation] | ||
if !ok { | ||
return nil, nil | ||
} | ||
|
||
integrationTestStatusDetails := &[]gitops.IntegrationTestStatusDetail{} | ||
err := json.Unmarshal([]byte(statusAnnotation), integrationTestStatusDetails) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to load tests statuses from the scenario annotation: %w", err) | ||
} | ||
return integrationTestStatusDetails, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
/* | ||
Copyright 2023. | ||
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 andF | ||
limitations under the License. | ||
*/ | ||
|
||
package statusreport | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/redhat-appstudio/integration-service/cache" | ||
|
||
"github.com/go-logr/logr" | ||
applicationapiv1alpha1 "github.com/redhat-appstudio/application-api/api/v1alpha1" | ||
"github.com/redhat-appstudio/integration-service/gitops" | ||
"github.com/redhat-appstudio/integration-service/helpers" | ||
"github.com/redhat-appstudio/integration-service/loader" | ||
"github.com/redhat-appstudio/operator-toolkit/controller" | ||
"k8s.io/apimachinery/pkg/api/errors" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
"sigs.k8s.io/controller-runtime/pkg/predicate" | ||
) | ||
|
||
// Reconciler reconciles an Snapshot object | ||
type Reconciler struct { | ||
client.Client | ||
Log logr.Logger | ||
Scheme *runtime.Scheme | ||
} | ||
|
||
// NewStatusReportReconciler creates and returns a Reconciler. | ||
func NewStatusReportReconciler(client client.Client, logger *logr.Logger, scheme *runtime.Scheme) *Reconciler { | ||
return &Reconciler{ | ||
Client: client, | ||
Log: logger.WithName("statusreport"), | ||
Scheme: scheme, | ||
} | ||
} | ||
|
||
//+kubebuilder:rbac:groups=appstudio.redhat.com,resources=snapshots,verbs=get;list;watch | ||
//+kubebuilder:rbac:groups=appstudio.redhat.com,resources=snapshots/status,verbs=get | ||
//+kubebuilder:rbac:groups=appstudio.redhat.com,resources=snapshotenvironmentbindings,verbs=get;list;watch | ||
//+kubebuilder:rbac:groups=appstudio.redhat.com,resources=snapshotenvironmentbindings/status,verbs=get | ||
//+kubebuilder:rbac:groups=tekton.dev,resources=pipelineruns,verbs=get;list;watch | ||
//+kubebuilder:rbac:groups=tekton.dev,resources=pipelineruns/status,verbs=get | ||
//+kubebuilder:rbac:groups=appstudio.redhat.com,resources=applications,verbs=get;list;watch | ||
//+kubebuilder:rbac:groups=appstudio.redhat.com,resources=applications/status,verbs=get | ||
//+kubebuilder:rbac:groups=appstudio.redhat.com,resources=components,verbs=get;list;watch | ||
//+kubebuilder:rbac:groups=appstudio.redhat.com,resources=components/status,verbs=get | ||
//+kubebuilder:rbac:groups=appstudio.redhat.com,resources=deploymenttargetclasses,verbs=get;list;watch | ||
//+kubebuilder:rbac:groups=appstudio.redhat.com,resources=deploymenttargetclaims,verbs=get;list;watch | ||
//+kubebuilder:rbac:groups=appstudio.redhat.com,resources=environments,verbs=get;list;watch; | ||
//+kubebuilder:rbac:groups=appstudio.redhat.com,resources=environments/status,verbs=get | ||
|
||
// Reconcile is part of the main kubernetes reconciliation loop which aims to | ||
// move the current state of the cluster closer to the desired state. | ||
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { | ||
logger := helpers.IntegrationLogger{Logger: r.Log.WithValues("snapshot", req.NamespacedName)} | ||
loader := loader.NewLoader() | ||
|
||
snapshot := &applicationapiv1alpha1.Snapshot{} | ||
err := r.Get(ctx, req.NamespacedName, snapshot) | ||
if err != nil { | ||
logger.Error(err, "Failed to get snapshot for", "req", req.NamespacedName) | ||
if errors.IsNotFound(err) { | ||
return ctrl.Result{}, nil | ||
} | ||
|
||
return ctrl.Result{}, err | ||
} | ||
|
||
application, err := loader.GetApplicationFromSnapshot(r.Client, ctx, snapshot) | ||
if err != nil { | ||
logger.Error(err, "Failed to get Application from the Snapshot") | ||
return ctrl.Result{}, err | ||
} | ||
logger = logger.WithApp(*application) | ||
|
||
component, err := loader.GetComponentFromSnapshot(r.Client, ctx, snapshot) | ||
if err != nil { | ||
logger.Error(err, "Failed to get Component from the Snapshot") | ||
return ctrl.Result{}, err | ||
} | ||
|
||
adapter := NewAdapter(snapshot, application, component, logger, loader, r.Client, ctx) | ||
|
||
return controller.ReconcileHandler([]controller.Operation{ | ||
adapter.EnsureSnapshotTestStatusReported, | ||
}) | ||
} | ||
|
||
// AdapterInterface is an interface defining all the operations that should be defined in an Integration adapter. | ||
type AdapterInterface interface { | ||
EnsureSnapshotTestStatusReported() (controller.OperationResult, error) | ||
} | ||
|
||
// SetupController creates a new Integration controller and adds it to the Manager. | ||
func SetupController(manager ctrl.Manager, log *logr.Logger) error { | ||
return setupControllerWithManager(manager, NewStatusReportReconciler(manager.GetClient(), log, manager.GetScheme())) | ||
} | ||
|
||
// setupCache indexes fields for each of the resources used in the statusreport adapter in those cases where filtering by | ||
// field is required. | ||
func setupCache(mgr ctrl.Manager) error { | ||
if err := cache.SetupBindingEnvironmentCache(mgr); err != nil { | ||
return err | ||
} | ||
|
||
return cache.SetupBindingApplicationCache(mgr) | ||
} | ||
|
||
// setupControllerWithManager sets up the controller with the Manager which monitors new Snapshots | ||
func setupControllerWithManager(manager ctrl.Manager, controller *Reconciler) error { | ||
err := setupCache(manager) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return ctrl.NewControllerManagedBy(manager). | ||
For(&applicationapiv1alpha1.Snapshot{}). | ||
WithEventFilter(predicate.Or( | ||
gitops.SnapshotTestAnnotationChangePredicate())). | ||
Complete(controller) | ||
} |
Oops, something went wrong.