|
| 1 | +# Lab 0: Set up from a team card |
| 2 | + |
| 3 | +**Cloud course** · 8 minutes, plus 5 on your own · CLI, Python, or TypeScript |
| 4 | + |
| 5 | +The organizers created an environment for your team on StreamNative Cloud. You |
| 6 | +build your **team card** from it, put it in `.env`, load the login stream into |
| 7 | +your team's Kafka cluster, and run the doctor. When this lab is done, the Agent |
| 8 | +Engine, Kafka, and Schema Registry on your card all answer, and your topic |
| 9 | +holds 246 logins. |
| 10 | + |
| 11 | +Your team is not in the organizers' environment sheet? |
| 12 | +[Lab 0: Set up](00-set-up.md) starts from an instance of your own instead. Both |
| 13 | +end in the same place, and Lab 1 is the same after either. |
| 14 | + |
| 15 | +## Before you start |
| 16 | + |
| 17 | +- The organizers created your team's environment and shared the **environment |
| 18 | + sheet** with you. On its **Team Environments** tab, one row is your team's: |
| 19 | + the names and addresses of a Kafka cluster, a SQL workspace that imports it, |
| 20 | + an agent workspace, and a service account. All of it already exists. In this |
| 21 | + lab you create one thing, an API key, and you do not need `snctl`. |
| 22 | +- You know your team's number: it is the **Team ID** of your row. |
| 23 | +- You can log in to the StreamNative Cloud console, in the organization your |
| 24 | + row names. You create your API key there in step 2, and Labs 2 and 3 use the |
| 25 | + same login. |
| 26 | +- You cloned this repository and opened a terminal in it. The terminal runs |
| 27 | + `bash`: on Windows that is WSL or Git Bash, on every path, because the checks |
| 28 | + are `bash` commands. |
| 29 | +- You have `git`, [`ork`](https://github.com/orca-ae/orca-cli) v0.6.0 or newer, |
| 30 | + and [`jq`](https://jqlang.org/download/). `ork` does the first MCP login in |
| 31 | + Lab 3 for all three paths, and `ork` with `jq` runs the checks in every lab. |
| 32 | + |
| 33 | +## Step 1: Install your path |
| 34 | + |
| 35 | +Pick **one** path. Your teammate can pick a different one. |
| 36 | + |
| 37 | +**Python** (3.11 or newer) |
| 38 | + |
| 39 | +```bash |
| 40 | +cd python |
| 41 | +python3 -m venv .venv |
| 42 | +source .venv/bin/activate # Git Bash on Windows: source .venv/Scripts/activate |
| 43 | +pip install -r requirements.txt |
| 44 | +``` |
| 45 | + |
| 46 | +**TypeScript** (Node.js 20 or newer) |
| 47 | + |
| 48 | +```bash |
| 49 | +cd typescript |
| 50 | +npm install |
| 51 | +``` |
| 52 | + |
| 53 | +**CLI**: `ork` and `jq` are all the labs need. Set up Python or TypeScript as |
| 54 | +above too: the doctor, the seeder, and the data injector come from one of them. |
| 55 | + |
| 56 | +### Check |
| 57 | + |
| 58 | +Run the doctor without the network. Every line says `PASS`. |
| 59 | + |
| 60 | +| Python or CLI | TypeScript | |
| 61 | +|---|---| |
| 62 | +| `python doctor.py --offline` | `npm run doctor -- --offline` | |
| 63 | + |
| 64 | +```text |
| 65 | +PASS Python 3.11+ 3.13 |
| 66 | +PASS package runorca |
| 67 | +PASS package confluent-kafka[avro] |
| 68 | +PASS package python-dotenv |
| 69 | +PASS ork found |
| 70 | +PASS jq found |
| 71 | +
|
| 72 | +All good: you're ready. |
| 73 | +``` |
| 74 | + |
| 75 | +## Step 2: Build your team card in `.env` |
| 76 | + |
| 77 | +Your team card is your team's row in the environment sheet, plus an API key |
| 78 | +that you create. `.env` is where you write it down. |
| 79 | + |
| 80 | +Open a second terminal at the repository root and copy the template: |
| 81 | + |
| 82 | +```bash |
| 83 | +cp .env.cloud.example .env |
| 84 | +``` |
| 85 | + |
| 86 | +`.env` is git-ignored. It will hold your key: do not commit it or paste it |
| 87 | +anywhere. |
| 88 | + |
| 89 | +**From the sheet.** Open the environment sheet on the **Team Environments** tab |
| 90 | +and find the row with your **Team ID**. Six lines of `.env` come from that row: |
| 91 | + |
| 92 | +| `.env` line | Column in your row | Write it as | |
| 93 | +|---|---|---| |
| 94 | +| `SN_SERVICE_ACCOUNT` | **Service Account**, with **StreamNative Cloud Organization** | `<Service Account>@<Organization>.auth.streamnative.cloud`. A cell that already ends in `.auth.streamnative.cloud` goes in as it is | |
| 95 | +| `ORCA_BASE_URL` | **Agent Workspace Endpoint** | `https://` and the host, with no `/v1` | |
| 96 | +| `KAFKA_BOOTSTRAP_SERVERS` | **Broker URL** | as it is: the host and its port, `:9093` | |
| 97 | +| `SCHEMA_REGISTRY_URL` | **Schema Registry URL** | as it is, with `https://` | |
| 98 | +| `SN_MCP_URL` | **SQL Workspace MCP Endpoint** | as it is | |
| 99 | +| `SN_SQL_DATABASE` | **SQL Database** | as it is. It is the database you open in Lab 2, and it is not your SQL workspace's name | |
| 100 | + |
| 101 | +A cell you need is empty? Ask a facilitator. One value you can build yourself: |
| 102 | +the MCP endpoint is |
| 103 | +`https://mcp.streamnative.cloud/mcp/x/<Organization>/sqlworkspace.compute.streamnative.io/<SQL Workspace Name>`, |
| 104 | +from two other cells of your row. |
| 105 | + |
| 106 | +**Your API key.** The sheet holds no keys. You create one in the StreamNative |
| 107 | +Cloud console, for the service account in your row: |
| 108 | + |
| 109 | +1. Log in to the console, in the organization your row names. |
| 110 | +2. Open the organization's **Settings**. Under **Access & Control**, click |
| 111 | + **Service Accounts**, then click your team's service account. |
| 112 | +3. Click **Create API key**. Give the key a **Name** that nobody else in the |
| 113 | + organization uses, in lowercase letters, digits, and dashes: your team and |
| 114 | + your name work, such as `team07-ana`. Leave **Expiration** at 30 days, and |
| 115 | + click **Create**. |
| 116 | +4. The next window shows the key, once. Click **Copy**, paste the key into |
| 117 | + `.env` as `SN_API_KEY` with nothing in front of it, then click **Close**. If |
| 118 | + you lose the key, create another. |
| 119 | + |
| 120 | +If **Create API key** is greyed out, your login may not create keys: ask a |
| 121 | +facilitator. |
| 122 | + |
| 123 | +Leave the other lines as they are: the MCP server uses a separate browser login |
| 124 | +in Lab 3, so `SN_MCP_AUTH=oauth` stays, and `SN_MCP_OAUTH_ISSUER` stays empty. |
| 125 | + |
| 126 | +Your finished card has these seven lines filled in: |
| 127 | + |
| 128 | +```text |
| 129 | +SN_API_KEY=<the key you copied> |
| 130 | +SN_SERVICE_ACCOUNT=<service account>@<organization>.auth.streamnative.cloud |
| 131 | +ORCA_BASE_URL=https://<agent workspace host> |
| 132 | +KAFKA_BOOTSTRAP_SERVERS=<broker host>:9093 |
| 133 | +SCHEMA_REGISTRY_URL=https://<schema registry host> |
| 134 | +SN_MCP_URL=https://mcp.streamnative.cloud/mcp/x/<organization>/sqlworkspace.compute.streamnative.io/<SQL workspace> |
| 135 | +SN_SQL_DATABASE=<SQL database> |
| 136 | +``` |
| 137 | + |
| 138 | +**Two people share one environment.** Your teammate fills in the same six lines |
| 139 | +from the same row, and can create a key of their own for the same service |
| 140 | +account. You both work in the same Kafka cluster and the same SQL database. |
| 141 | +Your agents stay apart: each is named after its owner's OS user name, like |
| 142 | +`hello-agent-ana`. If the two of you have the same user name, each set |
| 143 | +`PARTICIPANT` in `.env` to a name of your own. In Lab 2 the view and the table |
| 144 | +are created once for the team: if your teammate got there first, the `CREATE` |
| 145 | +statement says they already exist, and you go on to the step's check. The reset |
| 146 | +script that Lab 4 mentions drops them for both of you, so agree before one of |
| 147 | +you runs it. |
| 148 | + |
| 149 | +### Check |
| 150 | + |
| 151 | +One authenticated read of your Agent Engine. It prints `true` when the endpoint |
| 152 | +and the key on your card are accepted. |
| 153 | + |
| 154 | +```bash |
| 155 | +./lab-ork agent list -o json | jq -e 'has("data")' |
| 156 | +``` |
| 157 | + |
| 158 | +Before you filled in `.env`, the same command says |
| 159 | +`Missing ORCA_BASE_URL, SN_API_KEY` instead: the two values it needs. |
| 160 | + |
| 161 | +## Step 3: Load the login stream |
| 162 | + |
| 163 | +The course reads one topic in your team's Kafka cluster, |
| 164 | +`security.login_events`. It needs the login stream once, for the whole team. |
| 165 | +**One of you** runs the seeder, in your path's folder: |
| 166 | + |
| 167 | +| Python | TypeScript | CLI | |
| 168 | +|---|---|---| |
| 169 | +| `python seed.py` | `npm run seed` | `(cd ../python && .venv/bin/python seed.py)` or `(cd ../typescript && npm run seed)` | |
| 170 | + |
| 171 | +It prints one of two lines, and both are fine. A topic that was empty is now |
| 172 | +loaded: |
| 173 | + |
| 174 | +```text |
| 175 | +Loaded 246 logins for 91 accounts into security.login_events. |
| 176 | +``` |
| 177 | + |
| 178 | +A topic that the organizers or your teammate loaded before you is left as it is: |
| 179 | + |
| 180 | +```text |
| 181 | +security.login_events already holds 246 events, so it is seeded. To load another copy anyway: python seed.py --force |
| 182 | +``` |
| 183 | + |
| 184 | +Do not use `--force`: a second copy would double every count in Lab 2. The |
| 185 | +number is higher than 246 once someone on your team has run Lab 3, and the |
| 186 | +TypeScript seeder ends the line with `npm run seed -- --force`. |
| 187 | + |
| 188 | +The seeder replays [`data/login_events.jsonl`](../../data/login_events.jsonl): |
| 189 | +synthetic logins at a fictional bank, with their timestamps moved to now. It |
| 190 | +also registers the topic's Avro schema, which SQL Workspace needs in Lab 2. |
| 191 | + |
| 192 | +If it says `The topic security.login_events does not exist yet`, the topic was |
| 193 | +not created with your environment. Raise your hand, or create it yourself with |
| 194 | +`snctl`: [Lab 0: Set up](00-set-up.md), step 3. |
| 195 | + |
| 196 | +### Check |
| 197 | + |
| 198 | +Run the doctor. It checks your laptop, then each service on your card, and a |
| 199 | +failed check prints its fix on the next line. |
| 200 | + |
| 201 | +| Python | TypeScript | CLI | |
| 202 | +|---|---|---| |
| 203 | +| `python doctor.py` | `npm run doctor` | `(cd ../python && .venv/bin/python doctor.py)` or `(cd ../typescript && npm run doctor)` | |
| 204 | + |
| 205 | +After the lines from step 1, it prints: |
| 206 | + |
| 207 | +```text |
| 208 | +PASS .env cloud stack, participant: ana |
| 209 | +PASS ORCA_BASE_URL https://... |
| 210 | +PASS Agent Engine API key accepted |
| 211 | +PASS Kafka security.login_events has 1 partition(s) |
| 212 | +PASS Schema Registry security.login_events-value v1 |
| 213 | +PASS login topic schema has account_id, event_time, ip_address, result, failure_reason |
| 214 | +WAIT MCP OAuth no tutorial vault yet |
| 215 | + next: Nothing to do now: Lab 3 opens your browser to authorize the MCP server. Run doctor again after it. |
| 216 | +
|
| 217 | +You're ready. 1 check(s) wait for a later lab. |
| 218 | +``` |
| 219 | + |
| 220 | +`WAIT` is not a failure. The MCP server needs a login that only Lab 3 can do. |
| 221 | +On a topic that nobody has loaded yet, the `Schema Registry` line fails before |
| 222 | +this step: the seeder is what registers the schema. |
| 223 | + |
| 224 | +Still failing after two tries? Raise your hand, or see |
| 225 | +[Troubleshooting](troubleshooting.md). |
| 226 | + |
| 227 | +## Check your understanding |
| 228 | + |
| 229 | +**1. The doctor prints `WAIT MCP OAuth`. What should you do?** |
| 230 | + |
| 231 | +- A. Fix it now: the doctor has to print only `PASS`. |
| 232 | +- B. Nothing yet: Lab 3 does the browser login this check waits for. |
| 233 | +- C. Create a new API key. |
| 234 | + |
| 235 | +<details> |
| 236 | +<summary>Answer</summary> |
| 237 | + |
| 238 | +**B.** The MCP server wants an OAuth login, and the lab script does it the first |
| 239 | +time the agent needs the server. `WAIT` means "not ready, and not your mistake". |
| 240 | +A real problem prints `FAIL` and its fix. |
| 241 | + |
| 242 | +</details> |
| 243 | + |
| 244 | +**2. The seeder says `security.login_events already holds 246 events, so it is seeded`. What should you do?** |
| 245 | + |
| 246 | +- A. Run it again with `--force`, so that your copy is loaded too. |
| 247 | +- B. Nothing: the stream is there already, loaded by the organizers or by your teammate. |
| 248 | +- C. Ask for a new Kafka cluster. |
| 249 | + |
| 250 | +<details> |
| 251 | +<summary>Answer</summary> |
| 252 | + |
| 253 | +**B.** Your team shares one topic, and it needs the 246 logins once. A second |
| 254 | +copy would double every count in Lab 2. |
| 255 | + |
| 256 | +</details> |
| 257 | + |
| 258 | +**3. What does `./lab-ork` add to `ork`?** |
| 259 | + |
| 260 | +- A. It is a different CLI with its own commands. |
| 261 | +- B. It points `ork` at your Agent Engine with the key from `.env`, and fills in the ids your scripts saved. |
| 262 | +- C. It runs the lab's steps for you. |
| 263 | + |
| 264 | +<details> |
| 265 | +<summary>Answer</summary> |
| 266 | + |
| 267 | +**B.** Everything after `./lab-ork` goes to `ork` as you typed it. The wrapper |
| 268 | +only supplies the endpoint, the credential, and the four `@..._id` words. |
| 269 | + |
| 270 | +</details> |
| 271 | + |
| 272 | +## Try it yourself |
| 273 | + |
| 274 | +Make the doctor fail on purpose, so you know what a failure looks like before a |
| 275 | +real one. Change one value in `.env` so that a check fails, read the fix the |
| 276 | +doctor prints, then put the value back. |
| 277 | + |
| 278 | +### Check |
| 279 | + |
| 280 | +The doctor ends on the "ready" line again. |
| 281 | + |
| 282 | +```bash |
| 283 | +(cd python && .venv/bin/python doctor.py) | tail -n 1 |
| 284 | +``` |
| 285 | + |
| 286 | +On the TypeScript path, use `npm --prefix typescript run doctor | tail -n 1`. |
| 287 | + |
| 288 | +<details> |
| 289 | +<summary>Solution</summary> |
| 290 | + |
| 291 | +Add `/v1` to the end of `ORCA_BASE_URL` and run the doctor: |
| 292 | + |
| 293 | +```text |
| 294 | +FAIL ORCA_BASE_URL https://<your-host>/v1 |
| 295 | + fix: Use the host root only: ORCA_BASE_URL=https://<your-host> |
| 296 | +``` |
| 297 | + |
| 298 | +The doctor does not call an endpoint it can see is wrong. It skips the Agent |
| 299 | +Engine check, tells you the exact value to use, and ends with |
| 300 | +`1 check(s) failed`. Remove the `/v1` and run it again. |
| 301 | + |
| 302 | +</details> |
| 303 | + |
| 304 | +## Recap |
| 305 | + |
| 306 | +- `.env` holds your team card: six values from your team's row in the |
| 307 | + environment sheet, and an API key you created for your team's service |
| 308 | + account. It is git-ignored. |
| 309 | +- Your team shares that environment. The login stream is loaded once, and the |
| 310 | + seeder refuses a second copy. |
| 311 | +- The doctor checks each service on the card and prints the fix for a failure. |
| 312 | +- `./lab-ork` is how you look at your Agent Engine from the terminal. |
| 313 | + |
| 314 | +## What's next |
| 315 | + |
| 316 | +[Lab 1: Hello, agent](01-hello-agent.md) |
0 commit comments