Skip to content

Commit

Permalink
chore: ⚡ add stack for dev locally
Browse files Browse the repository at this point in the history
  • Loading branch information
titigmr committed Aug 17, 2024
1 parent 74180c5 commit 09c132f
Show file tree
Hide file tree
Showing 12 changed files with 260 additions and 363 deletions.
115 changes: 115 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
SHELL := /bin/bash
DOCKER := $(shell type -p docker)
KIND := $(shell type -p kind)
HELM := $(shell type -p helm)
KUBECTL := $(shell type -p helm)

WEBHOOK_IMAGE := external-dns-midaas-webhook:dev
WEBHOOK_FOLDER := ./


MIDAAS_IMAGE := api-midaas:dev
export MIDAAS_DEV_SUFFIX := dev.local
export MIDAAS_ENV_KEYNAME := d1
export MIDAAS_ENV_KEYVALUE := test
export MIDAAS_ENV_ZONES := d1.dev.local
MIDAAS_FOLDER := ./contribute/midaas-ws/

KIND_CLUSTER_NAME := midaas
KIND_INGRESS_CONTROLLER = NGINX

# Commons targets

all: deploy-MIDAAS deploy-WEBHOOK create-test-ingress

clean: delete-cluster delete-image-MIDAAS delete-image-WEBHOOK

create-test-ingress: create-cluster check-prerequisites-kubectl
@kubectl apply -f ./contribute/ressources/ingress.yaml

logs-%:
@kubectl logs -f deployments/external-dns -c $*

midaas-get-zone:
@kubectl exec midaas cat /tmp/$(MIDAAS_ENV_KEYNAME).$(MIDAAS_DEV_SUFFIX) | jq

# Check prerequisites

check-prerequisites-docker:
ifeq ("$(wildcard ${DOCKER})","")
@echo "docker not found" ; exit 1
endif
check-prerequisites-kind:
ifeq ("$(wildcard ${KIND})","")
@echo "'kind' not found" ; exit 1
endif
check-prerequisites-kubectl:
ifeq ("$(wildcard ${KUBECTL})","")
@echo "'kubectl' not found" ; exit 1
endif
check-prerequisites-helm:
ifeq ("$(wildcard ${HELM})","")
@echo "'helm' not found" ; exit 1
endif

# Kind targets

create-cluster: check-prerequisites-kind
ifeq ($(shell kind get clusters |grep $(KIND_CLUSTER_NAME)), $(KIND_CLUSTER_NAME))
@echo "Kind cluster '$(KIND_CLUSTER_NAME)' already exists, skipping"
else
@kind create cluster --name $(KIND_CLUSTER_NAME) --config ./contribute/kind/kind-config.yaml
@kubectl config use-context kind-$(KIND_CLUSTER_NAME)
endif

delete-cluster: check-prerequisites-kind
ifeq ($(shell kind get clusters |grep $(KIND_CLUSTER_NAME)), $(KIND_CLUSTER_NAME))
@kind delete cluster --name $(KIND_CLUSTER_NAME)
endif

start-ingress-controller: create-cluster
ifeq ($(KIND_INGRESS_CONTROLLER), NGINX)
@kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml
@kubectl wait --namespace ingress-nginx \
--for=condition=ready pod \
--selector=app.kubernetes.io/component=controller \
--timeout=90s
else ifeq ($(KIND_INGRESS_CONTROLLER), TRAEFIK)
@echo traefik
endif

# Docker build and push targets
build-%: check-prerequisites-docker
@if [ $* = WEBHOOK ]; then docker build --target dev ${OPTIONS} -t ${$*_IMAGE} ${$*_FOLDER}; else docker build ${OPTIONS} -t ${$*_IMAGE} ${$*_FOLDER}; fi

push-%: check-prerequisites-kind
kind load docker-image ${$*_IMAGE} --name $(KIND_CLUSTER_NAME)

delete-image-%: check-prerequisites-docker
docker rmi ${$*_IMAGE}

# Midaas deployment targets
delete-MIDAAS: create-cluster check-prerequisites-kubectl
@kubectl delete pod midaas --ignore-not-found
@kubectl delete svc midaas --ignore-not-found

deploy-MIDAAS: create-cluster check-prerequisites-kubectl build-MIDAAS push-MIDAAS delete-MIDAAS
@kubectl run --image $(MIDAAS_IMAGE) --expose=true --port 8080 \
--env "MIDAAS_KEYNAME=$(MIDAAS_ENV_KEYNAME)" \
--env "MIDAAS_KEYVALUE=$(MIDAAS_ENV_KEYVALUE)" \
--env "MIDAAS_ZONES=$(MIDAAS_ENV_ZONES)" midaas
@echo "Kubernetes midaas service is listening on port 8080"


