Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation: one-shot mode #1164

Open
stevecrozz opened this issue Jan 12, 2024 · 5 comments
Open

Documentation: one-shot mode #1164

stevecrozz opened this issue Jan 12, 2024 · 5 comments

Comments

@stevecrozz
Copy link

stevecrozz commented Jan 12, 2024

Description

Update the documentation so that readers will know that the program does not need to run as a daemon. That it runs in a one-shot mode when schedule is not provided.

@javydekoning
Copy link

Yeah, I'd like that as well! Not passing in a schedule should do a one-shot run.

I have k8s handle the scheduling for me. The way I handle this today is like this:

apiVersion: v1
metadata:
  name: r53creds
data:
  HOSTED_ZONE_ID: 
  RECORD_NAME: 
  AWS_ACCESS_KEY_ID:
  AWS_SECRET_ACCESS_KEY:
  AWS_DEFAULT_REGION:
kind: Secret
type: Opaque
---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: ddns
spec:
  schedule: "*/15 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
          - name: ddns
            image: alpine
            imagePullPolicy: IfNotPresent
            envFrom:
              - secretRef:
                  name: r53creds
            command: ["/bin/sh", "-c"]
            args:
              - |-
                apk add aws-cli curl jq --no-cache && \
                RECORD_TYPE="A" && \
                TTL=300 && \
                NEW_IP_ADDRESS=$(curl https://ipv4.icanhazip.com/) && \
                # Define the JSON in a multi-line variable
                CHANGE_BATCH=$(cat <<EOF
                {
                  "Changes": [
                    {
                      "Action": "UPSERT",
                      "ResourceRecordSet": {
                        "Name": "${RECORD_NAME}",
                        "Type": "${RECORD_TYPE}",
                        "TTL": ${TTL},
                        "ResourceRecords": [
                          {"Value": "${NEW_IP_ADDRESS}"}
                        ]
                      }
                    }
                  ]
                }
                EOF
                )

                aws route53 change-resource-record-sets \
                    --hosted-zone-id "$HOSTED_ZONE_ID" \
                    --change-batch "$CHANGE_BATCH" | jq -r '.ChangeInfo.Status'

Which works, but is less pretty ;-)

@stevecrozz stevecrozz changed the title One-shot mode support Documentation: one-shot mode Feb 6, 2024
@stevecrozz
Copy link
Author

I experimented a bit yesterday and found ddns-route53 already does behave the way I want. It seems ddns-route53 does run in a one-shot mode when a schedule is not provided. I updated the issue title and description to indicate this is a documentation task.

@javydekoning
Copy link

Can you include a quick example? Then I'll happily open a pull request tomorrow.

@stevecrozz
Copy link
Author

Sure. Looking at how it works, it seems the program runs one time right away, and then if there is no schedule, the program exits.

I think I would start with a note here in the online --help menu:

--schedule=STRING CRON expression format ($SCHEDULE).

-      --schedule=STRING         CRON expression format ($SCHEDULE).
+      --schedule=STRING         CRON expression format ($SCHEDULE). Leave empty to run once and exit.

@javydekoning
Copy link

Ok I have adopted this in k8s. Works like a charm:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: ddns-route53
spec:
  schedule: "*/15 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: Never
          containers:
            - name: ddns-route53
              image: crazymax/ddns-route53:latest
              imagePullPolicy: IfNotPresent
              env:
                - name: TZ
                  value: "Europe/Amsterdam"
                - name: LOG_LEVEL
                  value: info
                - name: LOG_JSON
                  value: "false"
              volumeMounts:
                - name: secret-volume
                  readOnly: true
                  mountPath: "/ddns-route53.yml"
                  subPath: ddns-route53.yml
          volumes:
            - name: secret-volume
              secret:
                secretName: route-53-credentials-ddns

My secret:

apiVersion: v1
kind: Secret
type: Opaque
metadata:
  name: route-53-credentials-ddns
  namespace: default
data:
  ddns-route53.yml: <removed>

If you want to load this secret from AWS Secrets Manger through external secrets consider this:

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: external-route-53-credentials-ddns
  namespace: default
spec:
  dataFrom:
  - extract:
      key: k8s-route-53-credentials
  refreshInterval: 1h
  secretStoreRef:
    kind: ClusterSecretStore
    name: aws-secretsmanager
  target:
    creationPolicy: Owner
    name: route-53-credentials-ddns
    template:
      data:
        ddns-route53.yml: |
          credentials:
            accessKeyID: "{{ .AWS_ACCESS_KEY_ID }}"
            secretAccessKey: "{{ .AWS_SECRET_ACCESS_KEY }}"

          route53:
            hostedZoneID: "{{ .HOSTED_ZONE_ID }}"
            recordsSet:
              - name: "{{ .RECORD_NAME }}"
                type: "A"
                ttl: 300
      mergePolicy: Replace

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants