Spec-Zone.ru › OpenTofu 1.11

Машиночитаемый интерфейс

По умолчанию многие команды OpenTofu отображают данные интерфейса в виде неструктурированного текста, предназначенного для чтения пользователем в эмуляторе терминала. Этот поток текста не является стабильным интерфейсом для интеграций. Некоторые команды поддерживают флаг -json, который включает режим структурированного вывода в формате JSON с определённым интерфейсом.

Для длительно выполняющихся команд, таких как plan, apply и refresh, флаг -json выводит поток сообщений интерфейса в формате JSON, по одному сообщению в строке. Их можно обрабатывать по одному сообщению, а интегрирующее программное обеспечение может фильтровать, объединять или изменять вывод по своему усмотрению.

Первое выводимое сообщение имеет тип version и содержит ключ ui со значением "1.0". Семантика этой версии такова:

  • Для обратно совместимых изменений и дополнений мы будем увеличивать младшую версию, например "1.1". Чтобы сохранить прямую совместимость с будущими младшими версиями, игнорируйте свойства объектов с неизвестными именами.
  • Для изменений, нарушающих обратную совместимость, мы будем увеличивать старшую версию, например "2.0". Отклоняйте любые входные данные, в которых указана неподдерживаемая старшая версия.

Мы будем вводить новые старшие версии только в рамках гарантий совместимости OpenTofu 1.0.

Пример вывода JSON​

Ниже приведён пример вывода команды tofu apply -json:

Блок кода
{"@level":"info","@message":"OpenTofu 1.6.0","@module":"tofu.ui","@timestamp":"2021-05-25T13:32:41.275359-04:00","tofu":"0.15.4","type":"version","ui":"0.1.0"}
{"@level":"info","@message":"random_pet.animal: Plan to create","@module":"tofu.ui","@timestamp":"2021-05-25T13:32:41.705503-04:00","change":{"resource":{"addr":"random_pet.animal","module":"","resource":"random_pet.animal","implied_provider":"random","resource_type":"random_pet","resource_name":"animal","resource_key":null},"action":"create"},"type":"planned_change"}
{"@level":"info","@message":"Plan: 1 to add, 0 to change, 0 to destroy.","@module":"tofu.ui","@timestamp":"2021-05-25T13:32:41.705638-04:00","changes":{"add":1,"change":0,"remove":0,"operation":"plan"},"type":"change_summary"}
{"@level":"info","@message":"random_pet.animal: Creating...","@module":"tofu.ui","@timestamp":"2021-05-25T13:32:41.825308-04:00","hook":{"resource":{"addr":"random_pet.animal","module":"","resource":"random_pet.animal","implied_provider":"random","resource_type":"random_pet","resource_name":"animal","resource_key":null},"action":"create"},"type":"apply_start"}
{"@level":"info","@message":"random_pet.animal: Creation complete after 0s [id=smart-lizard]","@module":"tofu.ui","@timestamp":"2021-05-25T13:32:41.826179-04:00","hook":{"resource":{"addr":"random_pet.animal","module":"","resource":"random_pet.animal","implied_provider":"random","resource_type":"random_pet","resource_name":"animal","resource_key":null},"action":"create","id_key":"id","id_value":"smart-lizard","elapsed_seconds":0},"type":"apply_complete"}
{"@level":"info","@message":"Apply complete! Resources: 1 added, 0 changed, 0 destroyed.","@module":"tofu.ui","@timestamp":"2021-05-25T13:32:41.869168-04:00","changes":{"add":1,"change":0,"remove":0,"operation":"apply"},"type":"change_summary"}
{"@level":"info","@message":"Outputs: 1","@module":"tofu.ui","@timestamp":"2021-05-25T13:32:41.869280-04:00","outputs":{"pets":{"sensitive":false,"type":"string","value":"smart-lizard"}},"type":"outputs"}

Каждая строка содержит объект JSON с несколькими ключами, общими для всех сообщений. Это:

  • @level: обычно имеет значение "info", но при отображении диагностических сообщений может иметь значение "error" или "warn"
  • @message: понятное человеку краткое описание содержимого этого сообщения
  • @module: при отображении вывода интерфейса всегда имеет значение "tofu.ui"
  • @timestamp: метка времени RFC3339, указывающая, когда было выведено сообщение
  • type: определяет тип сообщения и способ интерпретации других присутствующих ключей

