Compare commits

...

8 Commits

Author SHA1 Message Date
argo-bot
d5c6608827 Bump version to 2.1.4 2021-10-20 00:27:32 +00:00
argo-bot
0564de77e6 Bump version to 2.1.4 2021-10-20 00:27:18 +00:00
Alexander Matyushentsev
e1eec8a9dc fix: Operation has completed with phase: Running (#7482)
* fix: Operation has completed with phase: Running

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-10-19 17:17:34 -07:00
Alexander Matyushentsev
3d8d03f0a4 fix: Application status panel shows Syncing instead of Deleting (#7486)
Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-10-19 10:36:23 -07:00
pasha-codefresh
64f5c6aa85 fix: remove not existing repo (#7280)
* remove not existing repo

Signed-off-by: pashavictorovich <pavel@codefresh.io>

* fix test

Signed-off-by: pashavictorovich <pavel@codefresh.io>
2021-10-12 09:59:51 -07:00
Alexander Matyushentsev
f9e2fc9210 docs: update v2.3+ roadmap (#7353)
* docs: update v2.3+ roadmap

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>

* Address reviewer notes: Add 'Merge Argo CD Image Updater into Argo CD' and 'Multi-tenancy improvements'

Signed-off-by: Alexander Matyushentsev <AMatyushentsev@gmail.com>
2021-10-12 08:55:51 -07:00
Jan-Otto Kröpke
f9eac82928 docs: Kustomize load_restrictor -> load-restrictor (#7358)
Signed-off-by: Jan-Otto Kröpke <joe@adorsys.de>
2021-10-12 08:55:32 -07:00
Remington Breeze
bfbc19a583 fix(ui): Add Error Boundary around Extensions and comply with new Extensions API (#7215)
* fix: Add error boundary around Extensions and change path where UI looks for extensions

Signed-off-by: Remington Breeze <remington@breeze.software>

* Add error message to error boundary

Signed-off-by: Remington Breeze <remington@breeze.software>
2021-10-04 17:38:06 -07:00
19 changed files with 108 additions and 68 deletions

View File

@@ -1 +1 @@
2.1.3
2.1.4

View File

@@ -666,6 +666,16 @@ func (ctrl *ApplicationController) processAppOperationQueueItem() (processNext b
app := origApp.DeepCopy()
if app.Operation != nil {
// If we get here, we are about process an operation but we cannot rely on informer since it might has stale data.
// So always retrieve the latest version to ensure it is not stale to avoid unnecessary syncing.
// We cannot rely on informer since applications might be updated by both application controller and api server.
freshApp, err := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace).Get(context.Background(), app.ObjectMeta.Name, metav1.GetOptions{})
if err != nil {
log.Errorf("Failed to retrieve latest application state: %v", err)
return
}
app = freshApp
ctrl.processRequestedAppOperation(app)
} else if app.DeletionTimestamp != nil && app.CascadedDeletion() {
_, err = ctrl.finalizeApplicationDeletion(app)
@@ -1085,7 +1095,7 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta
}
appClient := ctrl.applicationClientset.ArgoprojV1alpha1().Applications(ctrl.namespace)
patchedApp, err := appClient.Patch(context.Background(), app.Name, types.MergePatchType, patchJSON, metav1.PatchOptions{})
_, err = appClient.Patch(context.Background(), app.Name, types.MergePatchType, patchJSON, metav1.PatchOptions{})
if err != nil {
// Stop retrying updating deleted application
if apierr.IsNotFound(err) {
@@ -1115,10 +1125,6 @@ func (ctrl *ApplicationController) setOperationState(app *appv1.Application, sta
ctrl.auditLogger.LogAppEvent(app, eventInfo, strings.Join(messages, " "))
ctrl.metricsServer.IncSync(app, state)
}
// write back to informer in order to avoid stale cache
if err := ctrl.appInformer.GetStore().Update(patchedApp); err != nil {
log.Warnf("Fails to update informer: %v", err)
}
return nil
})
}

View File

@@ -1083,12 +1083,10 @@ func TestProcessRequestedAppOperation_FailedNoRetries(t *testing.T) {
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
receivedPatch := map[string]interface{}{}
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
patchedApp := &v1alpha1.Application{}
if patchAction, ok := action.(kubetesting.PatchAction); ok {
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &patchedApp))
}
return true, patchedApp, nil
return true, nil, nil
})
ctrl.processRequestedAppOperation(app)
@@ -1110,12 +1108,10 @@ func TestProcessRequestedAppOperation_InvalidDestination(t *testing.T) {
fakeAppCs.Lock()
defer fakeAppCs.Unlock()
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
patchedApp := &v1alpha1.Application{}
if patchAction, ok := action.(kubetesting.PatchAction); ok {
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &patchedApp))
}
return true, patchedApp, nil
return true, nil, nil
})
}()
@@ -1138,12 +1134,10 @@ func TestProcessRequestedAppOperation_FailedHasRetries(t *testing.T) {
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
receivedPatch := map[string]interface{}{}
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
patchedApp := &v1alpha1.Application{}
if patchAction, ok := action.(kubetesting.PatchAction); ok {
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &patchedApp))
}
return true, patchedApp, nil
return true, nil, nil
})
ctrl.processRequestedAppOperation(app)
@@ -1183,12 +1177,10 @@ func TestProcessRequestedAppOperation_RunningPreviouslyFailed(t *testing.T) {
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
receivedPatch := map[string]interface{}{}
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
patchedApp := &v1alpha1.Application{}
if patchAction, ok := action.(kubetesting.PatchAction); ok {
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &patchedApp))
}
return true, patchedApp, nil
return true, nil, nil
})
ctrl.processRequestedAppOperation(app)
@@ -1218,12 +1210,10 @@ func TestProcessRequestedAppOperation_HasRetriesTerminated(t *testing.T) {
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
receivedPatch := map[string]interface{}{}
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
patchedApp := &v1alpha1.Application{}
if patchAction, ok := action.(kubetesting.PatchAction); ok {
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
assert.NoError(t, json.Unmarshal(patchAction.GetPatch(), &patchedApp))
}
return true, patchedApp, nil
return true, nil, nil
})
ctrl.processRequestedAppOperation(app)

