argocd-sync-failed #16
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: ArgoCD Deployment Failure Handler | |
| on: | |
| repository_dispatch: | |
| types: [argocd-sync-failed] | |
| permissions: | |
| issues: write | |
| contents: read | |
| jobs: | |
| create-issue: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Create GitHub Issue | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| const payload = context.payload.client_payload || {}; | |
| const appName = payload.app_name || 'unknown'; | |
| const clusterUrl = payload.cluster || 'unknown'; | |
| const clusterName = payload.cluster_name || clusterUrl; | |
| const namespace = payload.namespace || 'default'; | |
| const healthStatus = payload.health_status || 'unknown'; | |
| const syncStatus = payload.sync_status || 'unknown'; | |
| const message = payload.message || 'No error message available'; | |
| const revision = payload.revision || 'unknown'; | |
| const repoUrl = payload.repo_url || ''; | |
| const targetRevision = payload.target_revision || ''; | |
| const timestamp = payload.timestamp || new Date().toISOString(); | |
| const resources = payload.resources || []; | |
| // Build degraded resources section | |
| let degradedDetails = ''; | |
| const degradedResources = resources.filter(r => | |
| r.health && (r.health.status === 'Degraded' || r.health.status === 'Missing' || r.health.status === 'Unknown') | |
| ); | |
| if (degradedResources.length > 0) { | |
| degradedDetails = '\n### π΄ Degraded Resources\n\n'; | |
| for (const resource of degradedResources) { | |
| const kind = resource.kind || 'Unknown'; | |
| const name = resource.name || 'unknown'; | |
| const resourceNamespace = resource.namespace || namespace; | |
| const healthStatus = resource.health?.status || 'Unknown'; | |
| const healthMessage = resource.health?.message || 'No message'; | |
| const syncStatus = resource.status || 'Unknown'; | |
| degradedDetails += `#### ${kind}: \`${name}\`\n\n`; | |
| degradedDetails += `- **Namespace:** ${resourceNamespace}\n`; | |
| degradedDetails += `- **Health Status:** ${healthStatus}\n`; | |
| degradedDetails += `- **Sync Status:** ${syncStatus}\n`; | |
| degradedDetails += `- **Message:** ${healthMessage}\n\n`; | |
| // Add kubectl command for this specific resource | |
| degradedDetails += `**Troubleshoot:**\n\`\`\`bash\n`; | |
| degradedDetails += `kubectl describe ${kind.toLowerCase()} ${name} -n ${resourceNamespace}\n`; | |
| if (kind === 'Pod' || kind === 'Deployment' || kind === 'StatefulSet' || kind === 'DaemonSet') { | |
| degradedDetails += `kubectl logs ${kind.toLowerCase()}/${name} -n ${resourceNamespace}\n`; | |
| } | |
| degradedDetails += `\`\`\`\n\n`; | |
| } | |
| } | |
| const issueTitle = `π¨ ArgoCD Deployment Failed: ${appName}`; | |
| const issueBody = `## ArgoCD Deployment Failure | |
| **Application:** \`${appName}\` | |
| **Timestamp:** ${timestamp} | |
| ### Cluster Information | |
| | Field | Value | | |
| |-------|-------| | |
| | Cluster Name | \`${clusterName}\` | | |
| | Cluster URL | \`${clusterUrl}\` | | |
| | Namespace | \`${namespace}\` | | |
| ### Application Status | |
| | Field | Value | | |
| |-------|-------| | |
| | Health Status | \`${healthStatus}\` | | |
| | Sync Status | \`${syncStatus}\` | | |
| | Revision | \`${revision}\` | | |
| | Target Revision | \`${targetRevision}\` | | |
| | Repository | ${repoUrl} | | |
| ### Error Message | |
| \`\`\` | |
| ${message} | |
| \`\`\` | |
| ${degradedDetails} | |
| ### Troubleshooting Commands | |
| \`\`\`bash | |
| # Check application status in ArgoCD | |
| argocd app get ${appName} | |
| # Check pods in namespace | |
| kubectl get pods -n ${namespace} | |
| # Describe failed pods | |
| kubectl describe pods -n ${namespace} | |
| # Get pod logs | |
| kubectl logs -n ${namespace} <pod-name> | |
| # Check events | |
| kubectl get events -n ${namespace} --sort-by='.lastTimestamp' | |
| \`\`\` | |
| ### Quick Links | |
| - [ArgoCD UI](https://localhost:8080/applications/${appName}) | |
| - [Source Repository](${repoUrl}) | |
| --- | |
| *This issue was automatically created by ArgoCD Notifications* | |
| `; | |
| // Check if similar issue already exists (open) | |
| const existingIssues = await github.rest.issues.listForRepo({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| state: 'open', | |
| labels: 'argocd-deployment-failure', | |
| per_page: 100 | |
| }); | |
| const duplicateIssue = existingIssues.data.find(issue => | |
| issue.title.includes(appName) && issue.title.includes('Deployment Failed') | |
| ); | |
| if (duplicateIssue) { | |
| // Add comment to existing issue instead of creating new one | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: duplicateIssue.number, | |
| body: `### π Deployment Failed Again\n\n**Timestamp:** ${timestamp}\n**Revision:** \`${revision}\`\n\n${message ? '**Error:**\n```\n' + message + '\n```' : ''}` | |
| }); | |
| console.log(`Updated existing issue #${duplicateIssue.number}`); | |
| } else { | |
| // Create new issue | |
| const issue = await github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: issueTitle, | |
| body: issueBody, | |
| labels: ['argocd-deployment-failure', 'automated', 'bug'] | |
| }); | |
| console.log(`Created issue #${issue.data.number}`); | |
| } |