From ffc3432cf27d7a48a8b41d995d41fb0678f3db15 Mon Sep 17 00:00:00 2001 From: "Brian C. Lane" Date: Mon, 22 Apr 2019 15:26:47 -0700 Subject: [PATCH] Move the v0 API documentation into the functions --- src/pylorax/api/v0.py | 1944 ++++++++++++++++++++--------------------- src/pylorax/ltmpl.py | 1 + 2 files changed, 972 insertions(+), 973 deletions(-) diff --git a/src/pylorax/api/v0.py b/src/pylorax/api/v0.py index 3ca6bf16..580238a8 100644 --- a/src/pylorax/api/v0.py +++ b/src/pylorax/api/v0.py @@ -46,946 +46,6 @@ All of the blueprints routes support the optional `branch` argument. If it is no used then the API will use the `master` branch for blueprints. If you want to create a new branch use the `new` or `workspace` routes with ?branch= to store the new blueprint on the new branch. - -`/api/v0/blueprints/list` -^^^^^^^^^^^^^^^^^^^^^^^^^ - - List the available blueprints:: - - { "limit": 20, - "offset": 0, - "blueprints": [ - "atlas", - "development", - "glusterfs", - "http-server", - "jboss", - "kubernetes" ], - "total": 6 } - -`/api/v0/blueprints/info/[?format=]` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Return the JSON representation of the blueprint. This includes 3 top level - objects. `changes` which lists whether or not the workspace is different from - the most recent commit. `blueprints` which lists the JSON representation of the - blueprint, and `errors` which will list any errors, like non-existant blueprints. - - By default the response is JSON, but if `?format=toml` is included in the URL's - arguments it will return the response as the blueprint's raw TOML content. - *Unless* there is an error which will only return a 400 and a standard error - `Status Response`_. - - If there is an error when JSON is requested the successful blueprints and the - errors will both be returned. - - Example of json response:: - - { - "changes": [ - { - "changed": false, - "name": "glusterfs" - } - ], - "errors": [], - "blueprints": [ - { - "description": "An example GlusterFS server with samba", - "modules": [ - { - "name": "glusterfs", - "version": "3.7.*" - }, - { - "name": "glusterfs-cli", - "version": "3.7.*" - } - ], - "name": "glusterfs", - "packages": [ - { - "name": "2ping", - "version": "3.2.1" - }, - { - "name": "samba", - "version": "4.2.*" - } - ], - "version": "0.0.6" - } - ] - } - - Error example:: - - { - "changes": [], - "errors": ["ggit-error: the path 'missing.toml' does not exist in the given tree (-3)"] - "blueprints": [] - } - -`/api/v0/blueprints/changes/[?offset=0&limit=20]` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Return the commits to a blueprint. By default it returns the first 20 commits, this - can be changed by passing `offset` and/or `limit`. The response will include the - commit hash, summary, timestamp, and optionally the revision number. The commit - hash can be passed to `/api/v0/blueprints/diff/` to retrieve the exact changes. - - Example:: - - { - "errors": [], - "limit": 20, - "offset": 0, - "blueprints": [ - { - "changes": [ - { - "commit": "e083921a7ed1cf2eec91ad12b9ad1e70ef3470be", - "message": "blueprint glusterfs, version 0.0.6 saved.", - "revision": null, - "timestamp": "2017-11-23T00:18:13Z" - }, - { - "commit": "cee5f4c20fc33ea4d54bfecf56f4ad41ad15f4f3", - "message": "blueprint glusterfs, version 0.0.5 saved.", - "revision": null, - "timestamp": "2017-11-11T01:00:28Z" - }, - { - "commit": "29b492f26ed35d80800b536623bafc51e2f0eff2", - "message": "blueprint glusterfs, version 0.0.4 saved.", - "revision": null, - "timestamp": "2017-11-11T00:28:30Z" - }, - { - "commit": "03374adbf080fe34f5c6c29f2e49cc2b86958bf2", - "message": "blueprint glusterfs, version 0.0.3 saved.", - "revision": null, - "timestamp": "2017-11-10T23:15:52Z" - }, - { - "commit": "0e08ecbb708675bfabc82952599a1712a843779d", - "message": "blueprint glusterfs, version 0.0.2 saved.", - "revision": null, - "timestamp": "2017-11-10T23:14:56Z" - }, - { - "commit": "3e11eb87a63d289662cba4b1804a0947a6843379", - "message": "blueprint glusterfs, version 0.0.1 saved.", - "revision": null, - "timestamp": "2017-11-08T00:02:47Z" - } - ], - "name": "glusterfs", - "total": 6 - } - ] - } - -POST `/api/v0/blueprints/new` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Create a new blueprint, or update an existing blueprint. This supports both JSON and TOML - for the blueprint format. The blueprint should be in the body of the request with the - `Content-Type` header set to either `application/json` or `text/x-toml`. - - The response will be a status response with `status` set to true, or an - error response with it set to false and an error message included. - -DELETE `/api/v0/blueprints/delete/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Delete a blueprint. The blueprint is deleted from the branch, and will no longer - be listed by the `list` route. A blueprint can be undeleted using the `undo` route - to revert to a previous commit. This will also delete the workspace copy of the - blueprint. - - The response will be a status response with `status` set to true, or an - error response with it set to false and an error message included. - -POST `/api/v0/blueprints/workspace` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Write a blueprint to the temporary workspace. This works exactly the same as `new` except - that it does not create a commit. JSON and TOML bodies are supported. - - The workspace is meant to be used as a temporary blueprint storage for clients. - It will be read by the `info` and `diff` routes if it is different from the - most recent commit. - - The response will be a status response with `status` set to true, or an - error response with it set to false and an error message included. - -DELETE `/api/v0/blueprints/workspace/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Remove the temporary workspace copy of a blueprint. The `info` route will now - return the most recent commit of the blueprint. Any changes that were in the - workspace will be lost. - - The response will be a status response with `status` set to true, or an - error response with it set to false and an error message included. - -POST `/api/v0/blueprints/undo//` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - This will revert the blueprint to a previous commit. The commit hash from the `changes` - route can be used in this request. - - The response will be a status response with `status` set to true, or an - error response with it set to false and an error message included. - -POST `/api/v0/blueprints/tag/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Tag a blueprint as a new release. This uses git tags with a special format. - `refs/tags///r`. Only the most recent blueprint commit - can be tagged. Revisions start at 1 and increment for each new tag - (per-blueprint). If the commit has already been tagged it will return false. - - The response will be a status response with `status` set to true, or an - error response with it set to false and an error message included. - -`/api/v0/blueprints/diff///` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Return the differences between two commits, or the workspace. The commit hash - from the `changes` response can be used here, or several special strings: - - - NEWEST will select the newest git commit. This works for `from_commit` or `to_commit` - - WORKSPACE will select the workspace copy. This can only be used in `to_commit` - - eg. `/api/v0/blueprints/diff/glusterfs/NEWEST/WORKSPACE` will return the differences - between the most recent git commit and the contents of the workspace. - - Each entry in the response's diff object contains the old blueprint value and the new one. - If old is null and new is set, then it was added. - If new is null and old is set, then it was removed. - If both are set, then it was changed. - - The old/new entries will have the name of the blueprint field that was changed. This - can be one of: Name, Description, Version, Module, or Package. - The contents for these will be the old/new values for them. - - In the example below the version was changed and the ping package was added. - - Example:: - - { - "diff": [ - { - "new": { - "Version": "0.0.6" - }, - "old": { - "Version": "0.0.5" - } - }, - { - "new": { - "Package": { - "name": "ping", - "version": "3.2.1" - } - }, - "old": null - } - ] - } - -`/api/v0/blueprints/freeze/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Return a JSON representation of the blueprint with the package and module versions set - to the exact versions chosen by depsolving the blueprint. - - Example:: - - { - "errors": [], - "blueprints": [ - { - "blueprint": { - "description": "An example GlusterFS server with samba", - "modules": [ - { - "name": "glusterfs", - "version": "3.8.4-18.4.el7.x86_64" - }, - { - "name": "glusterfs-cli", - "version": "3.8.4-18.4.el7.x86_64" - } - ], - "name": "glusterfs", - "packages": [ - { - "name": "ping", - "version": "2:3.2.1-2.el7.noarch" - }, - { - "name": "samba", - "version": "4.6.2-8.el7.x86_64" - } - ], - "version": "0.0.6" - } - } - ] - } - -`/api/v0/blueprints/depsolve/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Depsolve the blueprint using yum, return the blueprint used, and the NEVRAs of the packages - chosen to satisfy the blueprint's requirements. The response will include a list of results, - with the full dependency list in `dependencies`, the NEVRAs for the blueprint's direct modules - and packages in `modules`, and any error will be in `errors`. - - Example:: - - { - "errors": [], - "blueprints": [ - { - "dependencies": [ - { - "arch": "noarch", - "epoch": "0", - "name": "2ping", - "release": "2.el7", - "version": "3.2.1" - }, - { - "arch": "x86_64", - "epoch": "0", - "name": "acl", - "release": "12.el7", - "version": "2.2.51" - }, - { - "arch": "x86_64", - "epoch": "0", - "name": "audit-libs", - "release": "3.el7", - "version": "2.7.6" - }, - { - "arch": "x86_64", - "epoch": "0", - "name": "avahi-libs", - "release": "17.el7", - "version": "0.6.31" - }, - ... - ], - "modules": [ - { - "arch": "noarch", - "epoch": "0", - "name": "2ping", - "release": "2.el7", - "version": "3.2.1" - }, - { - "arch": "x86_64", - "epoch": "0", - "name": "glusterfs", - "release": "18.4.el7", - "version": "3.8.4" - }, - ... - ], - "blueprint": { - "description": "An example GlusterFS server with samba", - "modules": [ - { - "name": "glusterfs", - "version": "3.7.*" - }, - ... - } - } - ] - } - -`/api/v0/projects/list[?offset=0&limit=20]` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - List all of the available projects. By default this returns the first 20 items, - but this can be changed by setting the `offset` and `limit` arguments. - - Example:: - - { - "limit": 20, - "offset": 0, - "projects": [ - { - "description": "0 A.D. (pronounced \"zero ey-dee\") is a ...", - "homepage": "http://play0ad.com", - "name": "0ad", - "summary": "Cross-Platform RTS Game of Ancient Warfare", - "upstream_vcs": "UPSTREAM_VCS" - }, - ... - ], - "total": 21770 - } - -`/api/v0/projects/info/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Return information about the comma-separated list of projects. It includes the description - of the package along with the list of available builds. - - Example:: - - { - "projects": [ - { - "builds": [ - { - "arch": "x86_64", - "build_config_ref": "BUILD_CONFIG_REF", - "build_env_ref": "BUILD_ENV_REF", - "build_time": "2017-03-01T08:39:23", - "changelog": "- restore incremental backups correctly, files ...", - "epoch": "2", - "metadata": {}, - "release": "32.el7", - "source": { - "license": "GPLv3+", - "metadata": {}, - "source_ref": "SOURCE_REF", - "version": "1.26" - } - } - ], - "description": "The GNU tar program saves many ...", - "homepage": "http://www.gnu.org/software/tar/", - "name": "tar", - "summary": "A GNU file archiving program", - "upstream_vcs": "UPSTREAM_VCS" - } - ] - } - -`/api/v0/projects/depsolve/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Depsolve the comma-separated list of projects and return the list of NEVRAs needed - to satisfy the request. - - Example:: - - { - "projects": [ - { - "arch": "noarch", - "epoch": "0", - "name": "basesystem", - "release": "7.el7", - "version": "10.0" - }, - { - "arch": "x86_64", - "epoch": "0", - "name": "bash", - "release": "28.el7", - "version": "4.2.46" - }, - { - "arch": "x86_64", - "epoch": "0", - "name": "filesystem", - "release": "21.el7", - "version": "3.2" - }, - ... - ] - } - -`/api/v0/projects/source/list` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Return the list of repositories used for depsolving and installing packages. - - Example:: - - { - "sources": [ - "fedora", - "fedora-cisco-openh264", - "fedora-updates-testing", - "fedora-updates" - ] - } - -`/api/v0/projects/source/info/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Return information about the comma-separated list of source names. Or all of the - sources if '*' is passed. Note that general globbing is not supported, only '*'. - - immutable system sources will have the "system" field set to true. User added sources - will have it set to false. System sources cannot be changed or deleted. - - Example:: - - { - "errors": [], - "sources": { - "fedora": { - "check_gpg": true, - "check_ssl": true, - "gpgkey_urls": [ - "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-28-x86_64" - ], - "name": "fedora", - "proxy": "http://proxy.brianlane.com:8123", - "system": true, - "type": "yum-metalink", - "url": "https://mirrors.fedoraproject.org/metalink?repo=fedora-28&arch=x86_64" - } - } - } - -POST `/api/v0/projects/source/new` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Add (or change) a source for use when depsolving blueprints and composing images. - - The ``proxy`` and ``gpgkey_urls`` entries are optional. All of the others are required. The supported - types for the urls are: - - * ``yum-baseurl`` is a URL to a yum repository. - * ``yum-mirrorlist`` is a URL for a mirrorlist. - * ``yum-metalink`` is a URL for a metalink. - - If ``check_ssl`` is true the https certificates must be valid. If they are self-signed you can either set - this to false, or add your Certificate Authority to the host system. - - If ``check_gpg`` is true the GPG key must either be installed on the host system, or ``gpgkey_urls`` - should point to it. - - You can edit an existing source (other than system sources), by doing a POST - of the new version of the source. It will overwrite the previous one. - - Example:: - - { - "name": "custom-source-1", - "url": "https://url/path/to/repository/", - "type": "yum-baseurl", - "check_ssl": true, - "check_gpg": true, - "gpgkey_urls": [ - "https://url/path/to/gpg-key" - ] - } - -DELETE `/api/v0/projects/source/delete/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Delete a user added source. This will fail if a system source is passed to - it. - - The response will be a status response with `status` set to true, or an - error response with it set to false and an error message included. - -`/api/v0/modules/list[?offset=0&limit=20]` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Return a list of all of the available modules. This includes the name and the - group_type, which is always "rpm" for lorax-composer. By default this returns - the first 20 items. This can be changed by setting the `offset` and `limit` - arguments. - - Example:: - - { - "limit": 20, - "modules": [ - { - "group_type": "rpm", - "name": "0ad" - }, - { - "group_type": "rpm", - "name": "0ad-data" - }, - { - "group_type": "rpm", - "name": "0install" - }, - { - "group_type": "rpm", - "name": "2048-cli" - }, - ... - ] - "total": 21770 - } - -`/api/v0/modules/list/[?offset=0&limit=20]` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Return the list of comma-separated modules. Output is the same as `/modules/list` - - Example:: - - { - "limit": 20, - "modules": [ - { - "group_type": "rpm", - "name": "tar" - } - ], - "offset": 0, - "total": 1 - } - -`/api/v0/modules/info/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Return the module's dependencies, and the information about the module. - - Example:: - - { - "modules": [ - { - "dependencies": [ - { - "arch": "noarch", - "epoch": "0", - "name": "basesystem", - "release": "7.el7", - "version": "10.0" - }, - { - "arch": "x86_64", - "epoch": "0", - "name": "bash", - "release": "28.el7", - "version": "4.2.46" - }, - ... - ], - "description": "The GNU tar program saves ...", - "homepage": "http://www.gnu.org/software/tar/", - "name": "tar", - "summary": "A GNU file archiving program", - "upstream_vcs": "UPSTREAM_VCS" - } - ] - } - -POST `/api/v0/compose` -^^^^^^^^^^^^^^^^^^^^^^ - - Start a compose. The content type should be 'application/json' and the body of the POST - should look like this - - Example:: - - { - "blueprint_name": "http-server", - "compose_type": "tar", - "branch": "master" - } - - Pass it the name of the blueprint, the type of output (from '/api/v0/compose/types'), and the - blueprint branch to use. 'branch' is optional and will default to master. It will create a new - build and add it to the queue. It returns the build uuid and a status if it succeeds - - Example:: - - { - "build_id": "e6fa6db4-9c81-4b70-870f-a697ca405cdf", - "status": true - } - -`/api/v0/compose/types` -^^^^^^^^^^^^^^^^^^^^^^^ - - Returns the list of supported output types that are valid for use with 'POST /api/v0/compose' - - Example:: - - { - "types": [ - { - "enabled": true, - "name": "tar" - } - ] - } - -`/api/v0/compose/queue` -^^^^^^^^^^^^^^^^^^^^^^^ - - Return the status of the build queue. It includes information about the builds waiting, - and the build that is running. - - Example:: - - { - "new": [ - { - "id": "45502a6d-06e8-48a5-a215-2b4174b3614b", - "blueprint": "glusterfs", - "queue_status": "WAITING", - "job_created": 1517362647.4570868, - "version": "0.0.6" - }, - { - "id": "6d292bd0-bec7-4825-8d7d-41ef9c3e4b73", - "blueprint": "kubernetes", - "queue_status": "WAITING", - "job_created": 1517362659.0034983, - "version": "0.0.1" - } - ], - "run": [ - { - "id": "745712b2-96db-44c0-8014-fe925c35e795", - "blueprint": "glusterfs", - "queue_status": "RUNNING", - "job_created": 1517362633.7965999, - "job_started": 1517362633.8001345, - "version": "0.0.6" - } - ] - } - -`/api/v0/compose/finished` -^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Return the details on all of the finished composes on the system. - - Example:: - - { - "finished": [ - { - "id": "70b84195-9817-4b8a-af92-45e380f39894", - "blueprint": "glusterfs", - "queue_status": "FINISHED", - "job_created": 1517351003.8210032, - "job_started": 1517351003.8230415, - "job_finished": 1517359234.1003145, - "version": "0.0.6" - }, - { - "id": "e695affd-397f-4af9-9022-add2636e7459", - "blueprint": "glusterfs", - "queue_status": "FINISHED", - "job_created": 1517362289.7193348, - "job_started": 1517362289.9751132, - "job_finished": 1517363500.1234567, - "version": "0.0.6" - } - ] - } - -`/api/v0/compose/failed` -^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Return the details on all of the failed composes on the system. - - Example:: - - { - "failed": [ - { - "id": "8c8435ef-d6bd-4c68-9bf1-a2ef832e6b1a", - "blueprint": "http-server", - "queue_status": "FAILED", - "job_created": 1517523249.9301329, - "job_started": 1517523249.9314211, - "job_finished": 1517523255.5623411, - "version": "0.0.2" - } - ] - } - -`/api/v0/compose/status/[?blueprint=&status=&type=]` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Return the details for each of the comma-separated list of uuids. A uuid of '*' will return - details for all composes. - - Example:: - - { - "uuids": [ - { - "id": "8c8435ef-d6bd-4c68-9bf1-a2ef832e6b1a", - "blueprint": "http-server", - "queue_status": "FINISHED", - "job_created": 1517523644.2384307, - "job_started": 1517523644.2551234, - "job_finished": 1517523689.9864314, - "version": "0.0.2" - }, - { - "id": "45502a6d-06e8-48a5-a215-2b4174b3614b", - "blueprint": "glusterfs", - "queue_status": "FINISHED", - "job_created": 1517363442.188399, - "job_started": 1517363442.325324, - "job_finished": 1517363451.653621, - "version": "0.0.6" - } - ] - } - -DELETE `/api/v0/compose/cancel/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Cancel the build, if it is not finished, and delete the results. It will return a - status of True if it is successful. - - Example:: - - { - "status": true, - "uuid": "03397f8d-acff-4cdb-bd31-f629b7a948f5" - } - -DELETE `/api/v0/compose/delete/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Delete the list of comma-separated uuids from the compose results. - - Example:: - - { - "errors": [], - "uuids": [ - { - "status": true, - "uuid": "ae1bf7e3-7f16-4c9f-b36e-3726a1093fd0" - } - ] - } - -`/api/v0/compose/info/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Get detailed information about the compose. The returned JSON string will - contain the following information: - - * id - The uuid of the comoposition - * config - containing the configuration settings used to run Anaconda - * blueprint - The depsolved blueprint used to generate the kickstart - * commit - The (local) git commit hash for the blueprint used - * deps - The NEVRA of all of the dependencies used in the composition - * compose_type - The type of output generated (tar, iso, etc.) - * queue_status - The final status of the composition (FINISHED or FAILED) - - Example:: - - { - "commit": "7078e521a54b12eae31c3fd028680da7a0815a4d", - "compose_type": "tar", - "config": { - "anaconda_args": "", - "armplatform": "", - "compress_args": [], - "compression": "xz", - "image_name": "root.tar.xz", - ... - }, - "deps": { - "packages": [ - { - "arch": "x86_64", - "epoch": "0", - "name": "acl", - "release": "14.el7", - "version": "2.2.51" - } - ] - }, - "id": "c30b7d80-523b-4a23-ad52-61b799739ce8", - "queue_status": "FINISHED", - "blueprint": { - "description": "An example kubernetes master", - ... - } - } - -`/api/v0/compose/metadata/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Returns a .tar of the metadata used for the build. This includes all the - information needed to reproduce the build, including the final kickstart - populated with repository and package NEVRA. - - The mime type is set to 'application/x-tar' and the filename is set to - UUID-metadata.tar - - The .tar is uncompressed, but is not large. - -`/api/v0/compose/results/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Returns a .tar of the metadata, logs, and output image of the build. This - includes all the information needed to reproduce the build, including the - final kickstart populated with repository and package NEVRA. The output image - is already in compressed form so the returned tar is not compressed. - - The mime type is set to 'application/x-tar' and the filename is set to - UUID.tar - -`/api/v0/compose/logs/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Returns a .tar of the anaconda build logs. The tar is not compressed, but is - not large. - - The mime type is set to 'application/x-tar' and the filename is set to - UUID-logs.tar - -`/api/v0/compose/image/` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Returns the output image from the build. The filename is set to the filename - from the build with the UUID as a prefix. eg. UUID-root.tar.xz or UUID-boot.iso. - -`/api/v0/compose/log/[?size=kbytes]` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - - Returns the end of the anaconda.log. The size parameter is optional and defaults to 1Mbytes - if it is not included. The returned data is raw text from the end of the logfile, starting on - a line boundry. - - Example:: - - 12:59:24,222 INFO anaconda: Running Thread: AnaConfigurationThread (140629395244800) - 12:59:24,223 INFO anaconda: Configuring installed system - 12:59:24,912 INFO anaconda: Configuring installed system - 12:59:24,912 INFO anaconda: Creating users - 12:59:24,913 INFO anaconda: Clearing libuser.conf at /tmp/libuser.Dyy8Gj - 12:59:25,154 INFO anaconda: Creating users - 12:59:25,155 INFO anaconda: Configuring addons - 12:59:25,155 INFO anaconda: Configuring addons - 12:59:25,155 INFO anaconda: Generating initramfs - 12:59:49,467 INFO anaconda: Generating initramfs - 12:59:49,467 INFO anaconda: Running post-installation scripts - 12:59:49,467 INFO anaconda: Running kickstart %%post script(s) - 12:59:50,782 INFO anaconda: All kickstart %%post script(s) have been run - 12:59:50,782 INFO anaconda: Running post-installation scripts - 12:59:50,784 INFO anaconda: Thread Done: AnaConfigurationThread (140629395244800) - """ import logging @@ -1051,7 +111,23 @@ v0_api = BlueprintSkip("v0_routes", __name__) @v0_api.route("/blueprints/list") def v0_blueprints_list(): - """List the available blueprints on a branch.""" + """List the available blueprints on a branch. + + **/api/v0/blueprints/list** + + List the available blueprints:: + + { "limit": 20, + "offset": 0, + "blueprints": [ + "atlas", + "development", + "glusterfs", + "http-server", + "jboss", + "kubernetes" ], + "total": 6 } + """ branch = request.args.get("branch", "master") if VALID_API_STRING.match(branch) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 @@ -1071,7 +147,70 @@ def v0_blueprints_list(): @v0_api.route("/blueprints/info/") @checkparams([("blueprint_names", "", "no blueprint names given")]) def v0_blueprints_info(blueprint_names): - """Return the contents of the blueprint, or a list of blueprints""" + """Return the contents of the blueprint, or a list of blueprints + + **/api/v0/blueprints/info/[?format=]** + + Return the JSON representation of the blueprint. This includes 3 top level + objects. `changes` which lists whether or not the workspace is different from + the most recent commit. `blueprints` which lists the JSON representation of the + blueprint, and `errors` which will list any errors, like non-existant blueprints. + + By default the response is JSON, but if `?format=toml` is included in the URL's + arguments it will return the response as the blueprint's raw TOML content. + *Unless* there is an error which will only return a 400 and a standard error + `Status Responses`_. + + If there is an error when JSON is requested the successful blueprints and the + errors will both be returned. + + Example of json response:: + + { + "changes": [ + { + "changed": false, + "name": "glusterfs" + } + ], + "errors": [], + "blueprints": [ + { + "description": "An example GlusterFS server with samba", + "modules": [ + { + "name": "glusterfs", + "version": "3.7.*" + }, + { + "name": "glusterfs-cli", + "version": "3.7.*" + } + ], + "name": "glusterfs", + "packages": [ + { + "name": "2ping", + "version": "3.2.1" + }, + { + "name": "samba", + "version": "4.2.*" + } + ], + "version": "0.0.6" + } + ] + } + + Error example:: + + { + "changes": [], + "errors": ["ggit-error: the path 'missing.toml' does not exist in the given tree (-3)"] + "blueprints": [] + } + """ if VALID_API_STRING.match(blueprint_names) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1144,7 +283,67 @@ def v0_blueprints_info(blueprint_names): @v0_api.route("/blueprints/changes/") @checkparams([("blueprint_names", "", "no blueprint names given")]) def v0_blueprints_changes(blueprint_names): - """Return the changes to a blueprint or list of blueprints""" + """Return the changes to a blueprint or list of blueprints + + **/api/v0/blueprints/changes/[?offset=0&limit=20]** + + Return the commits to a blueprint. By default it returns the first 20 commits, this + can be changed by passing `offset` and/or `limit`. The response will include the + commit hash, summary, timestamp, and optionally the revision number. The commit + hash can be passed to `/api/v0/blueprints/diff/` to retrieve the exact changes. + + Example:: + + { + "errors": [], + "limit": 20, + "offset": 0, + "blueprints": [ + { + "changes": [ + { + "commit": "e083921a7ed1cf2eec91ad12b9ad1e70ef3470be", + "message": "blueprint glusterfs, version 0.0.6 saved.", + "revision": null, + "timestamp": "2017-11-23T00:18:13Z" + }, + { + "commit": "cee5f4c20fc33ea4d54bfecf56f4ad41ad15f4f3", + "message": "blueprint glusterfs, version 0.0.5 saved.", + "revision": null, + "timestamp": "2017-11-11T01:00:28Z" + }, + { + "commit": "29b492f26ed35d80800b536623bafc51e2f0eff2", + "message": "blueprint glusterfs, version 0.0.4 saved.", + "revision": null, + "timestamp": "2017-11-11T00:28:30Z" + }, + { + "commit": "03374adbf080fe34f5c6c29f2e49cc2b86958bf2", + "message": "blueprint glusterfs, version 0.0.3 saved.", + "revision": null, + "timestamp": "2017-11-10T23:15:52Z" + }, + { + "commit": "0e08ecbb708675bfabc82952599a1712a843779d", + "message": "blueprint glusterfs, version 0.0.2 saved.", + "revision": null, + "timestamp": "2017-11-10T23:14:56Z" + }, + { + "commit": "3e11eb87a63d289662cba4b1804a0947a6843379", + "message": "blueprint glusterfs, version 0.0.1 saved.", + "revision": null, + "timestamp": "2017-11-08T00:02:47Z" + } + ], + "name": "glusterfs", + "total": 6 + } + ] + } + """ if VALID_API_STRING.match(blueprint_names) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1182,7 +381,17 @@ def v0_blueprints_changes(blueprint_names): @v0_api.route("/blueprints/new", methods=["POST"]) def v0_blueprints_new(): - """Commit a new blueprint""" + """Commit a new blueprint + + **POST /api/v0/blueprints/new** + + Create a new blueprint, or update an existing blueprint. This supports both JSON and TOML + for the blueprint format. The blueprint should be in the body of the request with the + `Content-Type` header set to either `application/json` or `text/x-toml`. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ branch = request.args.get("branch", "master") if VALID_API_STRING.match(branch) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 @@ -1212,7 +421,18 @@ def v0_blueprints_new(): @v0_api.route("/blueprints/delete/", methods=["DELETE"]) @checkparams([("blueprint_name", "", "no blueprint name given")]) def v0_blueprints_delete(blueprint_name): - """Delete a blueprint from git""" + """Delete a blueprint from git + + **DELETE /api/v0/blueprints/delete/** + + Delete a blueprint. The blueprint is deleted from the branch, and will no longer + be listed by the `list` route. A blueprint can be undeleted using the `undo` route + to revert to a previous commit. This will also delete the workspace copy of the + blueprint. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ if VALID_API_STRING.match(blueprint_name) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1232,7 +452,20 @@ def v0_blueprints_delete(blueprint_name): @v0_api.route("/blueprints/workspace", methods=["POST"]) def v0_blueprints_workspace(): - """Write a blueprint to the workspace""" + """Write a blueprint to the workspace + + **POST /api/v0/blueprints/workspace** + + Write a blueprint to the temporary workspace. This works exactly the same as `new` except + that it does not create a commit. JSON and TOML bodies are supported. + + The workspace is meant to be used as a temporary blueprint storage for clients. + It will be read by the `info` and `diff` routes if it is different from the + most recent commit. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ branch = request.args.get("branch", "master") if VALID_API_STRING.match(branch) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in branch argument"}]), 400 @@ -1258,7 +491,17 @@ def v0_blueprints_workspace(): @v0_api.route("/blueprints/workspace/", methods=["DELETE"]) @checkparams([("blueprint_name", "", "no blueprint name given")]) def v0_blueprints_delete_workspace(blueprint_name): - """Delete a blueprint from the workspace""" + """Delete a blueprint from the workspace + + **DELETE /api/v0/blueprints/workspace/** + + Remove the temporary workspace copy of a blueprint. The `info` route will now + return the most recent commit of the blueprint. Any changes that were in the + workspace will be lost. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ if VALID_API_STRING.match(blueprint_name) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1281,7 +524,16 @@ def v0_blueprints_delete_workspace(blueprint_name): @checkparams([("blueprint_name", "", "no blueprint name given"), ("commit", "", "no commit ID given")]) def v0_blueprints_undo(blueprint_name, commit): - """Undo changes to a blueprint by reverting to a previous commit.""" + """Undo changes to a blueprint by reverting to a previous commit. + + **POST /api/v0/blueprints/undo//** + + This will revert the blueprint to a previous commit. The commit hash from the `changes` + route can be used in this request. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ if VALID_API_STRING.match(blueprint_name) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1306,7 +558,18 @@ def v0_blueprints_undo(blueprint_name, commit): @v0_api.route("/blueprints/tag/", methods=["POST"]) @checkparams([("blueprint_name", "", "no blueprint name given")]) def v0_blueprints_tag(blueprint_name): - """Tag a blueprint's latest blueprint commit as a 'revision'""" + """Tag a blueprint's latest blueprint commit as a 'revision' + + **POST /api/v0/blueprints/tag/** + + Tag a blueprint as a new release. This uses git tags with a special format. + `refs/tags///r`. Only the most recent blueprint commit + can be tagged. Revisions start at 1 and increment for each new tag + (per-blueprint). If the commit has already been tagged it will return false. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ if VALID_API_STRING.match(blueprint_name) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1334,7 +597,54 @@ def v0_blueprints_tag(blueprint_name): ("from_commit", "", "no from commit ID given"), ("to_commit", "", "no to commit ID given")]) def v0_blueprints_diff(blueprint_name, from_commit, to_commit): - """Return the differences between two commits of a blueprint""" + """Return the differences between two commits of a blueprint + + **/api/v0/blueprints/diff///** + + Return the differences between two commits, or the workspace. The commit hash + from the `changes` response can be used here, or several special strings: + + - NEWEST will select the newest git commit. This works for `from_commit` or `to_commit` + - WORKSPACE will select the workspace copy. This can only be used in `to_commit` + + eg. `/api/v0/blueprints/diff/glusterfs/NEWEST/WORKSPACE` will return the differences + between the most recent git commit and the contents of the workspace. + + Each entry in the response's diff object contains the old blueprint value and the new one. + If old is null and new is set, then it was added. + If new is null and old is set, then it was removed. + If both are set, then it was changed. + + The old/new entries will have the name of the blueprint field that was changed. This + can be one of: Name, Description, Version, Module, or Package. + The contents for these will be the old/new values for them. + + In the example below the version was changed and the ping package was added. + + Example:: + + { + "diff": [ + { + "new": { + "Version": "0.0.6" + }, + "old": { + "Version": "0.0.5" + } + }, + { + "new": { + "Package": { + "name": "ping", + "version": "3.2.1" + } + }, + "old": null + } + ] + } + """ for s in [blueprint_name, from_commit, to_commit]: if VALID_API_STRING.match(s) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1382,7 +692,48 @@ def v0_blueprints_diff(blueprint_name, from_commit, to_commit): @v0_api.route("/blueprints/freeze/") @checkparams([("blueprint_names", "", "no blueprint names given")]) def v0_blueprints_freeze(blueprint_names): - """Return the blueprint with the exact modules and packages selected by depsolve""" + """Return the blueprint with the exact modules and packages selected by depsolve + + **/api/v0/blueprints/freeze/** + + Return a JSON representation of the blueprint with the package and module versions set + to the exact versions chosen by depsolving the blueprint. + + Example:: + + { + "errors": [], + "blueprints": [ + { + "blueprint": { + "description": "An example GlusterFS server with samba", + "modules": [ + { + "name": "glusterfs", + "version": "3.8.4-18.4.el7.x86_64" + }, + { + "name": "glusterfs-cli", + "version": "3.8.4-18.4.el7.x86_64" + } + ], + "name": "glusterfs", + "packages": [ + { + "name": "ping", + "version": "2:3.2.1-2.el7.noarch" + }, + { + "name": "samba", + "version": "4.6.2-8.el7.x86_64" + } + ], + "version": "0.0.6" + } + } + ] + } + """ if VALID_API_STRING.match(blueprint_names) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1448,7 +799,82 @@ def v0_blueprints_freeze(blueprint_names): @v0_api.route("/blueprints/depsolve/") @checkparams([("blueprint_names", "", "no blueprint names given")]) def v0_blueprints_depsolve(blueprint_names): - """Return the dependencies for a blueprint""" + """Return the dependencies for a blueprint + + **/api/v0/blueprints/depsolve/** + + Depsolve the blueprint using yum, return the blueprint used, and the NEVRAs of the packages + chosen to satisfy the blueprint's requirements. The response will include a list of results, + with the full dependency list in `dependencies`, the NEVRAs for the blueprint's direct modules + and packages in `modules`, and any error will be in `errors`. + + Example:: + + { + "errors": [], + "blueprints": [ + { + "dependencies": [ + { + "arch": "noarch", + "epoch": "0", + "name": "2ping", + "release": "2.el7", + "version": "3.2.1" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "acl", + "release": "12.el7", + "version": "2.2.51" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "audit-libs", + "release": "3.el7", + "version": "2.7.6" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "avahi-libs", + "release": "17.el7", + "version": "0.6.31" + }, + ... + ], + "modules": [ + { + "arch": "noarch", + "epoch": "0", + "name": "2ping", + "release": "2.el7", + "version": "3.2.1" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "glusterfs", + "release": "18.4.el7", + "version": "3.8.4" + }, + ... + ], + "blueprint": { + "description": "An example GlusterFS server with samba", + "modules": [ + { + "name": "glusterfs", + "version": "3.7.*" + }, + ... + } + } + ] + } + """ if VALID_API_STRING.match(blueprint_names) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1511,7 +937,31 @@ def v0_blueprints_depsolve(blueprint_names): @v0_api.route("/projects/list") def v0_projects_list(): - """List all of the available projects/packages""" + """List all of the available projects/packages + + **/api/v0/projects/list[?offset=0&limit=20]** + + List all of the available projects. By default this returns the first 20 items, + but this can be changed by setting the `offset` and `limit` arguments. + + Example:: + + { + "limit": 20, + "offset": 0, + "projects": [ + { + "description": "0 A.D. (pronounced \"zero ey-dee\") is a ...", + "homepage": "http://play0ad.com", + "name": "0ad", + "summary": "Cross-Platform RTS Game of Ancient Warfare", + "upstream_vcs": "UPSTREAM_VCS" + }, + ... + ], + "total": 21770 + } + """ try: limit = int(request.args.get("limit", "20")) offset = int(request.args.get("offset", "0")) @@ -1532,7 +982,45 @@ def v0_projects_list(): @v0_api.route("/projects/info/") @checkparams([("project_names", "", "no project names given")]) def v0_projects_info(project_names): - """Return detailed information about the listed projects""" + """Return detailed information about the listed projects + + **/api/v0/projects/info/** + + Return information about the comma-separated list of projects. It includes the description + of the package along with the list of available builds. + + Example:: + + { + "projects": [ + { + "builds": [ + { + "arch": "x86_64", + "build_config_ref": "BUILD_CONFIG_REF", + "build_env_ref": "BUILD_ENV_REF", + "build_time": "2017-03-01T08:39:23", + "changelog": "- restore incremental backups correctly, files ...", + "epoch": "2", + "metadata": {}, + "release": "32.el7", + "source": { + "license": "GPLv3+", + "metadata": {}, + "source_ref": "SOURCE_REF", + "version": "1.26" + } + } + ], + "description": "The GNU tar program saves many ...", + "homepage": "http://www.gnu.org/software/tar/", + "name": "tar", + "summary": "A GNU file archiving program", + "upstream_vcs": "UPSTREAM_VCS" + } + ] + } + """ if VALID_API_STRING.match(project_names) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1554,7 +1042,42 @@ def v0_projects_info(project_names): @v0_api.route("/projects/depsolve/") @checkparams([("project_names", "", "no project names given")]) def v0_projects_depsolve(project_names): - """Return detailed information about the listed projects""" + """Return detailed information about the listed projects + + **/api/v0/projects/depsolve/** + + Depsolve the comma-separated list of projects and return the list of NEVRAs needed + to satisfy the request. + + Example:: + + { + "projects": [ + { + "arch": "noarch", + "epoch": "0", + "name": "basesystem", + "release": "7.el7", + "version": "10.0" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "bash", + "release": "28.el7", + "version": "4.2.46" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "filesystem", + "release": "21.el7", + "version": "3.2" + }, + ... + ] + } + """ if VALID_API_STRING.match(project_names) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1574,7 +1097,23 @@ def v0_projects_depsolve(project_names): @v0_api.route("/projects/source/list") def v0_projects_source_list(): - """Return the list of source names""" + """Return the list of source names + + **/api/v0/projects/source/list** + + Return the list of repositories used for depsolving and installing packages. + + Example:: + + { + "sources": [ + "fedora", + "fedora-cisco-openh264", + "fedora-updates-testing", + "fedora-updates" + ] + } + """ with api.config["DNFLOCK"].lock: repos = list(api.config["DNFLOCK"].dbo.repos.iter_enabled()) sources = sorted([r.id for r in repos]) @@ -1584,7 +1123,36 @@ def v0_projects_source_list(): @v0_api.route("/projects/source/info/") @checkparams([("source_names", "", "no source names given")]) def v0_projects_source_info(source_names): - """Return detailed info about the list of sources""" + """Return detailed info about the list of sources + + **/api/v0/projects/source/info/** + + Return information about the comma-separated list of source names. Or all of the + sources if '*' is passed. Note that general globbing is not supported, only '*'. + + immutable system sources will have the "system" field set to true. User added sources + will have it set to false. System sources cannot be changed or deleted. + + Example:: + + { + "errors": [], + "sources": { + "fedora": { + "check_gpg": true, + "check_ssl": true, + "gpgkey_urls": [ + "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-28-x86_64" + ], + "name": "fedora", + "proxy": "http://proxy.brianlane.com:8123", + "system": true, + "type": "yum-metalink", + "url": "https://mirrors.fedoraproject.org/metalink?repo=fedora-28&arch=x86_64" + } + } + } + """ if VALID_API_STRING.match(source_names) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1619,7 +1187,43 @@ def v0_projects_source_info(source_names): @v0_api.route("/projects/source/new", methods=["POST"]) def v0_projects_source_new(): - """Add a new package source. Or change an existing one""" + """Add a new package source. Or change an existing one + + **POST /api/v0/projects/source/new** + + Add (or change) a source for use when depsolving blueprints and composing images. + + The ``proxy`` and ``gpgkey_urls`` entries are optional. All of the others are required. The supported + types for the urls are: + + * ``yum-baseurl`` is a URL to a yum repository. + * ``yum-mirrorlist`` is a URL for a mirrorlist. + * ``yum-metalink`` is a URL for a metalink. + + If ``check_ssl`` is true the https certificates must be valid. If they are self-signed you can either set + this to false, or add your Certificate Authority to the host system. + + If ``check_gpg`` is true the GPG key must either be installed on the host system, or ``gpgkey_urls`` + should point to it. + + You can edit an existing source (other than system sources), by doing a POST + of the new version of the source. It will overwrite the previous one. + + Example:: + + { + "name": "custom-source-1", + "url": "https://url/path/to/repository/", + "type": "yum-baseurl", + "check_ssl": true, + "check_gpg": true, + "gpgkey_urls": [ + "https://url/path/to/gpg-key" + ] + } + + + """ if request.headers['Content-Type'] == "text/x-toml": source = toml.loads(request.data) else: @@ -1680,7 +1284,16 @@ def v0_projects_source_new(): @v0_api.route("/projects/source/delete/", methods=["DELETE"]) @checkparams([("source_name", "", "no source name given")]) def v0_projects_source_delete(source_name): - """Delete the named source and return a status response""" + """Delete the named source and return a status response + + **DELETE /api/v0/projects/source/delete/** + + Delete a user added source. This will fail if a system source is passed to + it. + + The response will be a status response with `status` set to true, or an + error response with it set to false and an error message included. + """ if VALID_API_STRING.match(source_name) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1709,7 +1322,59 @@ def v0_projects_source_delete(source_name): @v0_api.route("/modules/list") @v0_api.route("/modules/list/") def v0_modules_list(module_names=None): - """List available modules, filtering by module_names""" + """List available modules, filtering by module_names + + **/api/v0/modules/list[?offset=0&limit=20]** + + Return a list of all of the available modules. This includes the name and the + group_type, which is always "rpm" for lorax-composer. By default this returns + the first 20 items. This can be changed by setting the `offset` and `limit` + arguments. + + Example:: + + { + "limit": 20, + "modules": [ + { + "group_type": "rpm", + "name": "0ad" + }, + { + "group_type": "rpm", + "name": "0ad-data" + }, + { + "group_type": "rpm", + "name": "0install" + }, + { + "group_type": "rpm", + "name": "2048-cli" + }, + ... + ] + "total": 21770 + } + + **/api/v0/modules/list/[?offset=0&limit=20]** + + Return the list of comma-separated modules. Output is the same as `/modules/list` + + Example:: + + { + "limit": 20, + "modules": [ + { + "group_type": "rpm", + "name": "tar" + } + ], + "offset": 0, + "total": 1 + } + """ if module_names and VALID_API_STRING.match(module_names) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1741,7 +1406,43 @@ def v0_modules_list(module_names=None): @v0_api.route("/modules/info/") @checkparams([("module_names", "", "no module names given")]) def v0_modules_info(module_names): - """Return detailed information about the listed modules""" + """Return detailed information about the listed modules + + **/api/v0/modules/info/** + + Return the module's dependencies, and the information about the module. + + Example:: + + { + "modules": [ + { + "dependencies": [ + { + "arch": "noarch", + "epoch": "0", + "name": "basesystem", + "release": "7.el7", + "version": "10.0" + }, + { + "arch": "x86_64", + "epoch": "0", + "name": "bash", + "release": "28.el7", + "version": "4.2.46" + }, + ... + ], + "description": "The GNU tar program saves ...", + "homepage": "http://www.gnu.org/software/tar/", + "name": "tar", + "summary": "A GNU file archiving program", + "upstream_vcs": "UPSTREAM_VCS" + } + ] + } + """ if VALID_API_STRING.match(module_names) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 try: @@ -1766,6 +1467,30 @@ def v0_compose_start(): blueprint_name - The blueprint name from /blueprints/list/ compose_type - The type of output to create, from /compose/types branch - Optional, defaults to master, selects the git branch to use for the blueprint. + + **POST /api/v0/compose** + + Start a compose. The content type should be 'application/json' and the body of the POST + should look like this + + Example:: + + { + "blueprint_name": "http-server", + "compose_type": "tar", + "branch": "master" + } + + Pass it the name of the blueprint, the type of output (from '/api/v0/compose/types'), and the + blueprint branch to use. 'branch' is optional and will default to master. It will create a new + build and add it to the queue. It returns the build uuid and a status if it succeeds + + Example:: + + { + "build_id": "e6fa6db4-9c81-4b70-870f-a697ca405cdf", + "status": true + } """ # Passing ?test=1 will generate a fake FAILED compose. # Passing ?test=2 will generate a fake FINISHED compose. @@ -1820,30 +1545,164 @@ def v0_compose_types(): """Return the list of enabled output types (only enabled types are returned) + + **/api/v0/compose/types** + + Returns the list of supported output types that are valid for use with 'POST /api/v0/compose' + + Example:: + + { + "types": [ + { + "enabled": true, + "name": "tar" + } + ] + } """ share_dir = api.config["COMPOSER_CFG"].get("composer", "share_dir") return jsonify(types=[{"name": k, "enabled": True} for k in compose_types(share_dir)]) @v0_api.route("/compose/queue") def v0_compose_queue(): - """Return the status of the new and running queues""" + """Return the status of the new and running queues + + **/api/v0/compose/queue** + + Return the status of the build queue. It includes information about the builds waiting, + and the build that is running. + + Example:: + + { + "new": [ + { + "id": "45502a6d-06e8-48a5-a215-2b4174b3614b", + "blueprint": "glusterfs", + "queue_status": "WAITING", + "job_created": 1517362647.4570868, + "version": "0.0.6" + }, + { + "id": "6d292bd0-bec7-4825-8d7d-41ef9c3e4b73", + "blueprint": "kubernetes", + "queue_status": "WAITING", + "job_created": 1517362659.0034983, + "version": "0.0.1" + } + ], + "run": [ + { + "id": "745712b2-96db-44c0-8014-fe925c35e795", + "blueprint": "glusterfs", + "queue_status": "RUNNING", + "job_created": 1517362633.7965999, + "job_started": 1517362633.8001345, + "version": "0.0.6" + } + ] + } + """ return jsonify(queue_status(api.config["COMPOSER_CFG"])) @v0_api.route("/compose/finished") def v0_compose_finished(): - """Return the list of finished composes""" + """Return the list of finished composes + + **/api/v0/compose/finished** + + Return the details on all of the finished composes on the system. + + Example:: + + { + "finished": [ + { + "id": "70b84195-9817-4b8a-af92-45e380f39894", + "blueprint": "glusterfs", + "queue_status": "FINISHED", + "job_created": 1517351003.8210032, + "job_started": 1517351003.8230415, + "job_finished": 1517359234.1003145, + "version": "0.0.6" + }, + { + "id": "e695affd-397f-4af9-9022-add2636e7459", + "blueprint": "glusterfs", + "queue_status": "FINISHED", + "job_created": 1517362289.7193348, + "job_started": 1517362289.9751132, + "job_finished": 1517363500.1234567, + "version": "0.0.6" + } + ] + } + """ return jsonify(finished=build_status(api.config["COMPOSER_CFG"], "FINISHED")) @v0_api.route("/compose/failed") def v0_compose_failed(): - """Return the list of failed composes""" + """Return the list of failed composes + + **/api/v0/compose/failed** + + Return the details on all of the failed composes on the system. + + Example:: + + { + "failed": [ + { + "id": "8c8435ef-d6bd-4c68-9bf1-a2ef832e6b1a", + "blueprint": "http-server", + "queue_status": "FAILED", + "job_created": 1517523249.9301329, + "job_started": 1517523249.9314211, + "job_finished": 1517523255.5623411, + "version": "0.0.2" + } + ] + } + """ return jsonify(failed=build_status(api.config["COMPOSER_CFG"], "FAILED")) @v0_api.route("/compose/status", defaults={'uuids': ""}) @v0_api.route("/compose/status/") @checkparams([("uuids", "", "no UUIDs given")]) def v0_compose_status(uuids): - """Return the status of the listed uuids""" + """Return the status of the listed uuids + + **/api/v0/compose/status/[?blueprint=&status=&type=]** + + Return the details for each of the comma-separated list of uuids. A uuid of '*' will return + details for all composes. + + Example:: + + { + "uuids": [ + { + "id": "8c8435ef-d6bd-4c68-9bf1-a2ef832e6b1a", + "blueprint": "http-server", + "queue_status": "FINISHED", + "job_created": 1517523644.2384307, + "job_started": 1517523644.2551234, + "job_finished": 1517523689.9864314, + "version": "0.0.2" + }, + { + "id": "45502a6d-06e8-48a5-a215-2b4174b3614b", + "blueprint": "glusterfs", + "queue_status": "FINISHED", + "job_created": 1517363442.188399, + "job_started": 1517363442.325324, + "job_finished": 1517363451.653621, + "version": "0.0.6" + } + ] + } + """ if VALID_API_STRING.match(uuids) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1886,7 +1745,20 @@ def v0_compose_status(uuids): @v0_api.route("/compose/cancel/", methods=["DELETE"]) @checkparams([("uuid", "", "no UUID given")]) def v0_compose_cancel(uuid): - """Cancel a running compose and delete its results directory""" + """Cancel a running compose and delete its results directory + + **DELETE /api/v0/compose/cancel/** + + Cancel the build, if it is not finished, and delete the results. It will return a + status of True if it is successful. + + Example:: + + { + "status": true, + "uuid": "03397f8d-acff-4cdb-bd31-f629b7a948f5" + } + """ if VALID_API_STRING.match(uuid) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1908,7 +1780,24 @@ def v0_compose_cancel(uuid): @v0_api.route("/compose/delete/", methods=["DELETE"]) @checkparams([("uuids", "", "no UUIDs given")]) def v0_compose_delete(uuids): - """Delete the compose results for the listed uuids""" + """Delete the compose results for the listed uuids + + **DELETE /api/v0/compose/delete/** + + Delete the list of comma-separated uuids from the compose results. + + Example:: + + { + "errors": [], + "uuids": [ + { + "status": true, + "uuid": "ae1bf7e3-7f16-4c9f-b36e-3726a1093fd0" + } + ] + } + """ if VALID_API_STRING.match(uuids) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1933,7 +1822,53 @@ def v0_compose_delete(uuids): @v0_api.route("/compose/info/") @checkparams([("uuid", "", "no UUID given")]) def v0_compose_info(uuid): - """Return detailed info about a compose""" + """Return detailed info about a compose + + **/api/v0/compose/info/** + + Get detailed information about the compose. The returned JSON string will + contain the following information: + + * id - The uuid of the comoposition + * config - containing the configuration settings used to run Anaconda + * blueprint - The depsolved blueprint used to generate the kickstart + * commit - The (local) git commit hash for the blueprint used + * deps - The NEVRA of all of the dependencies used in the composition + * compose_type - The type of output generated (tar, iso, etc.) + * queue_status - The final status of the composition (FINISHED or FAILED) + + Example:: + + { + "commit": "7078e521a54b12eae31c3fd028680da7a0815a4d", + "compose_type": "tar", + "config": { + "anaconda_args": "", + "armplatform": "", + "compress_args": [], + "compression": "xz", + "image_name": "root.tar.xz", + ... + }, + "deps": { + "packages": [ + { + "arch": "x86_64", + "epoch": "0", + "name": "acl", + "release": "14.el7", + "version": "2.2.51" + } + ] + }, + "id": "c30b7d80-523b-4a23-ad52-61b799739ce8", + "queue_status": "FINISHED", + "blueprint": { + "description": "An example kubernetes master", + ... + } + } + """ if VALID_API_STRING.match(uuid) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1951,7 +1886,19 @@ def v0_compose_info(uuid): @v0_api.route("/compose/metadata/") @checkparams([("uuid","", "no UUID given")]) def v0_compose_metadata(uuid): - """Return a tar of the metadata for the build""" + """Return a tar of the metadata for the build + + **/api/v0/compose/metadata/** + + Returns a .tar of the metadata used for the build. This includes all the + information needed to reproduce the build, including the final kickstart + populated with repository and package NEVRA. + + The mime type is set to 'application/x-tar' and the filename is set to + UUID-metadata.tar + + The .tar is uncompressed, but is not large. + """ if VALID_API_STRING.match(uuid) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1970,7 +1917,18 @@ def v0_compose_metadata(uuid): @v0_api.route("/compose/results/") @checkparams([("uuid","", "no UUID given")]) def v0_compose_results(uuid): - """Return a tar of the metadata and the results for the build""" + """Return a tar of the metadata and the results for the build + + **/api/v0/compose/results/** + + Returns a .tar of the metadata, logs, and output image of the build. This + includes all the information needed to reproduce the build, including the + final kickstart populated with repository and package NEVRA. The output image + is already in compressed form so the returned tar is not compressed. + + The mime type is set to 'application/x-tar' and the filename is set to + UUID.tar + """ if VALID_API_STRING.match(uuid) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -1989,7 +1947,16 @@ def v0_compose_results(uuid): @v0_api.route("/compose/logs/") @checkparams([("uuid","", "no UUID given")]) def v0_compose_logs(uuid): - """Return a tar of the metadata for the build""" + """Return a tar of the metadata for the build + + **/api/v0/compose/logs/** + + Returns a .tar of the anaconda build logs. The tar is not compressed, but is + not large. + + The mime type is set to 'application/x-tar' and the filename is set to + UUID-logs.tar + """ if VALID_API_STRING.match(uuid) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -2008,7 +1975,13 @@ def v0_compose_logs(uuid): @v0_api.route("/compose/image/") @checkparams([("uuid","", "no UUID given")]) def v0_compose_image(uuid): - """Return the output image for the build""" + """Return the output image for the build + + **/api/v0/compose/image/** + + Returns the output image from the build. The filename is set to the filename + from the build with the UUID as a prefix. eg. UUID-root.tar.xz or UUID-boot.iso. + """ if VALID_API_STRING.match(uuid) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 @@ -2033,7 +2006,32 @@ def v0_compose_image(uuid): @v0_api.route("/compose/log/") @checkparams([("uuid","", "no UUID given")]) def v0_compose_log_tail(uuid): - """Return the end of the main anaconda.log, defaults to 1Mbytes""" + """Return the end of the main anaconda.log, defaults to 1Mbytes + + **/api/v0/compose/log/[?size=kbytes]** + + Returns the end of the anaconda.log. The size parameter is optional and defaults to 1Mbytes + if it is not included. The returned data is raw text from the end of the logfile, starting on + a line boundry. + + Example:: + + 12:59:24,222 INFO anaconda: Running Thread: AnaConfigurationThread (140629395244800) + 12:59:24,223 INFO anaconda: Configuring installed system + 12:59:24,912 INFO anaconda: Configuring installed system + 12:59:24,912 INFO anaconda: Creating users + 12:59:24,913 INFO anaconda: Clearing libuser.conf at /tmp/libuser.Dyy8Gj + 12:59:25,154 INFO anaconda: Creating users + 12:59:25,155 INFO anaconda: Configuring addons + 12:59:25,155 INFO anaconda: Configuring addons + 12:59:25,155 INFO anaconda: Generating initramfs + 12:59:49,467 INFO anaconda: Generating initramfs + 12:59:49,467 INFO anaconda: Running post-installation scripts + 12:59:49,467 INFO anaconda: Running kickstart %%post script(s) + 12:59:50,782 INFO anaconda: All kickstart %%post script(s) have been run + 12:59:50,782 INFO anaconda: Running post-installation scripts + 12:59:50,784 INFO anaconda: Thread Done: AnaConfigurationThread (140629395244800) + """ if VALID_API_STRING.match(uuid) is None: return jsonify(status=False, errors=[{"id": INVALID_CHARS, "msg": "Invalid characters in API path"}]), 400 diff --git a/src/pylorax/ltmpl.py b/src/pylorax/ltmpl.py index ae70a021..88ec9a21 100644 --- a/src/pylorax/ltmpl.py +++ b/src/pylorax/ltmpl.py @@ -116,6 +116,7 @@ class TemplateRunner(object): # install a bunch of packages runner = LoraxTemplateRunner(inroot=rundir, outroot=rundir, dbo=dnf_obj) runner.run("install-packages.ltmpl") + NOTES: * Parsing procedure is roughly: