Возможности API
Документация API для внешней интеграции доступна в интерфейсе Deckhouse Commander в меню настроек в правом верхнем углу.
Для того чтобы использовать это API, нужно выпустить токен. Токен также выпускается в интерфейсе
Deckhouse Commander. Токен нужно передавать в заголовке X-Auth-Token
.
Что доступно в API
- Чтение шаблонов кластеров
GET /api/v1/cluster_templates
GET /api/v1/cluster_templates/:id
- Чтение каталогов инвентаря
GET /api/v1/catalogs
GET /api/v1/catalogs/:id
- Создание, изменение, удаление кластеров
POST /api/v1/clusters
GET /api/v1/clusters
GET /api/v1/clusters/:id
PUT /api/v1/clusters/:id
DELETE /api/v1/clusters/:id
- Создание, изменение, удаление записей в каталогах
POST /api/v1/records
GET /api/v1/records
GET /api/v1/records/:id
PUT /api/v1/records/:id
DELETE /api/v1/records/:id
Создание кластера с использованием записи из каталога
Получение актуальной версии шаблона
Чтобы создать кластер, нам нужен ID версии шаблона. Мы возьмем последнюю версию, которая
записана в шаблоне в поле current_cluster_template_version_id
. Тело версий шаблона громоздкое,
поэтому опустим вывод версий:
1curl -s -X 'GET' \
2 "https://$COMMANDER_HOST/api/v1/cluster_templates/$TEMPLATE_ID?without_archived=true" \
3 -H 'accept: application/json' \
4 -H "X-Auth-Token: $COMMANDER_TOKEN" |
5 jq -r 'del(.cluster_template_versions)'
Нас интересует поле current_cluster_template_version_id
:
1{
2 "id": "fb999a72-efe7-4db7-af53-11b17bc0a687",
3 "name": "YC Dev",
4 "current_cluster_template_version_id": "8e75210a-f05c-421d-84b3-fc0697814d6d",
5 "comment": "Канал обновлений и версия k8s задаются",
6 "current_revision": 12,
7 "immutable": false,
8 "created_at": "2024-02-05T17:35:44.318+03:00",
9 "updated_at": "2024-04-10T18:00:57.835+03:00",
10 "archived_at": null,
11 "archive_number": null
12}
1TEMPLATE_VERSION_ID="$(curl -s -X 'GET' \
2 "https://$COMMANDER_HOST/api/v1/cluster_templates/$TEMPLATE_ID?without_archived=true" \
3 -H 'accept: application/json' \
4 -H "X-Auth-Token: $COMMANDER_TOKEN" |
5 jq -r '.current_cluster_template_version_id')"
Получение записи для входных параметров
Получим схему входных параметров и убедимся, что среди них есть запись из каталога yandex-cloud-slot
1curl -s -X 'GET' \
2 "https://$COMMANDER_HOST/api/v1/cluster_templates/$TEMPLATE_ID?without_archived=true" \
3 -H 'accept: application/json' \
4 -H "X-Auth-Token: $COMMANDER_TOKEN" |
5 jq -r --arg templ_version "$TEMPLATE_VERSION_ID" '
6 .cluster_template_versions[]
7 | select(.id == $templ_version)
8 | .params'
Рассмотрим схему входных параметров шаблона, она же — схема параметров кластера. Схема
предусматривает три обязательных параметра среди которых запись из каталога yandex-cloud-slot
(параметр slot
, свойство catalog
):
1[
2 {
3 "header": "Параметры кластера"
4 },
5 {
6 "key": "slot",
7 "span": 4,
8 "title": "Слот для кластера в Yandex Cloud",
9 "catalog": "yandex-cloud-slot",
10 "immutable": true
11 },
12 {
13 "key": "releaseChannel",
14 "enum": [ "Alpha", "Beta", "EarlyAccess", "Stable", "RockSolid" ],
15 "span": 1,
16 "title": "Канал обновлений",
17 "default": "EarlyAccess"
18 },
19 {
20 "key": "kubeVersion",
21 "enum": [ "Automatic", "1.25", "1.26", "1.27", "1.28", "1.29" ],
22 "span": 1,
23 "title": "Версия Kubernetes",
24 "default": "Automatic"
25 }
26]
Найдем запись из этого каталога. Для начала определим ID каталога по его идентификатору (slug).
1CATALOG_ID="$(curl -s -X 'GET' \
2 "https://$COMMANDER_HOST/api/v1/catalogs?without_archived=true" \
3 -H 'accept: application/json' \
4 -H "X-Auth-Token: $COMMANDER_TOKEN" |
5 jq -r '.[] | select(.slug == "yandex-cloud-slot") | .id')"
Теперь выберем первую попавшуюся запись из этого каталога, который еще не занят другим кластером.
Эту запись нужно подготовить к использованию в кластере. Для записи необходимо помимо значений
указать его ID в специальном поле x-commander-record-id
. Это поле названо так, чтобы не вводить
ограничение на поле id
, которое может потребоваться пользователям в самих записях:
1SLOT_RECORD="$(curl -s -X 'GET' \
2 "https://$COMMANDER_HOST/api/v1/records?without_archived=true" \
3 -H 'accept: application/json' \
4 -H "X-Auth-Token: $COMMANDER_TOKEN" |
5 jq -rc --arg catalog_id "$CATALOG_ID" '[
6 .[] |
7 select(
8 .catalog_id == $catalog_id
9 and
10 .cluster_id == null
11 )
12 ][0]
13 | .values + { "x-commander-record-id": .id }')"
Полученная структура:
1{
2 "ip": "158.166.177.188",
3 "name": "x",
4 "x-commander-record-id": "5f6727e7-630c-4b18-bcf0-868ea96a27ee"
5}
Создание кластера
Теперь можем создать кластер:
1PAYLOAD="$(jq -nc --argjson slot "$SLOT_RECORD" '{
2 "name": "Кластер из API",
3 "cluster_template_version_id": "8e75210a-f05c-421d-84b3-fc0697814d6d",
4 "values": {
5 "kubeVersion": "1.29",
6 "releaseChannel": "EarlyAccess",
7 "slot": $slot
8 }
9}')"
10curl -v -X 'POST' \
11 "https://$COMMANDER_HOST/api/v1/clusters" \
12 -H 'accept: application/json' \
13 -H "X-Auth-Token: $COMMANDER_TOKEN" \
14 -H 'Content-Type: application/json' \
15 -d "'$PAYLOAD'"
16
17
18
19curl -v -X 'POST' \
20 "https://$COMMANDER_HOST/api/v1/clusters" \
21 -H 'accept: application/json' \
22 -H "X-Auth-Token: $COMMANDER_TOKEN" \
23 -H 'Content-Type: application/json' \
24 -d '{"name":"Кластер из API","cluster_template_version_id":"8e75210a-f05c-421d-84b3-fc0697814d6d","values":{"kubeVersion":"1.29","releaseChannel":"EarlyAccess","slot":{"ip":"158.160.110.223","name":"b","x-commander-record-id":"5f6727e7-630c-4b18-bcf0-868ea96a27ee"}}}'
25
26
27
28{
29 "name": "Кластер из API",
30 "cluster_template_version_id": "8e75210a-f05c-421d-84b3-fc0697814d6d",
31 "values": {
32 "kubeVersion": "1.29",
33 "releaseChannel": "EarlyAccess",
34 "slot": {
35 "x-commander-record-id": "5f6727e7-630c-4b18-bcf0-868ea96a27ee",
36 "ip": "158.166.177.188",
37 "name": "x"
38 }
39 }
40}
41
42"'" "$(jq -n --argjson slot "$SLOT_RECORD" '{
43 "name": "Кластер из API",
44 "cluster_template_version_id": "8e75210a-f05c-421d-84b3-fc0697814d6d",
45 "values": {
46 "kubeVersion": "1.29",
47 "releaseChannel": "EarlyAccess",
48 "slot": $slot
49 }
50 }')" "'"
В ответ на запрос создания придут данные кластера. Часть полей в примере ниже мы опустили для краткости, в том числе отрендеренную конфигурацию:
1{
2 "id": "5436e6ef-d811-472f-9c9c-46cb9c6321d9",
3 "name": "Кластер из API",
4 "values": {
5 "slot": {
6 "ip": "158.166.177.188",
7 "name": "x",
8 "x-commander-record-id": "5f6727e7-630c-4b18-bcf0-868ea96a27ee"
9 },
10 "kubeVersion": "1.29",
11 "releaseChannel": "EarlyAccess"
12 },
13 "cluster_template_version_id": "8e75210a-f05c-421d-84b3-fc0697814d6d",
14 "was_created": false,
15 "status": "new"
16}
Теперь проследим процесс создания кластера. Мы должны дождаться статуса in_sync
:
1cluster_status="$(curl -s -X 'GET' \
2 "https://$COMMANDER_HOST/api/v1/clusters/5436e6ef-d811-472f-9c9c-46cb9c6321d9" \
3 -H 'accept: application/json' \
4 -H "X-Auth-Token: $COMMANDER_TOKEN" |
5 jq -r '.status')"
6
7while [ "in_sync" != "$cluster_status" ]
8do
9 cluster_status="$(curl -s -X 'GET' \
10 "https://$COMMANDER_HOST/api/v1/clusters/5436e6ef-d811-472f-9c9c-46cb9c6321d9" \
11 -H 'accept: application/json' \
12 -H "X-Auth-Token: $COMMANDER_TOKEN" |
13 jq -r '.status')"
14 echo $cluster_status
15 sleep 5
16done
17
18creating
19creating
20creating
21creating
22creating
23creating
24creating
25creating
26creating
27creating
28creating
29creating
30creating
31creating
32creating
33creating
34# ...
35in_sync
Удаление кластера
Если кластер больше не нужен, его можно удалить. В ответ придет состояние кластера, но уже со
статусом delete
.
1curl -s -X 'DELETE' \
2 "https://$COMMANDER_HOST/api/v1/clusters/5436e6ef-d811-472f-9c9c-46cb9c6321d9" \
3 -H 'accept: application/json' \
4 -H "X-Auth-Token: $COMMANDER_TOKEN"
5
6{
7 "id": "5436e6ef-d811-472f-9c9c-46cb9c6321d9",
8 "current_revision": 1834,
9 "name": "Кластер из API",
10 "values": {
11 "slot": {
12 "ip": "158.166.177.188",
13 "name": "x",
14 "x-commander-record-id": "5f6727e7-630c-4b18-bcf0-868ea96a27ee"
15 },
16 "kubeVersion": "1.29",
17 "createWorker": true,
18 "releaseChannel": "EarlyAccess",
19 "installResources": true
20 },
21 "cluster_template_version_id": "8e75210a-f05c-421d-84b3-fc0697814d6d",
22 "cluster_template_version_switched_at": "2024-04-24T21:40:35.222+03:00",
23 "created_at": "2024-04-24T21:40:35.525+03:00",
24 "updated_at": "2024-04-25T12:57:51.621+03:00",
25 "archived_at": null,
26 "archive_number": null,
27 "was_created": true,
28 "is_locked": true,
29 "cluster_type": "cloud",
30 "status": "delete",
31 "agent_status": null,
32 "agent_api_key": null,
33 "cluster_configuration_applied_at": "2024-04-24T22:10:57.191+03:00",
34 "cluster_configuration_checked_at": "2024-04-25T12:57:45.479+03:00",
35 "resources_sync_state": "no",
36 "resources_state_results": [
37 // ...
38 ],
39 "resources_checked_at": "2024-04-25T12:57:31.084+03:00",
40 "resources_applied_at": "2024-04-24T22:04:59.813+03:00",
41 "init_configuration_rendered": "...",
42 "init_resources_rendered": "...",
43 "dhctl_configuration_rendered": "...",
44 "applied_cluster_configuration_rendered": "...",
45 "applied_provider_specific_cluster_configuration_rendered": "...",
46 "applied_resources_rendered": "......",
47 "desired_cluster_configuration_rendered": "...",
48 "desired_provider_specific_cluster_configuration_rendered": "...",
49 "desired_resources_rendered": "......",
50 "render_errors": [],
51 "cluster_agent_data": [
52 // ...
53 ]
54}