Этот пост является давно назревшим продолжением моего предыдущего поста о config API: https://medium.com/@pubuduf/ballerina-config-api-f6a9c455267b. Конфигурационный API претерпел серьезный рефакторинг для выпуска Ballerina 0.970.0. С новой системой типов, которая была представлена ​​для версии 0.970.0, получение конфигураций с использованием тогдашнего API стало обременительным. Были случаи, когда приходилось писать 5–10 строковых функций для чтения одного значения конфигурации в требуемом типе данных (например, получение номера порта как целого числа). Для решения этой проблемы был представлен новый комплексный API. Помимо изменения API, также были внесены следующие изменения:

  • Принятие TOML в качестве формата файла конфигурации.
  • Добавление механизма для безопасного хранения / чтения конфиденциальных данных в / из файла конфигурации.
  • Улучшения в разрешении конфигурации.

TOML для конфигураций

Инструмент управления пакетами Ballerina использует TOML для своих конфигураций. Чтобы сохранить единообразие во всех аспектах Ballerina и поскольку формат файла конфигурации уже был довольно близок к TOML, мы решили использовать TOML и для API конфигурации. Однако в настоящее время некоторые функции не поддерживаются (например, массивы, встроенные таблицы).

Давайте посмотрим на изменения, используя config API для настройки простой службы эха.

Новый формат файла конфигурации

Мы будем использовать следующий файл конфигурации для настройки эхо-службы.

Как видно, нет большой разницы между старым форматом и недавно принятым форматом TOML. Наиболее заметное различие будет в том, как значения конфигурации обрабатываются в конфигурациях на основе TOML. Раньше все значения конфигурации обрабатывались как строки. Следовательно, нет необходимости заключать строковые значения в кавычки. Однако в TOML значения могут быть следующих типов: строка, целое число, число с плавающей запятой, логическое значение, дата и время, массив или встроенная таблица. Однако config API поддерживает только следующие типы значений: строковое, целочисленное, с плавающей запятой и логическое значение. Если значение является строкой, теперь вы должны заключить значение в кавычки.

Разрешение конфигурации

Конфигурации разрешаются и сохраняются в реестре при запуске среды выполнения Ballerina. Иерархия приоритета источника конфигурации остается неизменной и выглядит следующим образом в порядке убывания приоритета:

  1. Параметры времени выполнения (предоставляются через интерфейс командной строки для команды run с использованием флага -e)
    например, $ ballerina run -e b7a.log.level=DEBUG foo.bal
  2. Переменные среды
    Так как точки не допускаются в переменных среды, точки в ключах конфигурации заменяются подчеркиванием при поиске переменных среды. Следовательно, если вы устанавливаете переменную среды для переопределения конфигурации, заданной с использованием файла конфигурации или конфигурации по умолчанию, вы должны использовать подчеркивания вместо точек (если они есть) в ключе конфигурации.
  3. Файл конфигурации
  4. Конфигурации по умолчанию (жестко заданные конфигурации, например, уровень журнала)

Конфигурации для данной программы могут быть смесью указанных выше 4 источников конфигураций. Если один и тот же конфигурационный ключ присутствует в нескольких источниках, приоритет отдается источнику с наивысшим приоритетом.

Новый API

Пользователю доступны следующие API:

  • public function contains(string key) returns boolean
    Это можно использовать, чтобы проверить, присутствует ли конкретная конфигурация в реестре конфигурации. Полезно, если необходимо различать значение по умолчанию, возвращаемое функцией getAsXXX (), и отсутствие конфигурации, поскольку значение по умолчанию возвращается и в отсутствие конфигурации.
  • public function getAsBoolean(string key, boolean default = false) returns boolean
    Возвращает значение конфигурации для указанного ключа как boolean. Если конфиг присутствует в реестре, он возвращается. Если значение, которое вы пытаетесь получить, является строкой, он попытается проанализировать его как boolean. Если значение равно «истина» (без учета регистра), оно вернет истину.
  • public function getAsFloat(string key, float default = 0.0) returns float
    Возвращает значение конфигурации для указанного ключа как float. Если фактическое значение не равно float, int и string, которое может быть проанализировано с float, это приведет к панике.
  • public function getAsInt(string key, int default = 0) returns int
    Возвращает значение конфигурации для указанного ключа как int. Если фактическое значение не является ни int, ни string, которое может быть проанализировано с int, это приведет к панике.
  • public function getAsMap(string key) returns map<any>
    Возвращает связанный набор конфигураций (таблица в терминах TOML) в виде карты. Например, вызов config:getAsMap("echo") вернет карту со всеми конфигурациями в таблице «echo». Если такой таблицы нет или это пустая таблица, будет возвращена пустая карта.
  • public function getAsString(string key, string default = "") returns string
    Возвращает значение конфигурации для указанного ключа как string.
  • public function setConfig(string key, string|int|float|boolean value)
    Можно использовать для добавления конфигов в реестр в коде Ballerina.

Обратите внимание на необязательный параметр default в функциях getAsXXX () (кроме getAsMap ()). Это значение возвращается, если указанный ключ конфигурации не может быть найден в реестре. Это полезно, если необходимая конфигурация отсутствует во время выполнения, но вы все равно хотите попытаться запустить ее со значением по умолчанию.
например, config:getAsString("host", default = "localhost")

Следующая простая эхо-служба демонстрирует использование этого нового API.

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

Вышеупомянутую службу можно запустить с файлом конфигурации как:
$ ballerina run -c echo.conf echo_service.bal или
$ ballerina run --config echo.conf echo_service.bal

Защита конфиденциальных значений конфигурации

Как вы могли заметить, в приведенном выше конфигурационном файле, который мы использовали, пароль хранилища ключей хранится в виде обычного текста. В Ballerina 0.970.0 конфигурационный API был дополнительно усовершенствован с помощью инструмента шифрования для шифрования конфиденциальных значений.

Чтобы зашифровать значение, можно использовать команду ballerina encrypt. Вот как это выглядит в терминале, когда пароль хранилища ключей зашифрован с помощью этого инструмента. Значение «балерина» было зашифровано с помощью секрета «1234».

$ ballerina encrypt
Enter value:
Enter secret:
Re-enter secret to verify:
Add the following to the runtime config:
@encrypted:{92XujbVRx+rXspbI/8sbdpdrmBmMF1PBDnuVUJKdK/0=}
Or add to the runtime command line:
-e<param>=@encrypted:{92XujbVRx+rXspbI/8sbdpdrmBmMF1PBDnuVUJKdK/0=}

Ниже приведен обновленный файл конфигурации, в котором текстовый пароль заменен его зашифрованной версией.

Теперь давайте попробуем запустить нашу эхо-службу с помощью этого обновленного файла конфигурации.

$ ballerina run -c secure-echo.conf echo_service.bal 
ballerina: enter secret for config value decryption:
Initiating service(s) in 'echo_service.bal'
[ballerina/http] started HTTPS/WSS endpoint 0.0.0.0:9095
[ballerina/http] started HTTP/WS endpoint 0.0.0.0:9090

Если среда выполнения обнаруживает какие-либо зашифрованные значения в предоставленных ей конфигурациях, она предложит пользователю ввести секрет (тот, который использовался при шифровании значений). Предоставление неверного секрета вызовет панику.

Все зашифрованные значения конфигурации, используемые при запуске программы, должны быть зашифрованы с использованием одного и того же секрета.

Кроме того, вы можете поместить секрет в файл и указать на него с помощью флага -e b7a.config.secret. Когда этот флаг установлен, среда выполнения считывает секрет из файла и удаляет файл. В этом случае пользователю не предлагается ввести секрет. Это более практичный способ предоставить секрет конфигурационного API.

Давай попробуем это. Создайте файл (скажем, secret.txt) и поместите в него секрет (в данном случае 1234).

$ ls
echo_service.bal  secret.txt  secure-echo.conf

Теперь запустите программу с установленным флагом b7a.config.secret.

$ ballerina run -c secure-echo.conf -e b7a.config.secret=secret.txt echo_service.bal
Initiating service(s) in 'echo_service.bal'
[ballerina/http] started HTTPS/WSS endpoint 0.0.0.0:9095
[ballerina/http] started HTTP/WS endpoint 0.0.0.0:9090

Как видно, пользователю не предлагается. Теперь, если мы снова запустим ls, мы увидим, что файл secret.txt удален.

$ ls
echo_service.bal  secure-echo.conf

С точки зрения кода, нет никакой разницы между доступом к обычным и зашифрованным конфигурациям: вы получаете их с помощью ключа. Внутри зашифрованные значения хранятся в реестре в зашифрованном виде, тогда как значения в виде обычного текста хранятся в реестре как есть. Зашифрованные конфигурации расшифровываются по запросу с использованием секрета, предоставленного в начале выполнения.

Чтение конфигураций из среды

Распространенным требованием является предоставление конфигурации программы через переменные среды. Поэтому давайте посмотрим и на это. Следует рассмотреть два случая:

  1. Чтение конфигурации из окружения
  2. Переопределение конфигурации в файле конфигурации с помощью переменной среды

В обоих случаях нам просто нужно установить переменную среды, а затем можно просто получить ее с помощью ключа. Однако в текущей реализации есть небольшая разница в поведении между вариантами 1 и 2. В первом случае он просто найдет переменную среды и вернет ее текущее значение. Во втором случае при разрешении конфигураций он будет искать ключ в переменных среды и, если такая переменная есть, сохранит ее значение в реестре конфигурации. Таким образом, такие переопределенные конфигурации всегда будут иметь значения соответствующих переменных среды при запуске среды выполнения.

Давайте рассмотрим пример с использованием модифицированной версии конфигурационного файла, который мы рассматривали ранее. Мы переопределим конфигурацию httpPort и установим конфигурацию httpsPort, используя переменные среды.

Чтобы установить переменные среды в Linux:

$ export echo_httpPort=8080
$ export echo_httpsPort=8085

Обратите внимание, как используется полный ключ конфигурации при установке переменной с точкой, замененной на _. Теперь давайте запустим это и убедимся, что конфигурации применены правильно.

$ ballerina run -c echo2.conf echo_service.bal 
Initiating service(s) in 'echo_service.bal'
[ballerina/http] started HTTPS/WSS endpoint 0.0.0.0:8085
[ballerina/http] started HTTP/WS endpoint 0.0.0.0:8080

Слушатели теперь находятся на портах 8080 и 8085 соответственно, вместо 9090 и 9095.

Итак, об управлении конфигурациями в Ballerina. Попробуйте и сообщите нам о своем опыте работы с ним. Были ли болевые точки? Есть какие-нибудь новые идеи о том, как и что мы можем улучшить? Напишите письмо нашей группе разработчиков: https://groups.google.com/forum/#!forum/ballerina-dev или откройте вопрос в нашем репозитории Github: https://github.com/ballerina- платформа / балерина-лэнг :)