@@ -188,208 +188,80 @@ Dec 02 18:00:01.093 DEBG registered endpoint, path: /producers, method: POST, lo
188188...
189189----
190190
191- Once everything is up and running, you can use `curl` directly to hit either of the servers. But it's easier to use the `oxapi_demo` wrapper (see below).
191+ Once everything is up and running, you can use `curl` directly to hit either of
192+ the servers. But it's easier to use the [`oxide` CLI](https://docs.oxide.computer/cli/manual) (see below).
192193
193194== Docker image
194195
195196This repo includes a Dockerfile that builds an image containing the Nexus and sled agent. There's a GitHub Actions workflow that builds and publishes the Docker image. This is used by the https://github.com/oxidecomputer/console/[console] project for prototyping, demoing, and testing. This is **not** the way Omicron will be deployed on production systems, but it's a useful vehicle for working with it.
196197
197198== Quick demo
198199
199- There's a small demo tool called `./tools/oxapi_demo` that provides a slightly friendlier interface than `curl`, with the same output format. To use the demo, the `node` and `json` programs should be installed and available in the users PATH:
200+ The `oxide` CLI can be installed from the [latest
201+ release](https://github.com/oxidecomputer/cli/releases).
200202
201- [source,text]
202- ----
203- pkg install node-12
204- npm i -g json
205- ----
203+ Run `oxide auth login` to authenticate with your Oxide account. Alternatively,
204+ `oxide` will respect the `OXIDE_TOKEN` and `OXIDE_HOST` environment variables.
205+
206+ If you find bugs or have feedback, leave it on the [cli
207+ repo](https://github.com/oxidecomputer/cli/issues).
206208
207209Here's a small demo that creates a project, creates an instance, and attaches a disk to it:
208210
209211[source,text]
210212----
211- $ ./tools/oxapi_demo
212- oxapi_demo: command not specified
213- usage: oxapi_demo [-A] [cmd] [args]
214-
215- GENERAL OPTIONS
216-
217- -A do not attempt to authenticate
218- (default behavior: use "spoof" authentication for endpoints
219- that require it)
220-
221- ORGANIZATIONS
222-
223- organizations_list
224- organization_create_demo ORGANIZATION_NAME
225- organization_delete ORGANIZATION_NAME
226- organization_get ORGANIZATION_NAME
227-
228- PROJECTS
229-
230- projects_list ORGANIZATION_NAME
231- project_create_demo ORGANIZATION_NAME PROJECT_NAME
232- project_delete ORGANIZATION_NAME PROJECT_NAME
233- project_get ORGANIZATION_NAME PROJECT_NAME
234- project_list_instances ORGANIZATION_NAME PROJECT_NAME
235- project_list_disks ORGANIZATION_NAME PROJECT_NAME
236- project_list_vpcs ORGANIZATION_NAME PROJECT_NAME
237-
238- INSTANCES
239-
240- instance_create_demo ORGANIZATION_NAME PROJECT_NAME INSTANCE_NAME
241- instance_get ORGANIZATION_NAME PROJECT_NAME INSTANCE_NAME
242- instance_delete ORGANIZATION_NAME PROJECT_NAME INSTANCE_NAME
243-
244- instance_stop ORGANIZATION_NAME PROJECT_NAME INSTANCE_NAME
245- instance_start ORGANIZATION_NAME PROJECT_NAME INSTANCE_NAME
246- instance_reboot ORGANIZATION_NAME PROJECT_NAME INSTANCE_NAME
247-
248- instance_attach_disk ORGANIZATION_NAME PROJECT_NAME INSTANCE_NAME DISK_NAME
249- instance_detach_disk ORGANIZATION_NAME PROJECT_NAME INSTANCE_NAME DISK_NAME
250- instance_list_disks ORGANIZATION_NAME PROJECT_NAME INSTANCE_NAME
251- instance_get_disk ORGANIZATION_NAME PROJECT_NAME INSTANCE_NAME DISK_NAME
252-
253- DISKS
254-
255- disk_create_demo ORGANIZATION_NAME PROJECT_NAME DISK_NAME
256- disk_get ORGANIZATION_NAME PROJECT_NAME DISK_NAME
257- disk_delete ORGANIZATION_NAME PROJECT_NAME DISK_NAME
258-
259- VPCS
260-
261- vpc_create_demo ORGANIZATION_NAME PROJECT_NAME VPC_NAME DNS_NAME
262- vpc_get ORGANIZATION_NAME PROJECT_NAME VPC_NAME
263- vpc_delete ORGANIZATION_NAME PROJECT_NAME VPC_NAME
264-
265- HARDWARE
266-
267- racks_list
268- rack_get RACK_ID
269-
270- sleds_list
271- sled_get SLED_ID
272- $ ./tools/oxapi_demo organization_create_demo myorg
273- ++ curl -sSi http://127.0.0.1:12220/organizations -X POST -T - -H 'oxide-authn-spoof: 001de000-05e4-0000-0000-000000004007'
274- ++ json -ga
275- HTTP/1.1 100 Continue
276-
277- HTTP/1.1 201 Created
278- content-type: application/json
279- x-request-id: 60ffbc0b-212a-4ffd-84f0-39aeb4b3b772
280- content-length: 194
281- date: Wed, 17 Nov 2021 01:43:52 GMT
282-
283- {
284- "id": "dbaf046f-1c05-4b6a-a749-5111a8cd9aa1",
285- "name": "myorg",
286- "description": "an organization called myorg",
287- "timeCreated": "2021-11-17T01:43:52.322629Z",
288- "timeModified": "2021-11-17T01:43:52.322629Z"
289- }
290- $ ./tools/oxapi_demo project_create_demo myorg myproject
291- ++ curl -sSi http://127.0.0.1:12220/organizations/myorg/projects -X POST -T -
292- ++ json -ga
293- HTTP/1.1 100 Continue
294-
295- HTTP/1.1 201 Created
296- content-type: application/json
297- x-request-id: bea0ba10-2916-473c-b3e4-461984b85c6b
298- content-length: 252
299- date: Wed, 17 Nov 2021 01:44:01 GMT
300-
301- {
302- "id": "c197b9d2-285c-4e9f-9461-1815ef093c8d",
303- "name": "myproject",
304- "description": "a project called myproject",
305- "timeCreated": "2021-11-17T01:44:01.933615Z",
306- "timeModified": "2021-11-17T01:44:01.933615Z",
307- "organizationId": "dbaf046f-1c05-4b6a-a749-5111a8cd9aa1"
308- }
309- $ ./tools/oxapi_demo instance_create_demo myorg myproject myinstance
310- ++ curl -sSi http://127.0.0.1:12220/organizations/myorg/projects/myproject/instances -X POST -T -
311- ++ json -ga
312- HTTP/1.1 100 Continue
313-
314- HTTP/1.1 201 Created
315- content-type: application/json
316- x-request-id: 3d07dfa2-efda-4085-ac9f-9e6bd3040997
317- content-length: 377
318- date: Wed, 17 Nov 2021 01:45:07 GMT
319-
213+ $ oxide org create myorg \
214+ --description "My organization"
215+ ✔ Created organization myorg
216+
217+ $ oxide project create myproject \
218+ --description "My project" \
219+ --organization myorg
220+ ✔ Created project myorg/myproject
221+
222+ $ oxide instance create myinstance \
223+ --description "My instance" \
224+ --project myproject \
225+ --org myorg \
226+ --hostname "myinstance.maze-war.com" \
227+ --ncpus 1 \
228+ --memory 8
229+ ✔ Created instance myinstance in myorg/myproject
230+
231+ $ oxide instance view myinstance \
232+ --org myorg \
233+ --project myproject \
234+ --format json
320235{
321236 "id": "99ad2514-050c-4493-9cb9-d9ceba980a98",
322237 "name": "myinstance",
323- "description": "an instance called myinstance ",
238+ "description": "My instance",
324239 "timeCreated": "2021-11-17T01:45:07.606749Z",
325240 "timeModified": "2021-11-17T01:45:07.606749Z",
326241 "projectId": "c197b9d2-285c-4e9f-9461-1815ef093c8d",
327242 "ncpus": 1,
328- "memory": 268435456,
329- "hostname": "myproject",
330- "runState": "starting",
331- "timeRunStateUpdated": "2021-11-17T01:45:07.618960Z"
332- }
333- $ ./tools/oxapi_demo instance_get myorg myproject myinstance
334- ++ curl -sSi http://127.0.0.1:12220/organizations/myorg/projects/myproject/instances/myinstance
335- ++ json -ga
336- HTTP/1.1 200 OK
337- content-type: application/json
338- x-request-id: 5870f965-06a8-41fc-967f-9021ec640ad4
339- content-length: 376
340- date: Wed, 17 Nov 2021 01:46:41 GMT
341-
342- {
343- "id": "99ad2514-050c-4493-9cb9-d9ceba980a98",
344- "name": "myinstance",
345- "description": "an instance called myinstance",
346- "timeCreated": "2021-11-17T01:45:07.606749Z",
347- "timeModified": "2021-11-17T01:45:07.606749Z",
348- "projectId": "c197b9d2-285c-4e9f-9461-1815ef093c8d",
349- "ncpus": 1,
350- "memory": 268435456,
351- "hostname": "myproject",
243+ "memory": 8,
244+ "hostname": "myinstance.maze-war.com",
352245 "runState": "running",
353246 "timeRunStateUpdated": "2021-11-17T01:45:09.120652Z"
354247}
355- $ ./tools/oxapi_demo disk_create_demo myorg myproject mydisk
356- ++ curl -sSi http://127.0.0.1:12220/organizations/myorg/projects/myproject/disks -X POST -T -
357- ++ json -ga
358- HTTP/1.1 100 Continue
359248
360- HTTP/1.1 201 Created
361- content-type: application/json
362- x-request-id: f6073b9d-4b07-4eba-b8cf-55d8158785eb
363- content-length: 324
364- date: Wed, 17 Nov 2021 01:47:36 GMT
249+ $ oxide disk create nginx \
250+ -D "The nginx disk." \
251+ -o myorg \
252+ -p myproject \
253+ --size 10
254+ ✔ Created disk nginx in myorg/myproject
365255
366- {
367- "id": "551bbe67-3640-41c9-b968-249a136e5e31",
368- "name": "mydisk",
369- "description": "a disk called mydisk",
370- "timeCreated": "2021-11-17T01:47:36.524136Z",
371- "timeModified": "2021-11-17T01:47:36.524136Z",
372- "projectId": "c197b9d2-285c-4e9f-9461-1815ef093c8d",
373- "snapshotId": null,
374- "size": 1024,
375- "state": {
376- "state": "creating"
377- },
378- "devicePath": "/mnt/mydisk"
379- }
380- $ ./tools/oxapi_demo disk_get myorg myproject mydisk
381- ++ curl -sSi http://127.0.0.1:12220/organizations/myorg/projects/myproject/disks/mydisk
382- ++ json -ga
383- HTTP/1.1 200 OK
384- content-type: application/json
385- x-request-id: bd1083a8-67f2-407a-8d33-068906e9f2f1
386- content-length: 324
387- date: Wed, 17 Nov 2021 01:48:17 GMT
388256
257+ $ oxide disk view nginx \
258+ --org myorg \
259+ --project myproject \
260+ --format json
389261{
390262 "id": "551bbe67-3640-41c9-b968-249a136e5e31",
391- "name": "mydisk ",
392- "description": "a disk called mydisk ",
263+ "name": "nginx ",
264+ "description": "The nginx disk. ",
393265 "timeCreated": "2021-11-17T01:47:36.524136Z",
394266 "timeModified": "2021-11-17T01:47:36.524136Z",
395267 "projectId": "c197b9d2-285c-4e9f-9461-1815ef093c8d",
@@ -398,46 +270,105 @@ date: Wed, 17 Nov 2021 01:48:17 GMT
398270 "state": {
399271 "state": "detached"
400272 },
401- "devicePath": "/mnt/mydisk "
273+ "devicePath": "/mnt/nginx "
402274}
403- $ ./tools/oxapi_demo instance_attach_disk myorg myproject myinstance mydisk
404- ++ curl -sSi http://127.0.0.1:12220/organizations/myorg/projects/myproject/instances/myinstance/disks
405- /mydisk -X PUT -T /dev/null
406- ++ json -ga
407- HTTP/1.1 201 Created
408- content-type: application/json
409- x-request-id: da298038-28fc-4eb2-a283-4182859d6f33
410- content-length: 205
411- date: Wed, 17 Nov 2021 01:48:41 GMT
412275
276+ $ oxide disk attach nginx myinstance \
277+ -o maze-war \
278+ -p prod-online
279+ ✔ Attached disk nginx to instance myinstance in myorg/myproject
280+
281+ $ oxide instance disks myinstance \
282+ -o maze-war \
283+ -p prod-online \
284+ --format json
413285{
414286 "instanceId": "99ad2514-050c-4493-9cb9-d9ceba980a98",
415287 "diskId": "551bbe67-3640-41c9-b968-249a136e5e31",
416- "diskName": "mydisk ",
288+ "diskName": "nginx ",
417289 "diskState": {
418- "state": "attaching ",
290+ "state": "attached ",
419291 "instance": "99ad2514-050c-4493-9cb9-d9ceba980a98"
420292 }
421293}
422- $ ./tools/oxapi_demo instance_list_disks myorg myproject myinstance
423- ++ curl -sSi http://127.0.0.1:12220/organizations/myorg/projects/myproject/instances/myinstance/disks
424- ++ json -ga
425- HTTP/1.1 200 OK
426- content-type: application/json
427- x-request-id: 9f0490d5-e09e-4831-900c-d39f5f07d2c8
428- content-length: 206
429- date: Wed, 17 Nov 2021 01:49:10 GMT
430294
295+ # Alternatively, you can use the API command to run any endpoint.
296+ # This operates like a fancy, authenticated curl.
297+
298+ $ oxide api --help
299+ Makes an authenticated HTTP request to the Oxide API and prints the response.
300+
301+ The endpoint argument should be a path of a Oxide API endpoint.
302+
303+ The default HTTP request method is "GET" normally and "POST" if any parameters
304+ were added. Override the method with `--method`.
305+
306+ Pass one or more `-f/--raw-field` values in "key=value" format to add static string
307+ parameters to the request payload. To add non-string or otherwise dynamic values, see
308+ `--field` below. Note that adding request parameters will automatically switch the
309+ request method to POST. To send the parameters as a GET query string instead, use
310+ `--method GET`.
311+
312+ The `-F/--field` flag has magic type conversion based on the format of the value:
313+
314+ - literal values "true", "false", "null", and integer/float numbers get converted to
315+ appropriate JSON types;
316+ - if the value starts with "@", the rest of the value is interpreted as a
317+ filename to read the value from. Pass "-" to read from standard input.
318+
319+ Raw request body may be passed from the outside via a file specified by `--input`.
320+ Pass "-" to read from standard input. In this mode, parameters specified via
321+ `--field` flags are serialized into URL query parameters.
322+
323+ In `--paginate` mode, all pages of results will sequentially be requested until
324+ there are no more pages of results.
325+
326+ USAGE:
327+ oxide api [OPTIONS] <endpoint>
328+
329+ ARGS:
330+ <endpoint>
331+ The endpoint to request
332+
333+ OPTIONS:
334+ -d, --debug
335+ Print debug info
336+
337+ [env: DEBUG=]
338+
339+ -f, --raw-field <RAW_FIELD>
340+ Add a string parameter in key=value format
341+
342+ -F, --field <FIELD>
343+ Add a typed parameter in key=value format
344+
345+ -h, --help
346+ Print help information
347+
348+ -H, --header <HEADER>
349+ Add a HTTP request header in `key:value` format
350+
351+ -i, --include
352+ Include HTTP response headers in the output
353+
354+ --input <INPUT>
355+ The file to use as body for the HTTP request (use "-" to read from standard input)
356+
357+ [default: ]
358+
359+ --paginate
360+ Make additional HTTP requests to fetch all pages of results
361+
362+ -X, --method <METHOD>
363+ The HTTP method for the request
364+
365+ $ oxide api /session/me
431366{
432- "instanceId": "99ad2514-050c-4493-9cb9-d9ceba980a98",
433- "diskId": "551bbe67-3640-41c9-b968-249a136e5e31",
434- "diskName": "mydisk",
435- "diskState": {
436- "state": "attached",
437- "instance": "99ad2514-050c-4493-9cb9-d9ceba980a98"
438- }
367+ "id": "99ad2514-050c-4493-9cb9-d9ceba980a98"
439368}
440- ----
369+
370+
371+ -----
441372
442373== Deploying Omicron
443374
0 commit comments