From bf20ad110250d298896e439fe64d11677428f02c Mon Sep 17 00:00:00 2001 From: LeeSeolHui Date: Sun, 2 Mar 2025 15:43:27 +0900 Subject: [PATCH 1/2] study --- .../06/README.md" | 108 ++++ .../06/application-yaml.yaml" | 30 + .../06/argocd-notifications-cm.yaml" | 538 ++++++++++++++++++ .../06/argocd-notifications-secret.yaml" | 8 + 4 files changed, 684 insertions(+) create mode 100644 "2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/README.md" create mode 100644 "2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/application-yaml.yaml" create mode 100644 "2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/argocd-notifications-cm.yaml" create mode 100644 "2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/argocd-notifications-secret.yaml" diff --git "a/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/README.md" "b/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/README.md" new file mode 100644 index 0000000..019c1d4 --- /dev/null +++ "b/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/README.md" @@ -0,0 +1,108 @@ +# ArgoCD Notification Controller 분석 + +## 1. Notification Controller 생성 과정 + +### 1-1. `NewFactory()` +`NewFactory()`는 `Settings` 기반으로 `apiFactory`를 초기화하고, ConfigMap/Secret을 조회하는 Lister를 설정한다. + +- **Informer에 이벤트 핸들러를 등록**하여 Secret/ConfigMap 변경을 감시한다. +- 특정 Secret 또는 ConfigMap이 추가/삭제/수정될 경우 `invalidateIfHasName()`을 실행한다. + - `obj`의 이름이 감시 대상(`name`)과 일치하면, 해당 네임스페이스의 API 캐시를 무효화한다. +- **캐시를 무효화(`apiMap[namespace] = nil`)하여 변경된 설정을 반영할 수 있도록 한다.** + +### 1-2. `skipProcessingOpt()` +Object를 알림에서 제외할지 확인한다. +- `true`면 skip하고, `false`면 skip하지 않는다. + +#### Skip 조건 +1. `obj`가 `*unstructured.Unstructured` 타입이 아닌 경우 +2. 애플리케이션이 `namespace` 또는 `applicationNamespaces`에 속하지 않은 경우 +3. 애플리케이션의 `sync status`가 최신 상태가 아닌 경우 + +### 1-3. `alertDestinations()` +- 알림 목적지를 가져와서 `alertDestinationsOpt`에 할당한다. +- **legacy annotations와 새로운 annotations를 합쳐서 가져온다.** + - 과거 버전 프로젝트에서도 알림 설정이 정상 동작하도록 보장하기 위함. + +### 1-4. Controller 생성 +`NewControllerWithNamespaceSupport()` +- `namespaceSupport`를 `true`로 설정하고 `NewController`를 호출. +- 내부적으로 **큐(queue)를 활용하여 이벤트 기반 알림 처리**를 수행함. +- **Informer에서 변경이 감지되면 `queue.Add()`를 호출하여 이벤트를 큐에 추가함.** + +## 2. Notification Controller 실행 과정 + +### 2-1. `processQueueItem()` 실행 +- Queue에서 이벤트를 꺼내와서 **EventSequence를 초기화**한다. +- **EventSequence는 알림 처리를 위한 이벤트 시퀀스 정보를 저장하는 구조체**이다. + +| 필드 | 타입 | 설명 | +| --- | --- | --- | +| `Delivered` | `[]NotificationDelivery` | 성공적으로 전송된 알림 목록 | +| `Errors` | `[]error` | 처리 중 발생한 오류 목록 | +| `Warnings` | `[]error` | 경고 메시지 목록 | + +### 2-2. 처리 흐름 +1. **Resource 조회** → 정상 조회되면 `resource` 할당. +2. **Skip 여부 판단** → 특정 조건 충족 시 알림 처리 스킵. +3. **Namespace 기반 API 설정 로드** + - `namespaceSupport == true`일 때 전역 네임스페이스 활용. + - `GetAPI()` 실행 시 `GetAPIsFromNamespace(DefaultNamespace)` 호출. + - `GetAPIsFromNamespace(namespace)` 실행하여 특정 네임스페이스 API 설정 로드. +4. **ConfigMap 및 Secret 파일 로드** → `NewService`를 생성. +5. **API 객체 생성 완료 후 트리거 실행** → `Trigger svc.Run()` + +## 3. 알림 전송 흐름 (`res` 처리) +```go +for _, cr := range res { + c.metricsRegistry.IncTriggerEvaluationsCounter(trigger, cr.Triggered) + + if !cr.Triggered { + for _, to := range destinations { + notificationsState.SetAlreadyNotified(c.isSelfServiceConfigureApi(api), apiNamespace, trigger, cr, to, false) + } + continue + } + + for _, to := range destinations { + if changed := notificationsState.SetAlreadyNotified(c.isSelfServiceConfigureApi(api), apiNamespace, trigger, cr, to, true); !changed { + logEntry.Infof("Notification about condition '%s.%s' already sent to '%v' using the configuration in namespace %s", trigger, cr.Key, to, apiNamespace) + eventSequence.addDelivered(NotificationDelivery{ + Trigger: trigger, + Destination: to, + AlreadyNotified: true, + }) + } else { + logEntry.Infof("Sending notification about condition '%s.%s' to '%v' using the configuration in namespace %s", trigger, cr.Key, to, apiNamespace) + if err := api.Send(un.Object, cr.Templates, to); err != nil { + logEntry.Errorf("Failed to notify recipient %s defined in resource %s/%s: %v using the configuration in namespace %s", to, resource.GetNamespace(), resource.GetName(), err, apiNamespace) + notificationsState.SetAlreadyNotified(c.isSelfServiceConfigureApi(api), apiNamespace, trigger, cr, to, false) + c.metricsRegistry.IncDeliveriesCounter(trigger, to.Service, false) + eventSequence.addError(fmt.Errorf("failed to deliver notification %s to %s: %v using the configuration in namespace %s", trigger, to, err, apiNamespace)) + } else { + logEntry.Debugf("Notification %s was sent using the configuration in namespace %s", to.Recipient, apiNamespace) + c.metricsRegistry.IncDeliveriesCounter(trigger, to.Service, true) + eventSequence.addDelivered(NotificationDelivery{ + Trigger: trigger, + Destination: to, + AlreadyNotified: false, + }) + } + } + } +} +``` + +### 3-1. 실행 흐름 분석 +1. `res`의 각 요소 `cr`을 순회하며, `trigger`가 발생했는지 확인. +2. 트리거가 발생하지 않았다면 해당 목적지(`to`)에 대해 **알림이 이미 전송되었음을 기록하고 종료**. +3. 트리거가 발생한 경우: + - `notificationsState.SetAlreadyNotified()`를 호출하여 이미 알림이 전송된 상태인지 확인. + - **이미 알림이 전송되었다면**, 로그를 남기고 `eventSequence.addDelivered()` 호출. + - **새롭게 알림을 보내야 하는 경우**, `api.Send()`를 호출하여 알림 전송. + - 전송 실패 시 로그를 남기고 실패 카운터 증가. + - 전송 성공 시 성공 카운터 증가 및 `eventSequence.addDelivered()` 호출. + +## 4. 결론 +ArgoCD Notification Controller는 Informer를 활용하여 설정 변경을 감지하고, Queue를 이용하여 이벤트를 비동기적으로 처리한다. `processQueueItem()`을 통해 알림 전송 여부를 판단하고, 알림을 전송하며 그 결과를 `eventSequence`에 기록하는 방식으로 동작한다. 이를 통해 안정적으로 알림을 관리하고, 실패한 알림에 대한 재시도를 할 수 있도록 구성되어 있다. + diff --git "a/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/application-yaml.yaml" "b/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/application-yaml.yaml" new file mode 100644 index 0000000..1cf8d08 --- /dev/null +++ "b/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/application-yaml.yaml" @@ -0,0 +1,30 @@ +--- +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: nginx + namespace: argocd + annotations: + notifications.argoproj.io/subscribe.on-deployed.slack: alerts + notifications.argoproj.io/subscribe.on-sync-failed.slack: alerts + notifications.argoproj.io/subscribe.on-sync-succeeded.slack: alerts + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + project: default + source: + repoURL: https://github.com/antonputra/lesson-179.git + targetRevision: HEAD + path: nginx + destination: + server: https://kubernetes.default.svc + syncPolicy: + automated: + prune: true + selfHeal: true + allowEmpty: false + syncOptions: + - Validate=true + - CreateNamespace=false + - PrunePropagationPolicy=foreground + - PruneLast=true diff --git "a/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/argocd-notifications-cm.yaml" "b/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/argocd-notifications-cm.yaml" new file mode 100644 index 0000000..c9c2929 --- /dev/null +++ "b/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/argocd-notifications-cm.yaml" @@ -0,0 +1,538 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: argocd-notifications-cm + namespace: argocd +data: + context: | + argocdUrl: http://localhost:8080 + service.slack: | + token: $slack-token + template.app-created: | + email: + subject: Application {{.app.metadata.name}} has been created. + message: Application {{.app.metadata.name}} has been created. + teams: + title: Application {{.app.metadata.name}} has been created. + template.app-deleted: | + email: + subject: Application {{.app.metadata.name}} has been deleted. + message: Application {{.app.metadata.name}} has been deleted. + teams: + title: Application {{.app.metadata.name}} has been deleted. + template.app-deployed: | + email: + subject: New version of an application {{.app.metadata.name}} is up and running. + message: | + {{if eq .serviceType "slack"}}:white_check_mark:{{end}} New version of *{{.app.metadata.name}}* is deployed. + slack: + attachments: | + [{ + "color": "#18be52", + "fields": [ + { + "title": "Author", + "value": "{{(call .repo.GetCommitMetadata .app.status.sync.revision).Author}}", + "short": true + }, + { + "title": "Message", + "value": "{{(call .repo.GetCommitMetadata .app.status.sync.revision).Message}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $image := .app.status.summary.images}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "Version", + "value": "{{$image}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Sync Status", + "value": "{{.app.status.sync.status}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + }, + { + "name": "Revision", + "value": "{{.app.status.sync.revision}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: |- + [{ + "@type":"OpenUri", + "name":"Operation Application", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + themeColor: '#000080' + title: New version of an application {{.app.metadata.name}} is up and running. + template.app-health-degraded: | + email: + subject: Application {{.app.metadata.name}} has degraded. + message: | + {{if eq .serviceType "slack"}}:exclamation:{{end}} Application {{.app.metadata.name}} has degraded. + Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}. + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link": "{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#f4c030", + "fields": [ + { + "title": "Health Status", + "value": "{{.app.status.health.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Health Status", + "value": "{{.app.status.health.status}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: | + [{ + "@type":"OpenUri", + "name":"Open Application", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + themeColor: '#FF0000' + title: Application {{.app.metadata.name}} has degraded. + template.app-sync-failed: | + email: + subject: Failed to sync application {{.app.metadata.name}}. + message: | + {{if eq .serviceType "slack"}}:exclamation:{{end}} The sync operation of application {{.app.metadata.name}} has failed at {{.app.status.operationState.finishedAt}} with the following error: {{.app.status.operationState.message}} + Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true . + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#E96D76", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Sync Status", + "value": "{{.app.status.sync.status}}" + }, + { + "name": "Failed at", + "value": "{{.app.status.operationState.finishedAt}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: |- + [{ + "@type":"OpenUri", + "name":"Open Operation", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + themeColor: '#FF0000' + title: Failed to sync application {{.app.metadata.name}}. + template.app-sync-running: | + email: + subject: Start syncing application {{.app.metadata.name}}. + message: | + The sync operation of application {{.app.metadata.name}} has started at {{.app.status.operationState.startedAt}}. + Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true . + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#0DADEA", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Sync Status", + "value": "{{.app.status.sync.status}}" + }, + { + "name": "Started at", + "value": "{{.app.status.operationState.startedAt}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: |- + [{ + "@type":"OpenUri", + "name":"Open Operation", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + title: Start syncing application {{.app.metadata.name}}. + template.app-sync-status-unknown: | + email: + subject: Application {{.app.metadata.name}} sync status is 'Unknown' + message: | + {{if eq .serviceType "slack"}}:exclamation:{{end}} Application {{.app.metadata.name}} sync is 'Unknown'. + Application details: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}. + {{if ne .serviceType "slack"}} + {{range $c := .app.status.conditions}} + * {{$c.message}} + {{end}} + {{end}} + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#E96D76", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Sync Status", + "value": "{{.app.status.sync.status}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: |- + [{ + "@type":"OpenUri", + "name":"Open Application", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + title: Application {{.app.metadata.name}} sync status is 'Unknown' + template.app-sync-succeeded: | + email: + subject: Application {{.app.metadata.name}} has been successfully synced. + message: | + {{if eq .serviceType "slack"}}:white_check_mark:{{end}} Application {{.app.metadata.name}} has been successfully synced at {{.app.status.operationState.finishedAt}}. + Sync operation details are available at: {{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true . + slack: + attachments: | + [{ + "title": "{{ .app.metadata.name}}", + "title_link":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}", + "color": "#18be52", + "fields": [ + { + "title": "Sync Status", + "value": "{{.app.status.sync.status}}", + "short": true + }, + { + "title": "Repository", + "value": "{{.app.spec.source.repoURL}}", + "short": true + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "title": "{{$c.type}}", + "value": "{{$c.message}}", + "short": true + } + {{end}} + ] + }] + deliveryPolicy: Post + groupingKey: "" + notifyBroadcast: false + teams: + facts: | + [{ + "name": "Sync Status", + "value": "{{.app.status.sync.status}}" + }, + { + "name": "Synced at", + "value": "{{.app.status.operationState.finishedAt}}" + }, + { + "name": "Repository", + "value": "{{.app.spec.source.repoURL}}" + } + {{range $index, $c := .app.status.conditions}} + {{if not $index}},{{end}} + {{if $index}},{{end}} + { + "name": "{{$c.type}}", + "value": "{{$c.message}}" + } + {{end}} + ] + potentialAction: |- + [{ + "@type":"OpenUri", + "name":"Operation Details", + "targets":[{ + "os":"default", + "uri":"{{.context.argocdUrl}}/applications/{{.app.metadata.name}}?operation=true" + }] + }, + { + "@type":"OpenUri", + "name":"Open Repository", + "targets":[{ + "os":"default", + "uri":"{{.app.spec.source.repoURL | call .repo.RepoURLToHTTPS}}" + }] + }] + themeColor: '#000080' + title: Application {{.app.metadata.name}} has been successfully synced + trigger.on-created: | + - description: Application is created. + oncePer: app.metadata.name + send: + - app-created + when: "true" + trigger.on-deleted: | + - description: Application is deleted. + oncePer: app.metadata.name + send: + - app-deleted + when: app.metadata.deletionTimestamp != nil + trigger.on-deployed: | + - description: Application is synced and healthy. Triggered once per commit. + oncePer: app.status.operationState.syncResult.revision + send: + - app-deployed + when: app.status.operationState.phase in ['Succeeded'] and app.status.health.status + == 'Healthy' + trigger.on-health-degraded: | + - description: Application has degraded + send: + - app-health-degraded + when: app.status.health.status == 'Degraded' + trigger.on-sync-failed: | + - description: Application syncing has failed + send: + - app-sync-failed + when: app.status.operationState.phase in ['Error', 'Failed'] + trigger.on-sync-running: | + - description: Application is being synced + send: + - app-sync-running + when: app.status.operationState.phase in ['Running'] + trigger.on-sync-status-unknown: | + - description: Application status is 'Unknown' + send: + - app-sync-status-unknown + when: app.status.sync.status == 'Unknown' + trigger.on-sync-succeeded: | + - description: Application syncing has succeeded + send: + - app-sync-succeeded + when: app.status.operationState.phase in ['Succeeded'] diff --git "a/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/argocd-notifications-secret.yaml" "b/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/argocd-notifications-secret.yaml" new file mode 100644 index 0000000..5128ce4 --- /dev/null +++ "b/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/argocd-notifications-secret.yaml" @@ -0,0 +1,8 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: argocd-notifications-secret + namespace: argocd +stringData: + slack-token: <<슬랫 bot 토큰>> From 16c784a940096e5747fe18e2554bacacabdbe9e3 Mon Sep 17 00:00:00 2001 From: LeeSeolHui Date: Sun, 2 Mar 2025 15:46:50 +0900 Subject: [PATCH 2/2] add TODO --- .../06/README.md" | 2 ++ .../06/argocd-notifications-secret.yaml" | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git "a/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/README.md" "b/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/README.md" index 019c1d4..3b6ed37 100644 --- "a/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/README.md" +++ "b/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/README.md" @@ -1,5 +1,7 @@ # ArgoCD Notification Controller 분석 +TODO: 북마크별로 상세 설명 필요 + ## 1. Notification Controller 생성 과정 ### 1-1. `NewFactory()` diff --git "a/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/argocd-notifications-secret.yaml" "b/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/argocd-notifications-secret.yaml" index 5128ce4..09e1476 100644 --- "a/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/argocd-notifications-secret.yaml" +++ "b/2401_argocd\354\275\224\353\223\234\353\266\204\354\204\235/06/argocd-notifications-secret.yaml" @@ -5,4 +5,4 @@ metadata: name: argocd-notifications-secret namespace: argocd stringData: - slack-token: <<슬랫 bot 토큰>> + slack-token: <<슬랙 bot 토큰>>