mirror of
https://github.com/hanzoai/cd.git
synced 2026-10-30 14:56:45 +00:00
clientgen/mockgen hadn't been rerun since the group rename, even though
pkg/apis/application/v1alpha1/doc.go and the shipped CRDs already say
apps.hanzo.ai. pkg/client/** still derived ArgoprojV1alpha1/Argoproj()
from the old argoproj.io group, and .mockery.yaml still named ArgoDB
(renamed to DB in util/db/db.go a few commits back) and
util/notification/cd (deleted in b2d7140a0, we use hanzoai/notify).
Reran clientgen (deepcopy-gen/client-gen/lister-gen/informer-gen) off
the current group, and mockgen after fixing .mockery.yaml. Moved every
hand-written call site that holds a versioned.Interface or
SharedInformerFactory with it: .ArgoprojV1alpha1() -> .AppsV1alpha1(),
ArgoprojV1alpha1Interface/Client -> AppsV1alpha1Interface/Client,
.Argoproj() -> .Apps() across controller, server, util, cmd,
hack/gen-resources, and test/e2e. controller/metrics/metrics_test.go's
mocks.NewArgoDB -> mocks.NewDB. Deleted the orphaned
util/db/mocks/ArgoDB.go; mockery writes DB.go for the renamed
interface but doesn't clean up the old filename on its own.
Left CHANGELOG.md/SECURITY.md's real argoproj/argo-cd history and
gitops-engine/pkg/diff/testdata/openapiv2.bin's Argo Rollouts OpenAPI
fixture untouched - genuine history and a real third-party schema, not
our naming.
go build/vet clean. Same 19 pre-existing package-level test failures
as baseline (missing git-verify-wrapper.sh, no live cluster, etc.),
none new. All 32 manifests/ kustomization paths still build;
manifests/ha/** untouched.
149 lines
6.0 KiB
Go
149 lines
6.0 KiB
Go
package controller
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"maps"
|
|
|
|
"github.com/hanzoai/cd/controller/hydrator/types"
|
|
appv1 "github.com/hanzoai/cd/pkg/apis/application/v1alpha1"
|
|
"github.com/hanzoai/cd/reposerver/apiclient"
|
|
"github.com/hanzoai/cd/util/cd"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
)
|
|
|
|
/**
|
|
This file implements the hydrator.Dependencies interface for the ApplicationController.
|
|
|
|
Hydration logic does not belong in this file. The methods here should be "bookkeeping" methods that keep hydration work
|
|
in the hydrator and app controller work in the app controller. The only purpose of this file is to provide the hydrator
|
|
safe, minimal access to certain app controller functionality to avoid duplicate code.
|
|
*/
|
|
|
|
func (ctrl *ApplicationController) GetProcessableAppProj(app *appv1.Application) (*appv1.AppProject, error) {
|
|
return ctrl.getAppProj(app)
|
|
}
|
|
|
|
// GetProcessableApps returns a list of applications that are processable by the controller.
|
|
func (ctrl *ApplicationController) GetProcessableApps() (*appv1.ApplicationList, error) {
|
|
// getAppList already filters out applications that are not processable by the controller.
|
|
return ctrl.getAppList(metav1.ListOptions{})
|
|
}
|
|
|
|
func (ctrl *ApplicationController) EvaluateAppRevisionsChanges(ctx context.Context, app *appv1.Application, source appv1.ApplicationSource, revision string, project *appv1.AppProject, noRevisionCache bool) (bool, string, error) {
|
|
sources := []appv1.ApplicationSource{source}
|
|
revisions := []string{revision}
|
|
|
|
hasChanges, resolvedRevisions, err := ctrl.appStateManager.EvaluateAppRevisionsChanges(ctx, app, sources, revisions, project, false, noRevisionCache)
|
|
if err != nil {
|
|
return false, "", err
|
|
}
|
|
if len(resolvedRevisions) != 1 {
|
|
return false, "", fmt.Errorf("expected exactly one resolved revision for single source, got %d", len(resolvedRevisions))
|
|
}
|
|
if resolvedRevisions[0] == "" {
|
|
return false, "", errors.New("resolved revision is empty for dry source")
|
|
}
|
|
return hasChanges, resolvedRevisions[0], nil
|
|
}
|
|
|
|
func (ctrl *ApplicationController) GetRepoObjs(ctx context.Context, app *appv1.Application, drySource appv1.ApplicationSource, revision string, project *appv1.AppProject) ([]*unstructured.Unstructured, *apiclient.ManifestResponse, error) {
|
|
drySources := []appv1.ApplicationSource{drySource}
|
|
dryRevisions := []string{revision}
|
|
|
|
appLabelKey, err := ctrl.settingsMgr.GetAppInstanceLabelKey()
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed to get app instance label key: %w", err)
|
|
}
|
|
|
|
// FIXME: use cache and revision cache
|
|
objs, resp, _, err := ctrl.appStateManager.GetRepoObjs(ctx, app, drySources, appLabelKey, dryRevisions, true, true, project.EffectiveSourceIntegrity(), project, false)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed to get repo objects: %w", err)
|
|
}
|
|
|
|
trackingMethod, err := ctrl.settingsMgr.GetTrackingMethod()
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed to get tracking method: %w", err)
|
|
}
|
|
for _, obj := range objs {
|
|
if err := cd.NewResourceTracking().RemoveAppInstance(obj, trackingMethod); err != nil {
|
|
return nil, nil, fmt.Errorf("failed to remove the app instance value: %w", err)
|
|
}
|
|
}
|
|
|
|
if len(resp) != 1 {
|
|
return nil, nil, fmt.Errorf("expected one manifest response, got %d", len(resp))
|
|
}
|
|
|
|
return objs, resp[0], nil
|
|
}
|
|
|
|
func (ctrl *ApplicationController) GetWriteCredentials(ctx context.Context, repoURL string, project string) (*appv1.Repository, error) {
|
|
return ctrl.db.GetWriteRepository(ctx, repoURL, project)
|
|
}
|
|
|
|
func (ctrl *ApplicationController) RequestAppRefresh(appName string, appNamespace string) error {
|
|
// We request a refresh by setting the annotation instead of by adding it to the refresh queue, because there is no
|
|
// guarantee that the hydrator is running on the same controller shard as is processing the application.
|
|
|
|
// This function is called for each app after a hydrate operation is completed so that the app controller can pick
|
|
// up the newly-hydrated changes. So we pass nil hydrateType to avoid a hydrate loop.
|
|
_, err := cd.RefreshApp(ctrl.applicationClientset.AppsV1alpha1().Applications(appNamespace), appName, appv1.RefreshTypeNormal, nil)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to request app refresh: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ctrl *ApplicationController) PersistHydrationStatus(orig *appv1.Application, newStatus *appv1.SourceHydratorStatus) {
|
|
newAnnotations := make(map[string]string)
|
|
maps.Copy(newAnnotations, orig.GetAnnotations())
|
|
delete(newAnnotations, appv1.AnnotationKeyHydrate)
|
|
status := orig.Status.DeepCopy()
|
|
status.SourceHydrator = *newStatus
|
|
// PersistHydrationStatus has no request context; the status write roots its own trace.
|
|
ctrl.persistAppStatus(context.Background(), orig, status, newAnnotations)
|
|
}
|
|
|
|
func (ctrl *ApplicationController) AddHydrationQueueItem(key types.HydrationQueueKey) {
|
|
ctrl.hydrationQueue.AddRateLimited(key)
|
|
}
|
|
|
|
func (ctrl *ApplicationController) GetHydratorCommitMessageTemplate() (string, error) {
|
|
sourceHydratorCommitMessageKey, err := ctrl.settingsMgr.GetSourceHydratorCommitMessageTemplate()
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to get sourceHydrator commit message template key: %w", err)
|
|
}
|
|
|
|
return sourceHydratorCommitMessageKey, nil
|
|
}
|
|
|
|
func (ctrl *ApplicationController) GetHydratorReadmeMessageTemplate() (string, error) {
|
|
readmeTemplate, err := ctrl.settingsMgr.GetHydratorReadmeTemplate()
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to get sourceHydrator README message template: %w", err)
|
|
}
|
|
|
|
return readmeTemplate, nil
|
|
}
|
|
|
|
func (ctrl *ApplicationController) GetCommitAuthorName() (string, error) {
|
|
authorName, err := ctrl.settingsMgr.GetCommitAuthorName()
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to get commit author name: %w", err)
|
|
}
|
|
return authorName, nil
|
|
}
|
|
|
|
func (ctrl *ApplicationController) GetCommitAuthorEmail() (string, error) {
|
|
authorEmail, err := ctrl.settingsMgr.GetCommitAuthorEmail()
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to get commit author email: %w", err)
|
|
}
|
|
return authorEmail, nil
|
|
}
|