Клиенты, отображающие журналы как пользовательский интерфейс, должны обрабатывать неожиданные типы сообщений, показывая пользователю как минимум поле @message.

Сообщения выводятся по мере возникновения соответствующих событий. Это означает, что сообщения, относящиеся к нескольким ресурсам, могут перемежаться (если OpenTofu выполняется с параллелизмом больше 1). Значение объекта resource можно использовать для связывания нескольких сообщений об одном ресурсе.

Типы сообщений​

Поддерживаются следующие типы сообщений:

Общие сообщения​

  • version: сведения о версии OpenTofu и версии схемы, используемой для следующих сообщений
  • log: неструктурированные понятные человеку строки журнала
  • diagnostic: диагностические предупреждения или сообщения об ошибках; подробнее о формате см. в документации tofu validate

Результаты операций​

  • resource_drift: описывает обнаруженное изменение отдельного ресурса, выполненное вне OpenTofu
  • planned_change: описывает запланированное изменение отдельного ресурса
  • change_summary: сводка всех запланированных или применённых изменений
  • outputs: список всех выходных данных корневого модуля

Ход выполнения операций с ресурсами​

  • apply_start, apply_progress, apply_complete, apply_errored: последовательность сообщений, показывающих ход применения изменений для отдельного ресурса
  • provision_start, provision_progress, provision_complete, provision_errored: последовательность сообщений, показывающих ход выполнения отдельного шага provisioner
  • refresh_start, refresh_complete: последовательность сообщений, показывающих ход обновления состояния отдельного ресурса

Сообщение о версии​

Вывод команды с машиночитаемым интерфейсом всегда начинается с сообщения version. Для этого типа сообщения определены следующие ключи:

  • tofu: версия OpenTofu, создавшая это сообщение
  • ui: версия схемы машиночитаемого интерфейса, определяющая значение последующих сообщений

Пример​

Блок кода
{
  "@level": "info",
  "@message": "OpenTofu 0.15.4",
  "@module": "tofu.ui",
  "@timestamp": "2021-05-25T13:32:41.275359-04:00",
  "tofu": "0.15.4",
  "type": "version",
  "ui": "0.1.0"
}

Расхождение состояния ресурса​

Если при планировании обнаружено расхождение состояния, OpenTofu выдаст сообщение resource_drift для каждого ресурса, изменённого вне OpenTofu. Это сообщение содержит встроенный объект change со следующими ключами:

  • resource: объект с описанием адреса изменяемого ресурса; подробности см. ниже в разделе «Объект ресурса»
  • action: действие, запланированное для ресурса. Значения: update, delete.

Это сообщение не содержит сведений о точных изменениях, из-за которых было запланировано изменение. Эта информация доступна в выводе плана в формате JSON.

Пример​

Блок кода
{
  "@level": "info",
  "@message": "random_pet.animal: Drift detected (update)",
  "@module": "tofu.ui",
  "@timestamp": "2021-05-25T13:32:41.705503-04:00",
  "change": {
    "resource": {
      "addr": "random_pet.animal",
      "module": "",
      "resource": "random_pet.animal",
      "implied_provider": "random",
      "resource_type": "random_pet",
      "resource_name": "animal",
      "resource_key": null
    },
    "action": "update"
  },
  "type": "resource_drift"
}

Запланированное изменение​

В конце планирования или перед применением изменений OpenTofu выдаст сообщение planned_change для каждого ресурса, изменения которого необходимо применить. Это сообщение содержит встроенный объект change со следующими ключами:

  • resource: объект с описанием адреса изменяемого ресурса; подробности см. ниже в разделе «Объект ресурса»
  • previous_resource: объект с описанием предыдущего адреса ресурса, если это изменение включает перемещение, заданное конфигурацией
  • action: действие, запланированное для ресурса. Значения: noop, create, read, update, replace, delete, move.
  • reason: необязательная причина изменения, указываемая только если действие — replace или delete. Значения:
    • tainted: ресурс помечен как повреждённый
    • requested: пользователь запросил замену ресурса, например с помощью флага плана -replace
    • cannot_update: изменения конфигурации требуют удалить и создать ресурс вместо его обновления
    • delete_because_no_resource_config: в конфигурации нет соответствующего ресурса
    • delete_because_wrong_repetition: ключ экземпляра ресурса не соответствует count или for_each в конфигурации
    • delete_because_count_index: ключ экземпляра ресурса выходит за пределы диапазона аргумента count
    • delete_because_each_key: ключ экземпляра ресурса не включён в аргумент for_each
    • delete_because_no_module: содержащий его экземпляр модуля отсутствует в конфигурации

