-
Notifications
You must be signed in to change notification settings - Fork 0
/
setup.ansible.yaml
273 lines (245 loc) · 9.73 KB
/
setup.ansible.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
- name: Check dependencies
hosts: localhost
gather_facts: yes
tasks:
- name: Check for required dependencies
command: "{{ item.cmd }}"
register: result
failed_when: result.rc != 0
changed_when: false
loop:
- { cmd: "docker --version", name: "Docker" }
- { cmd: "poetry --version", name: "Poetry" }
- { cmd: "git --version", name: "Git" }
- { cmd: "pyenv --version", name: "Pyenv" }
- { cmd: "kind version", name: "Kind" }
- { cmd: "yq --version", name: "yq" }
- { cmd: "kubectl version --client", name: "kubectl" }
loop_control:
label: "{{ item.name }}"
- name: Setup Development Environment
hosts: localhost
gather_facts: no
tasks:
- name: Ensure python env with Poetry
command: poetry env use 3.12
register: poetry_env_output
args:
chdir: todo-api
changed_when: "'Creating virtualenv' in poetry_env_output.stderr"
- name: Install dependencies with Poetry
command: poetry install
args:
chdir: todo-api
register: poetry_install_output
changed_when: >
"No dependencies to install or update" not in poetry_install_output.stdout
- name: Add poetry-plugin-export
command: poetry self add poetry-plugin-export
args:
chdir: todo-api
register: poetry_plugin_add_output
changed_when: >
"Nothing to add." not in poetry_plugin_add_output.stdout
- name: Export requirements.txt from lock
shell: |
poetry export -f requirements.txt --output src/requirements.txt.tmp && \
if ! cmp --silent src/requirements.txt.tmp src/requirements.txt; then
mv src/requirements.txt.tmp src/requirements.txt
echo "requirements.txt has changed"
else
rm src/requirements.txt.tmp
echo "No changes in requirements.txt"
fi
args:
chdir: todo-api
register: poetry_export_output
changed_when: "'requirements.txt has changed' in poetry_export_output.stdout"
- name: Export requirements.dev.txt from lock
shell: |
poetry export -f requirements.txt --output tests/requirements.dev.txt.tmp --only dev && \
if ! cmp --silent tests/requirements.dev.txt.tmp tests/requirements.dev.txt; then
mv tests/requirements.dev.txt.tmp tests/requirements.dev.txt
echo "requirements.dev.txt has changed"
else
rm tests/requirements.dev.txt.tmp
echo "No changes in requirements.dev.txt"
fi
args:
chdir: todo-api
register: poetry_export_output
changed_when: "'requirements.dev.txt has changed' in poetry_export_output.stdout"
- name: Activate pre-commit
shell: |
if [ -f .git/hooks/pre-commit ]; then
cp .git/hooks/pre-commit .git/hooks/pre-commit.bak
else
touch .git/hooks/pre-commit.bak # Ensure backup exists for comparison
fi
poetry -C todo-api run pre-commit install
if cmp --silent .git/hooks/pre-commit .git/hooks/pre-commit.bak; then
CHANGED="No changes in pre-commit hook"
STATUS=0
else
CHANGED="pre-commit hook has changed"
STATUS=1
fi
rm .git/hooks/pre-commit.bak
# Output result
echo $CHANGED
exit $STATUS
register: pre_commit_install_output
changed_when: pre_commit_install_output.rc == 1
failed_when: pre_commit_install_output.rc not in [0,1]
ignore_errors: false
- name: Get Python interpreter path
shell: poetry env info -p
args:
chdir: todo-api
register: poetry_env_path
changed_when: false
- name: Set Python interpreter as a fact
set_fact:
ansible_python_interpreter: "{{ poetry_env_path.stdout }}/bin/python"
- name: Create kuberenetes resources
hosts: localhost
gather_facts: no
vars:
ansible_python_interpreter: "{{ hostvars['localhost']['ansible_python_interpreter'] }}"
tasks:
- name: Start Kubernetes cluster using kind if it does not exist
shell: |
if ! kind get clusters | grep -q 12factor; then
sed "s|PWD_PLACEHOLDER|$(pwd)|g" deployment/local/kind-config-template.yaml | kind create cluster --name 12factor --wait 30s --config=-
echo "ClusterCreated"
else
echo "ClusterExists"
fi
register: kind_result
changed_when: "'ClusterCreated' in kind_result.stdout"
- name: Set kubectl context to kind-12factor
ansible.builtin.command:
cmd: kubectl config use-context kind-12factor
- name: Build docker image
shell: |
before_build_image_id=$(docker images -q todo-api)
docker build -t todo-api todo-api/src
after_build_image_id=$(docker images -q todo-api)
if [ "$before_build_image_id" != "$after_build_image_id" ]; then
echo "Docker image was rebuilt"
else
echo "Docker image was unchanged"
fi
register: build_status
changed_when: "'Docker image was rebuilt' in build_status.stdout"
- name: Build job docker image
shell: |
before_build_image_id=$(docker images -q todo-api-job)
docker build -t todo-api-job todo-api/tests
after_build_image_id=$(docker images -q todo-api-job)
if [ "$before_build_image_id" != "$after_build_image_id" ]; then
echo "Docker image was rebuilt"
else
echo "Docker image was unchanged"
fi
register: build_status
changed_when: "'Docker image was rebuilt' in build_status.stdout"
- name: Ensure Docker images are present in kind
shell: kind --name 12factor load docker-image {{ item }}
loop:
- todo-api
- todo-api-job
register: kind_image_sync
changed_when: "'not yet present' in kind_image_sync.stderr"
- name: Apply namespace configuration
k8s:
state: present
src: deployment/local/namespace.yaml
- name: Set current namespace context
shell: |
current=$(kubectl config view --minify --output 'jsonpath={..namespace}')
if [ "$current" != "todo-api" ]; then
kubectl config set-context --current --namespace=todo-api
echo "namespace changed"
else
echo "no change"
fi
register: namespace_change
changed_when: "'namespace changed' in namespace_change.stdout"
- name: Create ConfigMap from local.env
shell: |
if ! current=$(kubectl get configmap todo-api-config -o yaml | yq e 'del(.metadata)' -); then
echo "ConfigMap does not exist. Creating new one."
kubectl create configmap todo-api-config --from-env-file=local.env
echo "ConfigMapCreated"
else
desired=$(kubectl create configmap todo-api-config --from-env-file=local.env --dry-run=client -o yaml | yq e 'del(.metadata)' -)
if [ "$desired" != "$current" ]; then
echo "ConfigMap has changed. Updating."
kubectl create configmap todo-api-config --from-env-file=local.env --dry-run=client -o yaml | kubectl apply -f -
echo "ConfigMapUpdated"
else
echo "ConfigMap is up-to-date."
fi
fi
register: update_configmap
changed_when: "'ConfigMapCreated' in update_configmap.stdout or 'ConfigMapUpdated' in update_configmap.stdout"
- name: Create Secret from local.secret.env
shell: |
if ! current=$(kubectl get secret todo-api-secret -o yaml | yq e 'del(.metadata, .type)' -); then
echo "Secret does not exist. Creating new one."
kubectl create secret generic todo-api-secret --from-env-file=local.secret.env
echo "SecretCreated"
else
desired=$(kubectl create secret generic todo-api-secret --from-env-file=local.secret.env --dry-run=client -o yaml | yq e 'del(.metadata)' -)
if [ "$desired" != "$current" ]; then
echo "Secret has changed. Updating."
kubectl create secret generic todo-api-secret --from-env-file=local.secret.env --dry-run=client -o yaml | kubectl apply -f -
echo "SecretUpdated"
else
echo "Secret is up-to-date."
fi
fi
register: update_secret
changed_when: "'SecretCreated' in update_secret.stdout or 'SecretUpdated' in update_secret.stdout"
- name: Apply Kubernetes configurations
k8s:
state: present
namespace: todo-api
src: "{{ item }}"
loop:
- deployment/local/todo-api-db-volume-claim.yaml
- deployment/local/todo-api-db-deployment.yaml
- deployment/local/todo-api-db-service.yaml
- deployment/local/todo-api-deployment.yaml
- deployment/local/todo-api-service.yaml
register: k8s_apply_result
- name: Pause for 10 seconds
pause:
seconds: 10
changed_when: False
when: k8s_apply_result.results | map(attribute='changed') | list | select | list | length > 0
- name: Restart todo-api-deployment
command: kubectl rollout restart deployment/todo-api-deployment
changed_when: True
- name: Pause for 10 seconds
pause:
seconds: 10
changed_when: False
- name: Run migrations
shell: ./execute.sh src/manage.py migrate
register: migration_output
changed_when: "'No migrations to apply.' not in migration_output.stdout"
- name: Run tests
shell: ./execute.sh -m pytest
register: test_output
failed_when: "'failed' in test_output.stdout_lines[-1].lower()"
changed_when: False
- name: Health check for the service
uri:
url: http://localhost:30000/api/docs
method: GET
return_content: yes
status_code: 200
register: healthcheck_response
failed_when: healthcheck_response.status != 200