From a99d17cc0bfef4a1e4b521ecbc79b0e3cd2d5baf Mon Sep 17 00:00:00 2001 From: Joris Wouter Jonkers Date: Mon, 14 Sep 2026 14:01:33 +0200 Subject: [PATCH] docs: rewrite the Task 0 proposal around the joint EMF and TypeScript implementation --- CLAUDE.md | 3 +- docs/mde/README.md | 11 +- .../task-0-proposal/Sections/01-problem.tex | 6 +- .../task-0-proposal/Sections/02-solution.tex | 10 +- .../Sections/03-source-language.tex | 42 ++- .../Sections/04-generated-code.tex | 37 +-- .../Sections/05-metamodels.tex | 12 +- .../Sections/06-architecture.tex | 12 +- .../task-0-proposal/Sections/07-tooling.tex | 22 +- .../Sections/08-deliverables.tex | 12 +- .../task-0-proposal/Sections/09-appendix.tex | 49 --- docs/mde/task-0-proposal/Title/titlepage.tex | 4 +- .../listings/auth-api.policy.json | 13 - .../listings/auth-api.role.json | 9 - .../task-0-proposal/listings/auth-domain.yml | 68 ----- .../listings/ingressroutes.yaml | 56 ---- .../listings/kustomization-auth.yaml | 9 - .../listings/kustomization.yaml | 5 - .../task-0-proposal/listings/namespace.yaml | 7 - .../listings/networkpolicy.yaml | 165 ----------- docs/mde/task-0-proposal/listings/pdb.yaml | 17 -- .../listings/prometheusrules.yaml | 40 --- .../listings/serviceaccount.yaml | 24 -- .../listings/servicemonitor.yaml | 25 -- .../task-0-proposal/listings/workload.yaml | 279 ------------------ docs/mde/task-0-proposal/main.tex | 55 ---- ...-tycho-against-a-pinned-target-platform.md | 9 + emf/docs/architecture.md | 6 +- 28 files changed, 110 insertions(+), 897 deletions(-) delete mode 100644 docs/mde/task-0-proposal/Sections/09-appendix.tex delete mode 100644 docs/mde/task-0-proposal/listings/auth-api.policy.json delete mode 100644 docs/mde/task-0-proposal/listings/auth-api.role.json delete mode 100644 docs/mde/task-0-proposal/listings/auth-domain.yml delete mode 100644 docs/mde/task-0-proposal/listings/ingressroutes.yaml delete mode 100644 docs/mde/task-0-proposal/listings/kustomization-auth.yaml delete mode 100644 docs/mde/task-0-proposal/listings/kustomization.yaml delete mode 100644 docs/mde/task-0-proposal/listings/namespace.yaml delete mode 100644 docs/mde/task-0-proposal/listings/networkpolicy.yaml delete mode 100644 docs/mde/task-0-proposal/listings/pdb.yaml delete mode 100644 docs/mde/task-0-proposal/listings/prometheusrules.yaml delete mode 100644 docs/mde/task-0-proposal/listings/serviceaccount.yaml delete mode 100644 docs/mde/task-0-proposal/listings/servicemonitor.yaml delete mode 100644 docs/mde/task-0-proposal/listings/workload.yaml diff --git a/CLAUDE.md b/CLAUDE.md index c3a1243..a4f0862 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -59,7 +59,8 @@ model-level rule and point at the deferred set. The MDE course requires the compiler to be built with Ecore, Xtext, OCL, QVT-Operational and Acceleo, so `emf/` holds a second, hand-written Java -implementation (Maven and Tycho, JDK 21, no Eclipse IDE). It is deprecated +implementation (Maven and Tycho, JDK 21, no Eclipse IDE to build, but +loadable in Eclipse for the course's examiners). It is deprecated from the day it lands and deleted at its sunset: - **The root stays TypeScript.** Every pom, module, check, ledger and decision diff --git a/docs/mde/README.md b/docs/mde/README.md index 034ed99..6221f4d 100644 --- a/docs/mde/README.md +++ b/docs/mde/README.md @@ -14,7 +14,7 @@ One directory per deadline, named after the course's own task numbering. | Directory | Deliverable | Overleaf project | State | |---|---|---|---| -| [`task-0-proposal/`](task-0-proposal/) | Task 0 — project description, the proposal that must be approved before work starts | `6aa2ba0c3920baa59ec20901` | mirrored 2026-09-11 | +| [`task-0-proposal/`](task-0-proposal/) | Task 0 — project description, the proposal that must be approved before work starts | `6aa2ba0c3920baa59ec20901` | re-mirrored 2026-09-14, after the joint-implementation revision | | `task-1-metamodelling/` | Task 1 — domain analysis, modelling decisions, the two metamodels and their diagrams, example models | — | not started | | `task-2-transformations/` | Task 2 — the model-to-model transformation, its rules and limitations, evidence it runs | — | not started | | `task-3-code-generation/` | Task 3 — the model-to-text transformation, the generated code, evidence it loads | — | not started | @@ -48,7 +48,6 @@ documents whose parts are sections rather than chapters. main.tex root document: preamble, \tableofcontents, \input list Title/ title page and the University of Twente logo Sections/ one file per section, numbered in reading order, appendix last -listings/ verbatim inputs for \lstinputlisting — models and generated files *.sty, *.cfg vendored LaTeX packages, see below ``` @@ -96,11 +95,13 @@ Taken from the DoSA report, so that the four reports read as one series: - Headings are Title Case. Sections carry a `\label{sec:…}` and are cross-referenced as `Section~\ref{…}`; the appendix is `\appendix` plus one section, so its parts number `A.1`, `A.2` and so on. -- Tables are floats: `\begin{table}[ht]`, centred, `\hline` rules, caption - **below** the table, `\label{tab:…}`. +- Tables are floats: `\begin{table}[!htbp]`, centred, `\small`, ragged-right + `p` columns, `\hline` rules, caption **below** the table, `\label{tab:…}`. - Front matter is numbered in roman and the body in arabic, with a table of contents between them. - Code listings are called **Example**, not Listing (`\lstlistingname`). -- Every cross-reference is a live PDF link; `hyperref` colours them. +- Every cross-reference is a live PDF link; `hyperref` colours them. Prose never + says "the table below" or "the next section": it names the target with + `Table~\ref{…}` or `Section~\ref{…}`. - Files reproduced from the generator's intended output carry no commentary of any kind, because the real ones will not. diff --git a/docs/mde/task-0-proposal/Sections/01-problem.tex b/docs/mde/task-0-proposal/Sections/01-problem.tex index c4d8863..288b78c 100644 --- a/docs/mde/task-0-proposal/Sections/01-problem.tex +++ b/docs/mde/task-0-proposal/Sections/01-problem.tex @@ -1,12 +1,12 @@ \section{Problem Statement} \label{sec:problem} -A Kubernetes service is described by a workload, service, account, network +A Kubernetes application is described by a workload, service, account, network policy, ingress routes, monitoring rules and disruption budget. These resources repeat the same facts in different schemas. A port can occur in four files; a dependency determines both an address and an egress rule. Manual copies can drift while remaining syntactically valid. The cluster may -accept every file even though a service cannot reach its database or its metrics +accept every file even though an application cannot reach its database or its metrics are no longer collected. The selected problem is therefore to generate a -consistent Kubernetes deployment set from one abstract service model. +consistent Kubernetes deployment set from one abstract application model. diff --git a/docs/mde/task-0-proposal/Sections/02-solution.tex b/docs/mde/task-0-proposal/Sections/02-solution.tex index 799f614..f3d0fc4 100644 --- a/docs/mde/task-0-proposal/Sections/02-solution.tex +++ b/docs/mde/task-0-proposal/Sections/02-solution.tex @@ -1,15 +1,15 @@ \section{Solution} \label{sec:solution} -The domain-specific language records workloads, ports, dependencies, routes, +The domain-specific language records processes, ports, dependencies, routes, storage, secrets, health and operational requirements once, without naming Kubernetes resources or vendor fields. -For a version release, CI provides the Service Intent model, per-workload +For a version release, CI provides the Project Intent model, per-process environment files, an image lock mapping image names to immutable digests, and versioned platform data. The platform data defines namespace and label rules, -resource and security defaults, ingress and storage classes, the service -register, alert catalogue and cluster capabilities. The generator does not read +resource and security defaults, ingress and storage classes, the register +of unmanaged surfaces, alert catalogue and cluster capabilities. The generator does not read live cluster state or retrieve secret values. A model-to-model transformation turns these inputs into a \emph{Resolved @@ -18,7 +18,7 @@ \section{Solution} policy peers, routes, secret references, monitoring rules and configuration hashes. Renderers therefore make no deployment decisions. -The model-to-text step writes a per-service \emph{Deliverable Set}: a +The model-to-text step writes a per-application \emph{Deliverable Set}: a \texttt{kustomization.yaml} and its YAML and JSON resources. After validation, release CI deploys that version with \texttt{kubectl apply -k}. Platform changes remain confined to versioned generator inputs and rules. diff --git a/docs/mde/task-0-proposal/Sections/03-source-language.tex b/docs/mde/task-0-proposal/Sections/03-source-language.tex index 5c52c1e..a8dd6ed 100644 --- a/docs/mde/task-0-proposal/Sections/03-source-language.tex +++ b/docs/mde/task-0-proposal/Sections/03-source-language.tex @@ -1,30 +1,40 @@ \section{Source Language} \label{sec:sourcelanguage} -One source file represents a domain and its services. The table summarises the -language. Example~\ref{lst:auth} in Appendix~\ref{app:rendered} shows the -\texttt{auth} domain. +One source file represents a project and its applications. Table~\ref{tab:source_language} +summarises the language. -\begin{table}[ht] +\begin{table}[!htbp] \centering -\begin{tabular}{p{0.22\linewidth}p{0.68\linewidth}} +\small +\begin{tabular}{>{\raggedright\arraybackslash}p{0.24\linewidth}>{\raggedright\arraybackslash}p{0.68\linewidth}} \hline \textbf{Concern} & \textbf{Model content} \\ \hline -Ownership and release & Domain, responsible team and parts released together. \\ -Workloads & Container image and execution mode for each runnable part. \\ -Placement and scale & Resource, architecture and capability needs; replica count. \\ -Exposure and routing & Host, audience and path-to-workload mapping. \\ -Connections & Named provided ports and outgoing service dependencies. \\ -Health and cutover & Probes, allowed startup time and replacement strategy. \\ -Observability & Metrics surface and alert class. \\ -Storage and writes & Volume properties and paths writable under a read-only root. \\ -Secrets & Allowed paths, keys, access modes and delivery methods. \\ +Ownership and release & + Who owns the project, and which of its processes are released together as one application. \\ +Processes & + The processes that run, packaged as container images, and whether they are one-time executions or long-running. \\ +Placement and scale & + How much memory and CPU a process needs, which machines can host it, and how many instances run simultaneously. \\ +Exposure and routing & + The web address an application answers on, who may reach it, and which process handles each URL path. \\ +Connections & + The network ports a process offers, and the other applications it needs to reach. \\ +Health and cutover & + The checks that tell the platform a process is running and ready, and how an old version is replaced by a new one. \\ +Observability & + Where the platform collects measurements from a process, and how urgently a failure should alert someone. \\ +Storage and writes & + The disks a process stores data on, what recovery entails, and which folders it has access to. \\ +Secrets & + Which secrets a process may read from the vault, and whether they arrive as environment variables, files, or otherwise. \\ \hline \end{tabular} \caption{Concerns Defined by the Source Language} \label{tab:source_language} \end{table} -The model contains service requirements rather than Kubernetes kinds, proxy -fields or machine names. Platform mechanisms are derived in the next stage. +The model contains application requirements rather than Kubernetes kinds, proxy +fields or machine names. Platform mechanisms are derived in the next stage, described in +Section~\ref{sec:architecture}. diff --git a/docs/mde/task-0-proposal/Sections/04-generated-code.tex b/docs/mde/task-0-proposal/Sections/04-generated-code.tex index 0eab412..f3dc339 100644 --- a/docs/mde/task-0-proposal/Sections/04-generated-code.tex +++ b/docs/mde/task-0-proposal/Sections/04-generated-code.tex @@ -1,36 +1,30 @@ \section{Generated Code} \label{sec:generatedcode} -The generator emits one versioned release bundle per service. Its resources and -principal derivations are listed below. Appendix~\ref{app:rendered} contains the -hand-written target for the \texttt{auth} example. +The generator emits one versioned release bundle per application. Its resources and +principal derivations are listed in Table~\ref{tab:generated_resources}. -\begin{table}[ht] +\begin{table}[!htbp] \centering -\begin{tabular}{p{0.22\linewidth}p{0.56\linewidth}c} +\small +\begin{tabular}{>{\raggedright\arraybackslash}p{0.24\linewidth}>{\raggedright\arraybackslash}p{0.68\linewidth}} \hline -\textbf{Output} & \textbf{Principal derivation} & \textbf{Example} \\ +\textbf{Output} & \textbf{Principal derivation} \\ \hline \texttt{Namespace} and indexes & - Domain name, fixed labels and resolved output paths & - \ref{lst:namespace}, \ref{lst:kust-root}, \ref{lst:kust-auth} \\ + A named partition of the cluster for the project, and the index files listing what to deploy. \\ Workload resources & - Locked image, placement, probes, cutover, ports, identity, configuration and replicas & - \ref{lst:workload}, \ref{lst:serviceaccount}, \ref{lst:pdb} \\ + The definitions that start and restart processes, give each an identity, and keep enough instances running during maintenance. \\ \texttt{NetworkPolicy} & - Default deny, dependency edges, exposed surfaces and audience & - \ref{lst:networkpolicy} \\ + Firewall rules stating which processes may talk to which, with everything else blocked. \\ \texttt{IngressRoute} & - Routes, path specificity, content policy, audience and host & - \ref{lst:ingressroutes} \\ + The web-proxy rules sending incoming requests for an address and path to the right process. \\ Monitoring and alerts & - Scrape surface and alert class resolved through the rule catalogue & - \ref{lst:servicemonitor}, \ref{lst:prometheusrules} \\ + Instructions to collect measurements, and the conditions under which an alert fires. \\ Secret resources & - Grants, workload identity and environment, file or direct delivery & - \ref{lst:vaultpolicy}, \ref{lst:vaultrole} \\ + Permissions in the vault granting each process exactly the secrets it was allowed. \\ Backup and sweep jobs & - Volume durability and storage engine & n/a \\ + Scheduled jobs copying data somewhere safe, or cleaning up data that may be discarded. \\ \hline \end{tabular} \caption{Generated Resources and Their Principal Derivations} @@ -39,5 +33,6 @@ \section{Generated Code} The transformation computes limits, startup probes, route precedence and policy peers. For \texttt{auth}, about 90 source lines determine ten files containing -about 890 lines. The appendix is a manual oracle. The implemented generator must -reproduce it, validate the result and provide one Kustomize entry point for CI. +about 890 lines. Hand-written expected files kept in the repository are the oracle. Both +implementations (Section~\ref{sec:tooling}) must reproduce them, validate the result and provide one +Kustomize entry point for CI. diff --git a/docs/mde/task-0-proposal/Sections/05-metamodels.tex b/docs/mde/task-0-proposal/Sections/05-metamodels.tex index ec9f0ee..07a5ffc 100644 --- a/docs/mde/task-0-proposal/Sections/05-metamodels.tex +++ b/docs/mde/task-0-proposal/Sections/05-metamodels.tex @@ -1,11 +1,11 @@ \section{Metamodels} \label{sec:metamodels} -The three pipeline layers have separate metamodels: +The three pipeline layers of Section~\ref{sec:solution} have separate metamodels: \begin{enumerate} - \item \textbf{Service Intent}: \emph{Domain}, \emph{Service}, - \emph{Workload}, \emph{Exposure}, \emph{Route}, \emph{Placement}, + \item \textbf{Project Intent}: \emph{Project}, \emph{Application}, + \emph{Process}, \emph{Exposure}, \emph{Route}, \emph{Placement}, \emph{Probe}, \emph{Dependency}, \emph{Secret Grant} and \emph{Volume}. \item \textbf{Resolved Deployment}: concrete resources and relationships with every derived value, identity and output path present. @@ -13,6 +13,6 @@ \section{Metamodels} each with its path, content and producing adapter. \end{enumerate} -UML class diagrams document each metamodel. The implementation uses TypeScript -types and \texttt{zod} runtime schemas, as discussed in -Section~\ref{sec:tooling}. +UML class diagrams document each metamodel. Each metamodel is defined twice, +separately: in Ecore with OCL constraints, and as TypeScript types and +\texttt{zod} runtime schemas, as discussed in Section~\ref{sec:tooling}. diff --git a/docs/mde/task-0-proposal/Sections/06-architecture.tex b/docs/mde/task-0-proposal/Sections/06-architecture.tex index 5e0ba7b..9d94e58 100644 --- a/docs/mde/task-0-proposal/Sections/06-architecture.tex +++ b/docs/mde/task-0-proposal/Sections/06-architecture.tex @@ -5,13 +5,17 @@ \section{Architecture} \begin{enumerate} \item \textbf{Read and validate.} A \texttt{zod} schema validates the YAML - wire format, which a mapper converts to the Service Intent model. Keeping + wire format, which a mapper converts to the Project Intent model. In the + EMF implementation (Section~\ref{sec:tooling}), an Xtext grammar parses the same file and OCL + constraints validate the resulting model. Keeping wire and domain types separate allows the syntax to evolve independently. - \item \textbf{Resolve.} Named rules combine the source with the release lock + \item \textbf{Resolve.} Named rules, written in TypeScript and as a QVT-OM + transformation, combine the source with the release lock and versioned environment and platform data. They materialise all values needed to deploy without reading live cluster state. \item \textbf{Render.} An adapter for each resource family builds typed - objects. One serialiser writes YAML or JSON. Adapters do not make platform + objects. One serialiser writes YAML or JSON; in the EMF implementation, Acceleo + templates write the same files. Adapters do not make platform decisions or assign paths. \end{enumerate} @@ -19,5 +23,5 @@ \section{Architecture} run to report several errors and tests to identify the failed rule. Module dependency checks prevent renderers from importing source or resolution logic. With fixed inputs, repeated runs must produce identical bytes. CI validates the -bundle and applies its service-level Kustomize entry point on each version +bundle and applies its application-level Kustomize entry point on each version release. diff --git a/docs/mde/task-0-proposal/Sections/07-tooling.tex b/docs/mde/task-0-proposal/Sections/07-tooling.tex index db9d1d3..8a7d2b2 100644 --- a/docs/mde/task-0-proposal/Sections/07-tooling.tex +++ b/docs/mde/task-0-proposal/Sections/07-tooling.tex @@ -6,13 +6,17 @@ \section{Tooling Choice} \texttt{zod} provides runtime validation, inferred static types and an exported JSON Schema for editor support. -This differs from the prescribed Ecore, ATL or QVT-OM, and Acceleo stack. Those -tools provide established modelling languages, but add an Eclipse and JVM -toolchain not otherwise used by the deployment workflow. Here that cost does not -improve the model or the evidence. +The project is a joint implementation. The prescribed stack of Ecore, Xtext, +OCL, QVT-OM and Acceleo implements the same pipeline a second time, written +separately from the TypeScript code; neither is generated from the other. Both +are checked against the same committed expected outputs of +Section~\ref{sec:generatedcode}: the parsed model, the +Resolved Deployment, the generated files and the error codes reported for +invalid models. Agreement between the two follows from both matching these +outputs. -The substitution preserves the modelling stages: UML diagrams and executable -schemas define metamodels, tested functions implement model-to-model rules, and -typed builders plus one serialiser implement model-to-text generation. Models, -rules, generated artifacts and execution evidence remain in scope. Since the -named technologies are explicit, this change requires approval. +The EMF tools run headless through Maven for most of the project, so CI checks +them on every change without an IDE. The projects remain loadable in Eclipse +Modeling Tools: examiners can import them, open the metamodels, validate the +example models against the OCL constraints, and run the QVT-OM transformation +and the Acceleo generator from committed launch configurations. diff --git a/docs/mde/task-0-proposal/Sections/08-deliverables.tex b/docs/mde/task-0-proposal/Sections/08-deliverables.tex index e8eb530..69ef1a0 100644 --- a/docs/mde/task-0-proposal/Sections/08-deliverables.tex +++ b/docs/mde/task-0-proposal/Sections/08-deliverables.tex @@ -1,8 +1,12 @@ \section{Planned Deliverables} \label{sec:deliverables} -Subject to approval, the deliverables are UML metamodel diagrams and executable -schemas with example models; tested resolution rules with limitations and -diagnostics; and source models with generated YAML and JSON. Evidence includes -schema validation, a CI-style \texttt{kubectl apply -k} deployment to a local +The deliverables are UML metamodel diagrams, Ecore metamodels with OCL +constraints and an Xtext grammar, and the equivalent \texttt{zod} schemas, with +example models; resolution rules in QVT-OM and TypeScript, tested, with +limitations and diagnostics; and source models with YAML and JSON generated by +Acceleo templates and by the TypeScript renderer. Evidence includes schema and +OCL validation, parity between the two implementations (Section~\ref{sec:tooling}) on every +example, a +CI-style \texttt{kubectl apply -k} deployment to a local cluster and deterministic repeated runs. diff --git a/docs/mde/task-0-proposal/Sections/09-appendix.tex b/docs/mde/task-0-proposal/Sections/09-appendix.tex deleted file mode 100644 index 00151d4..0000000 --- a/docs/mde/task-0-proposal/Sections/09-appendix.tex +++ /dev/null @@ -1,49 +0,0 @@ -%=== APPENDIX === - -\section{Worked Example} -\label{app:rendered} - -Example~\ref{lst:auth} is a worked source model, the \texttt{auth} domain: one -service of two workloads, released together, behind a single address. Every file -after it is the output the generator is intended to produce from that model, -together with the per-workload environment file and the pinned platform inputs. - -The generator does not exist yet, so these files were written out by hand -against the model as specified; they are the target the implementation will be -measured against rather than a transcript of a run. They are shaped exactly as -the generator must write them: no commentary, and nothing added or annotated for -this report. - -\subsection{The Source Model} - -\lstinputlisting[caption={The \texttt{auth} domain.},label={lst:auth}]{listings/auth-domain.yml} - -\subsection{Namespace and Directory Indexes} - -\lstinputlisting[caption={\texttt{namespace.yaml}},label={lst:namespace}]{listings/namespace.yaml} -\lstinputlisting[caption={\texttt{kustomization.yaml}, the domain index},label={lst:kust-root}]{listings/kustomization.yaml} -\lstinputlisting[caption={\texttt{apps/auth/kustomization.yaml}, the service index},label={lst:kust-auth}]{listings/kustomization-auth.yaml} - -\subsection{Workload Controllers and Services} - -\lstinputlisting[caption={\texttt{apps/auth/workload.yaml}: two \texttt{Deployment} objects and their \texttt{Service} objects},label={lst:workload}]{listings/workload.yaml} -\lstinputlisting[caption={\texttt{apps/auth/serviceaccount.yaml}},label={lst:serviceaccount}]{listings/serviceaccount.yaml} -\lstinputlisting[caption={\texttt{apps/auth/pdb.yaml}},label={lst:pdb}]{listings/pdb.yaml} - -\subsection{Network Policy} - -\lstinputlisting[caption={\texttt{apps/auth/networkpolicy.yaml}},label={lst:networkpolicy}]{listings/networkpolicy.yaml} - -\subsection{Edge Routing} - -\lstinputlisting[caption={\texttt{edge/ingressroutes.yaml}},label={lst:ingressroutes}]{listings/ingressroutes.yaml} - -\subsection{Monitoring and Alerting} - -\lstinputlisting[caption={\texttt{apps/auth/servicemonitor.yaml}},label={lst:servicemonitor}]{listings/servicemonitor.yaml} -\lstinputlisting[caption={\texttt{observability/prometheusrules.yaml}},label={lst:prometheusrules}]{listings/prometheusrules.yaml} - -\subsection{Secret Store} - -\lstinputlisting[caption={\texttt{auth-api.policy.json}},label={lst:vaultpolicy}]{listings/auth-api.policy.json} -\lstinputlisting[caption={\texttt{auth-api.role.json}},label={lst:vaultrole}]{listings/auth-api.role.json} diff --git a/docs/mde/task-0-proposal/Title/titlepage.tex b/docs/mde/task-0-proposal/Title/titlepage.tex index b6d2936..107fc4d 100644 --- a/docs/mde/task-0-proposal/Title/titlepage.tex +++ b/docs/mde/task-0-proposal/Title/titlepage.tex @@ -2,6 +2,8 @@ \begin{figure}[H] \centering + + \includegraphics[width=0.55\linewidth]{Title/UT_Logo_0072_Black_EN.png} \caption*{} \label{fig:utlogo} @@ -11,7 +13,7 @@ ~\vspace{2cm} % vertical space \HRule \\[0.6cm] %Horizontal line and [0.4cm] extra spacing -\textbf{\LARGE Generating a Kubernetes Deployment Set from a Service-Intent Domain Model} \\[0.3cm] +\textbf{\LARGE Generating a Kubernetes Deployment Set from a Project-Intent Domain Model} \\[0.3cm] Project Task 0: Project Description \\ Project Type: Code Generation \\ Last Modified: \today\\[0.4cm] % Title of report diff --git a/docs/mde/task-0-proposal/listings/auth-api.policy.json b/docs/mde/task-0-proposal/listings/auth-api.policy.json deleted file mode 100644 index 8665ac8..0000000 --- a/docs/mde/task-0-proposal/listings/auth-api.policy.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "auth-api", - "policy": { - "path": { - "secret/data/platform/postgres/auth": { "capabilities": ["read"] }, - "secret/metadata/platform/postgres/auth": { "capabilities": ["read", "list"] }, - "secret/data/auth-api": { "capabilities": ["read"] }, - "secret/metadata/auth-api": { "capabilities": ["read", "list"] }, - "transit/sign/auth-api-jwt": { "capabilities": ["update"] }, - "transit/keys/auth-api-jwt/rotate": { "capabilities": ["update"] } - } - } -} diff --git a/docs/mde/task-0-proposal/listings/auth-api.role.json b/docs/mde/task-0-proposal/listings/auth-api.role.json deleted file mode 100644 index 4ea4de2..0000000 --- a/docs/mde/task-0-proposal/listings/auth-api.role.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "auth-api", - "role": { - "bound_service_account_names": ["auth-api"], - "bound_service_account_namespaces": ["auth-system"], - "token_policies": ["auth-api"], - "token_ttl": "1h" - } -} diff --git a/docs/mde/task-0-proposal/listings/auth-domain.yml b/docs/mde/task-0-proposal/listings/auth-domain.yml deleted file mode 100644 index 49254a6..0000000 --- a/docs/mde/task-0-proposal/listings/auth-domain.yml +++ /dev/null @@ -1,68 +0,0 @@ -schemaVersion: 1.0.0 # which version of this language the file is written in -domain: auth # one file per area; this one is about logging in -owner: joris # who to ask about anything in this file -services: - - id: auth # a service: the parts below are updated together - alertClass: wake-on-call # [none, business-hours, urgent, wake-on-call] urgency - exposure: # how the outside world reaches this service - - name: public # a label for this entry point - host: auth.example.dev - audience: anonymous # [anonymous, authenticated, internal, lan] who may connect - contentPolicy: strict # [strict, admin, workflow] browser security rules - routes: # which part of the address goes to which service - - {path: /api, match: prefix, workload: auth-api, surface: http} - - {path: /, match: prefix, workload: auth-ui, surface: http} - workloads: # the parts of the service, one container image each - - name: auth-api - lifecycle: service # [service, job] keeps running, or runs once and stops - image: auth-api # a name; the exact image version is filled in later - runtime: jvm # [jvm, python, node, static, none] how the service runs - provides: # the ports the service listens on, each with a name - http: 8080 - placement: # what the service needs from its machine - memory: 768Mi # how much memory the service may use - cpu: 250m # how much processor time the service asks for - arch: [amd64] - capabilities: [public-ingress] - writablePaths: [/tmp] # the only folders the service may write into - dependsOn: # the other services this service talks to - - {service: platform-postgres, surface: postgres} - - {service: platform-valkey, surface: redis} - - {service: platform-rabbitmq, surface: amqp} - - {service: stalwart, surface: smtp} - probes: # the addresses used to check that the service is healthy - readiness: {path: /api/actuator/health/readiness, port: 8081} - liveness: {path: /api/actuator/health/liveness, port: 8081} - startupBudget: 600s # how long the service may take to start before failing - cutover: rolling # [rolling, recreate] how a new version replaces the old - replicas: # how many copies of the service run; needs a reason - count: 2 - reason: Capacity on freed budget, not availability. - scrape: # where our monitoring takes its measurements - port: 8081 - path: /api/actuator/prometheus - secrets: # the passwords and keys the service may read, no others - - path: secret/data/platform/postgres/auth - keys: [user, password] - access: read # [read, self-renew, self-roll, custody] what is allowed - delivery: self # [env, file, self] the service fetches them itself - rotation: {tolerates: reload, maxAge: 168h} - - engine: transit # a signing key that never leaves the vault - key: auth-api-jwt - operations: [sign, rotate] - delivery: self - - name: auth-ui # the second part, updated together with the first - lifecycle: service - image: auth-ui - runtime: static # only files served by a web server, no Java - provides: - http: 80 - placement: - memory: 64Mi - cpu: 10m - writablePaths: [/var/cache/nginx, /var/run] - probes: - readiness: {path: /, port: 8080} - liveness: {path: /, port: 8080} - startupBudget: 30s - cutover: rolling diff --git a/docs/mde/task-0-proposal/listings/ingressroutes.yaml b/docs/mde/task-0-proposal/listings/ingressroutes.yaml deleted file mode 100644 index 1a322f8..0000000 --- a/docs/mde/task-0-proposal/listings/ingressroutes.yaml +++ /dev/null @@ -1,56 +0,0 @@ ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: auth-ui - namespace: auth-system - labels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`auth.jorisjonkers.dev`) && PathPrefix(`/`) - middlewares: - - name: security-headers-strict - namespace: kube-system - services: - - name: auth-ui - namespace: auth-system - port: 80 - priority: 1001 - tls: - certResolver: letsencrypt ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`auth.jorisjonkers.dev`) && PathPrefix(`/api`) - middlewares: - - name: security-headers-strict - namespace: kube-system - services: - - name: auth-api - namespace: auth-system - port: 8081 - priority: 1004 - tls: - certResolver: letsencrypt diff --git a/docs/mde/task-0-proposal/listings/kustomization-auth.yaml b/docs/mde/task-0-proposal/listings/kustomization-auth.yaml deleted file mode 100644 index 00e7a2b..0000000 --- a/docs/mde/task-0-proposal/listings/kustomization-auth.yaml +++ /dev/null @@ -1,9 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -namespace: auth-system -resources: -- workload.yaml -- serviceaccount.yaml -- pdb.yaml -- servicemonitor.yaml -- networkpolicy.yaml diff --git a/docs/mde/task-0-proposal/listings/kustomization.yaml b/docs/mde/task-0-proposal/listings/kustomization.yaml deleted file mode 100644 index 1dce8cd..0000000 --- a/docs/mde/task-0-proposal/listings/kustomization.yaml +++ /dev/null @@ -1,5 +0,0 @@ -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: -- namespace.yaml -- apps/auth diff --git a/docs/mde/task-0-proposal/listings/namespace.yaml b/docs/mde/task-0-proposal/listings/namespace.yaml deleted file mode 100644 index 0e93787..0000000 --- a/docs/mde/task-0-proposal/listings/namespace.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: auth-system - labels: - kubernetes.io/metadata.name: auth-system - app.kubernetes.io/part-of: auth diff --git a/docs/mde/task-0-proposal/listings/networkpolicy.yaml b/docs/mde/task-0-proposal/listings/networkpolicy.yaml deleted file mode 100644 index 5a1fa97..0000000 --- a/docs/mde/task-0-proposal/listings/networkpolicy.yaml +++ /dev/null @@ -1,165 +0,0 @@ ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: auth-system - labels: - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: {} - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - podSelector: - matchLabels: - k8s-app: kube-dns - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - podSelector: - matchLabels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - podSelector: - matchLabels: - app.kubernetes.io/name: traefik - ports: - - protocol: TCP - port: 8081 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: utility-system - podSelector: - matchLabels: - app.kubernetes.io/name: prometheus - ports: - - protocol: TCP - port: 8081 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - podSelector: - matchLabels: - k8s-app: kube-dns - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/name: postgres - ports: - - protocol: TCP - port: 5432 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/name: valkey - ports: - - protocol: TCP - port: 6379 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/name: rabbitmq - ports: - - protocol: TCP - port: 5672 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: utility-system - podSelector: - matchLabels: - app.kubernetes.io/name: vault - ports: - - protocol: TCP - port: 8200 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: auth-ui - namespace: auth-system - labels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static -spec: - podSelector: - matchLabels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - podSelector: - matchLabels: - app.kubernetes.io/name: traefik - ports: - - protocol: TCP - port: 80 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - podSelector: - matchLabels: - k8s-app: kube-dns - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/docs/mde/task-0-proposal/listings/pdb.yaml b/docs/mde/task-0-proposal/listings/pdb.yaml deleted file mode 100644 index ac06d4a..0000000 --- a/docs/mde/task-0-proposal/listings/pdb.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - selector: - matchLabels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - maxUnavailable: 1 diff --git a/docs/mde/task-0-proposal/listings/prometheusrules.yaml b/docs/mde/task-0-proposal/listings/prometheusrules.yaml deleted file mode 100644 index d5b3447..0000000 --- a/docs/mde/task-0-proposal/listings/prometheusrules.yaml +++ /dev/null @@ -1,40 +0,0 @@ -apiVersion: monitoring.coreos.com/v1 -kind: PrometheusRule -metadata: - name: auth - namespace: auth-system - labels: - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - release: metrics-stack -spec: - groups: - - name: auth.baseline - rules: - - alert: TargetAbsent - expr: absent(up{job="auth-api"}) == 1 - for: 10m - labels: - severity: page - receiver: pushover-page - service: auth - annotations: - summary: auth-api is not being scraped - - alert: RestartLoop - expr: increase(kube_pod_container_status_restarts_total{container="auth-api"}[15m]) > 3 - for: 5m - labels: - severity: page - receiver: pushover-page - service: auth - annotations: - summary: auth-api is restarting repeatedly - - alert: ProbeFailing - expr: kube_pod_status_ready{condition="false", pod=~"auth-api-.*"} == 1 - for: 10m - labels: - severity: page - receiver: pushover-page - service: auth - annotations: - summary: auth-api is not ready diff --git a/docs/mde/task-0-proposal/listings/serviceaccount.yaml b/docs/mde/task-0-proposal/listings/serviceaccount.yaml deleted file mode 100644 index 28b90e3..0000000 --- a/docs/mde/task-0-proposal/listings/serviceaccount.yaml +++ /dev/null @@ -1,24 +0,0 @@ ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: auth-ui - namespace: auth-system - labels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static diff --git a/docs/mde/task-0-proposal/listings/servicemonitor.yaml b/docs/mde/task-0-proposal/listings/servicemonitor.yaml deleted file mode 100644 index 3e13a44..0000000 --- a/docs/mde/task-0-proposal/listings/servicemonitor.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm - release: metrics-stack -spec: - selector: - matchLabels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - namespaceSelector: - matchNames: - - auth-system - endpoints: - - port: http - path: /api/actuator/prometheus - interval: 30s - scrapeTimeout: 10s diff --git a/docs/mde/task-0-proposal/listings/workload.yaml b/docs/mde/task-0-proposal/listings/workload.yaml deleted file mode 100644 index 4f4178b..0000000 --- a/docs/mde/task-0-proposal/listings/workload.yaml +++ /dev/null @@ -1,279 +0,0 @@ ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - replicas: 2 - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 1800 - selector: - matchLabels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - template: - metadata: - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm - spec: - serviceAccountName: auth-api - nodeSelector: - platform.jorisjonkers.dev/capability-public-ingress: 'true' - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/arch - operator: In - values: - - amd64 - securityContext: - runAsNonRoot: true - seccompProfile: - type: RuntimeDefault - runAsUser: 1000 - runAsGroup: 1000 - containers: - - name: auth-api - image: ghcr.io/jorisjonkers-dev/auth/auth-api@sha256:f8c36eb830a1d01ed91538c8defe7d55d82d76bf5228c2b5a0ef8056b662a512 - ports: - - name: http - containerPort: 8081 - resources: - requests: - memory: 768Mi - cpu: 250m - limits: - memory: 768Mi - securityContext: - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - env: - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SESSION_COOKIE_SECURE - value: 'true' - - name: DB_HOST - value: postgres.data-system.svc.cluster.local - - name: DB_PORT - value: '5432' - - name: VALKEY_HOST - value: valkey.data-system.svc.cluster.local - - name: VALKEY_PORT - value: '6379' - - name: SPRING_RABBITMQ_HOST - value: rabbitmq.data-system.svc.cluster.local - - name: SPRING_RABBITMQ_PORT - value: '5672' - - name: SERVER_PORT - value: '8081' - - name: AUTH_ISSUER - value: https://auth.jorisjonkers.dev - - name: AUTH_LOGIN_URL - value: https://auth.jorisjonkers.dev/login - - name: CONFIRMATION_URL - value: https://auth.jorisjonkers.dev/confirm - - name: MAIL_USERNAME - value: auth@jorisjonkers.dev - - name: VAULT_ENABLED - value: 'true' - - name: VAULT_AUTHENTICATION - value: KUBERNETES - - name: VAULT_KUBERNETES_ROLE - value: auth-api - - name: VAULT_DB_ENABLED - value: 'true' - - name: VAULT_ADDR - value: http://vault.utility-system.svc.cluster.local:8200 - - name: SPRING_CONFIG_IMPORT - value: vault:// - - name: AUTH_TRANSIT_ENABLED - value: 'true' - - name: AUTH_TRANSIT_KEY_NAME - value: auth-api-jwt - - name: OTEL_SERVICE_NAME - value: auth-api - startupProbe: - httpGet: - path: /api/actuator/health/liveness - port: 8081 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 120 - readinessProbe: - httpGet: - path: /api/actuator/health/readiness - port: http - timeoutSeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /api/actuator/health/liveness - port: http - timeoutSeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - initialDelaySeconds: 0 - volumeMounts: - - name: writable-tmp - mountPath: /tmp - volumes: - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi - automountServiceAccountToken: true ---- -apiVersion: v1 -kind: Service -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - selector: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - ports: - - name: http - port: 8081 - targetPort: http - protocol: TCP ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: auth-ui - namespace: auth-system - labels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static -spec: - replicas: 1 - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 90 - selector: - matchLabels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - template: - metadata: - labels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static - spec: - serviceAccountName: auth-ui - securityContext: - runAsNonRoot: true - seccompProfile: - type: RuntimeDefault - runAsUser: 101 - runAsGroup: 101 - containers: - - name: auth-ui - image: ghcr.io/jorisjonkers-dev/auth/auth-ui@sha256:eda66dbb44a90a9967a98599a9b4180cec0267350ba1a72cde1512b5d9356cbe - ports: - - name: http - containerPort: 80 - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - readOnlyRootFilesystem: false - capabilities: - drop: - - ALL - startupProbe: - httpGet: - path: / - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - readinessProbe: - httpGet: - path: / - port: http - timeoutSeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: / - port: http - timeoutSeconds: 5 - periodSeconds: 10 - failureThreshold: 3 - initialDelaySeconds: 0 - volumeMounts: - - name: writable-var-cache-nginx - mountPath: /var/cache/nginx - - name: writable-var-run - mountPath: /var/run - automountServiceAccountToken: false - volumes: - - name: writable-var-cache-nginx - emptyDir: - sizeLimit: 64Mi - - name: writable-var-run - emptyDir: - sizeLimit: 64Mi ---- -apiVersion: v1 -kind: Service -metadata: - name: auth-ui - namespace: auth-system - labels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static -spec: - selector: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - ports: - - name: http - port: 80 - targetPort: http - protocol: TCP diff --git a/docs/mde/task-0-proposal/main.tex b/docs/mde/task-0-proposal/main.tex index 963e08d..a75d570 100644 --- a/docs/mde/task-0-proposal/main.tex +++ b/docs/mde/task-0-proposal/main.tex @@ -30,7 +30,6 @@ linktoc=all, bookmarksnumbered=true, } -\renewcommand{\lstlistingname}{Example} % Heading and list layout. This is a short report, so the headings stay small % and the spacing around them tight. The Overleaf instance carries no titlesec @@ -47,56 +46,6 @@ \let\@listi\@listI \makeatother -% Source and generated files are set with listings; no package on the server -% highlights YAML, so the language is declared here. -\definecolor{yamlkey}{RGB}{17,72,140} -\definecolor{yamlval}{RGB}{140,60,10} -\definecolor{yamlcmt}{RGB}{110,120,130} -\definecolor{yamlpunct}{RGB}{150,150,160} -\definecolor{yamlframe}{RGB}{225,228,234} -\definecolor{yamlbg}{RGB}{250,250,252} -\lstdefinelanguage{yaml}{ - keywords={true,false,null}, - keywordstyle=\color{yamlval}\bfseries, - sensitive=false, - comment=[l]{\#}, - commentstyle=\color{yamlcmt}\itshape, - stringstyle=\color{yamlval}, - morestring=[b]', - morestring=[b]", - moredelim=[l][\color{yamlval}]{\&}, - moredelim=[l][\color{yamlval}]{*}, - moredelim=**[il][\color{yamlkey}\bfseries:]{:}, - literate={\{}{{\textcolor{yamlpunct}{\{}}}1 - {\}}{{\textcolor{yamlpunct}{\}}}}1 - {[}{{\textcolor{yamlpunct}{[}}}1 - {]}{{\textcolor{yamlpunct}{]}}}1 - {,}{{\textcolor{yamlpunct}{,}}}1 - {-}{{\textcolor{yamlpunct}{-}}}1, -} - -\lstset{ - language=yaml, - basicstyle=\ttfamily\scriptsize, - columns=fullflexible, - keepspaces=true, - showstringspaces=false, - breaklines=true, - frame=single, - framerule=0.4pt, - rulecolor=\color{yamlframe}, - backgroundcolor=\color{yamlbg}, - framesep=5pt, - framexleftmargin=5pt, - framexrightmargin=5pt, - xleftmargin=6pt, - xrightmargin=6pt, - aboveskip=6pt, - belowskip=4pt, - captionpos=b, - abovecaptionskip=3pt, -} - \begin{document} %==== FRONT PART==== \include{Title/titlepage} @@ -115,9 +64,5 @@ \input{Sections/07-tooling} \input{Sections/08-deliverables} -%==== APPENDIX ==== -\appendix -\input{Sections/09-appendix} - %==== END OF ALL === \end{document} diff --git a/emf/docs/adr/emf/0108-maven-and-tycho-against-a-pinned-target-platform.md b/emf/docs/adr/emf/0108-maven-and-tycho-against-a-pinned-target-platform.md index 7c5143a..1bc8a8c 100644 --- a/emf/docs/adr/emf/0108-maven-and-tycho-against-a-pinned-target-platform.md +++ b/emf/docs/adr/emf/0108-maven-and-tycho-against-a-pinned-target-platform.md @@ -10,6 +10,15 @@ rests-on: ["0106"] # Maven builds `emf/`, with Tycho resolving p2-only bundles against a pinned target platform, on JDK 21, with no Eclipse IDE +> **Amended 2026-09-14.** No Eclipse IDE is needed to build, and CI never +> uses one. The projects must still be loadable in Eclipse Modeling Tools for +> the course's examiners, as the Task 0 proposal now promises: they import as +> existing Maven projects, the metamodels open and the example models validate +> against the OCL constraints, and committed launch configurations run the +> QVT-Operational transformation and the Acceleo generator. Keeping that +> working is part of this decision; the Maven build stays the only path CI +> checks. + ## Rests on Resting on [0106](0106-the-model-is-expressible-in-the-emf-toolchain.md), the claim here is that every tool the course requires runs headless from one Maven diff --git a/emf/docs/architecture.md b/emf/docs/architecture.md index 89183de..8ed62b9 100644 --- a/emf/docs/architecture.md +++ b/emf/docs/architecture.md @@ -41,7 +41,11 @@ Maven, with Eclipse Tycho resolving the bundles that are published only to p2 update sites, against one target platform file pinned to exact versions. Plain Maven Central coordinates are used wherever a tool publishes there. JDK 21. No Eclipse IDE, workspace or launch configuration is part of the build: every -step a grader or CI runs is `mvn verify` from `emf/`. +step CI runs is `mvn verify` from `emf/`. The projects are nonetheless kept +loadable in Eclipse Modeling Tools for the course's examiners: they import as +existing Maven projects, the metamodels open and the example models validate +against the OCL constraints, and committed launch configurations run the +transformation and the generator. The first change to this tree is a walking skeleton that proves each tool runs headless in CI before any model work depends on it: an `.ecore` loads, an OCL