Это сообщение не содержит сведений о точных изменениях, из-за которых было запланировано изменение. Эта информация доступна в выводе плана в формате JSON.

Пример​

Блок кода
{
  "@level": "info",
  "@message": "random_pet.animal: Plan to create",
  "@module": "tofu.ui",
  "@timestamp": "2021-05-25T13:32:41.705503-04:00",
  "change": {
    "resource": {
      "addr": "random_pet.animal",
      "module": "",
      "resource": "random_pet.animal",
      "implied_provider": "random",
      "resource_type": "random_pet",
      "resource_name": "animal",
      "resource_key": null
    },
    "action": "create"
  },
  "type": "planned_change"
}

Сводка изменений​

По завершении операции планирования или применения OpenTofu выводит сводку изменений. Оба типа сообщений содержат объект changes со следующими ключами:

  • add: количество создаваемых ресурсов (в том числе при замене)
  • change: количество ресурсов, изменяемых на месте
  • remove: количество удаляемых ресурсов (в том числе при замене)
  • operation: одно из значений plan, apply или destroy

Пример​

Блок кода
{
  "@level": "info",
  "@message": "Apply complete! Resources: 1 added, 0 changed, 0 destroyed.",
  "@module": "tofu.ui",
  "@timestamp": "2021-05-25T13:32:41.869168-04:00",
  "changes": {
    "add": 1,
    "change": 0,
    "remove": 0,
    "operation": "apply"
  },
  "type": "change_summary"
}

Выходные данные​

После успешного планирования или применения сообщение типа outputs содержит значения всех выходных данных корневого модуля. Сообщение содержит объект outputs, ключами которого являются имена выходных данных. Значения выходных данных — это объекты со следующими ключами:

  • action: для запланированных выходных данных — действие, которое будет выполнено. Значения: noop, create, update, delete
  • value: для применённых выходных данных — значение выходных данных в формате JSON
  • type: для применённых выходных данных — определённый тип HCL значения выходных данных
  • sensitive: логическое значение true, если выходные данные являются конфиденциальными и по умолчанию должны быть скрыты в интерфейсе

Обратите внимание: выходные данные sensitive по-прежнему содержат поле value, и интегрирующее программное обеспечение должно учитывать уровень конфиденциальности в соответствии с конкретным сценарием использования.

Пример​

Блок кода
{
  "@level": "info",
  "@message": "Outputs: 1",
  "@module": "tofu.ui",
  "@timestamp": "2021-05-25T13:32:41.869280-04:00",
  "outputs": {
    "pets": {
      "sensitive": false,
      "type": "string",
      "value": "smart-lizard"
    }
  },
  "type": "outputs"
}

Сообщения об операциях​

Выполнение операций OpenTofu с ресурсом часто приводит к выводу нескольких сообщений. К ним относятся:

  • apply_start: начало применения изменений для ресурса
  • apply_progress: периодический вывод прошедшего времени
  • apply_complete: успешное завершение операции
  • apply_errored: обнаружение ошибки во время операции
  • provision_start: начало шага provisioner
  • provision_progress: вывод provisioner
  • provision_complete: успешное выполнение provisioner
  • provision_errored: обнаружение ошибки во время выполнения provisioner
  • refresh_start: чтение ресурса при обновлении состояния
  • refresh_complete: успешное обновление состояния

Каждое из этих сообщений содержит объект hook с полями, различающимися в зависимости от типа сообщения. Все обработчики содержат объект resource, указывающий, к какому ресурсу относится операция.

Начало применения​

Объект hook сообщения apply_start содержит следующие ключи:

  • resource: объект resource, идентифицирующий ресурс
  • action: действие, которое будет выполнено для ресурса. Значения: noop, create, read, update, replace, delete
  • id_key и id_value: пара ключ-значение для идентификации экземпляра ресурса; не указывается, если значение неизвестно

Пример​

