Стефан Грабер (Stéphane Graber) опубликовал новый пост, но не в рамках обозначенной им серии из 12 статей. В отдельной статье рассказывается как дёргать за ниточки демона LXD и получить требуемое, а не люлей.
Доступ к LXD REST API можно получить через локальный unix сокет или через HTTPS. В обоих случаях протокол идентичен, за исключением того, что через сокет идёт планарный текст с авторизацией за счёт файловой системы.
Включаем прослушивание сети - lxc config set core.https_address "[::]:8443"
Для установления доверительных отношений требуется пароль - lxc config set core.trust_password some-random-password
Как сказано выше, сокет не потребует аутентификации, поэтому curl'ом делаем так:
curl --unix-socket /var/lib/lxd/unix.socket s/
{"type":"sync","status":"Success","status_code":200,"metadata":["/1.0"]}
Не очень читабельно, но jq исправит
curl -s --unix-socket /var/lib/lxd/unix.socket s/ | jq .
{ "type": "sync", "status": "Success", "status_code": 200, "metadata": [ "/1.0" ] }
REST API проводит проверку с помощью сертификатов. LXD генерирует один при первом использовании командной строки, но можно создать с помощью OpenSSL, если хотите.
Сначала убедимся, что сертификат не является доверенным:
curl -s -k --cert ~/.config/lxc/client.crt --key ~/.config/lxc/client.key https://127.0.0.1:8443/1.0 | jq .metadata.auth
"untrusted"
Теперь скажем серверу, что мы знаем пароль и пусть добавит нас.
curl -s -k --cert ~/.config/lxc/client.crt --key ~/.config/lxc/client.key https://127.0.0.1:8443/1.0/certificates -X POST -d '{"type": "client", "password": "some-password"}' | jq .
{ "type": "sync", "status": "Success", "status_code": 200, "metadata": {} }
Проверим что нас аутентифицировали:
curl -s -k --cert ~/.config/lxc/client.crt --key ~/.config/lxc/client.key https://127.0.0.1:8443/1.0 | jq .metadata.auth
"trusted"
Убедитесь, что выглядит всё также как через сокет:
curl -s -k --cert ~/.config/lxc/client.crt --key ~/.config/lxc/client.key https://127.0.0.1:8443/ | jq .
{ "type": "sync", "status": "Success", "status_code": 200, "metadata": [ "/1.0" ] }
Чтобы команды выглядели покороче и нагляднее, примеры будут даны, используя сокеты. Но если дополнить команды, как дано выше, то всё работает и через HTTPS. Так же нужно предоставлять сертификат, чтобы подтверждать что вы не "человек по середине".
Вы можете получить в режиме реалтайм информацию о сервере:
curl -s --unix-socket /var/lib/lxd/unix.socket a/1.0 | jq .
{ "type": "sync", "status": "Success", "status_code": 200, "metadata": { "api_extensions": [], "api_status": "stable", "api_version": "1.0", "auth": "trusted", "config": { "core.https_address": "[::]:8443", "core.trust_password": true, "storage.zfs_pool_name": "encrypted/lxd" }, "environment": { "addresses": [ "192.168.54.140:8443", "10.212.54.1:8443", "[2001:470:b368:4242::1]:8443" ], "architectures": [ "x86_64", "i686" ], "certificate": "BIG PEM BLOB", "driver": "lxc", "driver_version": "2.0.0", "kernel": "Linux", "kernel_architecture": "x86_64", "kernel_version": "4.4.0-18-generic", "server": "lxd", "server_pid": 26227, "server_version": "2.0.0", "storage": "zfs", "storage_version": "5" }, "public": false } }
Все секции, что получили выше, доступны вам только на чтение, кроме секции config. Для примера отменим доверительный пароль (trust password) и скажем LXD не слушать больше сеть через HTTPS.
curl -s --unix-socket /var/lib/lxd/unix.socket -X PUT -d '{"config": {"storage.zfs_pool_name": "encrypted/lxd"}}' a/1.0 | jq .
{ "type": "sync", "status": "Success", "status_code": 200, "metadata": {} }
Для всего что может занять больше 1 секунды, LXD использует операции в фоне. Это позволяет клиенту легко сделать параллельно множество запросов и не плодить множество соединений к серверу.
Список всех текущих операций:
curl -s --unix-socket /var/lib/lxd/unix.socket a/1.0/operations | jq .
{ "type": "sync", "status": "Success", "status_code": 200, "metadata": { "running": [ "/1.0/operations/008bc02e-21a0-4070-a28c-633b79a46517" ] } }
Чуть подробнее про операцию
curl -s --unix-socket /var/lib/lxd/unix.socket a/1.0/operations/008bc02e-21a0-4070-a28c-633b79a46517 | jq .
{ "type": "sync", "status": "Success", "status_code": 200, "metadata": { "id": "008bc02e-21a0-4070-a28c-633b79a46517", "class": "task", "created_at": "2016-04-18T22:24:54.469437937+01:00", "updated_at": "2016-04-18T22:25:22.42813972+01:00", "status": "Running", "status_code": 103, "resources": { "containers": [ "/1.0/containers/blah" ] }, "metadata": { "download_progress": "48%" }, "may_cancel": false, "err": "" } }
В примере мы создали контейнер blah и его образ должен скачаться, что требует времени.
Можно "подписаться" на уведомления, используя /1.0/events веб-сокет. Если ваш клиент не очень умный, то можно сделать так:
curl -s --unix-socket /var/lib/lxd/unix.socket a/1.0/operations/b1f57056-c79b-4d3c-94bf-50b5c47a85ad/wait | jq .
Вам будет, как описано выше, постоянно печататься статус операции, пока она не выполнится успешно, прервётся с ошибкой или не будет отменена.
REST API обладает пунктами, доступными вам.
Детальная информация для различных действий доступна в rest-api.md
Давайте сосредоточимся на основных вещах при работе с контейнером: его создание, старт, правка файлов в нём, создание снимка и удаление контейнера.
Для создания контейнера xenial из образа Ubuntu 16.04 нужно запустить - curl -s --unix-socket /var/lib/lxd/unix.socket -X POST -d '{"name": "xenial", "source": {"type": "image", "protocol": "simplestreams", "server": "https://cloud-images.ubuntu.com/daily", "alias": "16.04"}}' a/1.0/containers | jq .
{ "type": "async", "status": "Operation created", "status_code": 100, "metadata": { "id": "e2714931-470e-452a-807c-c1be19cdff0d", "class": "task", "created_at": "2016-04-18T22:36:20.935649438+01:00", "updated_at": "2016-04-18T22:36:20.935649438+01:00", "status": "Running", "status_code": 103, "resources": { "containers": [ "/1.0/containers/xenial" ] }, "metadata": null, "may_cancel": false, "err": "" }, "operation": "/1.0/operations/e2714931-470e-452a-807c-c1be19cdff0d" }
Можно проследить за прогрессом операции:
curl -s --unix-socket /var/lib/lxd/unix.socket a/1.0/operations/e2714931-470e-452a-807c-c1be19cdff0d | jq .
{ "type": "sync", "status": "Success", "status_code": 200, "metadata": { "id": "e2714931-470e-452a-807c-c1be19cdff0d", "class": "task", "created_at": "2016-04-18T22:36:20.935649438+01:00", "updated_at": "2016-04-18T22:36:31.135038483+01:00", "status": "Running", "status_code": 103, "resources": { "containers": [ "/1.0/containers/xenial" ] }, "metadata": { "download_progress": "19%" }, "may_cancel": false, "err": "" } }
Давайте дождёмся операции до её завершения:
curl -s --unix-socket /var/lib/lxd/unix.socket a/1.0/operations/e2714931-470e-452a-807c-c1be19cdff0d/wait | jq .
{ "type": "sync", "status": "Success", "status_code": 200, "metadata": { "id": "e2714931-470e-452a-807c-c1be19cdff0d", "class": "task", "created_at": "2016-04-18T22:36:20.935649438+01:00", "updated_at": "2016-04-18T22:38:01.385511623+01:00", "status": "Success", "status_code": 200, "resources": { "containers": [ "/1.0/containers/xenial" ] }, "metadata": { "download_progress": "100%" }, "may_cancel": false, "err": "" } }
Запуск контейнера осуществляется модификацией его состояния:
curl -s --unix-socket /var/lib/lxd/unix.socket -X PUT -d '{"action": "start"}' a/1.0/containers/xenial/state | jq .
{
{ "type": "async", "status": "Operation created", "status_code": 100, "metadata": { "id": "614ac9f0-f0fc-4351-9e6f-14710fd93542", "class": "task", "created_at": "2016-04-18T22:39:42.766830946+01:00", "updated_at": "2016-04-18T22:39:42.766830946+01:00", "status": "Running", "status_code": 103, "resources": { "containers": [ "/1.0/containers/xenial" ] }, "metadata": null, "may_cancel": false, "err": "" }, "operation": "/1.0/operations/614ac9f0-f0fc-4351-9e6f-14710fd93542" }
Если вы выполните вышеописанную команду, то нет никакого способа получить доступ к операции или ожидать её, так как она быстро промелькнёт и данные по операции пропадут через 5 секунд.
Вы можете проверить текущий статус контейнера:
curl -s --unix-socket /var/lib/lxd/unix.socket -X GET a/1.0/containers/xenial/state | jq .metadata.status
"Running"
Или получить IP адрес:
curl -s --unix-socket /var/lib/lxd/unix.socket -X GET a/1.0/containers/xenial/state | jq .metadata.network.eth0.addresses
[ { "family": "inet", "address": "10.212.54.43", "netmask": "24", "scope": "global" }, { "family": "inet6", "address": "2001:470:b368:4242:216:3eff:fe17:331c", "netmask": "64", "scope": "global" }, { "family": "inet6", "address": "fe80::216:3eff:fe17:331c", "netmask": "64", "scope": "link" } ]
Чтение файла внутри контейнера очень простая операция:
curl -s --unix-socket /var/lib/lxd/unix.socket -X GET a/1.0/containers/xenial/files?path=/etc/hosts
127.0.0.1 localhost # The following lines are desirable for IPv6 capable hosts ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts
Чтобы положить файл внутрь контейнера нужно заполнить Content-Type:
curl -s --unix-socket /var/lib/lxd/unix.socket -X POST -H "Content-Type: application/octet-stream" -d 'abc' a/1.0/containers/xenial/files?path=/tmp/a
{"type":"sync","status":"Success","status_code":200,"metadata":{}}
Давайте проверим:
curl -s --unix-socket /var/lib/lxd/unix.socket -X GET a/1.0/containers/xenial/files?path=/tmp/a
abc
Сделать снимок контейнера можно так:
curl -s --unix-socket /var/lib/lxd/unix.socket -X POST -d '{"name": "my-snapshot"}' a/1.0/containers/xenial/snapshots | jq .
{ "type": "async", "status": "Operation created", "status_code": 100, "metadata": { "id": "d68141de-0c13-419c-a21c-13e30de29154", "class": "task", "created_at": "2016-04-18T22:54:04.148986484+01:00", "updated_at": "2016-04-18T22:54:04.148986484+01:00", "status": "Running", "status_code": 103, "resources": { "containers": [ "/1.0/containers/xenial" ] }, "metadata": null, "may_cancel": false, "err": "" }, "operation": "/1.0/operations/d68141de-0c13-419c-a21c-13e30de29154" }
Можно получить больше информации о созданном снимке:
curl -s --unix-socket /var/lib/lxd/unix.socket -X GET a/1.0/containers/xenial/snapshots/my-snapshot | jq .
{ "type": "sync", "status": "Success", "status_code": 200, "metadata": { "architecture": "x86_64", "config": { "volatile.base_image": "0b06c2858e2efde5464906c93eb9593a29bf46d069cf8d007ada81e5ab80613c", "volatile.eth0.hwaddr": "00:16:3e:17:33:1c", "volatile.last_state.idmap": "[{"Isuid":true,"Isgid":false,"Hostid":100000,"Nsid":0,"Maprange":65536}, {"Isuid":false,"Isgid":true,"Hostid":100000,"Nsid":0,"Maprange":65536}]" }, "created_at": "2016-04-18T21:54:04Z", "devices": { "root": { "path": "/", "type": "disk" } }, "ephemeral": false, "expanded_config": { "volatile.base_image": "0b06c2858e2efde5464906c93eb9593a29bf46d069cf8d007ada81e5ab80613c", "volatile.eth0.hwaddr": "00:16:3e:17:33:1c", "volatile.last_state.idmap": "[{"Isuid":true,"Isgid":false,"Hostid":100000,"Nsid":0,"Maprange":65536}, {"Isuid":false,"Isgid":true,"Hostid":100000,"Nsid":0,"Maprange":65536}]" }, "expanded_devices": { "eth0": { "name": "eth0", "nictype": "bridged", "parent": "lxdbr0", "type": "nic" }, "root": { "path": "/", "type": "disk" } }, "name": "xenial/my-snapshot", "profiles": [ "default" ], "stateful": false } }
Вы не можете удалить запущенный контейнер, так что сначала нужно его остановить:
curl -s --unix-socket /var/lib/lxd/unix.socket -X PUT -d '{"action": "stop", "force": true}' a/1.0/containers/xenial/state | jq .
{ "type": "async", "status": "Operation created", "status_code": 100, "metadata": { "id": "97945ec9-f9b0-4fa8-aaba-06e41a9bc2a9", "class": "task", "created_at": "2016-04-18T22:56:18.28952729+01:00", "updated_at": "2016-04-18T22:56:18.28952729+01:00", "status": "Running", "status_code": 103, "resources": { "containers": [ "/1.0/containers/xenial" ] }, "metadata": null, "may_cancel": false, "err": "" }, "operation": "/1.0/operations/97945ec9-f9b0-4fa8-aaba-06e41a9bc2a9" }
Теперь можно удалять:
curl -s --unix-socket /var/lib/lxd/unix.socket -X DELETE a/1.0/containers/xenial | jq .
{ "type": "async", "status": "Operation created", "status_code": 100, "metadata": { "id": "439bf4a1-e056-4b76-86ad-bff06169fce1", "class": "task", "created_at": "2016-04-18T22:56:22.590239576+01:00", "updated_at": "2016-04-18T22:56:22.590239576+01:00", "status": "Running", "status_code": 103, "resources": { "containers": [ "/1.0/containers/xenial" ] }, "metadata": null, "may_cancel": false, "err": "" }, "operation": "/1.0/operations/439bf4a1-e056-4b76-86ad-bff06169fce1" }
Подверимся с другой стороны:
curl -s --unix-socket /var/lib/lxd/unix.socket a/1.0/containers/xenial | jq .
{ "error": "not found", "error_code": 404, "type": "error" }
LXD API разработан быть простым и мощным одновременно. Его легко использовать даже простыми клиентами, но LXD поддерживает и расширенные функции для продвинутых клиентов, чтобы они были очень эффективны. REST API стабилен, то есть изменения будут полностью обратно совместимы, как это было с LXD 2.0. Делаются только дополнения, а не удаление или изменение поведения для существующих пунктов. Поддержка новых возможностей осуществляется клиентом при просмотре списка api_extensions. Сейчас это не рекламируется, но вскоре будет использоваться более активно.
Дата последней правки: 2023-12-27 16:49:49