# Webhook deployment targets

delete-WEBHOOK: create-cluster check-prerequisites-helm
@if [ "external-dns" == "$(shell helm ls -f external-dns -o json |jq -r .[].name)" ]; then helm delete external-dns; else echo "No external-dns release is currently running"; fi

deploy-WEBHOOK: start-ingress-controller check-prerequisites-helm build-WEBHOOK push-WEBHOOK delete-WEBHOOK
@echo "Adding repository"
@helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/
@envsubst < ./contribute/ressources/external-dns-values.yaml > /tmp/external-dns-values.yaml
@helm upgrade --force --install external-dns external-dns/external-dns -f /tmp/external-dns-values.yaml
@echo "external DNS is running with webhook in sidecar"

63 changes: 60 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,16 @@ helm repo add external-dns https://kubernetes-sigs.github.io/external-dns/
1. Create the helm values file `external-dns-midaas-values.yaml`:

```yaml
sources:
- ingress
# -- How DNS records are synchronized between sources and providers; available values are `sync` & `upsert-only`.
policy: sync
# -- Specify the registry for storing ownership and labels.
# Valid values are `txt`, `aws-sd`, `dynamodb` & `noop`.
# If `noop` midaas manage all records on zone
registry: txt
# can restrict zone
domainFilters: ["subzone.d1.dev.example.com"]
domainFilters: []
provider:
name: webhook
webhook:
Expand All @@ -43,7 +45,7 @@ provider:
2. Create helm deployment:
```sh
helm install external-dns external-dns -f external-dns-midaas-values.yaml
helm install external-dns external-dns/external-dns -f external-dns-midaas-values.yaml
```

## Parameters references
Expand All @@ -65,7 +67,62 @@ For example, `TSIG_ZONE_d1` with `PROVIDER_DNS_ZONE_SUFFIX` with `dev.example.co

## Local development

🚧 Work in progress.
### Prerequisite