Блок кода
{
  "@level": "info",
  "@message": "random_pet.animal: Creating...",
  "@module": "tofu.ui",
  "@timestamp": "2021-05-25T13:32:41.825308-04:00",
  "hook": {
    "resource": {
      "addr": "random_pet.animal",
      "module": "",
      "resource": "random_pet.animal",
      "implied_provider": "random",
      "resource_type": "random_pet",
      "resource_name": "animal",
      "resource_key": null
    },
    "action": "create"
  },
  "type": "apply_start"
}

Ход применения​

Объект hook сообщения apply_progress содержит следующие ключи:

  • resource: объект resource, идентифицирующий ресурс
  • action: выполняемое действие для ресурса. Значения: noop, create, read, update, replace, delete
  • elapsed_seconds: время, прошедшее с начала операции применения, в виде целого числа секунд

Пример​

Блок кода
{
  "@level": "info",
  "@message": "null_resource.none[4]: Still creating... [30s elapsed]",
  "@module": "tofu.ui",
  "@timestamp": "2021-03-17T09:34:26.222465-04:00",
  "hook": {
    "resource": {
      "addr": "null_resource.none[4]",
      "module": "",
      "resource": "null_resource.none[4]",
      "implied_provider": "null",
      "resource_type": "null_resource",
      "resource_name": "none",
      "resource_key": 4
    },
    "action": "create",
    "elapsed_seconds": 30
  },
  "type": "apply_progress"
}

Применение завершено​

Объект hook сообщения apply_complete содержит следующие ключи:

  • resource: объект resource, идентифицирующий ресурс
  • action: выполненное действие для ресурса. Значения: noop, create, read, update, replace, delete
  • id_key и id_value: пара ключ-значение для идентификации экземпляра ресурса; не указывается, если значение неизвестно
  • elapsed_seconds: время, прошедшее с начала операции применения, в виде целого числа секунд

Пример​

Блок кода
{
  "@level": "info",
  "@message": "random_pet.animal: Creation complete after 0s [id=smart-lizard]",
  "@module": "tofu.ui",
  "@timestamp": "2021-05-25T13:32:41.826179-04:00",
  "hook": {
    "resource": {
      "addr": "random_pet.animal",
      "module": "",
      "resource": "random_pet.animal",
      "implied_provider": "random",
      "resource_type": "random_pet",
      "resource_name": "animal",
      "resource_key": null
    },
    "action": "create",
    "id_key": "id",
    "id_value": "smart-lizard",
    "elapsed_seconds": 0
  },
  "type": "apply_complete"
}

Ошибка при применении​

Объект hook сообщения apply_complete содержит следующие ключи:

  • resource: объект resource, идентифицирующий ресурс
  • action: выполненное действие для ресурса. Значения: noop, create, read, update, replace, delete
  • elapsed_seconds: время, прошедшее с начала операции применения, в виде целого числа секунд

Подробное описание ошибки будет выведено в отдельном сообщении diagnostic.

Пример​

Блок кода
{
  "@level": "info",
  "@message": "null_resource.none[0]: Creation errored after 10s",
  "@module": "tofu.ui",
  "@timestamp": "2021-03-26T16:38:54.013910-04:00",
  "hook": {
    "resource": {
      "addr": "null_resource.none[0]",
      "module": "",
      "resource": "null_resource.none[0]",
      "implied_provider": "null",
      "resource_type": "null_resource",
      "resource_name": "none",
      "resource_key": 0
    },
    "action": "create",
    "elapsed_seconds": 10
  },
  "type": "apply_errored"
}

Начало provisioner​

Объект hook сообщения provision_start содержит следующие ключи:

  • resource: объект resource, идентифицирующий ресурс
  • provisioner: тип provisioner

Пример​

Блок кода
{
  "@level": "info",
  "@message": "null_resource.none[0]: Provisioning with 'local-exec'...",
  "@module": "tofu.ui",
  "@timestamp": "2021-03-26T16:38:43.997431-04:00",
  "hook": {
    "resource": {
      "addr": "null_resource.none[0]",
      "module": "",
      "resource": "null_resource.none[0]",
      "implied_provider": "null",
      "resource_type": "null_resource",
      "resource_name": "none",
      "resource_key": 0
    },
    "provisioner": "local-exec"
  },
  "type": "provision_start"
}

