Last active
January 29, 2025 00:01
-
-
Save troykelly/94c9d1fc3011abd3f0ba0a679a38c31a to your computer and use it in GitHub Desktop.
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
--- /home/vscode/.local/lib/python3.11/site-packages/octodns_cloudflare/__init__.py 2025-01-28 23:37:03.687375946 +0000 | |
+++ /workspaces/dns/temp-cloudflare-patch/__init__.py 2025-01-28 23:40:24.543880502 +0000 | |
@@ -1072,33 +1072,87 @@ | |
self._try_request('DELETE', path) | |
def _apply_Delete(self, change): | |
+ """ | |
+ Delete an existing record (DNS record or Pagerule) in Cloudflare. | |
+ | |
+ Raises CloudflareError if critical data (e.g., zone_id, record id) is missing, | |
+ so the entire sync fails rather than silently skipping. | |
+ """ | |
existing = change.existing | |
existing_name = existing.fqdn[:-1] | |
- # Make sure to map ALIAS to CNAME when looking for the target to delete | |
+ # Map ALIAS to CNAME for the purposes of deletion | |
existing_type = 'CNAME' if existing._type == 'ALIAS' else existing._type | |
+ | |
for record in self.zone_records(existing.zone): | |
+ # Handle pagerules | |
if 'targets' in record and self.pagerules: | |
- uri = record['targets'][0]['constraint']['value'] | |
+ constraint = record['targets'][0].get('constraint') | |
+ if not constraint or 'value' not in constraint: | |
+ raise CloudflareError({ | |
+ 'errors': [{ | |
+ 'message': ( | |
+ f"Pagerule for '{existing_name}' missing " | |
+ f"'constraint' or 'constraint.value'." | |
+ ) | |
+ }] | |
+ }) | |
+ | |
+ uri = constraint['value'] | |
uri = '//' + uri if not uri.startswith('http') else uri | |
parsed_uri = urlsplit(uri) | |
record_name = parsed_uri.netloc | |
record_type = 'URLFWD' | |
- zone_id = self.zones.get(existing.zone.name, False) | |
- if ( | |
- existing_name == record_name | |
- and existing_type == record_type | |
- ): | |
- path = f'/zones/{zone_id}/pagerules/{record["id"]}' | |
+ zone_id = self.zones.get(existing.zone.name) | |
+ if not zone_id: | |
+ raise CloudflareError({ | |
+ 'errors': [{ | |
+ 'message': ( | |
+ f"No zone_id found for pagerule in zone " | |
+ f"{existing.zone.name}." | |
+ ) | |
+ }] | |
+ }) | |
+ | |
+ rule_id = record.get('id') | |
+ if not rule_id: | |
+ raise CloudflareError({ | |
+ 'errors': [{ | |
+ 'message': ( | |
+ f"No pagerule 'id' found for record {record}." | |
+ ) | |
+ }] | |
+ }) | |
+ | |
+ if existing_name == record_name and existing_type == record_type: | |
+ path = f'/zones/{zone_id}/pagerules/{rule_id}' | |
self._try_request('DELETE', path) | |
+ | |
+ # Handle normal DNS records | |
else: | |
if ( | |
- existing_name == record['name'] | |
- and existing_type == record['type'] | |
+ existing_name == record.get('name') | |
+ and existing_type == record.get('type') | |
): | |
- path = ( | |
- f'/zones/{record["zone_id"]}/dns_records/' | |
- f'{record["id"]}' | |
- ) | |
+ zone_id = record.get('zone_id') or self.zones.get(existing.zone.name) | |
+ if not zone_id: | |
+ raise CloudflareError({ | |
+ 'errors': [{ | |
+ 'message': ( | |
+ f"No zone_id found for record {record} " | |
+ f"in zone {existing.zone.name}." | |
+ ) | |
+ }] | |
+ }) | |
+ | |
+ record_id = record.get('id') | |
+ if not record_id: | |
+ raise CloudflareError({ | |
+ 'errors': [{ | |
+ 'message': f"No record 'id' found for record {record}." | |
+ }] | |
+ }) | |
+ | |
+ path = f'/zones/{zone_id}/dns_records/{record_id}' | |
self._try_request('DELETE', path) | |
def _apply(self, plan): |
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: OctoDNS Sync | |
on: | |
pull_request: | |
paths: | |
- 'config/**' | |
- 'providers/**' | |
- '.github/workflows/sync-providers.yaml' | |
types: [closed] | |
branches: | |
- main | |
concurrency: | |
group: sync-providers-${{ github.head_ref || github.run_id }} | |
cancel-in-progress: true | |
env: | |
LOGFILE: sync.log | |
jobs: | |
sync: | |
name: Sync with Providers | |
runs-on: ubuntu-latest | |
if: github.event.pull_request.merged == true | |
steps: | |
- name: Checkout Repository | |
uses: actions/checkout@v4 | |
- name: Install Dependencies | |
run: | | |
sudo apt-get update && sudo apt-get install -y jq | |
pip install --upgrade pip | |
pip install -r requirements.txt | |
- name: Determine octodns-cloudflare version | |
id: determine_cf_version | |
run: | | |
CF_VERSION=$(pip show octodns-cloudflare | grep '^Version:' | awk '{print $2}') | |
echo "OCTODNS_CLOUDFLARE_VERSION=$CF_VERSION" >> "$GITHUB_OUTPUT" | |
- name: Patch Cloudflare provider if needed | |
if: steps.determine_cf_version.outputs.OCTODNS_CLOUDFLARE_VERSION == '0.0.7' | |
continue-on-error: true | |
run: | | |
echo "octodns-cloudflare is version 0.0.7. Attempting to apply patch..." | |
# 1. Ensure 'patch' is installed (usually pre-installed on Ubuntu runners). | |
if ! command -v patch >/dev/null 2>&1; then | |
echo "ERROR: 'patch' command is not available. Skipping patch." | |
exit 0 | |
fi | |
# 2. Download the patch file from Gist (fail if the request fails -f). | |
PATCH_URL="https://gist.githubusercontent.com/troykelly/94c9d1fc3011abd3f0ba0a679a38c31a/raw/octodns-cloudflare-keyerror.patch" | |
PATCH_TMP="/tmp/octodns-cloudflare-keyerror.patch" | |
echo "Downloading patch from $PATCH_URL ..." | |
if ! curl -fSL "$PATCH_URL" -o "$PATCH_TMP"; then | |
echo "ERROR: Failed to download patch from $PATCH_URL. Skipping patch." | |
exit 0 | |
fi | |
# 3. Check that the downloaded file isn't empty or missing. | |
if [ ! -s "$PATCH_TMP" ]; then | |
echo "ERROR: Patch file '$PATCH_TMP' is empty or missing. Skipping patch." | |
exit 0 | |
fi | |
# 4. Identify the location of the installed octodns-cloudflare package. | |
LOCATION=$(pip show octodns-cloudflare | grep '^Location:' | awk '{print $2}') | |
if [ -z "$LOCATION" ]; then | |
echo "ERROR: Could not determine octodns-cloudflare install location. Skipping patch." | |
exit 0 | |
fi | |
TARGET_FILE="${LOCATION}/octodns_cloudflare/__init__.py" | |
if [ ! -f "$TARGET_FILE" ]; then | |
echo "ERROR: Target file $TARGET_FILE does not exist. Skipping patch." | |
exit 0 | |
fi | |
# 5. Apply the patch (force to ignore already-applied hunks). | |
echo "Patching file: $TARGET_FILE" | |
if ! patch --force "$TARGET_FILE" "$PATCH_TMP"; then | |
echo "WARNING: Patch command failed. Continuing anyway." | |
fi | |
- name: Initialize OctoDNS Sync | |
env: | |
CLOUDFLARE_USERNAME: ${{ secrets.CLOUDFLARE_USERNAME }} | |
CLOUDFLARE_TOKEN: ${{ secrets.CLOUDFLARE_TOKEN }} | |
run: | | |
octodns-sync --doit --config-file="config/production.yaml" &>>"${{ env.LOGFILE }}" || \ | |
{ | |
echo "FAIL: octodns-sync exited with an error." | |
echo -e "\n\n## OctoDNS Failure by ${{ github.actor }}\n\n" >> "${{ env.LOGFILE }}" | |
exit 1 | |
} | |
- name: Create Branch and Commit Log File on Failure | |
if: ${{ failure() }} | |
run: | | |
git config --global user.name 'action-bot' | |
git config --global user.email '[email protected]' | |
git checkout -b issue/failure-log-${{ github.run_number }} | |
git add -f ${{ env.LOGFILE }} | |
git add . | |
git commit -m "Add failure log" | |
git push origin issue/failure-log-${{ github.run_number }} | |
- name: Create Issue and Reference File on Failure | |
if: ${{ failure() }} | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
github.rest.issues.create({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
title: 'Failed to sync OctoDNS', | |
body: `An error occurred during OctoDNS sync. Check the failure log for more details. | |
The log file is available in the branch [issue/failure-log-${{ github.run_number }}](/${{ github.repository }}/blob/issue/failure-log-${{ github.run_number }}/${{ env.LOGFILE }})`, | |
labels: ['report', 'automated issue'] | |
}) | |
- name: Cleanup Logfile | |
run: rm -f ${{ env.LOGFILE }} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment