Refactor: capabilities and workload in appfile parsing (#6250)

This commit is contained in:
qiaozp
2023-08-10 14:41:20 +08:00
committed by GitHub
parent cce1859294
commit bab5bb2caf
25 changed files with 343 additions and 395 deletions
@@ -258,7 +258,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
}
var phase = common.ApplicationRunning
if !hasHealthCheckPolicy(appFile.PolicyWorkloads) {
if !hasHealthCheckPolicy(appFile.ParsedPolicies) {
app.Status.Services = handler.services
if !isHealthy(handler.services) {
phase = common.ApplicationUnhealthy
@@ -498,7 +498,7 @@ func (r *Reconciler) doWorkflowFinish(logCtx monitorContext.Context, app *v1beta
logCtx.Info("Application manifests has applied by workflow successfully")
}
func hasHealthCheckPolicy(policies []*appfile.Workload) bool {
func hasHealthCheckPolicy(policies []*appfile.Component) bool {
for _, p := range policies {
if p.FullTemplate != nil && p.FullTemplate.PolicyDefinition != nil &&
p.FullTemplate.PolicyDefinition.Spec.ManageHealthCheck {
@@ -227,13 +227,13 @@ func (h *AppHandler) ProduceArtifacts(ctx context.Context, comps []*types.Compon
}
// collectTraitHealthStatus collect trait health status
func (h *AppHandler) collectTraitHealthStatus(wl *appfile.Workload, tr *appfile.Trait, appRev *v1beta1.ApplicationRevision, overrideNamespace string) (common.ApplicationTraitStatus, []*unstructured.Unstructured, error) {
func (h *AppHandler) collectTraitHealthStatus(comp *appfile.Component, tr *appfile.Trait, appRev *v1beta1.ApplicationRevision, overrideNamespace string) (common.ApplicationTraitStatus, []*unstructured.Unstructured, error) {
defer func(clusterName string) {
wl.Ctx.SetCtx(pkgmulticluster.WithCluster(wl.Ctx.GetCtx(), clusterName))
}(multicluster.ClusterNameInContext(wl.Ctx.GetCtx()))
comp.Ctx.SetCtx(pkgmulticluster.WithCluster(comp.Ctx.GetCtx(), clusterName))
}(multicluster.ClusterNameInContext(comp.Ctx.GetCtx()))
var (
pCtx = wl.Ctx
pCtx = comp.Ctx
appName = appRev.Spec.Application.Name
traitStatus = common.ApplicationTraitStatus{
Type: tr.Name,
@@ -249,55 +249,55 @@ func (h *AppHandler) collectTraitHealthStatus(wl *appfile.Workload, tr *appfile.
_accessor := util.NewApplicationResourceNamespaceAccessor(h.app.Namespace, traitOverrideNamespace)
templateContext, err := tr.GetTemplateContext(pCtx, h.r.Client, _accessor)
if err != nil {
return common.ApplicationTraitStatus{}, nil, errors.WithMessagef(err, "app=%s, comp=%s, trait=%s, get template context error", appName, wl.Name, tr.Name)
return common.ApplicationTraitStatus{}, nil, errors.WithMessagef(err, "app=%s, comp=%s, trait=%s, get template context error", appName, comp.Name, tr.Name)
}
if ok, err := tr.EvalHealth(templateContext); !ok || err != nil {
traitStatus.Healthy = false
}
traitStatus.Message, err = tr.EvalStatus(templateContext)
if err != nil {
return common.ApplicationTraitStatus{}, nil, errors.WithMessagef(err, "app=%s, comp=%s, trait=%s, evaluate status message error", appName, wl.Name, tr.Name)
return common.ApplicationTraitStatus{}, nil, errors.WithMessagef(err, "app=%s, comp=%s, trait=%s, evaluate status message error", appName, comp.Name, tr.Name)
}
return traitStatus, extractOutputs(templateContext), nil
}
// collectWorkloadHealthStatus collect workload health status
func (h *AppHandler) collectWorkloadHealthStatus(ctx context.Context, wl *appfile.Workload, appRev *v1beta1.ApplicationRevision, status *common.ApplicationComponentStatus, accessor util.NamespaceAccessor) (bool, *unstructured.Unstructured, []*unstructured.Unstructured, error) {
func (h *AppHandler) collectWorkloadHealthStatus(ctx context.Context, comp *appfile.Component, appRev *v1beta1.ApplicationRevision, status *common.ApplicationComponentStatus, accessor util.NamespaceAccessor) (bool, *unstructured.Unstructured, []*unstructured.Unstructured, error) {
var output *unstructured.Unstructured
var outputs []*unstructured.Unstructured
var (
appName = appRev.Spec.Application.Name
isHealth = true
)
if wl.CapabilityCategory == types.TerraformCategory {
if comp.CapabilityCategory == types.TerraformCategory {
var configuration terraforv1beta2.Configuration
if err := h.r.Client.Get(ctx, client.ObjectKey{Name: wl.Name, Namespace: accessor.Namespace()}, &configuration); err != nil {
if err := h.r.Client.Get(ctx, client.ObjectKey{Name: comp.Name, Namespace: accessor.Namespace()}, &configuration); err != nil {
if kerrors.IsNotFound(err) {
var legacyConfiguration terraforv1beta1.Configuration
if err := h.r.Client.Get(ctx, client.ObjectKey{Name: wl.Name, Namespace: accessor.Namespace()}, &legacyConfiguration); err != nil {
return false, nil, nil, errors.WithMessagef(err, "app=%s, comp=%s, check health error", appName, wl.Name)
if err := h.r.Client.Get(ctx, client.ObjectKey{Name: comp.Name, Namespace: accessor.Namespace()}, &legacyConfiguration); err != nil {
return false, nil, nil, errors.WithMessagef(err, "app=%s, comp=%s, check health error", appName, comp.Name)
}
isHealth = setStatus(status, legacyConfiguration.Status.ObservedGeneration, legacyConfiguration.Generation,
legacyConfiguration.GetLabels(), appRev.Name, legacyConfiguration.Status.Apply.State, legacyConfiguration.Status.Apply.Message)
} else {
return false, nil, nil, errors.WithMessagef(err, "app=%s, comp=%s, check health error", appName, wl.Name)
return false, nil, nil, errors.WithMessagef(err, "app=%s, comp=%s, check health error", appName, comp.Name)
}
} else {
isHealth = setStatus(status, configuration.Status.ObservedGeneration, configuration.Generation, configuration.GetLabels(),
appRev.Name, configuration.Status.Apply.State, configuration.Status.Apply.Message)
}
} else {
templateContext, err := wl.GetTemplateContext(wl.Ctx, h.r.Client, accessor)
templateContext, err := comp.GetTemplateContext(comp.Ctx, h.r.Client, accessor)
if err != nil {
return false, nil, nil, errors.WithMessagef(err, "app=%s, comp=%s, get template context error", appName, wl.Name)
return false, nil, nil, errors.WithMessagef(err, "app=%s, comp=%s, get template context error", appName, comp.Name)
}
if ok, err := wl.EvalHealth(templateContext); !ok || err != nil {
if ok, err := comp.EvalHealth(templateContext); !ok || err != nil {
isHealth = false
}
status.Healthy = isHealth
status.Message, err = wl.EvalStatus(templateContext)
status.Message, err = comp.EvalStatus(templateContext)
if err != nil {
return false, nil, nil, errors.WithMessagef(err, "app=%s, comp=%s, evaluate workload status message error", appName, wl.Name)
return false, nil, nil, errors.WithMessagef(err, "app=%s, comp=%s, evaluate workload status message error", appName, comp.Name)
}
output, outputs = extractOutputAndOutputs(templateContext)
}
@@ -306,14 +306,14 @@ func (h *AppHandler) collectWorkloadHealthStatus(ctx context.Context, wl *appfil
// nolint
// collectHealthStatus will collect health status of component, including component itself and traits.
func (h *AppHandler) collectHealthStatus(ctx context.Context, wl *appfile.Workload, appRev *v1beta1.ApplicationRevision, overrideNamespace string, skipWorkload bool, traitFilters ...TraitFilter) (*common.ApplicationComponentStatus, *unstructured.Unstructured, []*unstructured.Unstructured, bool, error) {
func (h *AppHandler) collectHealthStatus(ctx context.Context, comp *appfile.Component, appRev *v1beta1.ApplicationRevision, overrideNamespace string, skipWorkload bool, traitFilters ...TraitFilter) (*common.ApplicationComponentStatus, *unstructured.Unstructured, []*unstructured.Unstructured, bool, error) {
output := new(unstructured.Unstructured)
outputs := make([]*unstructured.Unstructured, 0)
accessor := util.NewApplicationResourceNamespaceAccessor(h.app.Namespace, overrideNamespace)
var (
status = common.ApplicationComponentStatus{
Name: wl.Name,
WorkloadDefinition: wl.FullTemplate.Reference.Definition,
Name: comp.Name,
WorkloadDefinition: comp.FullTemplate.Reference.Definition,
Healthy: true,
Namespace: accessor.Namespace(),
Cluster: multicluster.ClusterNameInContext(ctx),
@@ -324,7 +324,7 @@ func (h *AppHandler) collectHealthStatus(ctx context.Context, wl *appfile.Worklo
status = h.getServiceStatus(status)
if !skipWorkload {
isHealth, output, outputs, err = h.collectWorkloadHealthStatus(ctx, wl, appRev, &status, accessor)
isHealth, output, outputs, err = h.collectWorkloadHealthStatus(ctx, comp, appRev, &status, accessor)
if err != nil {
return nil, nil, nil, false, err
}
@@ -332,7 +332,7 @@ func (h *AppHandler) collectHealthStatus(ctx context.Context, wl *appfile.Worklo
var traitStatusList []common.ApplicationTraitStatus
collectNext:
for _, tr := range wl.Traits {
for _, tr := range comp.Traits {
for _, filter := range traitFilters {
// If filtered out by one of the filters
if filter(*tr) {
@@ -340,7 +340,7 @@ collectNext:
}
}
traitStatus, _outputs, err := h.collectTraitHealthStatus(wl, tr, appRev, overrideNamespace)
traitStatus, _outputs, err := h.collectTraitHealthStatus(comp, tr, appRev, overrideNamespace)
if err != nil {
return nil, nil, nil, false, err
}
@@ -108,8 +108,8 @@ func ByTraitType(readyTraits, checkTraits []*unstructured.Unstructured) TraitFil
// manifestDispatcher is a manifest dispatcher
type manifestDispatcher struct {
run func(ctx context.Context, wl *appfile.Workload, appRev *v1beta1.ApplicationRevision, clusterName string) (bool, error)
healthCheck func(ctx context.Context, wl *appfile.Workload, appRev *v1beta1.ApplicationRevision) (bool, error)
run func(ctx context.Context, c *appfile.Component, appRev *v1beta1.ApplicationRevision, clusterName string) (bool, error)
healthCheck func(ctx context.Context, c *appfile.Component, appRev *v1beta1.ApplicationRevision) (bool, error)
}
func (h *AppHandler) generateDispatcher(appRev *v1beta1.ApplicationRevision, readyWorkload *unstructured.Unstructured, readyTraits []*unstructured.Unstructured, overrideNamespace string) ([]*manifestDispatcher, error) {
@@ -124,25 +124,25 @@ func (h *AppHandler) generateDispatcher(appRev *v1beta1.ApplicationRevision, rea
}
dispatcher := new(manifestDispatcher)
dispatcher.healthCheck = func(ctx context.Context, wl *appfile.Workload, appRev *v1beta1.ApplicationRevision) (bool, error) {
skipWorkload, manifests := assembleManifestFn(wl.SkipApplyWorkload)
dispatcher.healthCheck = func(ctx context.Context, comp *appfile.Component, appRev *v1beta1.ApplicationRevision) (bool, error) {
skipWorkload, manifests := assembleManifestFn(comp.SkipApplyWorkload)
if !h.resourceKeeper.ContainsResources(manifests) {
return false, nil
}
_, _, _, isHealth, err := h.collectHealthStatus(ctx, wl, appRev, options.OverrideNamespace, skipWorkload,
_, _, _, isHealth, err := h.collectHealthStatus(ctx, comp, appRev, options.OverrideNamespace, skipWorkload,
ByTraitType(readyTraits, options.Traits))
if err != nil {
return false, err
}
return isHealth, nil
}
dispatcher.run = func(ctx context.Context, wl *appfile.Workload, appRev *v1beta1.ApplicationRevision, clusterName string) (bool, error) {
skipWorkload, dispatchManifests := assembleManifestFn(wl.SkipApplyWorkload)
if isHealth, err := dispatcher.healthCheck(ctx, wl, appRev); !isHealth || err != nil {
dispatcher.run = func(ctx context.Context, comp *appfile.Component, appRev *v1beta1.ApplicationRevision, clusterName string) (bool, error) {
skipWorkload, dispatchManifests := assembleManifestFn(comp.SkipApplyWorkload)
if isHealth, err := dispatcher.healthCheck(ctx, comp, appRev); !isHealth || err != nil {
if err := h.Dispatch(ctx, clusterName, common.WorkflowResourceCreator, dispatchManifests...); err != nil {
return false, errors.WithMessage(err, "Dispatch")
}
status, _, _, isHealth, err := h.collectHealthStatus(ctx, wl, appRev, options.OverrideNamespace, skipWorkload,
status, _, _, isHealth, err := h.collectHealthStatus(ctx, comp, appRev, options.OverrideNamespace, skipWorkload,
ByTraitType(readyTraits, options.Traits))
if err != nil {
return false, errors.WithMessage(err, "CollectHealthStatus")
@@ -108,8 +108,8 @@ func (h *AppHandler) GenerateApplicationSteps(ctx monitorContext.Context,
oamProvider.Install(handlerProviders, app, af, h.r.Client, h.applyComponentFunc(
appParser, appRev, af), h.renderComponentFunc(appParser, appRev, af))
pCtx := velaprocess.NewContext(generateContextDataFromApp(app, appRev.Name))
renderer := func(ctx context.Context, comp common.ApplicationComponent) (*appfile.Workload, error) {
return appParser.ParseWorkloadFromRevisionAndClient(ctx, comp, appRev)
renderer := func(ctx context.Context, comp common.ApplicationComponent) (*appfile.Component, error) {
return appParser.ParseComponentFromRevisionAndClient(ctx, comp, appRev)
}
multiclusterProvider.Install(handlerProviders, h.r.Client, app, af,
h.applyComponentFunc(appParser, appRev, af),
@@ -439,8 +439,8 @@ func (h *AppHandler) prepareWorkloadAndManifests(ctx context.Context,
comp common.ApplicationComponent,
appRev *v1beta1.ApplicationRevision,
patcher *value.Value,
af *appfile.Appfile) (*appfile.Workload, *types.ComponentManifest, error) {
wl, err := appParser.ParseWorkloadFromRevisionAndClient(ctx, comp, appRev)
af *appfile.Appfile) (*appfile.Component, *types.ComponentManifest, error) {
wl, err := appParser.ParseComponentFromRevisionAndClient(ctx, comp, appRev)
if err != nil {
return nil, nil, errors.WithMessage(err, "ParseWorkload")
}
@@ -490,10 +490,10 @@ func renderComponentsAndTraits(client client.Client, manifest *types.ComponentMa
return readyWorkload, readyTraits, nil
}
func checkSkipApplyWorkload(wl *appfile.Workload) {
for _, trait := range wl.Traits {
func checkSkipApplyWorkload(comp *appfile.Component) {
for _, trait := range comp.Traits {
if trait.FullTemplate.TraitDefinition.Spec.ManageWorkload {
wl.SkipApplyWorkload = true
comp.SkipApplyWorkload = true
break
}
}
@@ -213,7 +213,7 @@ func (h *AppHandler) gatherRevisionSpec(af *appfile.Appfile) (*v1beta1.Applicati
},
},
}
for _, w := range af.Workloads {
for _, w := range af.ParsedComponents {
if w == nil {
continue
}
@@ -238,7 +238,7 @@ func (h *AppHandler) gatherRevisionSpec(af *appfile.Appfile) (*v1beta1.Applicati
}
}
}
for _, p := range af.PolicyWorkloads {
for _, p := range af.ParsedPolicies {
if p == nil || p.FullTemplate == nil {
continue
}
@@ -177,7 +177,7 @@ var _ = Describe("test generate revision ", func() {
Expect(handler.FinalizeAndApplyAppRevision(ctx)).Should(Succeed())
prevHash := generatedAppfile.AppRevisionHash
handler.app.Status.LatestRevision = &common.Revision{Name: generatedAppfile.AppRevisionName, Revision: 1, RevisionHash: generatedAppfile.AppRevisionHash}
generatedAppfile.Workloads[0].FullTemplate.ComponentDefinition = nil
generatedAppfile.ParsedComponents[0].FullTemplate.ComponentDefinition = nil
generatedAppfile.RelatedComponentDefinitions = map[string]*v1beta1.ComponentDefinition{}
Expect(handler.PrepareCurrentAppRevision(ctx, generatedAppfile)).Should(Succeed())
nonChangeHash := generatedAppfile.AppRevisionHash