Files
cd/controller/hydrator_dependencies.go
zeekay 01a52090a9 pkg/client, mocks: regenerate off the apps.hanzo.ai group
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.
2026-09-05 13:44:46 -07:00

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
}