From 5cb6b90bd7f085eab4ae132d57f60ba4609a7159 Mon Sep 17 00:00:00 2001 From: danielambda Date: Wed, 28 Jan 2026 19:29:34 +0300 Subject: [PATCH 01/11] feat: implement lab01 devops info service --- .gitignore | 2 +- app_python/.gitingore | 6 + app_python/README.md | 110 ++++++++++++++ app_python/app.py | 141 +++++++++++++++++ app_python/docs/LAB01.md | 143 ++++++++++++++++++ .../docs/screenshots/01-main-endpoint.png | Bin 0 -> 78603 bytes .../docs/screenshots/02-health-check.png | Bin 0 -> 10579 bytes .../docs/screenshots/03-formatted-output.png | Bin 0 -> 79040 bytes app_python/requirements.txt | 7 + app_python/tests/__init__.py | 0 10 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 app_python/.gitingore create mode 100644 app_python/README.md create mode 100644 app_python/app.py create mode 100644 app_python/docs/LAB01.md create mode 100644 app_python/docs/screenshots/01-main-endpoint.png create mode 100644 app_python/docs/screenshots/02-health-check.png create mode 100644 app_python/docs/screenshots/03-formatted-output.png create mode 100644 app_python/requirements.txt create mode 100644 app_python/tests/__init__.py diff --git a/.gitignore b/.gitignore index 30d74d2584..9daeafb986 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -test \ No newline at end of file +test diff --git a/app_python/.gitingore b/app_python/.gitingore new file mode 100644 index 0000000000..97f0dda9ae --- /dev/null +++ b/app_python/.gitingore @@ -0,0 +1,6 @@ +__pycache__/ +*.py[cod] +venv/ +*.log + +.vscode/ diff --git a/app_python/README.md b/app_python/README.md new file mode 100644 index 0000000000..d9e17c48d4 --- /dev/null +++ b/app_python/README.md @@ -0,0 +1,110 @@ +# DevOps Info Service + +## Overview + +The DevOps Info Service is a Python web application that provides runtime, system, and request information via a REST API. + +## Features + +* Exposes system and runtime information +* Health check endpoint for monitoring +* Configurable via environment variables +* Clean, production-ready Flask application + +## Tech Stack + +* Python 3.11+ +* Flask 3.1.0 + +## Prerequisites + +Ensure the following are installed: + +* Python 3.11 or newer +* pip package manager +* Optional: jq for formatted JSON output + +Check Python version: + +```bash +python --version +``` + +## Installation + +Clone the repository and set up a virtual environment: + +```bash +python -m venv .venv +source .venv/bin/activate +pip install -r requirements.txt +``` + +## Running the Application + +Start the application with default settings: + +```bash +python app.py +``` + +Access the service at: + +``` +http://localhost:5000 +``` + +### Custom Configuration + +Set environment variables to customize host, port, and debug mode: + +```bash +HOST=127.0.0.1 PORT=8080 DEBUG=true python app.py +``` + +## API Endpoints + +### GET / + +Returns service metadata, system info, runtime details, request metadata, and available endpoints. + +Example: + +```bash +curl http://localhost:5000/ +``` + +Pretty-printed output: + +```bash +curl http://localhost:5000/ | jq +``` + +### GET /health + +Health check endpoint for monitoring and readiness probes. + +Example: + +```bash +curl http://localhost:5000/health +``` + +Response: + +```json +{ + "status": "healthy", + "timestamp": "2026-01-07T14:30:00Z", + "uptime_seconds": 3600 +} +``` + +## Configuration + +| Environment Variable | Default | Description | +| -------------------- | ------- | ------------------------- | +| HOST | 0.0.0.0 | Network interface to bind | +| PORT | 5000 | Application port | +| DEBUG | False | Enable Flask debug mode | + diff --git a/app_python/app.py b/app_python/app.py new file mode 100644 index 0000000000..d811f9c4bd --- /dev/null +++ b/app_python/app.py @@ -0,0 +1,141 @@ +""" +DevOps Info Service +Main application module +""" + +import os +import socket +import platform +import logging +from datetime import datetime, timezone +from flask import Flask, jsonify, request + +# ------------------------------------------------------------------------------ +# Configuration +# ------------------------------------------------------------------------------ +HOST = os.getenv("HOST", "0.0.0.0") +PORT = int(os.getenv("PORT", 5000)) +DEBUG = os.getenv("DEBUG", "False").lower() == "true" + +START_TIME = datetime.now(timezone.utc) + +# ------------------------------------------------------------------------------ +# Logging +# ------------------------------------------------------------------------------ +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s", +) +logger = logging.getLogger(__name__) + +# ------------------------------------------------------------------------------ +# App +# ------------------------------------------------------------------------------ +app = Flask(__name__) + + +# ------------------------------------------------------------------------------ +# Helpers +# ------------------------------------------------------------------------------ +def get_uptime(): + delta = datetime.now(timezone.utc) - START_TIME + seconds = int(delta.total_seconds()) + hours = seconds // 3600 + minutes = (seconds % 3600) // 60 + return { + "seconds": seconds, + "human": f"{hours} hours, {minutes} minutes", + } + + +def get_system_info(): + return { + "hostname": socket.gethostname(), + "platform": platform.system(), + "platform_version": platform.version(), + "architecture": platform.machine(), + "cpu_count": os.cpu_count(), + "python_version": platform.python_version(), + } + + +# ------------------------------------------------------------------------------ +# Routes +# ------------------------------------------------------------------------------ +@app.route("/", methods=["GET"]) +def index(): + logger.info("Handling main endpoint request") + + uptime = get_uptime() + + response = { + "service": { + "name": "devops-info-service", + "version": "1.0.0", + "description": "DevOps course info service", + "framework": "Flask", + }, + "system": get_system_info(), + "runtime": { + "uptime_seconds": uptime["seconds"], + "uptime_human": uptime["human"], + "current_time": datetime.now(timezone.utc).isoformat(), + "timezone": "UTC", + }, + "request": { + "client_ip": request.remote_addr, + "user_agent": request.headers.get("User-Agent"), + "method": request.method, + "path": request.path, + }, + "endpoints": [ + {"path": "/", "method": "GET", "description": "Service information"}, + {"path": "/health", "method": "GET", "description": "Health check"}, + ], + } + + return jsonify(response) + + +@app.route("/health", methods=["GET"]) +def health(): + uptime = get_uptime() + + return jsonify( + { + "status": "healthy", + "timestamp": datetime.now(timezone.utc).isoformat(), + "uptime_seconds": uptime["seconds"], + } + ) + + +# ------------------------------------------------------------------------------ +# Error Handling +# ------------------------------------------------------------------------------ +@app.errorhandler(404) +def not_found(error): + return jsonify( + { + "error": "Not Found", + "message": "Endpoint does not exist", + } + ), 404 + + +@app.errorhandler(500) +def internal_error(error): + return jsonify( + { + "error": "Internal Server Error", + "message": "An unexpected error occurred", + } + ), 500 + + +# ------------------------------------------------------------------------------ +# Entrypoint +# ------------------------------------------------------------------------------ +if __name__ == "__main__": + logger.info("Starting DevOps Info Service") + app.run(host=HOST, port=PORT, debug=DEBUG) diff --git a/app_python/docs/LAB01.md b/app_python/docs/LAB01.md new file mode 100644 index 0000000000..500ac10457 --- /dev/null +++ b/app_python/docs/LAB01.md @@ -0,0 +1,143 @@ +# LAB01 — DevOps Info Service + +## 1. Framework Selection + +### Chosen Framework: **Flask** + +Flask was selected as the web framework for this lab because it is lightweight, easy to understand, and provides explicit control over request handling. For a DevOps-focused service that performs system introspection and exposes operational endpoints, Flask offers the right balance between simplicity and flexibility. + +### Comparison with Alternatives + +| Framework | Pros | Cons | Decision | +| --------- | ------------------------------------------------------ | ---------------------------------------- | -------- | +| **Flask** | Lightweight, minimal magic, easy to debug, widely used | No built-in async, fewer defaults | ✅ | +| FastAPI | Async support, auto OpenAPI docs, modern | More abstraction, steeper learning curve | ❌ | +| Django | Full-featured, ORM, admin panel | Overbloated | ❌ | + +Flask allows full visibility into how requests are handled, which is ideal for learning DevOps concepts such as health checks, logging, and observability. + +--- + +## 2. Best Practices Applied + +### Clean Code Organization + +* Logical grouping of imports (standard library, third-party, local) +* Helper functions for uptime and system information +* PEP 8–compliant formatting + +### Error Handling + +Custom handlers were added for common HTTP errors to ensure consistent JSON responses: + +```python +@app.errorhandler(404) +def not_found(error): + return jsonify({ + 'error': 'Not Found', + 'message': 'Endpoint does not exist' + }), 404 +``` + +This improves client usability and prevents default HTML error pages. + +### Logging + +Structured logging is enabled at application startup: + +```python +logging.basicConfig(level=logging.INFO) +logger.info("Application starting") +``` + +Logging is critical for debugging, monitoring, and later integration with centralized logging systems. + +### Configuration via Environment Variables + +The application supports runtime configuration using environment variables: + +* `HOST` +* `PORT` +* `DEBUG` + +--- + +## 3. API Documentation + +### GET / + +Returns service metadata, system information, runtime details, request metadata, and available endpoints. + +Example request: + +```bash +curl http://localhost:5000/ +``` + +Example response (excerpt): + +```json +{ + "service": { + "name": "devops-info-service", + "version": "1.0.0", + "framework": "Flask" + }, + "system": { + "hostname": "my-host", + "platform": "Linux" + } +} +``` + +### GET /health + +Used for monitoring and readiness probes. + +```bash +curl http://localhost:5000/health +``` + +Response: + +```json +{ + "status": "healthy", + "uptime_seconds": 3600 +} +``` + +--- + +## 4. Testing Evidence + +The following evidence is provided in the `screenshots/` directory: + +* **01-main-endpoint.png** — Full JSON output from `GET /` +* **02-health-check.png** — Health endpoint response +* **03-formatted-output.png** — Pretty-printed JSON using `jq` + +Terminal commands used: + +```bash +curl http://localhost:5000/ | jq +curl http://localhost:5000/health +``` + +--- + +## 5. Challenges & Solutions + +### Challenge: Accurate Uptime Calculation + +Initially, uptime was calculated using local time, which could lead to timezone inconsistencies. + +**Solution:** +The application uses `datetime.now(timezone.utc)` consistently for all time-related values. + + +## 6. GitHub Community + +Starring repositories is a way to bookmark useful projects and support open-source maintainers by increasing visibility and engagement. + +Following developers and classmates helps build a professional network, makes collaboration easier, and allows learning from others' activity and code throughout the course and beyond. diff --git a/app_python/docs/screenshots/01-main-endpoint.png b/app_python/docs/screenshots/01-main-endpoint.png new file mode 100644 index 0000000000000000000000000000000000000000..a2587b86346e22a2a0b1cdc6c64058d8f6bb03c9 GIT binary patch literal 78603 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�=;@V;O;M628lzpX81K`U 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

