# CMPE273 Module 6 — disposable classroom exercise, not a production manifest
apiVersion: v1
kind: Namespace
metadata:
  name: cmpe273-module06
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: runtime-lab
  namespace: cmpe273-module06
data:
  server.py: |
    import json
    import os
    from pathlib import Path
    from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer

    class Handler(BaseHTTPRequestHandler):
        def do_GET(self):
            not_ready = Path('/tmp/not-ready').exists()
            if self.path == '/live':
                status, payload = 200, {'live': True}
            elif self.path == '/ready':
                status, payload = (503 if not_ready else 200), {'ready': not not_ready}
            elif self.path == '/':
                status, payload = 200, {'pod': os.environ.get('POD_NAME', 'local-demo')}
            else:
                status, payload = 404, {'error': 'not found'}
            body = json.dumps(payload).encode()
            self.send_response(status)
            self.send_header('Content-Type', 'application/json')
            self.send_header('Content-Length', str(len(body)))
            self.end_headers()
            self.wfile.write(body)

    ThreadingHTTPServer(('0.0.0.0', 8080), Handler).serve_forever()
  client.py: |
    import collections
    import http.client
    import json
    import time

    counts = collections.Counter()
    errors = 0
    for attempt in range(40):
        connection = http.client.HTTPConnection('inventory', 8080, timeout=2)
        try:
            connection.request('GET', '/', headers={'Connection': 'close'})
            response = connection.getresponse()
            payload = json.loads(response.read())
            if response.status != 200:
                raise RuntimeError(f'HTTP {response.status}: {payload}')
            counts[payload['pod']] += 1
            print(time.strftime('%H:%M:%S'), payload['pod'], flush=True)
        except Exception as error:
            errors += 1
            print(time.strftime('%H:%M:%S'), type(error).__name__, str(error), flush=True)
        finally:
            connection.close()
        time.sleep(0.2)
    print(json.dumps({'counts': dict(counts), 'errors': errors}, indent=2))
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: inventory
  namespace: cmpe273-module06
spec:
  replicas: 2
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: inventory
  template:
    metadata:
      labels:
        app: inventory
    spec:
      automountServiceAccountToken: false
      securityContext:
        runAsNonRoot: true
        runAsUser: 10001
        runAsGroup: 10001
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: inventory
          image: python:3.13-slim
          command:
            - python
            - -u
            - /lab/server.py
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
          ports:
            - name: http
              containerPort: 8080
          resources:
            requests:
              cpu: 50m
              memory: 32Mi
            limits:
              cpu: 250m
              memory: 128Mi
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
          readinessProbe:
            httpGet:
              path: /ready
              port: http
            periodSeconds: 2
            failureThreshold: 1
          livenessProbe:
            httpGet:
              path: /live
              port: http
            periodSeconds: 10
            failureThreshold: 3
          startupProbe:
            httpGet:
              path: /live
              port: http
            periodSeconds: 2
            failureThreshold: 30
          volumeMounts:
            - name: lab
              mountPath: /lab
              readOnly: true
      volumes:
        - name: lab
          configMap:
            name: runtime-lab
---
apiVersion: v1
kind: Service
metadata:
  name: inventory
  namespace: cmpe273-module06
spec:
  selector:
    app: inventory
  ports:
    - port: 8080
      targetPort: http
---
apiVersion: v1
kind: Pod
metadata:
  name: client
  namespace: cmpe273-module06
spec:
  automountServiceAccountToken: false
  securityContext:
    runAsNonRoot: true
    runAsUser: 10001
    runAsGroup: 10001
    seccompProfile:
      type: RuntimeDefault
  containers:
    - name: client
      image: python:3.13-slim
      command:
        - python
        - -c
        - import time; time.sleep(86400)
      resources:
        requests:
          cpu: 25m
          memory: 32Mi
        limits:
          cpu: 250m
          memory: 128Mi
      securityContext:
        allowPrivilegeEscalation: false
        capabilities:
          drop:
            - ALL
      volumeMounts:
        - name: lab
          mountPath: /lab
          readOnly: true
  volumes:
    - name: lab
      configMap:
        name: runtime-lab