Ход выполнения provisioner​

Объект hook сообщения provision_progress содержит следующие ключи:

  • resource: объект resource, идентифицирующий ресурс
  • provisioner: тип provisioner
  • output: журнал вывода provisioner

Для каждой полученной от provisioner строки журнала выводится отдельное сообщение provision_progress.

Пример​

Блок кода
{
  "@level": "info",
  "@message": "null_resource.none[0]: (local-exec): Executing: [\"/bin/sh\" \"-c\" \"sleep 10 && exit 1\"]",
  "@module": "tofu.ui",
  "@timestamp": "2021-03-26T16:38:43.997869-04:00",
  "hook": {
    "resource": {
      "addr": "null_resource.none[0]",
      "module": "",
      "resource": "null_resource.none[0]",
      "implied_provider": "null",
      "resource_type": "null_resource",
      "resource_name": "none",
      "resource_key": 0
    },
    "provisioner": "local-exec",
    "output": "Executing: [\"/bin/sh\" \"-c\" \"sleep 10 && exit 1\"]"
  },
  "type": "provision_progress"
}

Provisioner завершён​

Объект hook сообщения provision_complete содержит следующие ключи:

  • resource: объект resource, идентифицирующий ресурс
  • provisioner: тип provisioner

Пример​

Блок кода
{
  "@level": "info",
  "@message": "null_resource.none[0]: (local-exec) Provisioning complete",
  "@module": "tofu.ui",
  "@timestamp": "2021-03-17T09:34:06.239043-04:00",
  "hook": {
    "resource": {
      "addr": "null_resource.none[0]",
      "module": "",
      "resource": "null_resource.none[0]",
      "implied_provider": "null",
      "resource_type": "null_resource",
      "resource_name": "none",
      "resource_key": 0
    },
    "provisioner": "local-exec"
  },
  "type": "provision_complete"
}

Ошибка provisioner​

Объект hook сообщения provision_errored содержит следующие ключи:

  • resource: объект resource, идентифицирующий ресурс
  • provisioner: тип provisioner

Пример​

Блок кода
{
  "@level": "info",
  "@message": "null_resource.none[0]: (local-exec) Provisioning errored",
  "@module": "tofu.ui",
  "@timestamp": "2021-03-26T16:38:54.013572-04:00",
  "hook": {
    "resource": {
      "addr": "null_resource.none[0]",
      "module": "",
      "resource": "null_resource.none[0]",
      "implied_provider": "null",
      "resource_type": "null_resource",
      "resource_name": "none",
      "resource_key": 0
    },
    "provisioner": "local-exec"
  },
  "type": "provision_errored"
}

Начало обновления состояния​

Объект hook сообщения refresh_start содержит следующие ключи:

  • resource: объект resource, идентифицирующий ресурс
  • id_key и id_value: пара ключ-значение для идентификации экземпляра ресурса

Пример​

Блок кода
{
  "@level": "info",
  "@message": "null_resource.none[0]: Refreshing state... [id=1971614370559474622]",
  "@module": "tofu.ui",
  "@timestamp": "2021-03-26T14:18:06.508915-04:00",
  "hook": {
    "resource": {
      "addr": "null_resource.none[0]",
      "module": "",
      "resource": "null_resource.none[0]",
      "implied_provider": "null",
      "resource_type": "null_resource",
      "resource_name": "none",
      "resource_key": 0
    },
    "id_key": "id",
    "id_value": "1971614370559474622"
  },
  "type": "refresh_start"
}

Обновление состояния завершено​

Объект hook сообщения refresh_complete содержит следующие ключи:

  • resource: объект resource, идентифицирующий ресурс
  • id_key и id_value: пара ключ-значение для идентификации экземпляра ресурса

Пример​

Блок кода
{
  "@level": "info",
  "@message": "null_resource.none[0]: Refresh complete [id=1971614370559474622]",
  "@module": "tofu.ui",
  "@timestamp": "2021-03-26T14:18:06.509371-04:00",
  "hook": {
    "resource": {
      "addr": "null_resource.none[0]",
      "module": "",
      "resource": "null_resource.none[0]",
      "implied_provider": "null",
      "resource_type": "null_resource",
      "resource_name": "none",
      "resource_key": 0
    },
    "id_key": "id",
    "id_value": "1971614370559474622"
  },
  "type": "refresh_complete"
}

