Skip to content

Commit 3bc18f7

Browse files
authored
argocd: use native http client, apply fallback on sync timeout, local ITs instance script (#193)
1 parent 839098f commit 3bc18f7

File tree

28 files changed

+1751
-244
lines changed

28 files changed

+1751
-244
lines changed

tasks/argocd/README.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# `argocd` plugin for Concord
2+
3+
4+
## Integration Tests
5+
6+
Integration tests run against a local ArgoCD instance. Run the [`install_argo.sh`](./local_argo/install_argo.sh)
7+
script to set up an instance including
8+
9+
- Local K3s cluster in Docker
10+
- Basic ArgoCD installation
11+
- LDAP Dex connector
12+
- Git repository server
13+
- Default Repository in ArgoCD, with SSH keypair auth
14+
15+
### Prerequisites
16+
17+
- `git`
18+
- `docker` or `rancher`
19+
- `kubectl` (optionally `k9s`)
20+
- `ansible` with [`kubernetes` module](https://pypi.org/project/kubernetes/)
21+
and [`kubernetes.core` collection](https://galaxy.ansible.com/ui/repo/published/kubernetes/core/)
22+
23+
### Things To Know
24+
25+
#### Ingress Hostname
26+
27+
The trickiest part is getting a hostname to work both within docker (e.g. ITs executing
28+
through Concord testcontainers) and outside (e.g. direct JUnit ITs). The default
29+
setup uses `host.docker.internal`. That solves the internal problem. However, this
30+
requires some manual intervention on the host machine to resolve the hostname. This
31+
should be as simple as adding an `/etc/hosts` entry.
32+
33+
```
34+
# ...leave existing entries
35+
36+
# this is needed for the integration tests to work
37+
127.0.0.1 host.docker.internal
38+
```
39+
40+
Alternatively, use a hostname or IP address which is accessible on your
41+
network (e.g. your workstation's IP address).
42+
43+
#### Generated Files
44+
45+
Some required values and files must be generated at install-time, and it's just
46+
cleaner to keep "secrets" (event for testing) out of the repository. All of these
47+
generated files are saved to the
48+
[`local_argo/playbook/roles/argocd/files`](./local_argo/playbook/roles/argocd/files)
49+
directory.
50+
51+
- `argo_install_manifest.yml` - ArgoCD k8ts install manifest
52+
- `k3s_server_ca.crt` - kubernetes CA certificate
53+
- `k3s_token.txt` - init token for k3s
54+
- `kubeconfig.yaml` - kubeconfig for the k3s cluster
55+
- `ldap_cfg.txt` - admin password and user ldap info
56+
- `test_key` and `test_key.pub` - ssh keypair for git repo access
57+
- `test_input.properties` - consolidated info for integration test input
58+
59+
### Install ArgoCD in K3s
60+
61+
Use [install_argo.sh](./local_argo/install_argo.sh) to start a `k3s` instance with
62+
ArgoCD in the `argocd` namespace. This will also generate a `kubeconfig.yaml` which
63+
can be used to interact with the cluster (e.g. with `kubectl` or `k9s`) for debugging.
64+
65+
```
66+
$ cd local_argo
67+
$ ./install_argo.sh --ingress-host <your-hostname-or-ip>
68+
```
69+
70+
Optionally, skip downloading argocd manifest on first rut. Note: download will be
71+
skipped if the destination file already exists.
72+
73+
```
74+
$ ./install_argo.sh --skip-manifest-download
75+
```
76+
77+
### Run Integration Tests
78+
79+
```
80+
# run mvn from project root
81+
$ mvn clean install --pl tasks/argocd
82+
$ mvn verify --pl tasks/argocd -DskipArgoITs=false
83+
...
84+
[INFO] Results:
85+
[INFO]
86+
[INFO] Tests run: 4, Failures: 0, Errors: 0, Skipped: 0
87+
```

tasks/argocd/local_argo/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
playbook/roles/argocd/files/generated
2+
*venv
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# to run define K3S_TOKEN, K3S_VERSION is optional, eg:
2+
# K3S_TOKEN=${RANDOM}${RANDOM}${RANDOM} docker-compose up
3+
4+
services:
5+
6+
server:
7+
image: "rancher/k3s:${K3S_VERSION:-latest}"
8+
command: server
9+
tmpfs:
10+
- /run
11+
- /var/run
12+
ulimits:
13+
nproc: 65535
14+
nofile:
15+
soft: 65535
16+
hard: 65535
17+
privileged: true
18+
restart: always
19+
environment:
20+
- K3S_TOKEN=${K3S_TOKEN:?err}
21+
- K3S_KUBECONFIG_OUTPUT=/output/kubeconfig.yaml
22+
- K3S_KUBECONFIG_MODE=666
23+
volumes:
24+
- k3s-server:/var/lib/rancher/k3s
25+
# This is just so that we get the kubeconfig file out
26+
- ./playbook/roles/argocd/files/generated:/output
27+
ports:
28+
- 6443:6443 # Kubernetes API Server
29+
- 80:80 # Ingress controller port 80
30+
- 443:443 # Ingress controller port 443
31+
- 8080:8080 # port forward TODO be smarter (set up ingress to argo through ^^443^^)
32+
networks:
33+
- argo-net
34+
35+
agent:
36+
image: "rancher/k3s:${K3S_VERSION:-latest}"
37+
tmpfs:
38+
- /run
39+
- /var/run
40+
ulimits:
41+
nproc: 65535
42+
nofile:
43+
soft: 65535
44+
hard: 65535
45+
privileged: true
46+
restart: always
47+
environment:
48+
- K3S_URL=https://server:6443
49+
- K3S_TOKEN=${K3S_TOKEN:?err}
50+
volumes:
51+
- k3s-agent:/var/lib/rancher/k3s
52+
networks:
53+
- argo-net
54+
55+
volumes:
56+
k3s-server: {}
57+
k3s-agent: {}
58+
59+
networks:
60+
argo-net:
61+
ipam:
62+
config:
63+
- ip_range: "192.168.90.0/24"
64+
subnet: "192.168.90.0/24"
65+
gateway: "192.168.90.1"
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#!/bin/bash
2+
3+
set -o pipefail
4+
set -o errexit
5+
6+
printHelp() {
7+
echo "usage: $0 [-h] [---skip-manifest-download]"
8+
}
9+
10+
function join_by {
11+
local IFS="$1";
12+
shift;
13+
echo "$*";
14+
}
15+
16+
ingressHostname="host.docker.internal"
17+
generatedFilesDir="playbook/roles/argocd/files/generated"
18+
19+
while [ "$1" != "" ]; do
20+
case $1 in
21+
-h | --help ) printHelp
22+
exit
23+
;;
24+
-i | --ingress-hostname ) shift
25+
ingressHostname="${1}"
26+
;;
27+
-s | --skip-manifest-download )
28+
skipManifestDownload="true"
29+
;;
30+
* )
31+
echo "Invalid parameter '$1'"
32+
printHelp
33+
exit 1
34+
esac
35+
# Shift all the parameters down by one
36+
shift
37+
done
38+
39+
# install argocd
40+
41+
mkdir -p "${generatedFilesDir}"
42+
43+
if [ -f "${generatedFilesDir}/k3s_token.txt" ]; then
44+
K3S_TOKEN=$(cat "${generatedFilesDir}/k3s_token.txt")
45+
else
46+
K3S_TOKEN=$(head /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 32 | tee "${generatedFilesDir}/k3s_token.txt")
47+
fi
48+
49+
export K3S_TOKEN
50+
docker compose up -d
51+
52+
sleep 5
53+
54+
mkdir -p "${generatedFilesDir}"
55+
56+
# export server ca so ansible is less cranky
57+
docker cp local_argo-server-1:/var/lib/rancher/k3s/server/tls/server-ca.crt "${generatedFilesDir}/k3s_server_ca.crt"
58+
59+
if [ -f "${generatedFilesDir}/ldap_cfg.txt" ]; then
60+
ldapAdminPassword=$(grep 'adminPassword:' "${generatedFilesDir}/ldap_cfg.txt" | sed 's/adminPassword://')
61+
ldapUsername=$(grep 'username:' "${generatedFilesDir}/ldap_cfg.txt" | sed 's/username://')
62+
ldapPassword=$(grep 'password:' "${generatedFilesDir}/ldap_cfg.txt" | sed 's/password://')
63+
else
64+
ldapAdminPassword=$(head /dev/urandom | LC_ALL=C tr -dc 'A-Za-z0-9' | head -c 32)
65+
read -r -p "Enter LDAP username: " ldapUsername
66+
read -r -s -p "Enter LDAP password: " ldapPassword
67+
68+
echo "adminPassword:${ldapAdminPassword}" > "${generatedFilesDir}/ldap_cfg.txt"
69+
echo "username:${ldapUsername}" >> "${generatedFilesDir}/ldap_cfg.txt"
70+
echo "password:${ldapPassword}" >> "${generatedFilesDir}/ldap_cfg.txt"
71+
fi
72+
73+
# argocd kubernetes manifest
74+
if [[ -f "${generatedFilesDir}/argo_install_manifest.yml" || "${skipManifestDownload}" == *"true"* ]]; then
75+
echo "Skipping manifest download"
76+
else
77+
echo "Downloading latest ArgoCD manifest"
78+
curl -o "${generatedFilesDir}/argo_install_manifest.yml" https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
79+
fi
80+
81+
# keypair for git in-cluster git operations
82+
if [[ ! -f "${generatedFilesDir}/test_key" ]]
83+
then
84+
ssh-keygen -t rsa -b 4096 -C "[email protected]" -m pem -N '' -f "${generatedFilesDir}/test_key"
85+
fi
86+
87+
# python3 -m venv localvenv
88+
# source localvenv/bin/activate
89+
# pip install kubernetes
90+
# ansible-galaxy collection install kubernetes.core
91+
ansible-playbook -i ./playbook/inventory.yml \
92+
-e ingress_hostname="${ingressHostname}" \
93+
-e ldap_admin_password="${ldapAdminPassword}" \
94+
-e ldap_username="${ldapUsername}" \
95+
-e ldap_password="${ldapPassword}" \
96+
./playbook/main.yml
97+
98+
cat > "${generatedFilesDir}/test_input.properties" << EOF
99+
ARGO_IT_APP_NAMESPACE=test-namespace
100+
ARGO_IT_BASE_API=https://${ingressHostname}
101+
ARGO_IT_BASIC_ADMIN_PASSWORD=$(< "${generatedFilesDir}/argocd_admin_password.txt")
102+
ARGO_IT_KUBECONFIG_PATH=local_argo/${generatedFilesDir}/kubeconfig.yaml
103+
ARGO_IT_LDAP_USERNAME=${ldapUsername}
104+
ARGO_IT_LDAP_PASSWORD=${ldapPassword}
105+
EOF
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
local:
3+
hosts:
4+
k3s:
5+
ansible_host: localhost
6+
kubconfig_path: roles/argocd/files/generated/kubeconfig.yaml
7+
k8s_ca_cert: roles/argocd/files/generated/k3s_server_ca.crt
8+
ansible_connection: local
9+
k8s_ns: argocd
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
- name: Main playbook
3+
hosts: all
4+
gather_facts: false
5+
roles:
6+
- role: argocd
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
apiVersion: v1
2+
kind: ConfigMap
3+
metadata:
4+
labels:
5+
app.kubernetes.io/name: nginx-cm
6+
name: nginx-cm
7+
data:
8+
index.html: "hello world"
9+
---
10+
apiVersion: apps/v1
11+
kind: Deployment
12+
metadata:
13+
name: nginx
14+
labels:
15+
app: nginx
16+
spec:
17+
replicas: 1
18+
selector:
19+
matchLabels:
20+
app: nginx
21+
template:
22+
metadata:
23+
labels:
24+
app: nginx
25+
spec:
26+
volumes:
27+
- name: nginx-static-volume
28+
configMap:
29+
name: nginx-cm
30+
items:
31+
- key: "index.html"
32+
path: "index.html"
33+
containers:
34+
- name: nginx
35+
image: library/nginx:latest
36+
startupProbe:
37+
httpGet:
38+
path: /
39+
port: 80
40+
initialDelaySeconds: 15 # force a slow-ish startup, useful for testing timeouts
41+
periodSeconds: 5
42+
ports:
43+
- containerPort: 80
44+
volumeMounts:
45+
- name: nginx-static-volume
46+
mountPath: "/usr/share/nginx/html"
47+
readOnly: true

0 commit comments

Comments
 (0)