View File

@@ -5,12 +5,16 @@
- [Config Management Tools Integrations (proposal)](#config-management-tools-integrations-proposal)
- [Argo CD Extensions (proposal)](#argo-cd-extensions-proposal)
- [Project scoped repository and clusters (proposal)](#project-scoped-repository-and-clusters-proposal)
- [Core Argo CD (proposal)](#core-argo-cd-aka-gitops-agent-proposal)
- [v2.3 and beyond](#v23-and-beyond)
- [Application Details Page Usability](#application-details-page-usability)
- [Cluster Management User Interface](#cluster-management-user-interface)
- [Input Forms UI Refresh](#input-forms-ui-refresh)
- [Merge ApplicationSet controller into Argo CD](#merge-applicationset-controller-into-argo-cd)
- [Merge Argo CD Notifications into Argo CD](#merge-argo-cd-notifications-into-argo-cd)
- [Merge Argo CD Image Updater into Argo CD](#merge-argo-cd-image-updater-into-argo-cd)
- [Compact Resources Tree](#compact-resources-tree)
- [Multi-tenancy improvements](#multi-tenancy-improvements)
- [GitOps Engine Enhancements](#gitops-engine-enhancements)
- [Completed](#completed)
- [✅ Core Argo CD (proposal)](#core-argo-cd-aka-gitops-agent-proposal)
- [✅ Core Functionality Bug Fixes](#-core-functionality-bug-fixes)
- [✅ Performance](#-performance)
- [✅ ApplicationSet](#-applicationset)
@@ -20,7 +24,6 @@
- [✅ Automated Registry Monitoring](#-automated-registry-monitoring)
- [✅ Projects Enhancements](#-projects-enhancements)
## v2.2
### Config Management Tools Integrations ([proposal](https://github.com/argoproj/argo-cd/pull/5927))
@@ -44,17 +47,33 @@ Instead of asking an administrator to change Argo CD settings end users can perf
## v2.3 and beyond
### Application Details Page Usability
### Input Forms UI Refresh
Application details page has accumulated multiple usability and feature requests such as
[Node view](https://github.com/argoproj/argo-cd/issues/1483),
Network view ([1](https://github.com/argoproj/argo-cd/issues/2892), [2](https://github.com/argoproj/argo-cd/issues/2338))
[etc](https://github.com/argoproj/argo-cd/issues/2199).
Improved design of the input forms in Argo CD Web UI: https://www.figma.com/file/IIlsFqqmM5UhqMVul9fQNq/Argo-CD?node-id=0%3A1
### Cluster Management User Interface
### Merge ApplicationSet controller into Argo CD
The ApplicationSet functionality is available in Argo CD out-of-the-box ([#7351](https://github.com/argoproj/argo-cd/issues/7351)).
The Argo CD UI/CLI/API allows to manage ApplicationSet resources same as Argo CD Applications ([#7352](https://github.com/argoproj/argo-cd/issues/7352)).
### Merge Argo CD Notifications into Argo CD
The [Argo CD Notifications](https://github.com/argoproj-labs/argocd-notifications) should be merged into Argo CD and available out-of-the-box: [#7350](https://github.com/argoproj/argo-cd/issues/7350)
### Merge Argo CD Image Updater into Argo CD
The [Argo CD Image Updater](https://github.com/argoproj-labs/argocd-image-updater) should be merged into Argo CD and available out-of-the-box: [#7385](https://github.com/argoproj/argo-cd/issues/7385)
### Compact resources tree
An ability to collaps leaf resources tree to improve visualization of very large applications: [#7349](https://github.com/argoproj/argo-cd/issues/7349)
### Multi-tenancy improvements
The multi-tenancy improvements that allow end-users to create Argo CD applications using Kubernetes directly without accessing Argo CD API.
* [Applications outside argocd namespace](https://github.com/argoproj/argo-cd/pull/6409)
* [AppSource](https://github.com/argoproj-labs/appsource)
Argo CD has information about whole clusters, not just applications in it.
We need to provide a user interface for cluster administrators that visualize cluster level resources.
### GitOps Engine Enhancements
@@ -109,7 +128,7 @@ to improve user experience.
To make Argo CD successful we need to build tools that enable Argo CD administrators to handle scalability and performance issues in a self-service model.
That includes more metrics, out of the box alerts and a cluster management user interface.
That includes more metrics, out-of-the-box alerts and a cluster management user interface.
### ✅ Argo CD Notifications

View File

@@ -35,8 +35,8 @@ metadata:
app.kubernetes.io/name: argocd-cm
app.kubernetes.io/part-of: argocd
data:
kustomize.buildOptions: --load_restrictor LoadRestrictionsNone
kustomize.buildOptions.v3.9.1: --output /tmp
kustomize.buildOptions: --load-restrictor LoadRestrictionsNone
kustomize.buildOptions.v4.4.0: --output /tmp
```
## Custom Kustomize versions

View File

@@ -5,7 +5,7 @@ kind: Kustomization
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: v2.1.3
newTag: v2.1.4
resources:
- ./application-controller
- ./dex

View File

@@ -2988,7 +2988,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -3185,7 +3185,7 @@ spec:
key: controller.default.cache.expiration
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -11,4 +11,4 @@ resources:
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: v2.1.3
newTag: v2.1.4

View File

@@ -11,7 +11,7 @@ patchesStrategicMerge:
images:
- name: quay.io/argoproj/argocd
newName: quay.io/argoproj/argocd
newTag: v2.1.3
newTag: v2.1.4
resources:
- ../../base/application-controller
- ../../base/dex

View File

@@ -3684,7 +3684,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -3901,7 +3901,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -4154,7 +4154,7 @@ spec:
key: server.default.cache.expiration
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -4350,7 +4350,7 @@ spec:
key: controller.default.cache.expiration
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -1071,7 +1071,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -1288,7 +1288,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -1541,7 +1541,7 @@ spec:
key: server.default.cache.expiration
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -1737,7 +1737,7 @@ spec:
key: controller.default.cache.expiration
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -3049,7 +3049,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -3230,7 +3230,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -3479,7 +3479,7 @@ spec:
key: server.default.cache.expiration
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -3669,7 +3669,7 @@ spec:
key: controller.default.cache.expiration
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -436,7 +436,7 @@ spec:
- -n
- /usr/local/bin/argocd
- /shared/argocd-dex
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
name: copyutil
volumeMounts:
@@ -617,7 +617,7 @@ spec:
value: /helm-working-dir
- name: HELM_DATA_HOME
value: /helm-working-dir
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
@@ -866,7 +866,7 @@ spec:
key: server.default.cache.expiration
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
livenessProbe:
httpGet:
@@ -1056,7 +1056,7 @@ spec:
key: controller.default.cache.expiration
name: argocd-cmd-params-cm
optional: true
image: quay.io/argoproj/argocd:v2.1.3
image: quay.io/argoproj/argocd:v2.1.4
imagePullPolicy: Always
livenessProbe:
httpGet:

View File

@@ -2,6 +2,7 @@ import {DataLoader, Tab, Tabs} from 'argo-ui';
import {useData} from 'argo-ui/v2';
import * as React from 'react';
import {EventsList, YamlEditor} from '../../../shared/components';
import {ErrorBoundary} from '../../../shared/components/error-boundary/error-boundary';
import {Context} from '../../../shared/context';
import {Application, ApplicationTree, AppSourceType, Event, RepoAppDetails, ResourceNode, State, SyncStatuses} from '../../../shared/models';
import {services} from '../../../shared/services';
@@ -119,9 +120,9 @@ export const ResourceDetails = (props: ResourceDetailsProps) => {
title: 'More',
key: 'extension',
content: (
<div>
<ErrorBoundary message={`Something went wrong with Extension for ${state.kind}`}>
<ExtensionComponent tree={tree} resource={state} />
</div>
</ErrorBoundary>
)
});
}

View File

@@ -40,6 +40,12 @@ test('getOperationType.Sync.Operation', () => {
expect(state).toBe('Sync');
});
test('getOperationType.DeleteAndRecentSync', () => {
const state = getOperationType({metadata: {deletionTimestamp: '123'}, status: {operationState: {operation: {sync: {}}}}} as Application);
expect(state).toBe('Delete');
});
test('getOperationType.Sync.Status', () => {
const state = getOperationType({metadata: {}, status: {operationState: {operation: {sync: {}}}}} as Application);

View File

@@ -597,12 +597,12 @@ export const getAppOperationState = (app: appModels.Application): appModels.Oper
export function getOperationType(application: appModels.Application) {
const operation = application.operation || (application.status && application.status.operationState && application.status.operationState.operation);
if (application.metadata.deletionTimestamp && !application.operation) {
return 'Delete';
}
if (operation && operation.sync) {
return 'Sync';
}
if (application.metadata.deletionTimestamp) {
return 'Delete';
}
return 'Unknown';
}

View File

@@ -0,0 +1,20 @@
import * as React from 'react';
export class ErrorBoundary extends React.Component<{message?: string}, {hasError: boolean}> {
constructor(props: any) {
super(props);
this.state = {hasError: false};
}
static getDerivedStateFromError(error: React.ErrorInfo) {
return {hasError: true};
}
render() {
if (this.state.hasError) {
return <h1>{this.props.message ? this.props.message : 'Something went wrong.'}</h1>;
}
return this.props.children;
}
}

View File

@@ -1,7 +1,7 @@
import * as React from 'react';
import {ApplicationTree, State} from '../models';
const extensions: {[key: string]: Extension} = {};
const extensions: {resources: {[key: string]: Extension}} = {resources: {}};
const cache = new Map<string, Promise<Extension>>();
export interface Extension {
@@ -15,14 +15,14 @@ export interface ExtensionComponentProps {
export class ExtensionsService {
public async loadResourceExtension(group: string, kind: string): Promise<Extension> {
const key = `${group}-${kind}`;
const key = `${group}/${kind}`;
const res =
cache.get(key) ||
new Promise<Extension>((resolve, reject) => {
const script = document.createElement('script');
script.src = `extensions/${group}/${kind}/ui/extensions.js`;
script.src = `extensions/resources/${group}/${kind}/ui/extensions.js`;
script.onload = () => {
const ext = extensions[key];
const ext = extensions.resources[key];
if (!ext) {
reject(`Failed to load extension for ${group}/${kind}`);
} else {

View File

@@ -327,7 +327,6 @@ func TestNewFactory(t *testing.T) {
defer addBinDirToPath.Close()
closer := log.Debug()
defer closer()
type args struct {
url string
insecureIgnoreHostKey bool
@@ -337,7 +336,6 @@ func TestNewFactory(t *testing.T) {
args args
}{
{"GitHub", args{url: "https://github.com/argoproj/argocd-example-apps"}},
{"Azure", args{url: "https://jsuen0437@dev.azure.com/jsuen0437/jsuen/_git/jsuen"}},
}
for _, tt := range tests {