Download and install on your local machine:
- `make` in Debian/Ubuntu distrib with
```bash
sudo apt install build-essential
```
- [docker](https://docs.docker.com/engine/install/)
- [kubectl](https://github.com/kubernetes/kubectl)
- [kind](https://github.com/kubernetes-sigs/kind)
- [helm](https://github.com/helm/helm)

### Usage


You can create a development stack locally with this command:

```sh
make
```

This target do the following target successively:
- `create-cluster` : create a `kind` cluster locally with an ingress controller configured
- `deploy-MIDAAS` : build, push and deploy `midaas` [webservice mock](./contribute/midaas-ws/) in the cluster
- `deploy-WEBHOOK` : build, push and deploy `external-dns` with the midaas webhook in development mode. You can modify the code with hot reload.

For example, for restarting the webhook:

```bash
make deploy-WEBHOOK
```

Don't forget create an ingress for trigger `external-dns`, an [example](./contribute/ressources/ingress.yaml) can be created with:

```bash
make create-test-ingress
```

You can read the containers logs with:

```bash
make logs-webhook
```

or

```bash
make logs-external-dns
```

To clean all the components

```sh
make clean
```


## Contributions

Expand Down
31 changes: 0 additions & 31 deletions contribute/Makefile

This file was deleted.

38 changes: 38 additions & 0 deletions contribute/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Run all stack locally with docker

## Kind cluster

One single node is deployed but it can be customized in `./kind/kind-config.yml`. The cluster comes with [Traefik](https://doc.traefik.io/traefik/providers/kubernetes-ingress/) or [Nginx](https://kind.sigs.k8s.io/docs/user/ingress/#ingress-nginx) ingress controller installed with port mapping on both ports `8080` and `8443`.

The node is using `extraMounts` to provide a volume binding between host working directory and `/app` to give the ability to bind mount volumes into containers during development.


## Midaas Webservice

A wrapper of midaas is available for development on folder `./midaas-ws`. Note that tool not really do dns records. It only writes fake domain on container filesystem.

This webservice is written in python with `Fastapi` framework. The webservice listen on 3 endpoints:
- `GET` - `/ws/{domaine}` : retrieve all domains for a specific zone
- `PUT` - `/ws/{domaine}/{type}/{valeur}` : add or modify a DNS record
You must add this body in the request:
```json
{"ttl": 0, "keyname": "string", "keyvalue": "string"}
```
- `DELETE` - `/ws/{domaine}/{type}/{valeur}` : add or modify a DNS
You must add this body in the request:
```json
{"keyname": "string", "keyvalue": "string"}
```

The midaas webservice can be configured with the following environment variables:

| Name | Description | Default |
| --------------- | ---------------------- | --------- |
| MIDAAS_KEYNAME | TSIG Keyname | test |
| MIDAAS_KEYVALUE | TSIG Keyvalue | test |
| MIDAAS_ZONE | Zone managed by MiDaas | dev.local |


## External-DNS Locally

:construction:
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ nodes:
node-labels: "ingress-ready=true"
extraPortMappings:
- containerPort: 80
hostPort: 80
hostPort: 8080
protocol: TCP
- containerPort: 443
hostPort: 443
hostPort: 8443
protocol: TCP
extraMounts:
- hostPath: ./
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
---
providers:
kubernetesCRD:
namespaces:
- default
- ingress-traefik
enabled: false
kubernetesIngress:
namespaces:
- default
- ingress-traefik

ports:
web:
nodePort: 80
hostPort: 80
websecure:
nodePort: 443
hostPort: 443

service:
type: NodePort
type: ClusterIP
34 changes: 19 additions & 15 deletions contribute/midaas-ws/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,11 @@
from pydantic import BaseModel


KEYNAME = os.environ.get("MIDAAS_KEYNAME", "test")
KEYNAME = "ddns-key." + os.environ.get("MIDAAS_KEYNAME", "d1")
KEYVALUE = os.environ.get("MIDAAS_KEYVALUE", "test")
ZONES = os.environ.get("MIDAAS_ZONE", "dev.local,test.local")
ZONES = os.environ.get("MIDAAS_ZONES", "d1.dev.local")
ALL_ZONES = ZONES.split(",")

INFO = f"""
Informations about current midaas instance:
- keyname: {KEYNAME} - (MIDAAS_KEYNAME env var)
- keyvalue: {KEYVALUE} - (MIDAAS_KEYVALUE env var)
Availables zones are comma separated: {ZONES} (MIDAAS_ZONE env var)
"""
app = FastAPI()


Expand All @@ -32,7 +25,12 @@ class TTLCreate(BaseModel):


def check_TSIG(keyname, keyvalue):
return keyname == KEYNAME and KEYVALUE == keyvalue
if not keyname == KEYNAME and KEYVALUE == keyvalue:
print(f"Keyname or Keyvalue not match")
print(f"Keyname: {keyname} with {KEYNAME}")
print(f"Keyvalue: {keyname} with {KEYNAME}")
return False
return True


def create_zone(file):
Expand Down Expand Up @@ -78,6 +76,8 @@ async def health():

@app.put("/ws/{domaine}/{type}/{valeur}")
def create(response: Response, request: Request, domaine: str, type: str, valeur: str, TTL: TTLCreate) -> dict:
print(f"URL: {request.url}")
print(f"URL: {request.body}")
if not check_TSIG(keyname=TTL.keyname, keyvalue=TTL.keyvalue):
return {"status": "ERROR", "message": "wrong credentials"}

Expand All @@ -87,16 +87,19 @@ def create(response: Response, request: Request, domaine: str, type: str, valeur
create_zone_if_not_exist(file=file)
data = read_zone(file=file)
with open(file, "w+") as f:
updated_data = data | {domaine: {"type": type,
"valeur": valeur,
"ttl": TTL.ttl}}
updated_data = data | {f"{domaine}./{type}/{valeur}": {"type": type,
"valeur": valeur,
"ttl": TTL.ttl}}
json.dump(updated_data, f)
print(f"Zone content :{updated_data}")
return {"status": "OK"}
return {"status": "ERROR", "message": "zone not available"}


@app.delete("/ws/{domaine}/{type}/{valeur}")
def delete(response: Response, request: Request, domaine: str, type: str, valeur: str, TTL: TTLDelete) -> dict:
print(f"URL: {request.url}")
print(f"URL: {request.body}")
if not check_TSIG(keyname=TTL.keyname, keyvalue=TTL.keyvalue):
return {"status": "ERROR", "message": "wrong credentials"}

Expand All @@ -107,8 +110,9 @@ def delete(response: Response, request: Request, domaine: str, type: str, valeur
data = read_zone(file=file)
print(domaine, data)
with open(file, "w") as f:
if domaine in data:
data.pop(domaine)
if f"{domaine}./{type}/{valeur}" in data:
data.pop(f"{domaine}./{type}/{valeur}")
json.dump(data, f)
print(f"Zone content :{data}")
return {"status": "OK"}
return {"status": "ERROR", "message": "no domain"}
Loading

0 comments on commit 09c132f

Please sign in to comment.