mirror of
https://github.com/argoproj/argo-cd
synced 2026-04-21 17:07:16 +00:00
Merge 0393073c23 into a7853eb7b6
This commit is contained in:
commit
bb4b44dbc8
7 changed files with 98 additions and 0 deletions
|
|
@ -377,6 +377,11 @@ func (r *ApplicationSetReconciler) Reconcile(ctx context.Context, req ctrl.Reque
|
|||
if err != nil {
|
||||
return ctrl.Result{}, fmt.Errorf("failed to get current applications for application set: %w", err)
|
||||
}
|
||||
|
||||
if err := r.setOrphanedLabels(ctx, logCtx, applicationSetInfo, currentApplications, generatedApplications); err != nil {
|
||||
logCtx.WithError(err).Error("failed to update orphaned application labels")
|
||||
}
|
||||
|
||||
err = r.updateResourcesStatus(ctx, logCtx, &applicationSetInfo, currentApplications)
|
||||
if err != nil {
|
||||
return ctrl.Result{}, fmt.Errorf("failed to update resources status for application set: %w", err)
|
||||
|
|
@ -860,6 +865,43 @@ func (r *ApplicationSetReconciler) getCurrentApplications(ctx context.Context, a
|
|||
return current.Items, nil
|
||||
}
|
||||
|
||||
// setOrphanedLabels adds the orphaned-by-applicationset label to Applications that exist in the
|
||||
// cluster but are no longer produced by the generator (and therefore kept only by a create-only
|
||||
// policy). It also removes the label from Applications that have come back into the desired set.
|
||||
func (r *ApplicationSetReconciler) setOrphanedLabels(ctx context.Context, logCtx *log.Entry, appSet argov1alpha1.ApplicationSet, current []argov1alpha1.Application, desired []argov1alpha1.Application) error {
|
||||
desiredMap := make(map[string]bool, len(desired))
|
||||
for _, app := range desired {
|
||||
desiredMap[app.Name] = true
|
||||
}
|
||||
|
||||
for i := range current {
|
||||
app := ¤t[i]
|
||||
isOrphaned := !desiredMap[app.Name]
|
||||
_, hasLabel := app.Labels[common.LabelKeyOrphanedByApplicationSet]
|
||||
|
||||
if isOrphaned == hasLabel {
|
||||
continue
|
||||
}
|
||||
|
||||
updated := app.DeepCopy()
|
||||
if isOrphaned {
|
||||
if updated.Labels == nil {
|
||||
updated.Labels = map[string]string{}
|
||||
}
|
||||
updated.Labels[common.LabelKeyOrphanedByApplicationSet] = appSet.Name
|
||||
logCtx.Infof("Marking application %q as orphaned by ApplicationSet %q", app.Name, appSet.Name)
|
||||
} else {
|
||||
delete(updated.Labels, common.LabelKeyOrphanedByApplicationSet)
|
||||
logCtx.Infof("Removing orphan label from application %q", app.Name)
|
||||
}
|
||||
|
||||
if err := r.Patch(ctx, updated, client.MergeFrom(app)); err != nil {
|
||||
return fmt.Errorf("failed to patch orphan label on application %q: %w", app.Name, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// deleteInCluster will delete Applications that are currently on the cluster, but not in appList.
|
||||
// The function must be called after all generators had been called and generated applications
|
||||
func (r *ApplicationSetReconciler) deleteInCluster(ctx context.Context, logCtx *log.Entry, applicationSet argov1alpha1.ApplicationSet, desiredApplications []argov1alpha1.Application) error {
|
||||
|
|
|
|||
|
|
@ -192,6 +192,10 @@ const (
|
|||
LabelKeyAppName = "app.kubernetes.io/name"
|
||||
// LabelKeyAutoLabelClusterInfo if set to true will automatically add extra labels from the cluster info (currently it only adds a k8s version label)
|
||||
LabelKeyAutoLabelClusterInfo = "argocd.argoproj.io/auto-label-cluster-info"
|
||||
// LabelKeyOrphanedByApplicationSet is set on Application objects that are no longer produced by
|
||||
// an ApplicationSet generator but are preserved by a create-only sync policy. The label value
|
||||
// is the name of the owning ApplicationSet.
|
||||
LabelKeyOrphanedByApplicationSet = "argocd.argoproj.io/orphaned-by-applicationset"
|
||||
// LabelKeyLegacyApplicationName is the legacy label (v0.10 and below) and is superseded by 'app.kubernetes.io/instance'
|
||||
LabelKeyLegacyApplicationName = "applications.argoproj.io/app-name"
|
||||
// LabelKeySecretType contains the type of argocd secret (currently: 'cluster', 'repository', 'repo-config' or 'repo-creds')
|
||||
|
|
|
|||
|
|
@ -115,6 +115,15 @@ export const ApplicationDetails: FC<RouteComponentProps<{appnamespace: string; n
|
|||
...getExtensionsState()
|
||||
}));
|
||||
|
||||
const [orphanedAppNames, setOrphanedAppNames] = useState<Set<string>>(new Set());
|
||||
|
||||
useEffect(() => {
|
||||
services.applications
|
||||
.list([], 'application', {fields: ['items.metadata.name'], selector: 'argocd.argoproj.io/orphaned-by-applicationset'})
|
||||
.then(apps => setOrphanedAppNames(new Set(apps.items.map(a => a.metadata.name))))
|
||||
.catch(() => {/* non-critical, ignore */});
|
||||
}, []);
|
||||
|
||||
const getAppNamespace = useCallback(() => {
|
||||
if (typeof props.match.params.appnamespace === 'undefined') {
|
||||
return '';
|
||||
|
|
@ -734,6 +743,7 @@ Are you sure you want to disable auto-sync and rollback application '${props.mat
|
|||
showCompactNodes: pref.groupNodes,
|
||||
userMsgs: pref.userHelpTipMsgs,
|
||||
tree,
|
||||
orphanedAppNames,
|
||||
onClearFilter: clearFilter,
|
||||
onGroupdNodeClick: (nodeIds: string[]) => openGroupNodeDetails(nodeIds),
|
||||
zoom: pref.zoom,
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ export interface ApplicationResourceTreeProps {
|
|||
nameWrap: boolean;
|
||||
setNodeExpansion: (node: string, isExpanded: boolean) => any;
|
||||
getNodeExpansion: (node: string) => boolean;
|
||||
orphanedAppNames?: Set<string>;
|
||||
}
|
||||
|
||||
interface Line {
|
||||
|
|
@ -821,6 +822,13 @@ function renderResourceNode(props: ApplicationResourceTreeProps, id: string, nod
|
|||
{node.hook && <i title='Resource lifecycle hook' className='fa fa-anchor' />}
|
||||
{healthState != null && <HealthStatusIcon state={healthState} />}
|
||||
{comparisonStatus != null && <ComparisonStatusIcon status={comparisonStatus} resource={!rootNode && node} />}
|
||||
{appNode && !rootNode && props.orphanedAppNames?.has(node.name) && (
|
||||
<i
|
||||
className='fa fa-exclamation-triangle'
|
||||
title='Orphaned by ApplicationSet — no longer generated, kept by create-only policy'
|
||||
style={{color: '#f4c030', marginRight: '2px'}}
|
||||
/>
|
||||
)}
|
||||
{appNode && !rootNode && (
|
||||
<Consumer>
|
||||
{ctx => {
|
||||
|
|
|
|||
|
|
@ -229,6 +229,7 @@ export const ApplicationStatusPanel = ({application, showDiff, showOperation, sh
|
|||
const infos = cntByCategory.get('info');
|
||||
const warnings = cntByCategory.get('warning');
|
||||
const errors = cntByCategory.get('error');
|
||||
const orphanedByAppSet = application.metadata.labels?.['argocd.argoproj.io/orphaned-by-applicationset'];
|
||||
const source = getAppDefaultSource(application);
|
||||
const hasMultipleSources = application.spec.sources?.length > 0;
|
||||
const revisionType = source?.repoURL?.startsWith('oci://') ? 'oci' : source?.chart ? 'helm' : 'git';
|
||||
|
|
@ -381,6 +382,19 @@ export const ApplicationStatusPanel = ({application, showDiff, showOperation, sh
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
{orphanedByAppSet && (
|
||||
<div className='application-status-panel__item'>
|
||||
{sectionHeader({title: 'ORPHANED'})}
|
||||
<div className='application-status-panel__item-value'>
|
||||
<a className='warning'>
|
||||
<i className='fa fa-exclamation-triangle application-status-panel__item-value__status-button' /> Orphaned by ApplicationSet
|
||||
</a>
|
||||
</div>
|
||||
<div className='application-status-panel__item-name'>
|
||||
No longer generated by <strong>{orphanedByAppSet}</strong>. Kept by create-only policy.
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<DataLoader
|
||||
noLoaderOnInputChange={true}
|
||||
input={application}
|
||||
|
|
|
|||
|
|
@ -150,6 +150,14 @@ export const ApplicationTableRow = ({app, selected, pref, ctx, syncApplication,
|
|||
)}
|
||||
<AppUtils.ComparisonStatusIcon status={app.status.sync.status} />
|
||||
<span>{app.status.sync.status}</span> <OperationState app={app} quiet={true} />
|
||||
{app.metadata.labels?.['argocd.argoproj.io/orphaned-by-applicationset'] && (
|
||||
<>
|
||||
<br />
|
||||
<a className='warning'>
|
||||
<i className='fa fa-exclamation-triangle' /> Orphaned
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
<DropDownMenu
|
||||
anchor={() => (
|
||||
<button className='argo-button argo-button--light argo-button--lg argo-button--short'>
|
||||
|
|
|
|||
|
|
@ -170,6 +170,18 @@ export const ApplicationTile = ({app, selected, pref, ctx, tileRef, syncApplicat
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* Orphaned warning row */}
|
||||
{app.metadata.labels?.['argocd.argoproj.io/orphaned-by-applicationset'] && (
|
||||
<div className='row'>
|
||||
<div className='columns small-3' />
|
||||
<div className='columns small-9'>
|
||||
<a className='warning'>
|
||||
<i className='fa fa-exclamation-triangle' /> Orphaned by ApplicationSet
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Repository row */}
|
||||
<div className='row'>
|
||||
<div className='columns small-3' title='Repository:'>
|
||||
|
|
|
|||
Loading…
Reference in a new issue