Repository navigation
Expand file tree
/
Copy pathplatform.html
More file actions
214 lines (198 loc) · 12.2 KB
/
Copy pathplatform.html
File metadata and controls
214 lines (198 loc) · 12.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Adapters | Runtime Conditions</title>
<link rel="stylesheet" href="assets/styles.css" />
</head>
<body>
<header class="site-header">
<div class="header-inner">
<a class="brand" href="index.html">Runtime Conditions</a>
<nav class="top-links" aria-label="Top links">
<a href="https://github.com/runtimeconditions/spec/blob/main/docs/sixth-draft.md" data-tip="Read the latest draft of the specification"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8z"/><path d="M14 3v5h5"/><path d="M9 13h6"/><path d="M9 17h6"/></svg><span>Current Draft</span></a>
<a href="https://github.com/runtimeconditions/rc-demos/blob/main/README.md" data-tip="Run Runtime Conditions end to end on your own machine"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="10"/><polygon points="10 8 16 12 10 16 10 8"/></svg><span>Run Demo</span></a>
<a href="reference.html" data-tip="See where each part of this guide comes from in the source repositories"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M3 6l6-3 6 3 6-3v15l-6 3-6-3-6 3z"/><path d="M9 3v15"/><path d="M15 6v15"/></svg><span>Source Map</span></a>
<a href="https://github.com/runtimeconditions" data-tip="Browse the Runtime Conditions repositories on GitHub"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="currentColor" aria-hidden="true" focusable="false"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg><span>GitHub</span></a>
<a href="https://cloud-native.slack.com/archives/C0C0R4M65FZ" data-tip="Join the conversation on the CNCF Slack"><svg class="nav-icon" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M4 9h16"/><path d="M4 15h16"/><path d="M10 3L8 21"/><path d="M16 3l-2 18"/></svg><span>Slack</span></a>
</nav>
</div>
</header>
<div class="guide-layout">
<aside class="sidebar" aria-label="Guide chapters">
<p class="sidebar-title">Reader Guide</p>
<ol class="chapter-list">
<li><a href="index.html"><span class="num">00</span><span>Start here</span></a></li>
<li><a href="concepts.html"><span class="num">01</span><span>Core concepts</span></a></li>
<li><a href="spec.html"><span class="num">02</span><span>Profile shape</span></a></li>
<li><a href="developers.html"><span class="num">03</span><span>Code to profile</span></a></li>
<li><a href="extensions.html"><span class="num">04</span><span>Extensions</span></a></li>
<li><a aria-current="page" href="platform.html"><span class="num">05</span><span>Adapters</span></a></li>
<li><a href="demo.html"><span class="num">06</span><span>Run the demo</span></a></li>
<li><a href="reference.html"><span class="num">07</span><span>Reference</span></a></li>
</ol>
</aside>
<main class="content">
<p class="chapter-label">Chapter 5</p>
<h1 class="page-title">Adapters are where profile demand becomes platform action.</h1>
<p class="intro">
A valid profile is still just a requirements document. The adapter is the platform-specific component that decides how those requirements are satisfied and wired into the workload.
</p>
<section class="section">
<h2>Adapter responsibility</h2>
<ol class="step-list">
<li><span class="step-num">1</span><div><strong>Read a valid profile.</strong><span>The adapter starts from Conditions and their declared `configuration.env` inputs.</span></div></li>
<li><span class="step-num">2</span><div><strong>Validate against platform context.</strong><span>In the demo, API Conditions are checked against a catalog OpenAPI document.</span></div></li>
<li><span class="step-num">3</span><div><strong>Invoke provider interfaces.</strong><span>For Redis, the adapter emits a platform-owned resource request with resolved inputs.</span></div></li>
<li><span class="step-num">4</span><div><strong>Bind platform values.</strong><span>The adapter maps profile env names to service URLs and generated resource addresses.</span></div></li>
<li><span class="step-num">5</span><div><strong>Render workload deployment.</strong><span>The final Deployment contains target-specific references, but the profile remains target-neutral.</span></div></li>
</ol>
</section>
<section class="section">
<h2>Adapter input: a profile Condition</h2>
<p class="short">
The adapter is not guessing from the application source. It receives the generated profile and interprets Conditions that have already passed validation.
</p>
<div class="example">
<div class="example-title">Cache Condition from the profile</div>
<pre><code>- name: request-cache
kind: cache
interface:
type: key_value
engine: redis
configuration:
alternatives:
- env:
- property: url
name: REDIS_URL
- env:
- property: hostname
name: REDIS_HOST
- property: port
name: REDIS_PORT</code></pre>
</div>
</section>
<section class="section">
<h2>Adapter step: choose platform values for profile properties</h2>
<p class="short">
The Redis Promise owns Redis provisioning. The adapter emits a Redis request and satisfies profile properties from the generated service address.
</p>
<div class="example">
<div class="example-title">
<span>ApplicationRelease adapter resolver</span>
<a href="https://github.com/runtimeconditions/rc-demos/blob/main/kratix/promises/application-release/pipeline/resolver.py">source</a>
</div>
<pre><code>emitted.append(redis_request(redis_name, namespace, name))
redis_host = f"{redis_name}.{namespace}.svc.cluster.local"
env.extend(
[
{"name": "REDIS_URL", "value": f"redis://{redis_host}:6379"},
{"name": "REDIS_HOST", "value": redis_host},
{"name": "REDIS_PORT", "value": "6379"},
]
)</code></pre>
</div>
</section>
<section class="section">
<h2>Adapter step: validate API compatibility before deployment</h2>
<p class="short">
The API Condition declares `GET /todos/{id}` and an expected response shape. The adapter compares that requirement with the catalog OpenAPI document before creating the workload.
</p>
<div class="example">
<div class="example-title">API validation path</div>
<pre><code>for condition in conditions:
if condition.get("kind") != "api":
continue
api = validate_api_condition(condition, apis)
env_name = api_url_env_name(condition.get("name") or api.name)
base_url = api.base_url or f"http://{api.name}.{namespace}.svc.cluster.local:{port}"
env.append({"name": env_name, "value": base_url})</code></pre>
</div>
</section>
<section class="section">
<h2>Adapter step: call platform interfaces, not invent a second profile</h2>
<p class="short">
The adapter should trigger existing provider interfaces directly. In this demo those interfaces are Kratix Promises. The important boundary is that the adapter is not creating another Runtime Conditions document between itself and the Promise.
</p>
<div class="table-wrap">
<table>
<thead>
<tr><th>Profile Requirement</th><th>Adapter Calls</th><th>Provider Owns</th></tr>
</thead>
<tbody>
<tr><td>`kind: cache`, `engine: redis`</td><td>Redis Promise interface</td><td>Redis Deployment and Service</td></tr>
<tr><td>`kind: api`, `interface.type: http`</td><td>API catalog validation</td><td>Catalog-owned OpenAPI document and base URL</td></tr>
<tr><td>`ApplicationRelease` request</td><td>Kubernetes workload renderer</td><td>Deployment and Service for the application</td></tr>
</tbody>
</table>
</div>
</section>
<section class="section">
<h2>Provider request: Redis custom resource</h2>
<p class="short">
The adapter asks the platform for Redis by emitting the provider-owned resource. The profile declares `kind: cache`; the platform decides what Redis means in the cluster.
</p>
<div class="example">
<div class="example-title">
<span>Redis request emitted by the ApplicationRelease resolver</span>
</div>
<pre><code>apiVersion: platform.demoteam.io/v1alpha1
kind: Redis
metadata:
name: request-logger-cache
namespace: demo
labels:
kratix.io/component-of-promise-name: application-release
spec:
size: small</code></pre>
</div>
</section>
<section class="section">
<h2>Final workload binding</h2>
<p class="short">
This is where the profile's environment variable names meet platform-provided values. The application still reads the same env vars it declared in source.
</p>
<div class="example">
<div class="example-title">Rendered Deployment env entries</div>
<pre><code>env:
- name: TODOS_API_URL
value: http://todos-api.demo.svc.cluster.local:8080
- name: REDIS_URL
value: redis://request-logger-cache.demo.svc.cluster.local:6379
- name: REDIS_HOST
value: request-logger-cache.demo.svc.cluster.local
- name: REDIS_PORT
value: "6379"</code></pre>
</div>
</section>
<section class="section">
<h2>Boundary summary</h2>
<div class="table-wrap">
<table>
<thead>
<tr><th>Component</th><th>Owns</th><th>Does Not Own</th></tr>
</thead>
<tbody>
<tr><td>Generator</td><td>Source-to-profile extraction.</td><td>Provisioning, deployment, target values.</td></tr>
<tr><td>Adapter</td><td>Profile interpretation for one platform.</td><td>Extension vocabulary or provider internals.</td></tr>
<tr><td>Promise</td><td>Concrete provider implementation.</td><td>Application source analysis or profile generation.</td></tr>
</tbody>
</table>
</div>
</section>
<nav class="page-nav" aria-label="Page navigation">
<a href="extensions.html">Previous: Extensions</a>
<a href="demo.html">Next: Run the demo</a>
</nav>
</main>
</div>
<footer class="footer">
<div class="footer-inner">
<span>Chapter 5 of 7</span>
<a href="demo.html">Continue</a>
</div>
</footer>
<script src="assets/syntax.js" defer></script>
</body>
</html>