Объект ресурса​

Объект resource — это разложенная на составляющие структура, представляющая адрес ресурса в конфигурации. Она используется для определения ресурса, к которому относится конкретное сообщение. Объект содержит следующие ключи:

  • addr: полный уникальный адрес ресурса в виде строки
  • module: адрес модуля, содержащего ресурс, в формате module.foo.module.bar или пустая строка для ресурса корневого модуля
  • resource: адрес относительно модуля; для ресурсов корневого модуля совпадает с addr
  • resource_type: тип адресуемого ресурса
  • resource_name: метка имени ресурса
  • resource_key: ключ адреса (значение count или for_each) либо null, если не используется ни один из них
  • implied_provider: тип провайдера, подразумеваемый типом ресурса; он может не соответствовать провайдеру ресурса, если используются псевдонимы провайдеров

Пример​

Блок кода
{
  "addr": "module.pets.random_pet.pet[\"friend\"]",
  "module": "module.pets",
  "resource": "random_pet.pet[\"friend\"]",
  "implied_provider": "random",
  "resource_type": "random_pet",
  "resource_name": "pet",
  "resource_key": "friend"
}

Сообщения о тестировании​

Запуск тестов OpenTofu приводит к выводу нескольких сообщений. К ним относятся:

  • test_abstract: сводка по найденным тестовым файлам и тестам
  • test_file: сводка по выполнению тестового файла
  • test_run: сводка по выполнению тестов
  • test_summary: сводка об общем статусе и статистике выполнения тестовых файлов

Общие сведения о тестах​

Объект test_abstract сообщения test_abstract содержит динамические ключи, составленные из имени тестового файла:

  • main.tftest.hcl: список тестов, найденных в тестовом файле

Пример​

Блок кода
{
    "@level": "info",
    "@message": "Found 1 file and 1 run block",
    "@module": "tofu.ui",
    "@timestamp": "2024-04-20T17:24:48.418126+10:00",
    "test_abstract": {
        "main.tftest.hcl": [
            "test"
        ]
    },
    "type": "test_abstract"
}

Тестовый файл​

Объект test_file сообщения test_file содержит следующие ключи:

  • path: относительный путь к тестовому файлу
  • status: общий статус выполнения тестов

Пример​

Блок кода
{
    "@level": "info",
    "@message": "main.tftest.hcl... pass",
    "@module": "tofu.ui",
    "@testfile": "main.tftest.hcl",
    "@timestamp": "2024-04-20T17:24:48.588473+10:00",
    "test_file": {
        "path": "main.tftest.hcl",
        "status": "pass"
    },
    "type": "test_file"
}

Запуск теста​

Объект сообщения test_run test_run содержит следующие ключи:

  • path: относительный путь к файлу теста
  • run: название выполненного теста
  • status: общий статус выполнения тестов

Пример​

Блок кода
{
    "@level": "info",
    "@message": "  \"test\"... pass",
    "@module": "tofu.ui",
    "@testfile": "main.tftest.hcl",
    "@testrun": "test",
    "@timestamp": "2024-04-20T17:24:48.588519+10:00",
    "test_run": {
        "path": "main.tftest.hcl",
        "run": "test",
        "status": "pass"
    },
    "type": "test_run"
}

Сводка по тестам​

Объект сообщения test_summary test_summary содержит следующие ключи:

  • status: общий статус всех выполненных тестов
  • passed: общее количество успешно пройденных тестов
  • failed: общее количество тестов, завершившихся неудачей
  • errored: общее количество тестов, завершившихся с ошибкой
  • skipped: общее количество пропущенных тестов

Пример​

Блок кода
{
    "@level": "info",
    "@message": "Success! 1 passed, 0 failed.",
    "@module": "tofu.ui",
    "@timestamp": "2024-04-20T17:24:48.716977+10:00",
    "test_summary": {
        "status": "pass",
        "passed": 1,
        "failed": 0,
        "errored": 0,
        "skipped": 0
    },
    "type": "test_summary"
}

Copyright (c) The OpenTofu Authors
Copyright (c) 2014 HashiCorp, Inc.
Mozilla Public License, version 2.0
https://opentofu.org/docs/v1.11/internals/machine-readable-ui/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API