D@4u_K$ z&E{Tm0$0DB0LgK6u(h3W6;T$k+0o9#_qOGjuJ6A);{gO10NeR?Gz|XCe z%sJmq6UF<@O2aZH&v+h4k@v2jamhSD@Z$6iS@h`stR+MFS(P2uYF9#*RiNK6Z)yVO zI;OID&qLIp{Rpz7UXrM1gP^cjHx<_F$kCRw+iU!2M6H)d5y#oxjRN@om@Rg$@O#j5 zw{3j||C4PmMA7C7ZanL3KXTMiqECk{?>Bs??bhf3c=^_|hJr{tJ}Gcu%g}S8-e+Kb zMNOm=5@Z~FjBr8uKVcW>7#|t~6lkwFt*)dV{9}7UpSjZi-qI<)NwJ2y!iTwqMH@y$N_@21N}-s* zwYIjTT)Qo`{qw?!0#fa99;eC(FqKX_EoAD(F9QIZolHK$^ z8aC9?xhfw$IsbJZtb>F-Hlx&SujcOnjllieA0Mu)M|8Ha)e5uN)bN8)0 z?%kI;&eDZ(^A$(tG9DL%BGf1!8o)A>7JvFFTsvfA8O?jHd;E1MpVw9wf426HMrbh5 z)i`aeZ1PfGOHt3N6*>Iu($YeSU)&6#YS<36?xu4(eVaLi`)alg#*ET}yC2LhxbN*!RDN!eUr;@Jp44+*)9iHHZO0g5)~tdJ+uRbB=L8Jn)G-IOmte~ZC> zYWB#wh0*+r+hSlGi#tym{CamyYO>=pf%HGMu@YG>_8|P@rk^hjP5P@>ty$p%H!f<7 zdKG(nh)F}E9(@szcRH=TVS8GxkQ(QtO$*ROcZjuv1F#vN-PMeZeKufTdQm;Bh$Ghv z>hJH=@V+s<*b9y63zhY~!IZf&tBX*>wT?q$?q}M3(1eKCc$JmqZLj3)Mpyn1dduag z-alvZ)oMIN`R-HUwYJazix3U*m3N7kx%UvQL!rIBod)UJYxsy|20yS`)@Av@)GY)0 zQrmSsk5g4p>diSAXcyAu;;RunU{0;lIr0r$wzPLazllymo4Vz3@Q6Jxyp{$z5uI-A zPe;BM%h4&s!K9#oHl;l9cQ(+TUOiaZs$ce`dWU2Zf7}Zchtv-ZS)2?%Dv@p-NkF7+ zGG>5ocAXd%S#MJ@b`JU=f0>mva~;LTwY45!aZ$j10aZ~+diGXrP-igE4i4KMN-9XI zTfYV_bCF;asPa02ecHPpA8!HVo1ZRftPx=cXdHg~{S1OXBfC>7ijun>v%Ec!H70S8 z9Vpblx}Wm%D7j3yQm$@Yxo)QADuzThnsYcglo~BB#C~lFJaif|J}%!o+=s@+K_GqI z3EdiwK2~2r@9V~~)8Z(1Zlt@Xb{g8c*3xM}a7M-te}9`ZyReP*HRB@fa4<$mN_0M% zcADX=JF7U%e)kgD0DoZ(^Y7McZKBElA!~1`r|Q`b+DM1K+Ah6|9RLD-9P+a}5}`v8 z`^(47qseYd-T#Yn2~+k!JsjX{RfOux*?To17GJ*rWx1S|K;W0J?Vw{z`tasEghbM_ zT-Jv=XX)_2fxy($YrMZkjYK3xRYYhU?(b3`XV|||gCHqy0QI=M@jwV(0 z@*%u-D)#hq^CYLSOh@U^zw?`V`|9HNIIX7C^G)p3U6&k)!@d)CNkP7)EarK+Y$p(b zUTgMrSyXSE9?)H^Hb@A5yoy{FCA0fL1R&f}x2}$1&9il=BObb`kv|n7paZyws(rL5 z(qm>HQThUGRa77fRso&`Z1#=!Q9BA=m}m+sym|d4`J+67CVMDG@bZ!q0=Vq?(KTgk zP^PY}E>BFHLcNaqMn^}h6%qWEI@(}blaC(c;nn$nS8hlS}ZL-9x6@<5L8)=i-e|ZzJC7cQN7`jrKe}2a(apEvY^+cCLo9M zm|+#Co$Z*AlxAVU98E=SGt-lnww*6e{B+bb)U!#O+x;<|y6cA54^yJ!s;;^vj`?yy z9?tELuVs1x9GawE!S7yTPS6?EQxD3LXn4hiM~yx0(5PUp^2&MjI}v9`SMhB2Iv~Cia*qUpHi9;XTg_I=VWpB8imH3bh-(eVhTXh**w|Kk#)guCN?4==0)Ki6V82aRIpKfM>-{M&S0FkISvHOTxHi9h3le})F)1C~=f0WMZt&G#>h9e; z1c81QA+|wc-8PQ3?9WHXk(X?ROdnynnB=opv64r8drwLjBP6P-ct8i`L5f4~pyW0d zcC41FA}IxQCIgk3Q!|I#pojcg9(Om;Jt!?ox5^j8tuLjEvXq{k~3xalQWyLtSXkTwRhk0f8;Vf&kG_X*y zv@)CJs!B;UqK_EZw+y8qiJ(nS5xi`A%aVB$a^T9(zAj5oi>XTl5M*PImv($W}WU8Blviv-tmL)}u*J18r@fV>@H;A3GatALpD; zjsBbM1or9O3`0er?MaPGyUZT%Sq=%3wCJ@dD6koP`kyuw`ttbxmX22N(t#s<1QHMa zUm6(lYXNlt?DO$-T$YxC0A3vh`d7$_N(Fd##8fmSOyEU2SB_rWGT5!$FP};tU$lyaL^|EZyf{CaT@n8an$5c0qwB<@{uF zvNa+v@5;x0;_Uoa!3#Cul-}~?$=Y}RBQ*4zpb$WXH0YLB0g-$FK$RC;#*cl=N;uL} z3^%;aGfCn%Wf_$f6tcu%Tjf_bXf5E^!wn-rNLxziSBpEZIw6qzh7zJL6}w15n`?wE z4#Li1WOySZZUa2QLh0gC3>7sc+>Gw? zD&R{F%H>GNc2ieh8cg}PByz%|j_iKM=0A-9y~+vM8t%e{iYzSK*y#whp51Ew5=Drfh=`O_Ghh5@pF^jn+M+eV2zr&aVptZ4$;r(wl0LvOd3v}1|L9T9 zJxTZ&QJ@9s=?rvb-!{9V6XJ3%_h>q=rl;a>mDnu0K&~VT)k!&om!2;bV{m>!u%Un5 z9Szp!ZJKxHpN}^$1RcCpUR{>-nXt)?;T~xV8AFB4%t?6GWY(Z1eLJ-*i-fyg{mIuL zZY++Lhg4rJzH&8FVqlQ1j0uj(H{nuB2Z~&JUaooOAx83Od^}zA5bU_@>>NJ6uYm9u zT=BlEryAhZX4$2W!1P1k_Jh64{*|2s4 z!YqcpJEeq?8^tk9H*V~8+==o9ZmNnHugr-l8m9OwJg>n1EACOj!%O&_fV>d6oZ zd*q>;nM=Rphy_v{KM&bh4!=`laYs>6K}>Y7cB+}y9mW|eCF%6y zYn%4mLIenlnJO`wUPw7}e~*Ssbhm{e$`m`2!gE&W6h1)r<@FSE9-o`7n~jO*y8^g@ z-m+S;UsjE$Og&-Bdjmp(D0QY``R1MG7<$A5;~u8>)9>x(&xWAY1aAxNMpnag#sD>b zaLS!#-(xoUuAw*YP20I{ujf&p=`qh3gI1M~Zls!*N<%{f$@w{H`VPoTQOZ_|)mpC# z2=*`O#Udgm01bhbF$tx}nAK1CMz!=~@{x70Hp3G72aSYTy%o-{>h|jxjxW3}_x9xy zrmyq>BmTO{m_5c!<=Iq5jbWa{V!2#v#1+Y|zl3Q-zknbn-FK@&ZNglA1=hmSsPO2t zbi|?u`w)H+)kMv>z;<0;i?1v0W69o*N$tV`dv}|E@3C;#I0)k;K%9#_C>)rPQe#_Ed57m!wirac;hyC1okR z*kW$M$IA!~cJ`f<>bMDuS2XXH1K$G>aqiSE@a*XdsM@xf3k1guw5!7p_(mS*et9e& zVi6P^eQ5kzu35H|uS|1l1kr%lX7U0!h{MS_YJI@Bw3OO|y%0-|Ar+PGp2N*yF`Q|Z z9?JY*#c#ooM+()*?K55?K&{XE*vkyb`683}PV~UJHr;*{7U8q42D&r}#)ohq**691 zAo*0lwhfqqNDnU>#Iiq6!GwT|Q~^iYd*Bob@lN;k!2!4Rjg+%D!0nFp>l1JT;Um2- zfV{==Gf_+6rt&?l(y6ArcYDffyN--P9t}K_U|K@$E_gMrb0Wo2yML5dN{GKbad^HM zsN}$DT5(6a)Ql5XtJeOV^6B^F)>5%n#E5F^Fczy_h|&vvUs)LQpZQt`GO3f{zxfEcFW{%$qAS z-~v+0F`{v%z{a0V=hv}$|N7z8?$$V;fY%sX_dC_&noqJ+Ws{XAUiLHSf;NWAxfi?T zn0Ih6nXhJ{{ueYL8=I0cvB-3i5bnZMaasiSsyA&YbVm(FupY+DjftzqI2>X5osLzl ztI2_2w$|yl#6oVa?AjW2(&%XUxkWP|m0Pb)J_NoCbPV^eu9o#YH4z;guJDgSQ1RwD zc-Ddq${B&f1YDF&_3IX-4=kq91Ie5(&TM7g*<_ZLfpFo`(~hDLa(-$mX6C+itLmX? zX5fW=rO$b^cfaOxNh5^(!2J^53g>n~97T=KpO5Exbw1Oq(R}N6VdmyyBVl6cN!j?N zrBy7Oq4(gBzf=V{EiL1lALAi3m?9e*E;|C=0<)}On5jt?h?>Q_6J3Guq_DEu9+^I0 zZmkIk_ByBjpzG5`a&^L7Q-dSOdx@(N8WHjKjVj|&lxo*fZS7P?QTj%*r-I3tlwZj3 zqY-~SmnA}ElsPR9T4CY9=Z80N@if7 z?xLI7sKnyw^7;aq!6KpgxLT=7_E7b)px1L*<|I3thPJ2e{TGXZq$^QgXYGEu$A0`< z9@e#cISQ#?zl@!EjF&&&``D_r;|@+(0<#jJ*3MMUR+6OZUr(bQqOY;+D2Nn)K!)eE z)uj@FPxp!{@6)0m-1bw$=r{sI`t*;CL@~AZAou-xmJJ8f`%~u6qRJ4a@tZp$A{3DI42rR}EC==jM*KyyWvn zMif=p*e7m>d~rWrf%e`B4X1|XRb8g{3J{YhJ&1^GZfeS3{QUWq8r%hk+#bs7w%3tr zn)r=-XRh<8hWu#4NC!j^)>dF?%$@Rh-SU6(gv%iQ%?jPo@vhc(2j-&dLe2!LFYagG zSEK@a`arZs*f=~gsk)PZ?=3LQu>}ANAy@i&0mqzHL9^ zI1RiAl=8ZVU$VG6uT5oIHAG4h^)0Gwvm+u<^Z_B1jXQH|W8)FkXJL?^@#P6OP0$xo zx5Et|;iW8Y1nTfXe>&zRZ%uM? zqNjQfOT{g8t#x&+y(byDxD1rDBb{q|re9Kl9nMsik^UOQ5P^qTD;iAjRa3=nQCnQd zShbvuJ^B3icR9gRYx&)HYaIhR0zMruNH(i8@w@jB1&O)oHPDiRkhu+06_qGSZrrGE zqM{@mInw|!&rcseY#R`J9J`6z*VM#?D?v>HSDHQ~NlPm>KN1lQn5Cq;bNg=LwpmPq zA&H1+SQve)N4!}D93>NM@c_rSoc_m%Ctno zh=V#Py@-j3H0d7H9t}XZr;3;vcvX`7*ak-`xIEWt_uqpleto2NtK4biP)l=gU|_(u zXmw*1uQ1oGuebRQTHM7~8yy3%H;cuNb@k3iG|@Q>oK_mns?O$`s8Hteq5cim2jg+< zQ)M4q_!9J)+|=-)z0iWg9FE+$0-d?VS)e){A1?Ls1Q^4F3QU{eOn zyPA04!B0A}VeIvZ^FE_jlqVbKAaFnhjsg~A4_J73`UQXYw!gIC$ey=37d97EbtTB8iIX{~C5_ znX8^E31{90-h>#~aCedVkZaZgS4O0x*jKc6_+ zuh*P|Lcn%IRwKKulb4l2JXN7529lb5afEpbM~!hQRtC$?Nrk>uUk}f5({sxBH=ewT zksm{ua&cJ+K>jZlhU!8c9Gwv-X=z4J#eB7*otyDDGPZ_cy{D)CW@NNVlu5j0RxLEt zwR=%s7cwJSVov~^^59N1!AMJ{hsTJK!P4!U9~(R?-aL`+Y-5p;J3c%tEKxAYsxx?u z>))(L4%Jbt{`5sUZ55PWPEcmt%_)Sim@;rlBqKe)0Q$5OflUio)iJsAX1dpYemd`? zCtL!QtDeW4MN4u|>7U9-Mvj@6mX5=M%UVJFEgCu+p8T6P&vD-yF8}B@jIf>Cnsh7^ zbJPYE%?!2~%`B^fgTn&hgBRLVizm*9U9+-Ol^#{^duu;^x?zjZLJNMT#l?ISwXjHd z=O!u@&@ujVAs_Je8OIM?7CTHPIJ*U&iy1@3S+=C3`|maw9DrX&E}zC{(_3tQEw5K; z=MC79;31zC`ElOI%H4gi)u~1?hITjV%SF@Idw3B&VNzdF(Tc(FpFJp5^M$XZ>MiA(C_i0nyJnxU%2Fs}uyrY5BP&Y$|eN$uCj z*u=?vdH<;E&s{PL>?E(ZZSlW+WwGCP{2z)nJ!cqtfP9{{AJITz zzTGPDfl2cnt0XC57`onpnQxD{7OGl*t`-x2*5i8g2-F5JjbV`Bs*?X6`MP?4B9Tgu zz1kMvv*Acu0Vu`8d&LSCpp1t=u)FOBe4)@EUwp-VBWqqcXn;_~nB9o~V#%xqNvbv^|dbKnve%Q;Izmz1BsQ=x?XKYyvK+*hvY z`Q?2HX>(NE)q@`a*NZH?uGjzhg(+u&fEw_*6NxZ%%HfOUP0EW25E uS&&a~4t22{L;eAg`}luZvHi!xS2(tc=MAB|)yR(kk$5F5nk%gP@&5z44Wym` literal 0 HcmV?d00001 diff --git a/app_python/docs/screenshots/02-health-check.png b/app_python/docs/screenshots/02-health-check.png new file mode 100644 index 0000000000000000000000000000000000000000..e3752c4a43008d7a5c7b4294e266b171dd2606e4 GIT binary patch literal 10579 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 DqAe-Y literal 0 HcmV?d00001 diff --git a/app_python/docs/screenshots/03-formatted-output.png b/app_python/docs/screenshots/03-formatted-output.png new file mode 100644 index 0000000000000000000000000000000000000000..f71e10a493b8e0f83b69ece5b6b123f6e53a7d4a GIT binary patch literal 79040 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

?E-*r)--w(g}6 z98@9*wpM}yAVvr10bsyT1VU)PlLX`f3n8+-ruapGH21$u1>S}6Ppba~7&`jD06`$o zfH8o?5Ct1F9i$7CAV^0befY~nLeop{YIRPYk5UgaUr}$!-t(6*05W1r3_#iC#b0y( zg^D4_P#F;Pf8*dN#Mp5DrQF}#!lL~R%Q5~cE&p;?dG?Gsswt6|X z|BM4D=l&mn-)t!3{|W{GU}XU&Da8L9@Fg+^#@~&oe=V=n`n3H*vq1BWZ)4)W(*Jx9 zw@1_urhuaQGyUK4Si)>oe0`C8|Hk+;VOe50u+Qnw)PK(_Y6}XhM=MgnRso{BDE^)Q zPl_=BfJpr-1N%?P-&{dZ!+%Uqf5ZMCvY>_`=t=v3vVVW0fT;*Sbi$IWuLe2N-qjn> zhb$H?hGipC_~#-}ix%Mu{U9ioVCNSECSba4g_q8-Oo0>sKHN|^U-JPF`ToP$|D$f$ z^}S1v#l{6#P*bs~L%*&)G1i}-`8#ju%KNe}23m6X@euUah~HE(jyPBV8VXDwO5%US zK~wyvTKGi)5{_d6pfC$?QOA;WCqb$Xy5<++01KWr67htG07{t18#2o~F zrwAr7X%s9JAx`PPzyTx-K`&D9bKe#c{pWuv><~d)02Ai$%M2L+Oc>W+RrQ-jt~vR# z8LLqfEQe@1{+}i@DmWYr$eUG+;_vJF#liYN`2SNH3I=5>_`mrxE5lN`LFRQ(FCA#| ze@g$=&D;eJfsQs6q85UL@?Y`)NmKAQ5=`ma`j41jSSWCcX&)c}m5mDY&!T^QC9mH) zWTP<0x%xkb1S~b6Bquid4NgMOUsv=`s)FPsARdg`ZwPoRo;}wi#R~pTAfzWV0su!* zx0+J2ox@+cwKzdqxTB)F!;bX8^2tCz>mh~$gv4ixhO-SzXYzsoN{oy84MpM$HVF{q z#ax&h_ufT`tp|-R=s!FgiUROoB{a}~1p`2YlK-F6ukZ_)5a|vI8s-HQ;CJ+e{|Ud4 zfT8Rh0ExaZeZEB@cHv|Ug2;l1P!NzP268Xjr?(qCvikL#k&tjU)7lMT9T3=L4n&oTzqUqHh*8?sj2^}rD9j4-q|tZBSs?>rZ2UJ9z5 zD`nnQ%TmadM0Ai@K*ndJ)7FQPb>gaGC3f}=q|DZT@@0QYE+k#v6ef|EG(YS2 zfQkBm4s8?np*i`6*MsH9E;miz?de*A_0af6Z!)cXwXUzYI9BG?(IcBO;RYGG6O=e$ z4SKGieFUkDEMB?6`^6R3MgTC#S;SbyAaL|2U`S0G__z%%Pc{XuAn)yt@6e7z5oew; z*45iJ0R5O`179#wEo@qlTXpwJ;o=cw$914+t)IE^%@Z0_bzOk|T7Mp7=#Iv}nAB@1 zd%}}qV?7zDGSdE@iUOOg=lgNqF^UW?1C9fagH?z*obYITx`1XzyBAjJ(a5(PNs{j~ z%0bpCq+#eo;{-$qmOWSPPEMdPxs$T@_dYk&?i?%6{e7y{Cb1`Z9)vX{#RA^r0p2MJ zJ>s3&`9o+Ma?VT&J!)9Z<-YXi}*E&l`oV?a`Z~`K7~meXnI3D%8=hj zKdPfrap}lnI40}kDY7KcKdOCtkQthD}8Il6F|!I6A-uN07C2Tcu$dpl6<^aG`fs^|NVds zYqT|*=7q+3DUxX^fE925nP@@M52a=4;@$gV2sCD!HBmU z3YTIwvxq3h07$v*%;PNs1uwJLiH~!z%m9-6_J)=chLi2|rVu0~HtmsY=+d=`n4Txt zfS|IML_RMa3XjReDU$)(ah>QhoU#DQ#Tgu`;XL$Wo#I>17@2Jw&4VmW0juvR{H}`$ zSM&cE^P~0!L#c1d$pu$BUB74vKT63}eba7Zj7l_*PTPnSVZlRq&Ei&fR8onph4;iy zW;EPV&hQDMXA2h9;H`LkM6u#pXxI4hjc?}1vzSZNSkHaSx+#OE@s%BJ5C%J36Julw zN`rL@rUV$6QjEq~*^$a@?XuJ&RA+|CiN|`1q4ls=BcU6Ta(HicOJJ$3Hl{5Y;20V| zj@6O>x+voU-Llr^w*xZnexj8LIk{oS)j5$iaO682ovaC65zRGH0!E*{_ z;e8xfZ)(eM>c#Z)Waa3o&~)qD=M=()XFr^vZ2vDag-AZN>yF4N)Mp?3v=AsRXU$6z z7C4mamlhq*l4RXG(9nyHSmP4!{T7rL3~ERSy}OTd*H7w(4!N?L%!2$H;RCxwpf0dR zBh3BAkqcYLZdqFdGQ{h*xq>Gnt;YQY6cREw4Okz44IejY(epcF9R*M4Y9YvmesTHP z35|EYd`1M0)g_4E`eS@Xi=uS7Ce#SO9x025W=w{6qvX;d3(HS{C9nr(A7|UOpl3vi z+rArpR8conygtHVyjq~)DLwIg{svQx{y6kyuLS>WUYS%BI!-z(;clm&{2A8;rq0a_ zo!PsS9Sh*Fe;k$~V?dD$Kf{g zm#mN6vHXOIHIR5YF*HH6lCu7Exoe%-jd!82zQjhSpVUO+I7wUtBy#D_Acl6s&KOn< zL9jh^FI-|`b}~!;Tp^M)N_}=RCp|nQK99XvlhCUg!RkU-_@98=FcFtjW=2Ci%Sxzs zNYh(|#=IU!k|&kZdO@O-bnp{GZbja@y#iA8Tnw73@Tc$*Z*=5JFJD*Hk5Fh(~#10eD-y4UdgMEI!Mp8t>zZ- zGRD8#H#Q@DFE5ZbnmzWQ^=yR??wLz?M23j}?pcYeyIYwg|MFbKfmb`+?4~vjWg5sr zkht8U-I{->$Cs`?>!g|89zVY?c6+vCcv)dL*yi0=L~~LcuWvl_A{Be6kRzu8GdG3F zDpI2}#9d`ss-QJH_G5Pzn0w8e(Lg(+NOLG>1D&rz--nEKRW5ty$jG2EGl`QJ7Y=e( zOYQ;;7EJr9QrDFTnt}U5p1L%5^Ty>1n2hf!NaR~rzPoO?p&S154Ef{etOpCs?zWF{ zb6k1m{SU=yQo;L9)?1N-ILoYv+F*R5#61qI0X-hn=iCT6c|@}8WkHiFxJ(}OY{{T zR;$#w)(6RVG&cL>e{ma368S)v_Q{eEJ(q6>2MD)#41Qg4zS(xsVHm&9!D`uidYv&Q zT@c1yV$gbqug5xT^u^%I1aegoK=sGb;vT$p@5s8_PUeh`frf_>_oJezN6WdVQN!@+ zTSA#?*;($71I0zQSiyzFt8GchW=+qEkMY#DT^?-Q}EW&mE@VmlFI9Dpmi#HP7s;G%8 zu7xb0n6;dNfdd29#i&ZdWll2;$QbaVV921`OU?5Wb<#jr;yybWMSWqB;n;tVhr~Eq z&Ba)VsB5@fdH+(~#dUT87l?H;d-K7-?Xn^WG#M7Q4B$$hq<7c1YKwhg)7ncSmoa*h zuk5ZoN+Xx#u0nTQP#-%gNOxRTV~-V4a?idJc~2gWgRdot-r42kz!@hlVv(@D^rViO zKj7%E7H+o4dxmpsoAGp!+6k&c`O=yp8)bH(OjiwV!Hp=cR$~_T_CL#kNP>(INe~L= zmn8Tr{gO1HFaduA;!4Q-B?>|$!L4(O3o$mQKLkPOUxMI^MjQ)KpAlsqvzY5y+i6T% z;BurDPX431Zhk=%gCJEwJ%b?14Tb9EQJtWQYYV%U4K}+nn>xJN{b$3PCuxhkiko$g z$xhjK?vT&W75SXM%1=P_+}zD)6!p1ZY1$?u`vQ4Atn)`q>F3yd#tc^daw6rWFrr{B3!ir&jetyoW;qpn&w*PrXM$Usp z$>VJ2ZZgU7C)emZDU!o)j1IbLzGpVttW|}bVWWpeHc~7gg|x+#24d)UA>+}&kuxP= zD^-^LOffXwq$gK-YNxJBVgiAW3V{_a=ok;dG}KC#G!oxO%1$*1`3Z697<0%;4#C)T z76r=QS*oS2%~?2f_Uer_TubzcJ@Z)=TRc0HEvuk3ze;kH;ZYL1w;WvldvXE$*SP;5 zUvC)|M-X+3&Hw|05AN;|2oAyBf(&lKCAbB5cXxMpf(Ca2!9BPnxVz`^$^GtH_rCZ3 z^;*^4)m5vz>zsXd?S0;gk+CIp72NG+Oz03uGR*gm-AdIdPzDW~Gmen&bxHL&SqRvf?WrHoHqDQjJ>lMe0A4qGpqBZ!AOr5QSl(>rg&q|1 zVz_|sdlla{SK?!3D}1EEfoC__9HXhJ!uMSuUiLJQAa^kPbKiD`=|j5of?Q+(|( z9h6VnHtKx1DF?~3F62i_l{QgepVsz}c%k&ep6`SjhOWyNo7z6!RM`oBu}CJMzK?W{ zz*tX=mXDZB#qgMO_lXPyXIVB+$!UN6F2LE;Q=NPJ%qz93KD4o5^KSD-aCbJ+g?9HM zZIwPahWDf0Ak-xe^@4 z#Z@xN_)W!LeIrzZo60bp*KId9AQ4N5@&wMp|rq**;B>h-t(oG3FK|L&6F>o z3Dp}VHfIo_u&;~#siH7tZ`?S5G5oMwtUDP<`L(o14F}dPVtOn6R|Bi~{PE|9 zQ;|=tPiIcy`HKZD@NbweP!Wk2rBjX?EyXDb<|!QqF`nzK@kjNJt#42J%S^QOE)V5> z_&kd)1+*}~X1$t`sia(mrXndLONHItXEAj-j+C@2R;ADPYXF>D9e0doWAx4;0P?dL zwTuExb)TUJ()k1q$+S0p#sOFe9UcvO#+d_6CVf#ueUW7>^(si0~kEkkXM zbkugE@Y}^nQ25AX+tZeNh#cr8s)g2P=oUG<6UG|E-MN{os1E#!;z+8+nT#y)AmqGK z@?H0EB$o*+P^A4yxBeU)o8wLIWXP+qqrKdy{L%QyhRnSb#=O9$-)TxtmV1I{$79CW zETg%4IFDe`ZI@|es zo2xkxn@JNfx9637v;k~*nH252PT#IUwwNj;CH zFf)|!FIt=F+|Xrm4pjpgWNNX8?Lm5AxSLpxsw`uA0wy7>bY`JsHpD>BvX<6u>42Ed zG>^Idbo$YG?!(1MG(oC;U8oqX_WnNrf2{ceI0#POvFEg+B_t`9f&B=bc+Mj6IzJfS z@%xiNrH(d7Y0`k)&ZizuOie$7NSX96mfeDupC;ODC0w0LzC-aD5NJfk^^@f^KARVt ze-zQeK}^qwK|%&XmBUps=s#cs1M@Q?VS3BuhX4@2X%tMMd0j*Tw>%xOtEX1E@60V} zQc73(HQ|S6Da^?}uG9(QFcXsrq{-nEIl}I4Ch4>3^@xW?q>f^}j+2GwSz}SgxK_Ic zb$obIJZ`tqYL3^^WXlzZ4b=uNu}W9P7=%Zs*Ai&FW^1uYO62J1JR8NW%3?~p-5cD^ z0HQcg?4(xkfY3K=wm(<&qOXKL(~!kP`t?uNcn{6U*+z>kOy9&OljnC^gEk5ZovvoB zj6N!|2o!mGC6B!R#SpC_P|G_!NUnz=BPnHT?Sh+SCw{4PM_h7W$-d0oz`b1Y;i*8O z!rWUVT8)S(jv1xh0DGm-0P1gyS31jq0%(3;o+%3x`HNl1Ep8fOMNfwVAUkscm9&0* z&;WqKyE{{7h4%WJ?IBLk*T>fC*++xpkI-8BtIJidy9p&{lG6|6cgDJFyRp*z)3SOf znNjB>THIzSt3>YFYz*AV3-HUP! zYy)(m_Y)G;+D?}HZ_v+DTwEhX3PS>O)xLkVnCG`Pt!XXOMKZ0+rWA*57oQ#v#rLMx zJm+xBP6adlci)~lCBfxwm#;O5b%${}^^H#^i(!}@%2R~0vV%8;QI@aG1e_gM&zuY# zPjs_|+OzeW0%Yh+bHy@oPkmbSfA}0C{>)Z7{{!%B_ZORU@U9a%702UbXYGZ{GNEgy_qUt?_>bQq*ZzHeK+DHy( zT66Xsa`-a-t6IqC9_8B|ik$LU0=(Tp&s?aqrMdP5iE9l0>w~y6Y|oy&IB|8cy%-is zBvd;5q+$WT(4Le=PA!5Qo(-l_0Ps0;7;|+YkZSKlAHu|wHh1sE`R;DZ4tmGyyU4Z$ zs2ttOlpHmq)=lzV#ZN)qs8dgE>pH}eHS|dA1a@Sf>HBRF8Eeq%5g!3<&7zOeDMQ-_ zp*-IdM|@2KGOe3Z_SjC9XX6ZH#27!5AH?6dOD+$$g;F>nn*@jQqxegoitW=lOR`XZ zETkLk-K>?#fvIR$+#l!2Q!iG+*XVg+=)%Y{#l&27!pj*f;+sudywX>`mhH?_OGS($ z{(UK%fBrKQ8SdA+Maw8yjV z-B?m1g5YIt@m-8 zz+I$A+~xfqLMHITa=)#T;25mHg5=n8pY$^K2uEh;^wsv9QWoyspB|Xf3IFAj2tUi$ zK%ylpj+07-gl`kV9p>xL7gy_LTla^deB+&}0YP>{=NsN`PmJ1|WteNHN$1;Zd)g%{ zwKAHYrcR)7E^MX@GfdG2qTB90NOFyEU$Qm?zRATP2Xfv$G|Qsa;ATrC@NHS}iox7< zK7Ds8%ta2i^AwEK?Sf6G(krxNjQwgrSERxe**fd^_g23AYkMJ|%SBmiK))ONVOWVJ z`7fU%6>W+rllu}5Unez!6u0Ovd{$+}}d3vso!N zB`tYzR@toSbG~Kja*3u`@|ll!;tVf&m4hWy_NYfNUzQYvEYw!iZcAjC!Aim#?3OA6 zrk@7(-`5I|^y9FQYmsQw$bJlulE32c*+(zJIXq_)ZoPdQRfZ&fTRy+0MtfM3TpeQ? z*+SFOj|)@@%I>EJb!Rx3e|?qdSemlS0M{iv91;;7Wt>x~^$UR%bTKlG?#9)$Lfuv; zS=p82SGL6px<|!hE?)^9bi&AkZsta#%5O&)yWz&kP-YgRZOgkiuuBzkgOmHSVPoDH z6vk(0p#Olb%cFC7n%2h#MdRfMk@2*Su z#WIT-efGkPM)17u^R&kCPHIH1qMD^h$RL1mN(7sTVeuzM)XJOpMN$){UKcwku~uG9 z5)|~Eo&1l6m3xC7cAz*kBT{q}3I&3`Hu!?{)4PC%ej*pCK1mx1P@{<-hX^Uul64DY zR^!}OZ?r+O@Xm3WD<5ZP4n?%Da)GDKv|PAOD{TMOnyP(b1dBb08p!b3Lou|crkQ4X zT6CH}`CL!<5%0g0px=uS?_$tEI2hRX1K9tSfI^HM$qfVEm7rOn7w<`^ga74!W}xrs zsxaiig$D(MEg|tDTz-Aanh13Cc=+P8%>WhMtR?d!%h_uGbvRf353m$8Rk44gHtKF` zaaHceTLBHX6HazJ?9Eb7WCUJVpYGlSuT&>M(Sr=^@!OvJRq}&+z6kvTNbkC{aC^C0 zZ!3oS7QsG`p&K5%_toGx3FfI$$r_$nQkaCeXh4w6X-K&wPe?o#Lh6xoN3m@1Q=8{s(Zy zpPznV`v=G&*XgcAZzNR{??82%dy{8^SJ&|O@csT^k?cy*I-t+SKv^s(78u~uHUcBY z`TZn5r0{TJ!$u=qWs;GIEy>K~v%kl;O-T$G*569QpU5%cRz8w{+-dUyQB#1>j%zbE zNPzmXU${qK<02h_bIaRo1x+)HF%R<_Uod3U+4c&4Q4z^X;lY#*tBx)j#(&9%uIhE> zxf?q^vx-fwV4$sz6Nd4sQNwQm8qaOE#w6HCg86;+t0j^&&g;qYC%D2^;3HmkIfbpo zOjqNW2hp&8L8o5q?N4B$K;S#t5xSa%DCgL`ydaULKusRd)+G-1F<&e=4dqhffRP@%@Ez)5~5HV*>o@eZ)UbZsh z!73Su3%YgKUXHin&vw_PJdYAtCqb(0{QFUa^IKLr80)eD*3KVb>cgIgEpe87XveWu zU`7pTbNpJ-@k9W(D&rXz^Y@fSS#lgNO(;a2W`z=EKY1McLTo%!D(gxw_ZTqG%3%6? zw6XaM-XsQyio+}Q4<`P`bxjQ`r1SDANKRx`C$#)vLuxrdNreB8JEdr@rk|qN!B@l- z%@*#5bVQx3Y<8;oeiOIUeK6qdEkn%p_XLwk_x;URN1K+8n(`&+W0=ii`75wjI8&Nz z;g2V}56dZ*zA=%r9&7#D)}ncby;lK{6)o(uMAnYz5(3z(0lyl>W$&@a7AI~EchIRx zTKQ%BD#B{w51(JC?%3N#x*mx~RJ|rd}%appO|s zm%p_rZ~Zefe#NJ4ulxhNtY1fCd7FvUEnXN2nG(U|Mp}jrQgHq4kZQwTY%#PCUlPDU zdTPZ<2oD0OJ7c+ycEpf`$qCqtVZO4Q<=z!Wgm>+aeIO8^mOc{qD`@*sY2lsoI@^dnIdpc1oLk7&eL-LoH1 zaf>B%Mm5lrS5&P8s0fe>&~e5)HYZv7B+`ey+wFcGapIX`lk>^++qK+6z3;`LADNQhQh>7__;d3p1dH@* zRx8te_i_*=FX=hgC1B&E&{l`}GT?hl{={-l^;){mu%q{G1c`eRIBl+9c_Y(4$2V&l z2;NY>Ao>T;T9>@}X0Ws!Oxul}lEc~p_nUm-`DaQ00aGTRn{E+qk!o=TA(4#ej9tIU z1}Or*{$%fiFyJqMrYXq!oB7$s;)1ID$4^=Z7IH`p5~2bPLhH68e=3J4dn~c*mWf$2 z8Jm}R8#0+5z!6Ev@wM$Xg-_GR{6bK5e=tuT3;M3yxX3NTh2wS=Cu@fV#Fv)!MV*ha zLDB)dld>a#Z~!V9^{m;NzosN zrYn`T3S^{cnlDp)0?_G+kgR0)#@8r>Hl1L%Jpw7=O9)DgXuMea&2(~t#_-_O@QZzu z+YF?agMaWKZ#pj}`Lfzco{^{_jP7O%I&1;S9R2(}=z0CUEQlE2Crr{bTf%-CA?G~k zCY2FZ8Iw=d>@r09(o;gC-0|0ng&<|CVHkR}p$6Lb-y0@_Z7#jk4%0jzNEF@*heWI> zrR8k8S(ayHuXA?Y=Gb)Nw)n;p6J5Ckgr$Mv3YuJr#ek7ab;*A zcHRqMn#$QZdQIdM>p*y5@2P%Y$H|eZ5?CaM@W;fbCa=^=$Y2GZ1tT==<<;aiA{m+qFP^0!JK;US|l0M+qtPf?fy=7L6+b@gVh|X_PzB zW)%DT9*in+0oZ-v>*w^2D`Nf3eAI7w(*xU-QT>)e+4y+KYUVgfblC_$zgZ+Ts1C3< zwp@?`iw=ApGphLm)l_a9AAVJ0+(<|jl1oorh7?LhXu5ZJ*3Fi!tR*A7fZYUH^KSXTqg zu%f}S>)bdz_x}JEGGXTB$U?XNYLe#lkW`|~LCH^FtSD%dM;j!=DRZ}pou5ZCLFpJ; zLV7v&nD^qS)rZ^>N4A5G>LzrNe+~R28o%EbLh+0bU-XQ*C3FBPJz? z-s2LgDZ_=B>cm;tT7e8_7$ZuZ9{JhR~}Sr_fK^aYsr8D zBDJ0;R>Uva$mySa-8>KBcG`olYktsJdJu^M?pD^apQ9_QUHPDCSZnI^`QXdhAUi$Mi%bd@C%ulrCq8EgXhn3y)BNh~_B{d49(;NcQUp9+A`_^AOf)Uyfwx18uqk}2tx-b5_Rr9}FogwHB zD6go!MHV;kYXWOxz%$@z{ppkw;Jsqf%oc8 z1Q9Vtr>OS*vPM1NspFC`}9Sl!zJBRHBke-L3jAr%%KQtzo~p#nywxK_Ad4aYw4 z!h{`gYmeC#OCPy^!<3~4yiiDBlkhxF2sP9bCqVrL%Dn%U8R5Wc22ieCZ*fTA=^|*V zuco2?gj7Px{+4vJe$0nxajoO|49;TzG{Oww>nYqr3v}q!R>5)`W{!^{;YgNPwjLMz zDG8|#1_Hg+;Gm&TLS`_onfkB zpq{{hS$64>gl}0GYeCL7vhtR;dBeJMRAJhga5=pKP{P90M*4s;GOjo&?}IkwDQUjJ zWf1dV^^B`!@xqG9t(0<6Z)w*fn|`+pTv%#a_ltbc2Xg+)E#YWVFrl7Wm_^DG7Fy1J zyPUF%$Dck-6%b}f`KI7|VW*6Z7UPJbXVS9&az!S}E>8=+gTB#|eB{C#4gcoi1EHr| z8?VV+Z@uN=#veus>p6LQMd~>mLc89cU3lFH?ZT5e*{Y_Iqv#^(00plr<1X)bM0Dnl zJ`Wl2S|V<{y?*!t5YF}rv>B#aS`z*#=j6hp>(PtEQ|LRy~C@L%=(Fw3Q-ulrOu4l(Z>P3fF>Mdro;&X^P;3s>*hdLGTaZ zLjQVX(P@*&YN~2eFh}QUuij%x(1U|go%@fLQfP^~maVsM-1$L;EP}zJ9xqj4ZRG)u zqarU%l-R<#bpFpYY=q@}eyiw_hglrWswW7Y`sr4_nHfQN1dc}4Q!06kb1u~Jo2`6- zTxI>r!-ED$`g;g%rE(hjhH40Hv6OWO>xRoGgB@Y~|LM&vFAp%E*-Y5ZH6Gz8;u8tm zQa;XWaw!sC#?*4VbgWR2mOt}$arR2XKO^dDSa-B~)af5`V?DRDd9Ygeak_?kX~|#_ z$HARiTVZFx*}#C`M>8JM9pmZw{Az&}mQI8BbQj3-Kc#>Y3T z`V@+{QGYbw5a^+g+`a3ZX$ECxGL^wEBL+$qSlt&*8^axSbz;98#IlBBJYdkkh?ATH z-S$$^xBG;;cJ@{>#8T9anlJwWD935z%87n&5x>qKen*ldhCh(K_aCDt!X;e^%M)&& z`n*XDQ*Bg?zMjuapARg7JMB>gC|dbnFv=SvqaSrpvOC=AF5=1cq@_)XevY zX#Mfi-XJ>sxk-~0TbIppj$(SQ!{zLgLp#<3Y+&od@M7RRMVT*YJ=j-9k!kT^ba%Ke zp&f7VwugU5x5T`{7F`I8$GsjT-Td@>zXwcIMqvtD%b5{PH7oGigFEZO#EHCQ_Ybfu zH*Y0N039QI8bWS5yQ|$?jT{Mq1GCJH`MHbn{aKc=|GIfrAR$FZ4C}iHeq89feQwHH z;gHN<_Q<}ztn06#Ga*Ai1c@+SuvTuB!l){ZyayJ%+8$q{^DEw6x8tg%;P4|F9%=8Q zXDql$zY4qswMzh?Npd!%84jTG*lF>b5nhLu3EXA@^ut((ZQD#{D|fQkYY1e}Sc|-; zD&_7{k>>C|VUn1+QL;t}_6h9}0u)nVsQ2{S%uD1bUG=Ct^=*ibji=LPDaG=UcS8nL z=$VC}Fc!l&9d@%}_~!;_S9)^38opicO%thj^d*;hoeAf;O@2b+9W7EP<8LK21*?A+ zQp$0knB;1skWHG~&<%`AgkNpXTncrIzGBAgOtB;X+tSm?uC(5H< zR?y?G0o|YI!ZzDc^V*bOXY zQUu|=V8MT`!Jf{Py2JAtV_V^*uH`FZXCFo`U1aKIVfm`VK4PO*b16;26j&2%rE2`p z|G$RVvkc=wxg}z=HZs$E?=CjO-#M39Uu{*{q`*D-{8i;= z<0jB`>w#Bxn#PpVnHSgzyuTL?-0ZjjqX!7GXZha=c<{VVRG{Khc*h3SOp z-Cd+iTF?DKLL*8~1ynL^{-eFf;rsk{ZOj%PjPlO{yPfl=k)3oKqMx05W>@)2q>((0 zFl~7^L)hw{bso~w8`K)c2@js{$9YmpVEdZ&XLyb5X6!O;4L*9grQ$7Yi@>Mw1WQ^p zFOci#!P~3ARt}2<@g27k87hNJBgkQU++aVD^AIv8$<{@RvAOyu<^ALN;exb-8o9FBo$g4F{A2GSHJE zp@XSd25B2~e?-w75*Eofy7U6YA~+8&AD(*9 zXXIcFV-t9PROt9))`T^?#V*e!Jtqcx?UH%L+s`9x+;@WeDX4Z44oZOa(lXg!%$V!( zv}U^MzFFeASV|SleR?*9FaWTDvzZ38jf2u9EHwFg@FX0fTb`9Wtw2or+onDUA~|oX zLc8GpBWqCf*YIbZ}`=tFot@j zD^lqA%DhNV;mW7kOUk3SuEGvbV--qsBZ zeu*DK1PEue+><*wZw0QdnH3$1C~N(YJ|@C$SCdQnXxuRNJx|&}WcfqBkV5wHR1yZR z=_&C&_6u2?G3zU9$mc0szad0%&xpvlY1fR?=$n0n0>M3{zqAFelFmvIyxH9 zCxP8CTlLUpZ_lT6#`xPyKneW9e%!iJH|BIu{Uch~Sz!=_bB0fW$)j3yb}TyBx)06w zxI%ZIxS*nR`gP@hzp_Cw@83uc>RSR#i04BuYE?Tf`jU|FQBtA2Qs)Oeo%=Xs^a7XeW#8!sGaC(dwn=X=S*-dZqX*=HH_`6f?-EB8O5|je$&S zn67JA@|^b_wq8;|e`2#|7cFLpiGr%`O}loLB$)^XRVbs}g7gNY^}YLY<`2whCfwzU zuN|d*2Nvkhk}6dc1V<|Cq5Jz?{cw0d$x@70Uo?4;5ki{MZLr{~!dA=TeaC%plpKr= zd9(M9ZfWw_cIgx?i+yFU9cov403a5d0STR8|D0|E(%LVWS5;g1jhO)erI<}yCdpp@DndJ0lS-jB=1J6rrkX6HC zZ@T&@;tsdn>-FF-GX6Q7AiI#)_(&}k@i~(1pIZ*1h-#sTVgY?ewO~km`?t^R&5HqD z1?i6drdUz^=`)A)Bb8K~#)9|+A5)@BaviVdf~DYN^aliJbLsCT2Sw{q+lyMy(c1h2 z^$^Pp&Pl-0?3P$EJ5dI84c;%UJu%yN(Sr2RLmC~vk_qF023wG`m&1h`r_cFN)1Fq6nr7-5K#hSxs zVo(Y8yE8;i>yc3tFfcFxWa8{~8_(`PL=QVKk*;QWkY=>~*uSina{_`@X8!rX@KT2l z3M=V$pFB%g?+*RA$VOP$7r3B>&{d21?Is+IQ$;(yHtkIgV2u^ zh)JJ=jvqe~U6TPs_4uI%QD^HdUr{fJ)7MV{P`!3;zlf{JM0w(6aU~%Jv2p@q+`azy zZ=+PC8XkrvWctx1uKPC<$UxQ|&_;hPKc2A6!-9e}@!nYoi zINwz`=05cWlZD27K#9Rez~kD;(^Xw2^ZO--v|92-L9t!4ZTFuX4I>?P{Fyq zSZHv7L`YNAi|?^jp8{-X;C+pOUkjeqL?LG-8h@TPTsizIbzqNvmAC0fAa(rm=cT#M zuM2bS75c~S4g{5WnZ5B@YA40fCvy4n?kSj00 z>U;B)J{vV3xVt?VqYW}syg|O`Y|1T?1|#UUn32>EfshZ0qD}(U?D>*ouL)fZJHwQWYsvd4 zMCzO#(<>I^W0<4%9(@fcoxt4J0M?yhOd$t$iTS1O9Eg^ zdUL~V4!8)DEZ2@=BQFu;tUpJ%kjPaOklSA;5_rK{EOzk-7&n)`#&y(qcDz<0{Z4aG zq8GSs+hzG68vb@9N=)ASW5!wEOaVT3aw@E7_g+<%xH$k7Zt>;sQ!E$q{`uxvFxsRn z#EGXYv#0$Z;Ht}MWb$UnaJ9hCMF`@eGbq(*J&a7(ST>M4ajbFkIuA1&2_S?juHLee zrY979mcAdiXgV9A>5vup9g=apfn|hST9@sYf@y~uqL+F0Wi$IJrv6yoamQ6!1R1V_0E@s(3p z|Kkv;I8|@*2M?vI4!R%t(~1d#WRoI)4*Ni@J%Dq??K;Ny?OJc_GJrA1{`w054gTTp z5voI;2mrX-$j{*yjIwNjO4hCLj!2Xastx|ddEM&kkDrw|sLPirnO?o6VPQEtYrRfc zFg#?yxcv?$eud@%kOEe1yTsay3F6n)R*~}!VS7|`qS{2&u{1Hi%H=h8R_dqitR?BtWVwdou6%9l+LWe?sY8LR*yaL@80 zDL(p#NFHPcsN!ZuNDZ`|w3mn?Y2^&>I}jB((83{CI(b@sb4t<)O;}3%TVd%#;kk^! zd#{KW9w_Vw*Yo7XOWqLb%Xp>1*K9f5NqUYK^V+W&$HtFxMxlW;*cid-iU~c~;*Q)l zi}u^LVa~LLA2$?>L&*C~#P{8X3CjGOx>LKp$k%4)(3_WDt^Ga1Abj#VaVSyYFPN?* zCE8C15-i&x@klQ@#t|oBt8jNGX&$>18Y`T(WWIe%mRqnE`ZB8Se_tS{5UM*#JR(9K zqc=tJs}lNmlRPB5&e0#Z6@iBe%GCtd{%IkUmiBQ!cX(yhISTr-Mr!&%L;_r~>i!4l zHl`o~5X`BGw-4P217j!w=*<00KbS)kW;XTt*S^tcz;1*vaN`5ooq-zVP;=(X>l4`5 zKjEd3u%@uk{kY$$DLkf3uy!H8$S4E@J$;3|{sHV+k0#07m&sAl)wVo*Rdl6(-w-+W z)U$?@&$fU3qU}TUb@}8`!0_NS|M#El>(Bs8z+J$v@-8jcz@(4!5Iow#{9nnlUpJ zd@_YU!)``^*%)~QFdH1XUR(Q6e#}ly46ce9ryULfNle(}MWWCq9fw<AbeZ-~b_$j+uf8jw7~^8^!LQfJn-^yrz5`RWYc_&ssj#L@^!w$e)}jg)*D?2m z1L52+)lb8m4kz5FjjB4szmR3JeqVRN8xVB0{^7#D7ue!MG#YD#Xea<|l;{>6$0^7; zHJ5r)u7=3{3)|CFQWHoxM+^2AJc*B-4P3plC)Pd@!l!ibi&i zUW6s-Q3LrTc6J$T{o99QPQ7w-Nu`Lods+YQ5UK0I;8-+mgzbL?JRc<@VyE$W9h8-E zyh<<8NNCn=>*mrgu!G;}7Coq)5>CXH1ov0W{?HG)1e`nd>E@om19BfSn9-BNi@%MY z3thr?$24bP42c8xk(yAga88OxCw=!k^pmSwM_SCiTs0PVR@{VG*!}?Dh7Z}~K>dbU z>eEH?tXk38VzSy7=5o%@l|9p@)gdbajG!l;qz=;}$x7CxR((fY5FQeQY1U(5Fq|NF z5nBQ;j>Paz6ukC{dA{|S{`!POkQ=_}b(f!35*q05GDOHZ4W^yt^LfF$>yIB*BU!bN z2(U6ge_+J9bqpLP4{C_OSZLM6uwP=XVCG##-Exva`V0bmBp{a2{h^VsYEla#{`~jz z!+-@&TzzSP64o%ADgP{|2-D%*7N3BBpG3WSI3Z7{niXlwT|56VF1uc&X#W}r^m%ju?%^wFJ@Oqa9!Q;{Z;W4SC98my6mGHRaMolgyg#-M;OO^Ncvz6zxzLO zf2$KxX!Ngx>J%>T#1<~Q6^F_=Kb~kiQFeLnEu^N=5R&_yN+Q0)yND&v| zb&qwu3eEokS&}VbT{&WQ*v1{GcRIB;i9lEH`Qo*P5&=pUYZg6Y?vPH<+=Gy?@S}9k zj=kbN4KCJDG4Y#E-t;yhK*N!NJ+@>`ikvvWL4{bRFJOei4@yBPhG${?O1lCRP~@o_ zzls0J{hAcgKHDsRkE(4eBXjc~eESD*vFQ{25a{mdJ?;Wh!bGDsJcRgA#T8y_kbng#!OlVwGU?a@y zrvZ<##y#Nh3n4SQV2`fF$9F@~Y$X@tyB~fw#m7pDKTfsQg@G!I1#XeZn`>{#zGsN~ z+Qh*`nIl}5{4}CMc^(IB4CG9QI^yZ1mS9Bo8WEpOUZHiZ(9;jK%XnK5G8j)Yp448P zdWu(XHJ0`84p#r*p8dPGTh?&;O5~wkNz*!I%AQyNlR1mWDW^TZC&^jk8!^8qZ?N z;DJH6kHd#F4Jzi=dW{=E>X(DX>GlBa)+;o429TfQ%$3=v)%rroWS3 z;DXfXy=RFU$@nNC*e@ks84XLQdc(WhKy2{I?vBY4MnK5hUmeDBOkttK!N8a048v|t2ZU-C`cW;0Vks-|8~fb-o=ooBhLB{`L-yIYm4uW|wtIZ9v>;hx$rud9*MUD9ekzD1 ztY^JL(>kf;@n#saba;S1TEL*{h*y+WzDy2|ibdBRJ!yWrA748D%&V-|CZcfi-*(3cMyk-6sZs+T^A%hrH zhYPTWIWj}3z$f4-FQPT@-z* zTL|4l|IT!NRsz`0{XQ#;Hbt}4uOslc+GljaJD2hMGp{6-&U;|gM;S4P$!Xt{<#d)C4L80{u~o-^U{o%JXujrjq$97l#* z^KOAqs!d=vI)vK1I<-$eJYLr>R~mC=y=jAR3>KT-(&McvQH7_IQ(jHv(bR@oczU?u zBKok?*!Jf=42J07<0x*w$qMX@$HV`YLOtL+69e>$V=RleZh#!%c+g@LxUyy{vx*6s z3h&?Ac{b(WK|(!s`(I6L1JSVL+4|TcC$c}PN(6*4x}Wy`;NnvPsS$7wTctaB>1%L2 zhp+o$&9NnBigT`ZGz82O8Ji>5;ADyx=g?^3fW7eWB7o}MGP}a4#d84(Pn8`V(6rGU zCn-W@-GDs?aTuYL&r8OgG^{ZlaUe5+AQfWr{c89r%D3L9;UNioZ7K=*TB$h%G>C|2 z#Y0*5nzV&UypM@>3dR>&QaE6LNtVOZcU~e4-ai-?qlftN6?Mxa7A6kqSF~bOSYFsK zpBgBq5lX~4#E*$E1Km1<`Tm1Nd7-J#jV>3J%UmY?`>*c>U>kr?nYI#5$(q>2W3I$|IB=n}fFTVtuOZ0atroYx_}q}5Fv1S^AP*M#uLWel z0u}^weZ~-VC8N{FM-A`(oYCzw}!mS{Z{r_ zIfF&ArJ2n(Nv`Ai>fnmy@TtlFA1J1>a=4}QSUM}*^5+worspk>zbaY(Pz_M;KG>%l zipWcf+FkFgke}8@j>-4Gk(hAe9A5I4`wt|enSrND_+F_}TS1-{-g9I=-?90l-U(aa zxZGbzH*rRz!Fi}+>akNe`7g2n^U{BSH1P~*iGSh7BFaY=1xeC8lbK@Wk_orsk^zhR z`r8Ycwv?=QUz?lD{h#vn-Mt34fj;D5!vCae8D1mdCM>ECfFjGS_hb`;=Emua$@hH zXqx#{{cNl!18kz7jCB=u#O(jDhIE{s?Xm6idul$UO+qu|M};u5*}&9Gb{9_+mW$^qA0b~s8d zL@macbI2s#7A-S^@2U_ti>7)$_}38nnDN-tHHOe4>}eJr`Bxam3oNgvVSyI|rGEgU z{Y4iq#zs2&g0}n2HqmpZ0(C@$gyGy00Mz~DGuHA;{55_9){uzMxzo0QdIQRGfsc6y z9FS#{i>IRcEr(ldOxr^~JA^cpD{CW$Kb9z54TkejQ`95N=wN%z7eOgt6GWMMgs-d+ zaOSf;EYL|pXuDnOMhB~fpquSoB7+QZ z_*yOocjLkP+aC&kVyO6wX&H4mJ%e62G_03^PqtRqwqi$#7tMY8Mow4q@)$2#MX^r; zAaJ(JiGS#gP zh($x}=8g%(dXQvzK2@XBChm?FAW#fd2~Ue8qi(!lHcs#_3~TO24aDlB-|~cp zh7JRd$Bwb!auP&>1Z{j72`|4xeO12)m`UEg%-3GK)@COX0u2#ne&-bX00R4J4?512 zlMm<;=>4h?6zKESCMqB2_fN6m4BM%sF~l}j7+l_Q0=AFzE3isfzu&&~fw*4iTdz}k zzWmkmH7Wg8sjzKQsk5idiQO|f86kj4Nl6H z#+ufwkF%Q=A|7$GBRu|eqWrW`w#Jm6a6hK( zSC6hsFn2#hyB?*zDDJV?L%%KXy9KPVhfrgz5hAd#yX%E!^c5TAuY(putZqbNLN1!K zZwGTe@quh0(8p_J033qcUKzSH{9VRqp6LjONBYk3lyor|GcQBfCDK`b+J>37`24}} z9_(s_G%$YY=fbf7K?3W%(f+@}tn4`==ygbeuZH2Su}upt@8!fH^W}-}mZV9OwM-y5 zI(J5bds+$?rNH(gG(p)tBS6erG$qL+7whgkcKzMOlD^51RUx0KOpjJTv^ER9&NB+o zQWAhlPiOm-;l&hMR3o~N(u_fd-cOaKBZF4n_1e`;jm=La^`d03S7^(HyWBvru*l64 zJg6h}jG+3#4pWhki`SeIo>)6teApvqW94tJMq!{A*}AARGx5+ys$)CG&0^W zcCZ4ad74^!64{JTayj50{s6j-p zVK90mL`z1W!Dt~edguSnbI$*Hp0mz--uIk!zW>&JuXTU;?R#JQ+Ix2?#v`g)FHg@# zxPijM;C>_^%c;VZJ-rOg58yqIyGBJbHnYx3u3+riF8yDbi?B6dW&Kp54XCLV`-KKl z%NM&f1*I;3KDJcbMkolVR#Un|!rDVe4QY%58pFP7hv49jO`+i%{l1Blrh`N?=Y#Sm z7WQv6014xXx6GOM35G_3=Y5$m>WI)laxR!u^jl$>6b>KF& zY+Lq+Y>r!|;OkJvv*FTeWz@HInf7<~1TgT8tM zV+$pdd=nHTB$;2lY`S0nef5$%o9%l!Unv?;oFE`_&ugv6>PrMjpTGD1;=l>a#+@BDDOr(~4ffJPDX&lNv`xz)tV+qT{pd>d} zFQP7~Rhp{jEOHbyDe((B`l!RQ!Ij!dFA48yzz!r`7rvXOkg+v{6M5grd-E8Brps-J zH@p%`6a3CNR7k^FR1GemgemY-gbTy=kC?gQ1qA*xl!nY0aB$x6!^2`tX$kPrhGvSN z^i_%q`uRIQVgk+OTc^iw)5O7qKTU;I$zehcBf2m1Lc~!lV+=xIK8v!jWT#^ItZdH% z#DTsDlwP|^9>1!K%mlG*dQTY}>eI?*n~)HdaNYh!OrM_R=59W>TPtYJGAhj>xy|y2 zB7c1doUBalg}kEI0s;&nqSSR?fvmx5BVceed`#4CmHlm86d(@s#ji{5a z3G{XxWqtGR^H&+GzW~9fk(zXqJZGo`c(c&)u6qU2k( ziSAJ|*%4SeE|KxM;`wl-xo*Hi0((|W{_7&JNi&paXYsZQbSzpooRE&dTZR@quLx2M zf2vLomd&E!3iZVRsJj%P-PLdNR)Ojh+O0V59e=BzB}59R`}AqNY2`!@F#bBiBKu`; z-uMrRGnW;_BmzQ~hMq}IZ8f)i=wr@1NhH&_!?$72BHzbnOBN`{LPbmiyP($BpnfW% z`x@BNHr%JvQN*!jn&}Wt$lV7l85^VjvzHDt`34yKfjNE+>P&4+Id%bg=orS`)&WD# zfP%~#9=&2iSRQ1F1ee;cBU*vsV}?{}PqQlKd^Niw*X)v_R)46ldBicrO&FVNW`8uo^9nwj zk<$STYH3#2LK{th*$do^D|8j{0qm62w4CSTR+pc{uA(wu)5+_%-F5A+F8yf?H3f8; zsi)TU59TB?%NDtqi<2Y}<+8Z^8OiW{5Arf)s^urCw>I>&HD&V_BXIu*+`~2#rgXov zWkE?lQYy|AHci$B>7A$|WF7i;>@6+g#vDnKk^<(%)HS6lAQ%nm@0 z*tS{&Pl~Ud^vwhABy29{zrBg}ZMCDr5sy+&>kfqA9yPFQUDBZm58qG@Ntmg(@oql> zE{Y`QN$b}Mu0N;j<09btL`PDu5At-A5WALY9s@pMtUUBNO?>t`LPb>k_|iCXZ|zg5 zUKiqh>a$-O^geoa0|UJd1!6>ts6QTa4g`67Zf6(BLv5%|wmb08dGE>gfSj9iAhLaj z#uLmmn#;cdF>uct;*}Q_cqk5~h0fqny()o|ZfwtEkjvwE(eKUajnWh4C$2eX8& zM5=Wed_%A6r8^fgE(Yh{8rWB9TuKhkrgNus`N5hD$pO|T3-ani8s(k^{out>~)aNpHhBE=Tp zSx@DE!c-|a8p&WGJ|iY_FF2G>ttNc@j4C@GdUdeIG^+J}c!1yUwh*Kq(FgG4us`bN zIs=(q$-6Aw58eFcVvKa0BVO5Il1iedH`Xc?{~gex0T;rnKkd0*fL86OB)wx% zMf!HMkoL|=f1tt)05CnXpG$Y~j=4mH$@a;l!!aZppoBr(qRuHHR~OwV+;7daZ^wKX zzK@2`y0)+EjhQVZmERJt=o5~zJ(xEnnIr8?Ea%$>`IRuU7Q`srp(ZYgaB|td&h@Ve zm}P6<4%w($^lYLiZzbGem23Iq#rvm5=*K-*Rj0gzJM^9p`jhWOb`KsNpbw6;-|Z5> z6F%BcLNO+q2d;_fx=-|=9TfLm;K*Z(Gp|*?46OEe&qR*<=$m_@Su97+AHJU`-e;GV z=Jh=)kv~mtOn3C`^@=tpRg*w%QviT9j~vqHh-}0ITy9t@%Ao<3E~&!W@;$@>*%<%8 z)t#}3ZtErVp{tMeVPT3)n8d&*4bE)lT%pg@7NJ+l?hv%U%inL1pXMbST+zkhI7;Ja z=n^-J7VSmyw2h1h&NgUy`9K%nywa`$1)jhWHt$yPqzPX?4`B>ecuZL^*l< zUG*4jeXQ?BZXCI&&Nfi~z=QEjF9*-Ys${ai}bNX5>NgIuS_`F{TKYYOc&il}vy!df6OvszFV%8YF*v_w9m2szdFG17U>lcAX&OZVE3B(pI+E5_CPCO z!AIu04#jhnxL(C3BaUCThTmphHkr$K)Y*3+;~neQ_j;O!nQV(8x1!Vt1s2n0^WOHb zWq#wJ*kr9)PkxFM=H1eC>s~h+M(-!x=@k0VoI-|eL37b!m;L&d5c;;bYU6~2@q}){ zUbRHlX9c&i5h(6o&RXg+%L%GJDIOSJZ4CpD&ng+lyxNv(W7yV2v|>p}uFBp9OxoJS z-0L?5Euv8YBqx(uucKE_q;(hZH5wlqC3s0WK8Klq$%v_?9y{FEYC{%-pUqU%jp<_K z*C`ET6aG+cJ3vg#nNo(BHu<5hYFvZY^w<{N7a&D+52iP|%DXYbawrPhu=(TgLX|h@ z#oOuH$X8CW0!#jwFf@_v+G`gzu<;_F%y8qfSv{sxTxJtT zGp0$(TAcjeaOMByYW@b`V+W|$*aefs7OXX{+^7DquRtMN{=m&+-Y2*BF(GHHSZWrYl)q`((v;GDKi9(2c>-|l~7O-c0-x@~fxK()3$O16W8RY?&8+4IvH#uKK~MA>L%-Uwr5?%-NN#;;p<1bWz&p$!u}JNM%(3R zdc%a&yCM)m0KU{2r0CmRmtlEMBFOWj1eNyo3HdRC`QC%k_B)$75-rT~aje3l>I}>T z7T*`|++Jh2QTyj52e|iOQyzavGID|G1;?jQj~*)}&rZGi|ErZF58L~YoqZI%sMGOVys4L z$boL~=imblC^6Uzo+x$58y8DDwxJD_k-O?(?`w8qqGvZfB+S>P=L@q|9&^~%A)XS4 zu2C80L#)I0sE+=y9(-89VX*u#iVAkkcTgc`OSRKCo6~+VGG3(+*QQ$alwW!n7Qc4d zc4Kj#;i%TtdBbv-=+Irv;Jb;KPbM;@7hf!1Ih=rTHxIY8Bv*yL{Z7a1zFb_h0LT9h z9_YX0NtM5UbqYDJfk4Y#GsxI$ZuiwpI9n$0R~$Rks8a_4h}URXg*Vw;_H?oVq|k=d zA5By+y;e_J`h#FJMg#@4eN>ivnd9S1fqOOqUs+jrC71=aunv6w1W2Lxi`FjGTjk+A zktr{$J4QZE&t2EN#^5Xji}f>frxlfR!?O4b2^1G~$VJxj4*g(qiAyb08a(Xx1H-fm zM7G55hO@EPG8F3Q3}Kjm#ft|+D>>NPXAHr{LRQb_&%YFieFs)4_T@=-$t_UU-S6+| zKdF*pNG=k+ME%pqk+#TM5T2f=A_f8>^TxW93x5H|8Z8N~NIp8?q~Ec9A3~4fyZF{4 z?u54Q6MW>6F{x>?rd&VPaeo?S-ebF8kAjo57)Xi^o_-WiP=|DO_WUmduo66I%owr5 zP$Ty{V#(ttnm_L&!T%6!AeRlw<_sAxiC^wLn1;Tv&>%H?{H~^QfEB1#@)NCw+GwcO z0Quuqeh?tVrV_oBBB%eiWMnUmndEq5D*Top;3EP^M^~g_nDlpo5}6T&gn~+Sd2KPd z=;};{=(hV=q4Qwf!nY%-Z}|RPa^$eD^esp~{;{W8whu3Dg}c7?AK%p!kFfLOJK3Oe z-j%8oWS!2-_wZHE6s$nBF+oe!o9$Sp84RJ6L=pP%s*4}7xwYwJzH|cwq9!Xg|IS#L zoRb~{n@{>g`17T`{KtC`;zXy>NYbuTLrH-)XL{5t2c^Ky{?#YpRPxqsNhwRm?vTCn zz0-j+f#2evU$9`TwA87EwhaOe4p*|7cUfsIIn3T!t$<`JE#DjD=Jxg}l`^0`F)69U*e%589m@Y4hVXI7itwJRsWp9?mo?u{??QjfzybLSuA zBiqfjXAO47zRiEoh-L7N^m(5w(@hLA)9O-=(gZ@y8`Vn+Ww8J1mZ zAf_;+eUpg(3-C#s_hE)Zllrxit0Li*04;piKyKw&$i}2t>3CA{(kS$u2E7IG>VDk$ z2!v(g!G5H`F5q=T(FzXRnF++<8xSl+BoE zUroFzg(`ce+|w?HBbi)mAVF$W7^#xI;syqhb!3YU**$|y@$eU8ltvDH`B1p1^i8(> zY>7{?P9fuInR4vh=ykf?%y6uj(_S`f5#-E?Yn)SR8mM_Qev}+L>manBlpuE zJT)&QVXPhE(WWM{El~Ttp}sn#QB5Af?%T+wL2hhT82+B*({4~b5o-SEtK!-?a}vR# zk4|b^Oh!yFU1^?N+Eyb6V{8JapR}*Z1OQJjn5>5J!()wrtejk(nNn8ZI_<0 zazmweK8T}R%J3t03RLKLp(KCkUWhzOOy<|$d88pk93}SRQ%RPVYUWB|uep%egdJy( z!EH!=S?P?f)weu1P$KtH4@!hif9_3mT;@n@YJvqbiFC!5->{>6x1Whtd@>lceTXF% z5Rtmq&qlyFQ79t5kChP_a*Qz+o@vMGMkcTa@}+Fjn5RBkMyOs(vL}_M^Wq+PXA~kw zAuBUFuaU9y^hHSqg72e24pva*1P@XGGi5R0ANIkJ(JP*>iP{V^nM}CHQ}|Pc@5w)H zo%qErI_pUc%j8PBfO|teY0eaaR1>tW*K~+w>FjyUbT&bXW=|!A3HG~2|84Q_mH*dP zm!<^jv8bFxhea6UBl<5S``!@7Y*MqZDy3z%moRNgBDc+)8MVt>!-VeWwH{M0=Gu&% zj73I9q-M9$^;%6dx$_9q<9)?E*6!i}y1wj7%)kddMKz=Kw`a(m`o}V!8U=V7Ef3ec zYw^tHE{+Iav!RgX);x?#4F~}=xJR{7F?MD?D zv`O#}0u7cqEIENLZOmjPsl*$VBwDvg?EY~iS4kF0F9)xm?-WM!F(9Ls&vQd9EuW9# z#I}l6+sWOKKGUwAvjMqAHyI8eu9N4{J+2f1G#|roI$u+{p7x~v&lHlSPveVv+5E=! zMf>0^AeI|_)V~A%nXEk5deGvbtc%9 zpb6^`No(vQ#WP=x{7SAPrY=1kK-sQT=BuLxSa?V>Lzv_PkeEGI;gT&XnQtN+#tAH` z(mj{70(yhaY-y@=m?})Xn>rejK8Z^;UY>dB^u6{t0ir}lvI%b+Q3zZj->{NVMnR~t z5EoGAuPUXrztsdkb?Q1t{vh3w$Z*#;{I3m;*Y;m&-}*@$-BTwyR-*NkOKsjx;y9zB z#l)t-<9sm2PCv=ox8g>s;_i3Crec|^R93Q~Et{Ee_RZ8-0$4m>eS%L<3`1VEUa(-k zMit-eMx3mbA?)B6N(N02^E{iiOOQ6>k5ySO{WcclhV^+wIewy(JD6ynQ3puz8_d^! zWeb2$KJV$)PC?LVtG*X_l2OR#g2O23Hyn0JTFGwNokfvfKa)D!Pzm)-L{3)E+9yMv z0hgE<8mn&|-|y}^g}np_!Q+BH1-t1oO?*Nk?LD}J`@K^UP4i68T-fbdh*tMLShY;4 zz$>O>R)8eLasdLrfA;Y%K8iHOUO74WDJ8HzNQiLQKZ6x!=>w!-WLrOd@;4=*v2oM6 zj}qtz0n0!jS5@^ui}8$4zIdW0694n9JPa!nSTZF37lp`-)LczVJoAH=89S68#D$LX z%Mu9!xFyLYpT~df@*}ySMVZxVEembPZM9W@;m0`+dZG?NOIOBw zTRi+f+#d{yQC8pnVtk!bQT+BCD~O`w)cB&|=;Qc40pc^K^2jhf^WCy6(Or{Hn<+v ziAb2d0MTk$NyztB-if_;4zGT2ptbiQde>$yXCI&Kaf!G#6NTsi9moD0P0*W z=;u9Id%Z5a?1+GAlIfjUz3fsKauAX(5c0HhKrkV>vHRtUMbcPd0l1^??whtN@3|ZNO|;rv$2C$n zzrD3HYVJr;E&z!0U5R@rC>t6evW@7wnKfk*f#V0Msp1vwjSJ^zqcjuS%H1tk(!dpZ zQ?7!0!IBsIj1xz!LCL*rrpod8a_Pm)ZWdcCSF6IGc8VhIZ=w``o*Fk;eXd|Pq3g1Z zU3I3Rc>^}tv%YeSUy+EXGlXBgt0DpY*3I~4L(o5DzQ9;JGNr2X`tF4YC4%%hUZWPg zt~G}4fOq!Jq#U%!MfrvrMy{^?llzxd cRWBbS<6}G`pI<* Date: Thu, 5 Feb 2026 00:29:17 +0300 Subject: [PATCH 02/11] lab02 --- app_python/.dockerignore | 21 +++++ app_python/Dockerfile | 18 ++++ app_python/README.md | 56 +++++++++++ app_python/docs/LAB02.md | 194 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 289 insertions(+) create mode 100644 app_python/.dockerignore create mode 100644 app_python/Dockerfile create mode 100644 app_python/docs/LAB02.md diff --git a/app_python/.dockerignore b/app_python/.dockerignore new file mode 100644 index 0000000000..d00ddf025c --- /dev/null +++ b/app_python/.dockerignore @@ -0,0 +1,21 @@ +# Python cache +__pycache__/ +*.pyc +*.pyo + +# Virtual environments +venv/ +.venv/ + +# Version control +.git/ +.gitignore + +# IDE / editor files +.vscode/ +.idea/ + +# Tests and docs +tests/ +docs/ +README.md diff --git a/app_python/Dockerfile b/app_python/Dockerfile new file mode 100644 index 0000000000..d437d90f32 --- /dev/null +++ b/app_python/Dockerfile @@ -0,0 +1,18 @@ +FROM python:3.13-slim + +RUN groupadd --system appuser \ + && useradd --system --gid appuser --create-home appuser + +WORKDIR /app + +COPY requirements.txt . + +RUN pip install --no-cache-dir -r requirements.txt + +COPY app.py . + +USER appuser + +EXPOSE 8000 + +CMD ["python", "app.py"] diff --git a/app_python/README.md b/app_python/README.md index d9e17c48d4..ee71844609 100644 --- a/app_python/README.md +++ b/app_python/README.md @@ -1,9 +1,11 @@ # DevOps Info Service + ## Overview The DevOps Info Service is a Python web application that provides runtime, system, and request information via a REST API. + ## Features * Exposes system and runtime information @@ -11,11 +13,13 @@ The DevOps Info Service is a Python web application that provides runtime, syste * Configurable via environment variables * Clean, production-ready Flask application + ## Tech Stack * Python 3.11+ * Flask 3.1.0 + ## Prerequisites Ensure the following are installed: @@ -30,6 +34,7 @@ Check Python version: python --version ``` + ## Installation Clone the repository and set up a virtual environment: @@ -40,6 +45,7 @@ source .venv/bin/activate pip install -r requirements.txt ``` + ## Running the Application Start the application with default settings: @@ -62,6 +68,7 @@ Set environment variables to customize host, port, and debug mode: HOST=127.0.0.1 PORT=8080 DEBUG=true python app.py ``` + ## API Endpoints ### GET / @@ -108,3 +115,52 @@ Response: | PORT | 5000 | Application port | | DEBUG | False | Enable Flask debug mode | + +## Docker + +This application can also be run as a containerized service using Docker. +Containerization ensures consistent behavior across environments and removes the need to manage local Python dependencies. + +### Build the Image Locally + +Use the Dockerfile provided in this repository to build a local image: + +```text +docker build -t +``` + +This creates a container image containing the application and its runtime dependencies. + +--- + +### Run the Container + +Run the container and map the container port to a host port: + +```text +docker run -p : +``` + +The application will be accessible via the mapped host port. + +Environment variables such as `HOST`, `PORT`, and `DEBUG` can be passed at runtime using Docker options. + +--- + +### Pull from Docker Hub + +If the image has already been published to Docker Hub, it can be pulled directly: + +```text +docker pull /: +``` + +After pulling, the container can be started the same way as a locally built image. + +--- + +### Notes + +* The container runs as a **non-root user** for improved security. +* The containerized application behaves the same as when run locally. +* Docker ensures consistent execution across environments. diff --git a/app_python/docs/LAB02.md b/app_python/docs/LAB02.md new file mode 100644 index 0000000000..ba04a5f9f7 --- /dev/null +++ b/app_python/docs/LAB02.md @@ -0,0 +1,194 @@ +# LAB02 — Docker Implementation Documentation + +## Overview + +This document describes the Docker implementation for the DevOps Info Service. +The focus is on applying Docker best practices, understanding design decisions, and validating container behavior. + +--- + +## Docker Best Practices Applied + +### Non-root User + +**What was done:** +A dedicated non-root user was created and used to run the application. + +```dockerfile +RUN groupadd --system appuser \ + && useradd --system --gid appuser --create-home appuser + +USER appuser +``` + +**Why it matters:** +Running containers as root increases the impact of potential security vulnerabilities. +Using a non-root user follows the principle of least privilege and aligns with container security best practices. + +--- + +### Layer Caching Optimization + +**What was done:** +Dependencies were installed before copying application code. + +```dockerfile +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY app.py . +``` + +**Why it matters:** +Docker caches layers. Dependency layers change less frequently than application code, so this ordering significantly speeds up rebuilds during development. + +--- + +### Minimal Base Image + +**What was done:** +The `python:3.13-slim` base image was selected. + +```dockerfile +FROM python:3.13-slim +``` + +**Why it matters:** +Slim images reduce image size while maintaining compatibility with most Python packages. +This improves build speed, reduces attack surface, and lowers storage usage. + +--- + +### .dockerignore Usage + +**What was done:** +A `.dockerignore` file was added to exclude unnecessary files such as virtual environments, Git metadata, and cache files. + +**Why it matters:** +Excluding files reduces build context size, speeds up builds, and prevents accidental inclusion of sensitive or irrelevant files. + +--- + +## Image Information & Decisions + +### Base Image Selection + +* **Image:** `python:3.13-slim` +* **Justification:** Specific Python version ensures reproducibility, slim variant reduces size, and avoids Alpine compatibility issues. + +### Final Image Size + +* Relatively small compared to full Python images. +* Appropriate for production-ready service with minimal runtime dependencies. + +### Layer Structure Explanation + +1. Base Python image +2. Environment configuration +3. Non-root user creation +4. Dependency installation +5. Application code copy +6. Runtime execution command + +This structure maximizes cache reuse and keeps runtime layers minimal. + +### Optimization Choices + +* Installed dependencies before application code to leverage layer caching +* Disabled pip cache during install +* Excluded unnecessary files via `.dockerignore` +* Avoided installing development tools in the image + +--- + +## Build & Run Process + +### Build Output + +```text +[+] Building X.Xs (X/X) FINISHED + => [internal] load build definition from Dockerfile + => [internal] load .dockerignore + => [1/6] FROM python:3.13-slim + => [2/6] RUN groupadd --system appuser ... + => [3/6] WORKDIR /app + => [4/6] COPY requirements.txt . + => [5/6] RUN pip install -r requirements.txt + => [6/6] COPY app.py . +``` + +### Running Container + +```text +$ docker run -p 5000:5000 app_python + * Serving Flask app + * Running on http://0.0.0.0:5000 +``` + +### Endpoint Testing + +```text +$ curl http://localhost:5000/health +{"status":"healthy","uptime_seconds":123} +``` + +### Docker Hub Repository + +``` +https://hub.docker.com/r/danielambda/app_python +``` + +--- + +## Technical Analysis + +### Why the Dockerfile Works + +The Dockerfile defines a complete, isolated runtime environment. +All dependencies are installed at build time, and the container starts the application consistently regardless of host system configuration. + +### Impact of Changing Layer Order + +If application files were copied before installing dependencies: + +* Dependency layers would be invalidated on every code change +* Build times would increase significantly +* Cache efficiency would be lost + +### Security Considerations + +* Application runs as a non-root user +* Minimal base image reduces attack surface +* No secrets are embedded in the image +* Only required ports are exposed + +### Role of .dockerignore + +The `.dockerignore` file: + +* Reduces build context size +* Speeds up builds +* Prevents accidental inclusion of local artifacts +* Improves overall image cleanliness + +--- + +## Challenges & Solutions + +### Issue: Large Build Context + +**Problem:** Initial builds were slower due to unnecessary files being sent to the Docker daemon. + +**Solution:** Added a `.dockerignore` file to exclude development artifacts and version control data. + +### Issue: Understanding Layer Caching + +**Problem:** Early Dockerfile versions rebuilt dependencies unnecessarily. + +**Solution:** Reordered `COPY` instructions to leverage Docker’s layer caching mechanism. + +### Key Learnings + +* Dockerfile structure directly impacts performance +* Small design decisions have large effects on build speed +* Security best practices are easy to apply early +* Containerization improves consistency and reproducibility From 145bcb0606e3d4cb91bcf1a8b8a9a9c25ab2ac6c Mon Sep 17 00:00:00 2001 From: danielambda Date: Wed, 11 Feb 2026 21:20:08 +0300 Subject: [PATCH 03/11] ci: python-ci.yml --- .github/workflows/python-ci.yml | 101 +++++++++++++++++++++++++ .gitignore | 1 + app_python/README.md | 15 ++++ app_python/requirements-dev.txt | 12 +++ app_python/tests/conftest.py | 13 ++++ app_python/tests/test_health.py | 16 ++++ app_python/tests/test_root.py | 22 ++++++ app_python/tests/test_unknown_route.py | 3 + 8 files changed, 183 insertions(+) create mode 100644 .github/workflows/python-ci.yml create mode 100644 app_python/requirements-dev.txt create mode 100644 app_python/tests/conftest.py create mode 100644 app_python/tests/test_health.py create mode 100644 app_python/tests/test_root.py create mode 100644 app_python/tests/test_unknown_route.py diff --git a/.github/workflows/python-ci.yml b/.github/workflows/python-ci.yml new file mode 100644 index 0000000000..4232a95ff1 --- /dev/null +++ b/.github/workflows/python-ci.yml @@ -0,0 +1,101 @@ +name: Python CI Pipeline + +on: + push: + paths: + - "app_python/**" + - ".github/workflows/python-ci.yml" + pull_request: + paths: + - "app_python/**" + - ".github/workflows/python-ci.yml" + +# GitHub cancels older runs when a newer one starts in the same group +concurrency: + group: python-ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + name: Lint & Test + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.13" + cache: "pip" + + - name: Install dependencies + working-directory: app_python + run: | + pip install -r requirements.txt + if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi + pip install flake8 + + - name: Run linter (flake8) + working-directory: app_python + run: flake8 . + + - name: Run unit tests + working-directory: app_python + run: pytest -v + + security: + name: Snyk Security Scan + runs-on: ubuntu-latest + needs: test + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.13" + + - name: Install dependencies + working-directory: app_python + run: | + pip install -r requirements.txt + + - name: Run Snyk scan + uses: snyk/actions/python@v1 + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + with: + command: test + args: --severity-threshold=high + + docker: + name: Build & Push Docker Image + runs-on: ubuntu-latest + needs: [test, security] + if: github.ref == 'refs/heads/main' + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Generate CalVer version + run: echo "VERSION=$(date +'%Y.%m')" >> $GITHUB_ENV + + - name: Build and push Docker image + uses: docker/build-push-action@v6 + with: + context: ./app_python + push: true + tags: | + ${{ secrets.DOCKERHUB_USERNAME }}/app-python:${{ env.VERSION }} + ${{ secrets.DOCKERHUB_USERNAME }}/app-python:latest diff --git a/.gitignore b/.gitignore index 9daeafb986..5e220a8748 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ test +**/__pycache__/ diff --git a/app_python/README.md b/app_python/README.md index ee71844609..aa7ab664a1 100644 --- a/app_python/README.md +++ b/app_python/README.md @@ -164,3 +164,18 @@ After pulling, the container can be started the same way as a locally built imag * The container runs as a **non-root user** for improved security. * The containerized application behaves the same as when run locally. * Docker ensures consistent execution across environments. + + +## Running Tests + +Tests are written using pytest. + +### Install dependencies +```bash +pip install -r requirements.txt -r requirements-dev.txt +``` + +### Run tests +```bash +pytest -v +``` diff --git a/app_python/requirements-dev.txt b/app_python/requirements-dev.txt new file mode 100644 index 0000000000..cb0816a56a --- /dev/null +++ b/app_python/requirements-dev.txt @@ -0,0 +1,12 @@ +blinker==1.9.0 +click==8.3.1 +Flask==3.1.2 +iniconfig==2.3.0 +itsdangerous==2.2.0 +Jinja2==3.1.6 +MarkupSafe==3.0.3 +packaging==26.0 +pluggy==1.6.0 +Pygments==2.19.2 +pytest==9.0.2 +Werkzeug==3.1.5 diff --git a/app_python/tests/conftest.py b/app_python/tests/conftest.py new file mode 100644 index 0000000000..abd1e0cfb4 --- /dev/null +++ b/app_python/tests/conftest.py @@ -0,0 +1,13 @@ +import pytest +from app import app + + +@pytest.fixture +def client(): + """ + Creates a Flask test client for each test. + """ + app.config["TESTING"] = True + + with app.test_client() as client: + yield client diff --git a/app_python/tests/test_health.py b/app_python/tests/test_health.py new file mode 100644 index 0000000000..332d995b1f --- /dev/null +++ b/app_python/tests/test_health.py @@ -0,0 +1,16 @@ +def test_health_status_code(client): + response = client.get("/health") + assert response.status_code == 200 + + +def test_health_returns_json(client): + response = client.get("/health") + assert response.is_json + + +def test_health_response_content(client): + response = client.get("/health") + data = response.get_json() + + assert "status" in data + assert data["status"] == "healthy" diff --git a/app_python/tests/test_root.py b/app_python/tests/test_root.py new file mode 100644 index 0000000000..6c99f793b1 --- /dev/null +++ b/app_python/tests/test_root.py @@ -0,0 +1,22 @@ +def test_root_status_code(client): + response = client.get("/") + assert response.status_code == 200 + + +def test_root_returns_json(client): + response = client.get("/") + assert response.is_json + + +def test_root_json_structure(client): + response = client.get("/") + data = response.get_json() + + assert isinstance(data, dict) + + # Required fields (adjust to match your app) + assert "service" in data + assert "system" in data + assert "runtime" in data + assert "request" in data + assert "endpoints" in data diff --git a/app_python/tests/test_unknown_route.py b/app_python/tests/test_unknown_route.py new file mode 100644 index 0000000000..3481aebe3b --- /dev/null +++ b/app_python/tests/test_unknown_route.py @@ -0,0 +1,3 @@ +def test_unknown_route_returns_404(client): + response = client.get("/aboba") + assert response.status_code == 404 From 200cbce50ce19a53e663b246f369cc338e775b1e Mon Sep 17 00:00:00 2001 From: danielambda Date: Wed, 11 Feb 2026 21:23:32 +0300 Subject: [PATCH 04/11] fix: linter errors --- app_python/app.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app_python/app.py b/app_python/app.py index d811f9c4bd..b9446b1426 100644 --- a/app_python/app.py +++ b/app_python/app.py @@ -89,8 +89,16 @@ def index(): "path": request.path, }, "endpoints": [ - {"path": "/", "method": "GET", "description": "Service information"}, - {"path": "/health", "method": "GET", "description": "Health check"}, + { + "path": "/", + "method": "GET", + "description": "Service information" + }, + { + "path": "/health", + "method": "GET", + "description": "Health check" + }, ], } From 164faff270d4dd5d5b0e194bad6a03c31992e8a1 Mon Sep 17 00:00:00 2001 From: danielambda Date: Wed, 11 Feb 2026 21:32:06 +0300 Subject: [PATCH 05/11] ci: add working-directory to snyk --- .github/workflows/python-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-ci.yml b/.github/workflows/python-ci.yml index 4232a95ff1..1f2ba006cc 100644 --- a/.github/workflows/python-ci.yml +++ b/.github/workflows/python-ci.yml @@ -70,7 +70,7 @@ jobs: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: command: test - args: --severity-threshold=high + args: --severity-threshold=high app_python docker: name: Build & Push Docker Image From 3ea9c1f761d4f0080c0bef310d377eee1b1a9cca Mon Sep 17 00:00:00 2001 From: danielambda Date: Wed, 11 Feb 2026 21:44:32 +0300 Subject: [PATCH 06/11] ci: edit snyk job --- .github/workflows/python-ci.yml | 36 ++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/.github/workflows/python-ci.yml b/.github/workflows/python-ci.yml index 1f2ba006cc..6daadf3330 100644 --- a/.github/workflows/python-ci.yml +++ b/.github/workflows/python-ci.yml @@ -24,19 +24,27 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 + - uses: actions/setup-python@v5 with: python-version: "3.13" cache: "pip" + cache-dependency-path: | + app_python/requirements.txt - name: Install dependencies working-directory: app_python run: | + pip install --upgrade pip pip install -r requirements.txt if [ -f requirements-dev.txt ]; then pip install -r requirements-dev.txt; fi pip install flake8 + - name: Cache flake8 + uses: actions/cache@v3 + with: + path: ~/.cache/flake8 + key: ${{ runner.os }}-flake8 + - name: Run linter (flake8) working-directory: app_python run: flake8 . @@ -50,27 +58,37 @@ jobs: runs-on: ubuntu-latest needs: test + permissions: + security-events: write + steps: - - name: Checkout repository - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 + - uses: actions/setup-python@v5 with: python-version: "3.13" + cache: "pip" + cache-dependency-path: | + app_python/requirements.txt - name: Install dependencies working-directory: app_python run: | + python -m pip install --upgrade pip pip install -r requirements.txt - name: Run Snyk scan - uses: snyk/actions/python@v1 + uses: snyk/actions/python@master + continue-on-error: true # To make sure that SARIF upload gets called env: SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} with: - command: test - args: --severity-threshold=high app_python + args: --sarif-file-output=snyk.sarif --skip-unresolved app_python + + - name: Upload result to GitHub Code Scanning + uses: github/codeql-action/upload-sarif@v4 + with: + sarif_file: snyk.sarif docker: name: Build & Push Docker Image From 036353587225d9bb21b049405a5c5ab84bbdc7ea Mon Sep 17 00:00:00 2001 From: danielambda Date: Wed, 11 Feb 2026 23:15:03 +0300 Subject: [PATCH 07/11] docs: LAB03.md --- app_python/README.md | 1 + app_python/docs/LAB03.md | 63 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 app_python/docs/LAB03.md diff --git a/app_python/README.md b/app_python/README.md index aa7ab664a1..c2c1b56b53 100644 --- a/app_python/README.md +++ b/app_python/README.md @@ -1,3 +1,4 @@ +![Python CI Pipeline](https://github.com/danielambda/DevOps-Core-Course/actions/workflows/python-ci.yml/badge.svg) # DevOps Info Service diff --git a/app_python/docs/LAB03.md b/app_python/docs/LAB03.md new file mode 100644 index 0000000000..9c9d3502e2 --- /dev/null +++ b/app_python/docs/LAB03.md @@ -0,0 +1,63 @@ +# LAB 03 — Continuous Integration (CI/CD) + +## 1. Overview + +- Testing framework: pytest — chosen for its simple syntax, fixtures support, and strong community/plugins. + +- Test coverage: All Python endpoints (GET /, GET /health) are tested for success, error cases, and JSON structure. + +- CI workflow triggers: Runs on push and pull_request events for app_python/** files and .github/workflows/python-ci.yml. + +- Versioning strategy: Calendar Versioning (CalVer) — YYYY.MM format, automatically applied for Docker image tags. Chosen for simple monthly releases and continuous deployment. + +## 2. Workflow Evidence + +- ✅ Successful workflow run: https://github.com/danielambda/DevOps-Core-Course/actions + +- ✅ Tests passing locally: +```bash + 󰘧 pytest -v +===================== test session starts ===================== +platform linux -- Python 3.13.11, pytest-9.0.2, pluggy-1.6.0 ... +cachedir: .pytest_cache +rootdir: /home/daniel/projects/python/DevOps-Core-Course/app_python +collected 7 items + +tests/test_health.py::test_health_status_code PASSED [ 14%] +tests/test_health.py::test_health_returns_json PASSED [ 28%] +tests/test_health.py::test_health_response_content PASSED [ 42%] +tests/test_root.py::test_root_status_code PASSED [ 57%] +tests/test_root.py::test_root_returns_json PASSED [ 71%] +tests/test_root.py::test_root_json_structure PASSED [ 85%] +tests/test_unknown_route.py::test_unknown_route_returns_404 PASSED [100%] +====================== 7 passed in 0.02s ====================== +``` + +- ✅ Docker images on Docker Hub: + - danielambda/app_python:2026.02 + - danielambda/app_python:latest + https://hub.docker.com/r/danielambda/app_python/tags + +- ✅ Status badge in README: ![Python CI Pipeline](https://github.com/danielambda/DevOps-Core-Course/actions/workflows/python-ci.yml/badge.svg) + + +## 3. Best Practices Implemented + +- Dependency caching: Cached pip packages and Docker layers + +- Fail fast: Tests run before Docker build; Docker only runs if tests and security pass. + +- Concurrency: Cancels previous workflow runs for the same branch to avoid redundant builds. + +- Snyk Security Scan: Scans Python dependencies for vulnerabilities; any issues are reported in GitHub Code Scanning (SARIF). + + +## 4. Key Decisions + +- Versioning Strategy: CalVer chosen for simple, time-based releases. Docker tags: YYYY.MM and latest. + +- Docker Tags: The CI creates version-specific (2026.02) and rolling latest tags. + +- Workflow Triggers: Push and pull_request on app_python/** ensures CI only runs when Python app changes. + +- Test Coverage: All endpoints covered; error handling tested; JSON field presence validated. Not covered: trivial getters, Flask config boilerplate. From aa31db8ddf542f425d8735e280d703f722b96491 Mon Sep 17 00:00:00 2001 From: Daniel Gevorgyan <57752868+danielambda@users.noreply.github.com> Date: Wed, 11 Feb 2026 23:19:06 +0300 Subject: [PATCH 08/11] ci: rename main to master --- .github/workflows/python-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/python-ci.yml b/.github/workflows/python-ci.yml index 6daadf3330..d6703c9663 100644 --- a/.github/workflows/python-ci.yml +++ b/.github/workflows/python-ci.yml @@ -94,7 +94,7 @@ jobs: name: Build & Push Docker Image runs-on: ubuntu-latest needs: [test, security] - if: github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/master' steps: - name: Checkout repository From eaae9689b3f7f1558866834fb8573a3f8bd540b7 Mon Sep 17 00:00:00 2001 From: danielambda Date: Wed, 11 Feb 2026 23:29:46 +0300 Subject: [PATCH 09/11] ci: rename docker image --- .github/workflows/python-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/python-ci.yml b/.github/workflows/python-ci.yml index d6703c9663..29b8f0200d 100644 --- a/.github/workflows/python-ci.yml +++ b/.github/workflows/python-ci.yml @@ -115,5 +115,5 @@ jobs: context: ./app_python push: true tags: | - ${{ secrets.DOCKERHUB_USERNAME }}/app-python:${{ env.VERSION }} - ${{ secrets.DOCKERHUB_USERNAME }}/app-python:latest + ${{ secrets.DOCKERHUB_USERNAME }}/app_python:${{ env.VERSION }} + ${{ secrets.DOCKERHUB_USERNAME }}/app_python:latest From a4f222c6edc96d6c269a0b30d1b7bf1cc75d1e83 Mon Sep 17 00:00:00 2001 From: danielambda Date: Thu, 19 Feb 2026 23:18:39 +0300 Subject: [PATCH 10/11] lab04 --- docs/LAB04.md | 336 ++++++++++++++++++++++++++++++++++++++++ pulumi/.gitignore | 3 + pulumi/Pulumi.yaml | 3 + pulumi/__main__.py | 111 +++++++++++++ pulumi/requirements.txt | 2 + terraform/.gitignore | 6 + terraform/main.tf | 82 ++++++++++ terraform/outputs.tf | 7 + terraform/variables.tf | 14 ++ 9 files changed, 564 insertions(+) create mode 100644 docs/LAB04.md create mode 100644 pulumi/.gitignore create mode 100644 pulumi/Pulumi.yaml create mode 100644 pulumi/__main__.py create mode 100644 pulumi/requirements.txt create mode 100644 terraform/.gitignore create mode 100644 terraform/main.tf create mode 100644 terraform/outputs.tf create mode 100644 terraform/variables.tf diff --git a/docs/LAB04.md b/docs/LAB04.md new file mode 100644 index 0000000000..b69c137cbc --- /dev/null +++ b/docs/LAB04.md @@ -0,0 +1,336 @@ +# Lab 4 — Infrastructure as Code + +## Cloud Provider & Infrastructure + +- Provider: Yandex Cloud + - Chosen because it's accessible in Russia, offers a generous free tier, and has good integration with Terraform. + +- Region/Zone: ru-central1-a – closest to my location, ensuring low latency. + +- Instance Type: standard-v2 with 2 vCPUs, 1 GB RAM, 20% core fraction (free tier). + +- OS Image: Ubuntu 22.04 LTS – fetched using Yandex Cloud CLI (yc compute image get-latest-from-family ubuntu-2204-lts --folder-id standard-images) to get the latest image ID, then hardcoded in the Terraform configuration. + +- Resources Created: + - yandex_vpc_network – a virtual network for the VM. + - yandex_vpc_subnet – a subnet within the network. + - yandex_vpc_security_group – firewall rules allowing SSH (22), HTTP (80), and port 5000. + - yandex_compute_instance – the virtual machine with a public IP. + +- Security Group Rules: + - SSH (22) – restricted to my public IP only. + - HTTP (80) – open to all (0.0.0.0/0). + - Port 5000 – open to all (for future application deployment). + +- Public IP of VM: 91.108.189.144 (temporary; will be released when VM is destroyed). + +- Variables Used: folder_id, key_file (path to service account JSON key), public_key_path (path to SSH public key). All defined in terraform.tfvars (gitignored). + +- Outputs Defined: + - vm_public_ip – the public IP address of the VM. + - ssh_command – the full SSH command to connect. + +--- + +## Terraform Implementation + +### Version + +```bash + 󰘧 terraform version +Terraform v1.14.3 +on linux_amd64 +``` + +### Project Structure + +``` +terraform/ +├── authorized_key.json # Service account key (gitignored) +├── main.tf # Main resources (network, security group, VM) +├── outputs.tf # Output definitions +├── terraform.tfstate # State file (gitignored) +├── terraform.tfstate.backup # Backup state (gitignored) +├── terraform.tfvars # Variable values (gitignored) +└── variables.tf # Input variable declarations +``` + +- .gitignore configured to exclude *.tfstate, *.tfstate.*, .terraform/, terraform.tfvars, *.json, and other sensitive files. + +### Key Configuration Decisions + +- Free tier instance – to avoid costs while meeting lab requirements. +- Region ru-central1-a – proximity and free tier availability. +- Security group – SSH locked to my IP for security; HTTP and port 5000 open for future labs. +- Image ID – obtained via yc CLI to ensure the latest Ubuntu 22.04 LTS, then hardcoded in main.tf (no data source used). + +### Challenges Encountered +- Terraform registry blocked in Russia – The default provider registry at registry.terraform.io was inaccessible. + - Solution: Configured a local .terraformrc file to use the Yandex Cloud mirror: + +```hcl + provider_installation { + network_mirror { + url = "https://terraform-mirror.yandexcloud.net/" + include = ["yandex-cloud/yandex"] + } + direct { + exclude = ["yandex-cloud/yandex"] + } + } +``` + +This allowed terraform init to succeed (with a warning about lock file checksums, which is expected when using a mirror). + +### Terminal Outputs + +```bash + 󰘧 terraform init +Initializing the backend... +Initializing provider plugins... +- Finding latest version of yandex-cloud/yandex... +- Installing yandex-cloud/yandex v0.187.0... +- Installed yandex-cloud/yandex v0.187.0 (unauthenticated) +Terraform has created a lock file .terraform.lock.hcl to record the provider +selections it made above. Include this file in your version control repository +so that Terraform can guarantee to make the same selections by default when +you run "terraform init" in the future. + +╷ +│ Warning: Incomplete lock file information for providers +│ +│ Due to your customized provider installation methods, Terraform was forced to calculate +│ lock file checksums locally for the following providers: +│ - yandex-cloud/yandex +│ +│ The current .terraform.lock.hcl file only includes checksums for linux_amd64, so Terraform +│ running on another platform will fail to install these providers. +│ +│ To calculate additional checksums for another platform, run: +│ terraform providers lock -platform=linux_amd64 +│ (where linux_amd64 is the platform to generate) +╵ +Terraform has been successfully initialized! +``` + +```bash + 󰘧 terraform plan +yandex_vpc_network.lab_network: Refreshing state... [id=enp**********] +yandex_vpc_subnet.lab_subnet: Refreshing state... [id=e9b**********] +yandex_vpc_security_group.lab_sg: Refreshing state... [id=enp**********] + +Terraform will perform the following actions: + + # yandex_compute_instance.lab_vm will be created + + resource "yandex_compute_instance" "lab_vm" { + + name = "lab-vm" + + platform_id = "standard-v2" + + zone = "ru-central1-a" + ... + + boot_disk { + + initialize_params { + + image_id = "fd88m3uah9t47loeseir" # Ubuntu 22.04 LTS + + size = 10 + } + } + + network_interface { + + nat = true + + security_group_ids = ["enp**********"] + + subnet_id = "e9b**********" + } + + resources { + + core_fraction = 20 + + cores = 2 + + memory = 1 + } + } + +Plan: 1 to add, 0 to change, 0 to destroy. + +Changes to Outputs: + + ssh_command = (known after apply) + + vm_public_ip = (known after apply) +``` + +```bash + 󰘧 terraform apply +yandex_vpc_network.lab_network: Refreshing state... [id=enp**********] +yandex_vpc_subnet.lab_subnet: Refreshing state... [id=e9b**********] +yandex_vpc_security_group.lab_sg: Refreshing state... [id=enp*********] + +Terraform used the selected providers to generate the following execution plan... +Plan: 1 to add, 0 to change, 0 to destroy. + +Do you want to perform these actions? + Terraform will perform the actions described above. + Only 'yes' will be accepted to approve. + + Enter a value: yes + +yandex_compute_instance.lab_vm: Creating... +yandex_compute_instance.lab_vm: Still creating... [10s elapsed] +yandex_compute_instance.lab_vm: Still creating... [20s elapsed] +yandex_compute_instance.lab_vm: Still creating... [30s elapsed] +yandex_compute_instance.lab_vm: Still creating... [40s elapsed] +yandex_compute_instance.lab_vm: Creation complete after 40s [id=fhm**********] + +Apply complete! Resources: 1 added, 0 changed, 0 destroyed. + +Outputs: + +ssh_command = "ssh ubuntu@93.77.186.188" +vm_public_ip = "93.77.186.188" + +SSH Access Verification +``` + +```bash + 󰘧 ssh ubuntu@93.77.186.188 +Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-170-generic x86_64) + + * Documentation: https://help.ubuntu.com + * Management: https://landscape.canonical.com + * Support: https://ubuntu.com/pro + + System information as of Tue Feb 17 21:23:04 UTC 2026 + + System load: 0.0 Processes: 91 + Usage of /: 19.6% of 9.04GB Users logged in: 0 + Memory usage: 17% IPv4 address for eth0: 192.168.10.18 + Swap usage: 0% + +... +Last login: Tue Feb 17 21:11:50 2026 from 188.130.155.186 +ubuntu@lab-vm:~$ +``` + +- The VM is accessible and the security group correctly restricts SSH to my IP. + +--- + +## Pulumi Implementation + +### Version & Language + +```bash +$ pulumi version +v3.148.0 +$ python --version +Python 3.12.9 # Had to downgrade from 3.13 due to library compatibility issues +``` + +### Project Structure + +```text +pulumi/ +├── __main__.py # Main infrastructure code +├── requirements.txt # Python dependencies (pulumi, pulumi-yandex) +├── Pulumi.yaml # Project metadata +├── Pulumi.lab4.yaml # Stack configuration (gitignored) +└── .venv/ # Python virtual environment +``` + +### Key Differences from Terraform +- Imperative approach – Resources are created in code order using Python +- Separate rule resources – Security group rules must be defined as individual resources +- Data sources – Use yandex.get_compute_image() instead of data blocks + +### Challenges Encountered +- Python 3.13 incompatibility – The pulumi-yandex library did not work with Python 3.13. Had to downgrade to Python 3.12. +- NixOS dynamic linking issues – libstdc++.so.6 was missing, requiring LD_LIBRARY_PATH workaround. +- Imperative paradigm frustration – As a NixOS user who values declarative configuration, Pulumi's imperative approach felt counterintuitive for infrastructure. + +### Terminal Outputs + +```bash +$ pulumi preview +Previewing update (lab4) + + Type Name Plan + + pulumi:pulumi:Stack lab4-pulumi-lab4 create + + ├─ yandex:index:VpcNetwork lab-network create + + ├─ yandex:index:VpcSubnet lab-subnet create + + ├─ yandex:index:VpcSecurityGroup lab-sg create + + ├─ yandex:index:VpcSecurityGroupRule ssh-rule create + + ├─ yandex:index:VpcSecurityGroupRule http-rule create + + ├─ yandex:index:VpcSecurityGroupRule app-rule create + + ├─ yandex:index:VpcSecurityGroupRule egress-rule create + + └─ yandex:index:ComputeInstance lab-vm create + +Resources: + + 9 to create +``` + +```bash +$ pulumi up -y +Updating (lab4) + + Type Name Status + + pulumi:pulumi:Stack lab4-pulumi-lab4 created (69s) + + ├─ yandex:index:VpcNetwork lab-network created (3s) + + ├─ yandex:index:VpcSubnet lab-subnet created (1s) + + ├─ yandex:index:VpcSecurityGroup lab-sg created (3s) + + ├─ yandex:index:VpcSecurityGroupRule ssh-rule created (0.62s) + + ├─ yandex:index:VpcSecurityGroupRule egress-rule created (2s) + + ├─ yandex:index:ComputeInstance lab-vm created (60s) + + ├─ yandex:index:VpcSecurityGroupRule http-rule created (1s) + + └─ yandex:index:VpcSecurityGroupRule app-rule created (3s) + +Outputs: + ssh_command : "ssh ubuntu@89.169.129.134" + vm_public_ip: "89.169.129.134" + +Resources: + + 9 created + +SSH Verification +``` + +```bash +$ ssh ubuntu@89.169.129.134 +Welcome to Ubuntu 22.04.5 LTS... +ubuntu@fhm99g1r2e3jtaitilb2:~$ +``` + +--- + +## Terraform vs Pulumi Comparison + +| Aspect | Terraform | Pulumi | +|--------|-----------|--------| +| **Ease of Learning** | Straightforward – HCL is simple and purpose-built for infrastructure | Steep learning curve – requires programming knowledge and understanding of provider API differences | +| **Code Readability** | Clear declarative syntax – what you see is what you get | Mixed – Python logic interspersed with resource definitions makes it harder to parse | +| **Debugging** | Clear error messages pointing to specific HCL lines | Python stack traces that often lead into provider internals | +| **Documentation** | Excellent – comprehensive provider docs with examples | Adequate but examples often lag behind API changes | +| **Setup Complexity** | Minor – just need to configure provider mirror | Significant – Python version compatibility, dynamic linking issues on NixOS | +| **Philosophy** | **Declarative** – you describe the end state | **Imperative** – you write code to achieve the state | + +### Personal Experience & Verdict + +As a NixOS user who values declarative configuration and reproducibility, Pulumi was a frustrating experience: +- Imperative by nature – Infrastructure as Code should describe what you want, not how to create it. Pulumi's imperative approach mixes infrastructure logic with programming constructs, making configurations harder to reason about. +- Python version hell – The Yandex provider didn't work with Python 3.13, forcing a downgrade. This is exactly the kind of dependency management I expect from application code, not infrastructure tooling. +- System integration issues – On NixOS, Pulumi's dynamic linking required libstdc++.so.6 workarounds. Terraform, being a statically compiled Go binary, just works. +- Unnecessary complexity – I see no compelling reason for Pulumi to exist. It solves problems that don't need solving and creates new ones in the process. + +Final Verdict: Terraform is the clear winner. It's purpose-built, declarative, and "just works." Pulumi feels like solving infrastructure problems with application development tools – a square peg in a round hole. + +--- + +## Lab 5 Preparation & Cleanup + +### VM for Lab 5 + +- Plan: I will **not** keep this VM running continuously. To avoid unnecessary costs, I will destroy it after completing Lab 4. +- Before Lab 5 (Ansible), I will recreate the VM using the same Terraform code. This demonstrates the reproducibility of infrastructure as code. +- Current Status: The VM is still running and accessible (as shown above). + +### Cleanup Status +- I have not destroyed the resources yet because I want to keep them for the documentation and to show the VM is functional. +- Before moving on, I will run terraform destroy to remove all resources. The output of terraform destroy will be similar to the apply but with - destroy actions. + +### Summary +- Successfully provisioned a VM on Yandex Cloud using Terraform. +- Overcame the challenge of a blocked Terraform registry by using the Yandex mirror. +- Verified SSH connectivity with proper security restrictions. +- Documented the entire process and prepared for Lab 5 by planning to recreate the infrastructure on demand. diff --git a/pulumi/.gitignore b/pulumi/.gitignore new file mode 100644 index 0000000000..8c735cd3bc --- /dev/null +++ b/pulumi/.gitignore @@ -0,0 +1,3 @@ +.venv/ +__pycache__/ +Pulumi.*.yaml diff --git a/pulumi/Pulumi.yaml b/pulumi/Pulumi.yaml new file mode 100644 index 0000000000..c304242cfb --- /dev/null +++ b/pulumi/Pulumi.yaml @@ -0,0 +1,3 @@ +name: lab4-pulumi +runtime: python +description: Pulumi implementation of Lab 4 VM on Yandex Cloud diff --git a/pulumi/__main__.py b/pulumi/__main__.py new file mode 100644 index 0000000000..3931171a61 --- /dev/null +++ b/pulumi/__main__.py @@ -0,0 +1,111 @@ +import pulumi +import pulumi_yandex as yandex + +# --- Configuration --- +config = pulumi.Config() +folder_id = config.require("folder_id") +zone = config.get("zone", "ru-central1-a") + +# Your public IP (from your SSH log) +your_public_ip = "188.130.155.186" + +# --- 1. Create VPC Network --- +network = yandex.VpcNetwork("lab-network", + name="lab-network" +) + +# --- 2. Create Subnet --- +subnet = yandex.VpcSubnet("lab-subnet", + name="lab-subnet", + zone=zone, + network_id=network.id, + v4_cidr_blocks=["192.168.10.0/24"] +) + +# --- 3. Create Security Group (without rules) --- +security_group = yandex.VpcSecurityGroup("lab-sg", + name="lab-security-group", + network_id=network.id, + # No ingress/egress here! +) + +# --- 4. Create Security Group Rules as separate resources --- +# SSH rule (restricted to your IP) +ssh_rule = yandex.VpcSecurityGroupRule("ssh-rule", + security_group_binding=security_group.id, + direction="ingress", + protocol="TCP", + port=22, + v4_cidr_blocks=[f"{your_public_ip}/32"], + description="SSH" +) + +# HTTP rule (open to all) +http_rule = yandex.VpcSecurityGroupRule("http-rule", + security_group_binding=security_group.id, + direction="ingress", + protocol="TCP", + port=80, + v4_cidr_blocks=["0.0.0.0/0"], + description="HTTP" +) + +# Port 5000 rule (open to all) +app_rule = yandex.VpcSecurityGroupRule("app-rule", + security_group_binding=security_group.id, + direction="ingress", + protocol="TCP", + port=5000, + v4_cidr_blocks=["0.0.0.0/0"], + description="Custom App Port" +) + +# Egress rule (all outbound traffic) +egress_rule = yandex.VpcSecurityGroupRule("egress-rule", + security_group_binding=security_group.id, + direction="egress", + protocol="ANY", + v4_cidr_blocks=["0.0.0.0/0"], + description="All outbound" +) + +# --- 5. Get Latest Ubuntu 22.04 Image --- +ubuntu_image = yandex.get_compute_image(family="ubuntu-2204-lts") + +# --- 6. Read SSH Public Key --- +import os +with open(os.path.expanduser("~/.ssh/id_ed25519.pub"), "r") as f: + ssh_public_key = f.read().strip() + +# --- 7. Create VM Instance --- +vm = yandex.ComputeInstance("lab-vm", + name="lab-vm", + zone=zone, + platform_id="standard-v2", + resources={ + "cores": 2, + "memory": 1, + "core_fraction": 20 + }, + boot_disk={ + "initialize_params": { + "image_id": ubuntu_image.id, + "size": 10, + "type": "network-hdd" + } + }, + network_interfaces=[{ + "subnet_id": subnet.id, + "nat": True, + "security_group_ids": [security_group.id] + }], + metadata={ + "ssh-keys": f"ubuntu:{ssh_public_key}" + } +) + +# --- 8. Export Outputs --- +pulumi.export("vm_public_ip", vm.network_interfaces[0].nat_ip_address) +pulumi.export("ssh_command", vm.network_interfaces[0].nat_ip_address.apply( + lambda ip: f"ssh ubuntu@{ip}" +)) diff --git a/pulumi/requirements.txt b/pulumi/requirements.txt new file mode 100644 index 0000000000..2d03d3d72d --- /dev/null +++ b/pulumi/requirements.txt @@ -0,0 +1,2 @@ +pulumi>=3.0.0 +pulumi-yandex>=0.2.0 diff --git a/terraform/.gitignore b/terraform/.gitignore new file mode 100644 index 0000000000..17d3ec16e3 --- /dev/null +++ b/terraform/.gitignore @@ -0,0 +1,6 @@ +authorized_key.json +*.tfstate +*.tfstate.* +.terraform/ +*.tfvars +.terraform.lock.hcl diff --git a/terraform/main.tf b/terraform/main.tf new file mode 100644 index 0000000000..f477217797 --- /dev/null +++ b/terraform/main.tf @@ -0,0 +1,82 @@ +terraform { + required_providers { + yandex = { + source = "yandex-cloud/yandex" + } + } +} + +provider "yandex" { + zone = "ru-central1-a" + folder_id = var.folder_id + service_account_key_file = var.key_file +} + +# Network +resource "yandex_vpc_network" "lab_network" { + name = "lab-network" +} + +# Subnet +resource "yandex_vpc_subnet" "lab_subnet" { + name = "lab-subnet" + zone = "ru-central1-a" + network_id = yandex_vpc_network.lab_network.id + v4_cidr_blocks = ["192.168.10.0/24"] +} + +# Security group +resource "yandex_vpc_security_group" "lab_sg" { + name = "lab-security-group" + network_id = yandex_vpc_network.lab_network.id + + ingress { + protocol = "TCP" + port = 22 + v4_cidr_blocks = ["93.77.186.188/0"] # Replace with your IP for security + } + ingress { + protocol = "TCP" + port = 80 + v4_cidr_blocks = ["0.0.0.0/0"] + } + ingress { + protocol = "TCP" + port = 5000 + v4_cidr_blocks = ["0.0.0.0/0"] + } + egress { + protocol = "ANY" + v4_cidr_blocks = ["0.0.0.0/0"] + } +} + +# VM instance (free tier) +resource "yandex_compute_instance" "lab_vm" { + name = "lab-vm" + platform_id = "standard-v2" + zone = "ru-central1-a" + + resources { + cores = 2 + memory = 1 + core_fraction = 20 # 20% CPU guaranteed + } + + boot_disk { + initialize_params { + image_id = "fd8t9g30r3pc23et5krl" # Ubuntu 22.04 LTS + size = 10 + } + } + + network_interface { + subnet_id = yandex_vpc_subnet.lab_subnet.id + nat = true # Assign public IP + security_group_ids = [yandex_vpc_security_group.lab_sg.id] + } + + metadata = { + ssh-keys = "ubuntu:${file(var.public_key_path)}" + } +} diff --git a/terraform/outputs.tf b/terraform/outputs.tf new file mode 100644 index 0000000000..a0069469a0 --- /dev/null +++ b/terraform/outputs.tf @@ -0,0 +1,7 @@ +output "vm_public_ip" { + value = yandex_compute_instance.lab_vm.network_interface[0].nat_ip_address +} + +output "ssh_command" { + value = "ssh ubuntu@${yandex_compute_instance.lab_vm.network_interface[0].nat_ip_address}" +} diff --git a/terraform/variables.tf b/terraform/variables.tf new file mode 100644 index 0000000000..4df4800ad6 --- /dev/null +++ b/terraform/variables.tf @@ -0,0 +1,14 @@ +variable "folder_id" { + description = "Yandex Cloud Folder ID" + type = string +} + +variable "key_file" { + description = "Path to service account JSON key" + type = string +} + +variable "public_key_path" { + description = "Path to SSH public key" + type = string +} From 4232f902fc04d6eb8d452a913d96de3470b24557 Mon Sep 17 00:00:00 2001 From: danielambda Date: Wed, 25 Feb 2026 21:00:58 +0300 Subject: [PATCH 11/11] lab 5 --- ansible/.gitignore | 1 + ansible/ansible.cfg | 11 ++ ansible/docs/LAB05.md | 198 +++++++++++++++++++++ ansible/inventory/hosts.ini | 2 + ansible/playbooks/deploy.yml | 6 + ansible/playbooks/provision.yml | 7 + ansible/playbooks/site.yml | 0 ansible/roles/app_deploy/defaults/main.yml | 1 + ansible/roles/app_deploy/handlers/main.yml | 4 + ansible/roles/app_deploy/tasks/main.yml | 37 ++++ ansible/roles/common/defaults/main.yml | 7 + ansible/roles/common/tasks/main.yml | 13 ++ ansible/roles/docker/defaults/main.yml | 5 + ansible/roles/docker/handlers/main.yml | 4 + ansible/roles/docker/tasks/main.yml | 42 +++++ terraform/main.tf | 2 +- 16 files changed, 339 insertions(+), 1 deletion(-) create mode 100644 ansible/.gitignore create mode 100644 ansible/ansible.cfg create mode 100644 ansible/docs/LAB05.md create mode 100644 ansible/inventory/hosts.ini create mode 100644 ansible/playbooks/deploy.yml create mode 100644 ansible/playbooks/provision.yml create mode 100644 ansible/playbooks/site.yml create mode 100644 ansible/roles/app_deploy/defaults/main.yml create mode 100644 ansible/roles/app_deploy/handlers/main.yml create mode 100644 ansible/roles/app_deploy/tasks/main.yml create mode 100644 ansible/roles/common/defaults/main.yml create mode 100644 ansible/roles/common/tasks/main.yml create mode 100644 ansible/roles/docker/defaults/main.yml create mode 100644 ansible/roles/docker/handlers/main.yml create mode 100644 ansible/roles/docker/tasks/main.yml diff --git a/ansible/.gitignore b/ansible/.gitignore new file mode 100644 index 0000000000..317b15dd9b --- /dev/null +++ b/ansible/.gitignore @@ -0,0 +1 @@ +inventory/group_vars/all.yml diff --git a/ansible/ansible.cfg b/ansible/ansible.cfg new file mode 100644 index 0000000000..0ddcbf1672 --- /dev/null +++ b/ansible/ansible.cfg @@ -0,0 +1,11 @@ +[defaults] +inventory = inventory/hosts.ini +roles_path = roles +host_key_checking = False +remote_user = ubuntu +retry_files_enabled = False + +[privilege_escalation] +become = True +become_method = sudo +become_user = root diff --git a/ansible/docs/LAB05.md b/ansible/docs/LAB05.md new file mode 100644 index 0000000000..911c66946e --- /dev/null +++ b/ansible/docs/LAB05.md @@ -0,0 +1,198 @@ +# Lab 5 — Ansible Fundamentals Documentation + +## 1. Architecture Overview + +- **Ansible version:** 2.20.0 +- **Target VM OS:** Ubuntu 24.04 LTS +- **Role-based structure:** + The project uses a modular role-based approach with three main roles: `common`, `docker`, and `app_deploy`. Each role contains tasks, handlers, and default variables to ensure reusability and maintainability. + +**Role structure diagram:** + +``` +ansible/ +├── roles/ +│ ├── common/ +│ ├── docker/ +│ └── app_deploy/ +├── playbooks/ +│ ├── site.yml +│ ├── provision.yml +│ └── deploy.yml +├── inventory/ +│ └── hosts.ini +├── group_vars/ +│ └── all.yml +└── ansible.cfg +``` + + +**Why roles instead of monolithic playbooks?** +Roles allow modular, reusable, and maintainable automation. Changes can be made in one role without affecting others, and roles can be reused across multiple playbooks or projects. + +--- + +## 2. Roles Documentation + +### 2.1 `common` Role + +- **Purpose:** System provisioning, including updating apt cache, installing essential packages, and configuring basic system settings. +- **Variables (defaults/main.yml):** +```yaml + common_packages: + - python3-pip + - curl + - git + - vim + - htop +``` + +- Tasks: + - Update apt cache + - Install common packages +- Handlers: None +- Dependencies: None + +2.2 `docker` **Role** +- Purpose: Install Docker engine, manage Docker service, and configure user access. +- Variables (defaults/main.yml): +```yaml +docker_user: ubuntu +docker_packages: + - docker-ce + - docker-ce-cli + - containerd.io +``` + +- Tasks: + - Add Docker GPG key and repository + - Install Docker packages + - Add user to docker group + +- Handlers: + - `restart docker` — triggered if Docker service needs to restart + +- Dependencies: None + +2.3 `app_deploy` Role +- Purpose: Deploy containerized Python application. +- Variables (vaulted in group_vars/all.yml): +```yaml +dockerhub_username: +dockerhub_password: +app_name: devops-app +docker_image: "{{ dockerhub_username }}/{{ app_name }}" +docker_image_tag: latest +app_port: 5000 +app_container_name: "{{ app_name }}" +``` + +- Tasks: + - Docker login with vaulted credentials + - Pull Docker image + - Stop and remove existing container + - Run new container with port mapping and restart policy + - Wait for port to become available + - Health check via /health endpoint + +- Handlers: + - `restart app container` — triggered if container needs to restart + +- Dependencies: Docker must be installed (docker role) + +## 3. Idempotency Demonstration + +### First Run (provision.yml) +```text +TASK [common : Update apt cache] ... changed +TASK [common : Install common packages] ... changed +TASK [docker : Install Docker packages] ... changed +TASK [docker : Add user to docker group] ... changed +``` + +### Second Run (provision.yml) +```text +TASK [common : Update apt cache] ... ok +TASK [common : Install common packages] ... ok +TASK [docker : Install Docker packages] ... ok +TASK [docker : Add user to docker group] ... ok +``` + +### Analysis: + +- First run shows changed because packages and users were added. +- Second run shows ok because the desired state is already achieved. +- This confirms idempotency of roles and tasks. + +--- + +## 4. Ansible Vault Usage + +- Purpose: Securely store sensitive credentials (Docker Hub username and password). +- Vault file: inventory/group_vars/all.yml +- Vault commands used: + +```bash +ansible-vault create inventory/group_vars/all.yml +ansible-playbook playbooks/deploy.yml --ask-vault-pass +``` + +- Vault password management: Prompted interactively during playbook runs. Password not stored in repo. + +- Importance: Prevents sensitive data from being exposed in version control or logs. + +--- + +## 5. Deployment Verification + +- Playbook run: + +```text +TASK [app_deploy : Login to Docker Hub] ... ok +TASK [app_deploy : Pull Docker image] ... ok +TASK [app_deploy : Run app container] ... ok +``` + +- Container status: + +``` +yandex-cluod | CHANGED | rc=0 >> +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +d55ac5f0abd1 danielambda/devops-app:latest "python app.py" 47 minutes ago Up 47 minutes 0.0.0.0:5000->5000/tcp, 8000/tcp devops-app +``` + +- Health check: + +```bash + 󰘧 curl http://89.169.148.189:5000/health +{"status":"healthy","timestamp":"2026-02-25T17:54:54.118796+00:00","uptime_seconds":2987} +``` + +- Handler execution: +The `restart app container` handler triggers only if the container needs a restart. + +--- + +## 6. Key Decisions + +- Why use roles instead of plain playbooks? + Roles improve modularity, reusability, and maintainability; tasks are organized logically. + +- How do roles improve reusability? + Each role can be used in multiple playbooks or projects without rewriting tasks. + +- What makes a task idempotent? + Tasks use stateful modules (`apt`, `service`, `docker_container`) to ensure repeated runs produce the same outcome. + +- How do handlers improve efficiency? + Handlers run only when triggered, reducing unnecessary service restarts and optimizing playbook execution. + +- Why is Ansible Vault necessary? + Vault encrypts sensitive credentials (like Docker Hub passwords), allowing secure storage in version control. + +--- + +## 7. Challenges (Optional) +- Initial confusion with group_vars location; fixed by placing it under inventory/. +- Docker image 404 error because image was not pushed to Docker Hub; resolved by building and pushing the image. +- Ensuring idempotency in package installation and Docker tasks. diff --git a/ansible/inventory/hosts.ini b/ansible/inventory/hosts.ini new file mode 100644 index 0000000000..3c515c23ea --- /dev/null +++ b/ansible/inventory/hosts.ini @@ -0,0 +1,2 @@ +[webservers] +yandex-cluod ansible_host=89.169.148.189 ansible_user=ubuntu diff --git a/ansible/playbooks/deploy.yml b/ansible/playbooks/deploy.yml new file mode 100644 index 0000000000..10be59c817 --- /dev/null +++ b/ansible/playbooks/deploy.yml @@ -0,0 +1,6 @@ +- name: Deploy application + hosts: webservers + become: yes + + roles: + - app_deploy diff --git a/ansible/playbooks/provision.yml b/ansible/playbooks/provision.yml new file mode 100644 index 0000000000..1e88a7e3ca --- /dev/null +++ b/ansible/playbooks/provision.yml @@ -0,0 +1,7 @@ +- name: Provision web servers + hosts: webservers + become: yes + + roles: + - common + - docker diff --git a/ansible/playbooks/site.yml b/ansible/playbooks/site.yml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ansible/roles/app_deploy/defaults/main.yml b/ansible/roles/app_deploy/defaults/main.yml new file mode 100644 index 0000000000..b357f093a8 --- /dev/null +++ b/ansible/roles/app_deploy/defaults/main.yml @@ -0,0 +1 @@ +restart_policy: unless-stopped diff --git a/ansible/roles/app_deploy/handlers/main.yml b/ansible/roles/app_deploy/handlers/main.yml new file mode 100644 index 0000000000..67c94bf245 --- /dev/null +++ b/ansible/roles/app_deploy/handlers/main.yml @@ -0,0 +1,4 @@ +- name: restart app container + community.docker.docker_container: + name: "{{ app_container_name }}" + state: restarted diff --git a/ansible/roles/app_deploy/tasks/main.yml b/ansible/roles/app_deploy/tasks/main.yml new file mode 100644 index 0000000000..c0f77a2ff4 --- /dev/null +++ b/ansible/roles/app_deploy/tasks/main.yml @@ -0,0 +1,37 @@ +- name: Login to Docker Hub + community.docker.docker_login: + username: "{{ dockerhub_username }}" + password: "{{ dockerhub_password }}" + no_log: true + +- name: Pull Docker image + community.docker.docker_image: + name: "{{ docker_image }}" + tag: "{{ docker_image_tag }}" + source: pull + +- name: Remove existing container + community.docker.docker_container: + name: "{{ app_container_name }}" + state: absent + force_kill: true + +- name: Run container + community.docker.docker_container: + name: "{{ app_container_name }}" + image: "{{ docker_image }}:{{ docker_image_tag }}" + state: started + restart_policy: "{{ restart_policy }}" + ports: + - "{{ app_port }}:5000" + +- name: Wait for app to be ready + wait_for: + port: "{{ app_port }}" + delay: 5 + timeout: 60 + +- name: Verify health endpoint + uri: + url: "http://localhost:{{ app_port }}/health" + status_code: 200 diff --git a/ansible/roles/common/defaults/main.yml b/ansible/roles/common/defaults/main.yml new file mode 100644 index 0000000000..677e5e8b22 --- /dev/null +++ b/ansible/roles/common/defaults/main.yml @@ -0,0 +1,7 @@ +common_packages: + - python3-pip + - curl + - git + - vim + - htop +timezone: UTC diff --git a/ansible/roles/common/tasks/main.yml b/ansible/roles/common/tasks/main.yml new file mode 100644 index 0000000000..c2cb5f1a38 --- /dev/null +++ b/ansible/roles/common/tasks/main.yml @@ -0,0 +1,13 @@ +- name: Update apt cache + apt: + update_cache: yes + cache_valid_time: 3600 + +- name: Install common packages + apt: + name: "{{ common_packages }}" + state: present + +- name: Set timezone + timezone: + name: "{{ timezone }}" diff --git a/ansible/roles/docker/defaults/main.yml b/ansible/roles/docker/defaults/main.yml new file mode 100644 index 0000000000..b7ef2201eb --- /dev/null +++ b/ansible/roles/docker/defaults/main.yml @@ -0,0 +1,5 @@ +docker_user: ubuntu +docker_packages: + - docker-ce + - docker-ce-cli + - containerd.io diff --git a/ansible/roles/docker/handlers/main.yml b/ansible/roles/docker/handlers/main.yml new file mode 100644 index 0000000000..1907c4cd1c --- /dev/null +++ b/ansible/roles/docker/handlers/main.yml @@ -0,0 +1,4 @@ +- name: restart docker + service: + name: docker + state: restarted diff --git a/ansible/roles/docker/tasks/main.yml b/ansible/roles/docker/tasks/main.yml new file mode 100644 index 0000000000..cdfd70673d --- /dev/null +++ b/ansible/roles/docker/tasks/main.yml @@ -0,0 +1,42 @@ +- name: Install required packages + apt: + name: + - ca-certificates + - curl + - gnupg + state: present + update_cache: yes + +- name: Add Docker GPG key + apt_key: + url: https://download.docker.com/linux/ubuntu/gpg + state: present + +- name: Add Docker repository + apt_repository: + repo: "deb https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable" + state: present + notify: restart docker + +- name: Install Docker packages + apt: + name: "{{ docker_packages }}" + state: present + update_cache: yes + +- name: Ensure Docker is running + service: + name: docker + state: started + enabled: yes + +- name: Add user to docker group + user: + name: "{{ docker_user }}" + groups: docker + append: yes + +- name: Install python docker module + apt: + name: python3-docker + state: present diff --git a/terraform/main.tf b/terraform/main.tf index f477217797..7b6b17f7ed 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -33,7 +33,7 @@ resource "yandex_vpc_security_group" "lab_sg" { ingress { protocol = "TCP" port = 22 - v4_cidr_blocks = ["93.77.186.188/0"] # Replace with your IP for security + v4_cidr_blocks = ["0.0.0.0/0"] # Replace with your IP for security } ingress { protocol = "TCP"