Конфигурация | CUE
Управление текстовыми файлами для определения желаемого состояния системы.
Можно утверждать, что проверка должна быть главной задачей любого языка конфигурации. Однако большинство языков конфигурации фокусируются на удалении шаблонов. CUE отличается тем, что сначала занимает позицию проверки. Но ограничения CUE также эффективны для сокращения шаблонов, хотя подход, который он использует, сильно отличается от обычного языки шаблонов данных.
Базовая операция CUE объединяет конфигурации таким образом, что результат всегда одно и то же, независимо от порядка, в котором оно выполняется (она ассоциативна, коммутативна и идемпотентна). Это свойство является основой для многих других благоприятных свойств, которые обсуждаются ниже.
Основные вопросы, решаемые CUE
Проверка типов
Для больших кодовых баз никто не будет оспаривать требование иметь скомпилированный/типизированный язык. Почему бы не требовать такой же строгости для данных?
Многие языки конфигурации, включая GCL и его потомки, сосредоточены на сокращение шаблона как основной задачи конфигурации.
Некоторые языки поддерживают ввод текста, но обычно ограничивается проверкой базовых типов, как это принято в языках программирования. Однако для данных этого недостаточно. Доказательством этого является появление таких стандартов, как CDDL и OpenAPI, которые выйти за рамки простого набора текста.
В CUE типы и значения представляют собой единую концепцию, что придает ему очень выразительные, но интуитивно понятные и компактные возможности набора текста.
#Спецификация: { вид: строка имя: { first: !="" // должно быть указано и не должно быть пустым middle?: !="" // необязательно, но должно быть непустым, если указано последний: !="" } // Минимум должен быть строго меньше максимума и наоборот. минимум?: int & <максимум максимум?: int & >минимум } // Спецификация имеет тип #Spec спецификация: #Spec спецификация: { knid: "Homo Sapiens" // ошибка, опечатка в поле имя: первое: "Джейн" имя: фамилия: "Доу" }
Простота в масштабе
При использовании языка конфигурации для сокращения шаблонного кода следует подумать, стоит ли уменьшенная многословность повышенная сложность. В большинстве конфигураций используется модель переопределения для уменьшения шаблонного кода: существующая конфигурация используется в качестве базовой и модифицируется для получения новая конфигурация. Часто это происходит в форме наследования.
Для небольших проектов, использование наследования может быть слишком сложным, а простота изложение всего часто является превосходным подходом. Однако для крупномасштабных проектов использование наследования часто приводит к наслоения модификаций, из-за чего очень трудно понять, откуда берутся значения. В конце концов, снова возникает вопрос, стоит ли добавленная сложность того.
Как и в случае с другими языками конфигурации, CUE может добавить сложности, если значения организованы, чтобы прийти из нескольких мест. Однако, поскольку CUE запрещает переопределения, глубокие слои естественным образом предотвращаются. Что еще более важно, CUE также может улучшить читаемость. Определение в одном файле может применяться к значениям во многих других файлах. Где обычно приходится открывать все эти файлы для проверки достоверности; с CUE можно увидеть это с первого взгляда.
Подход CUE прошел боевые испытания в компьютерной лингвистике, где он десятилетиями использовался для описания человеческих языков; эффективно очень большие, сложные и нерегулярные конфигурации.
Абстракции против прямого доступа
Распространенный спор о языках конфигурации заключается в том, обеспечить уровень абстракции для API. С одной стороны, уровни абстракции позволяют защитить пользователя от неправильного использования. С другой стороны, им нужно идти в ногу с изменениями API и неизбежно склонны к дрейфу. Такие вот дела.CUE решает обе проблемы. С одной стороны, его мелкозернистая типизация позволяет наслаивать подробные ограничения. поверх нативных API, без необходимости в слое абстракции. Новые функции можно использовать без поддержки существующих определений.
С другой стороны, независимость CUE от порядка позволяет слоям абстракции для контролируемого внедрения произвольного необработанного API, предоставление общего аварийного люка для поддержки новых или раскрытых функций. См. раздел «Руководство» Учебник по Kubernetes для примера.
Инструменты
Язык конфигурации обычно преобразует свои конфигурации в представление более низкого уровня, такое как JSON, YAML или Protobuf, чтобы его можно использовать с помощью инструментов, использующих эти языки. Направление такого вывода на необходимые инструменты работает изначально; но рано или поздно появится желание это автоматизировать, обычно в виде какого-то инструмента.
И так далее. Рост систем, требующих расширенной настройки, был сопряжен с появлением еще более специализированных инструментов командной строки. Основная структура всех этих инструментов более или менее одинакова. Что еще более раздражает, многие из них имеют перекрывающиеся функции, но их трудно расширить. или совместимые. В последнем случае может возникнуть необходимость добавить еще один набор инструментов.
Наличие таких инструментов, как kubectl
или etcdctl
, которые непосредственно контролируют
основная инфраструктура имеет смысл, но на более высоких уровнях
абстракции нужен более открытый подход.
CUE пытается решить эту проблему, открывая, уровень декларативного сценария поверх уровня конфигурации. Помимо вышеупомянутого случая, он предназначен для решения различных другие проблемы:
- ввести данные об окружающей среде в конфигурацию, что-то не разрешено в самом CUE (он чистый, или герметичный, или без побочных эффектов)
- вводить вычисляемые данные в конфигурации как часть конвейера
- позволяет компоновать интеграцию инструментов
Опять же, возможность детерминированного объединения данных из разных источников сделайте это задачей для CUE.
Сравнения
Языки конфигурации на основе наследования
Наследование, это некоммутативна и идемпотентна в общем случае. Другими словами, порядок имеет значение. Это затрудняет отслеживание того, откуда берутся значения. Это верно не только для людей, но и для машин. Это делает очень сложным, если не невозможным, выполнение любого вида автоматизация. Сложность наследования еще больше, если значения может войти в объект с одного из нескольких направлений (супер, оверлей и т.
Основная операция CUE является коммутативной, ассоциативной и идемпотентной. Эта независимость от порядка помогает как люди и машины. Полученная модель намного менее сложна.
Хотя можно создавать экземпляры значений (помните, что типы — это значения), нельзя изменить ни одно из значений родителя. Шаблон действует как тип. Как и в статически типизированных языках, где нельзя присвоить целое число строка, нельзя нарушать свойства типа в CUE.
Эти ограничения снижают гибкость, но также повышают ясность. Чтобы убедиться, что конфигурация содержит определенное свойство, просто объявите его в любом файле, включенном в проект, чтобы сделать это так. Нет необходимости смотреть другие файлы. Как мы видели; введенные ограничения также могут улучшить, а не навредить, возможность удалять шаблоны по сравнению с языками, основанными на наследовании.
Сложность моделей, основанных на наследовании, также препятствует автоматизации. Внедрение GCL сопровождалось обещанием передовых инструментов. Мантра декларативных языков даже повторялась с некоторыми из его потомство. Однако инструменты так и не материализовались, поскольку модель делала их неуправляемыми.
CUE уже предоставляет электроинструменты, такие как триммер, а его API обеспечивает операции унификации и отнесения к неполным конфигурациям, построение блоки для мощного анализа.
Jsonnet/ GCL
Как и Jsonnet, CUE является надмножеством JSON. Они также оба находятся под влиянием GCL. CUE, в свою очередь, находится под влиянием Jsonnet. Это может создать впечатление, что языки очень похожи. Хотя в основе они очень разные.
Основное внимание CUE уделяется проверке данных, тогда как Jsonnet фокусируется на шаблонах данных. (удаление шаблона). Jsonnet не был разработан с учетом проверки.
Jsonnet и GCL могут быть весьма эффективными в сокращении шаблонов. Цель CUE не в том, чтобы лучше удалять шаблоны, чем Jsonnet или GCL. CUE был разработан как ответ на два основных недостатка этих подходов: сложность и отсутствие типизации. Jsonnet уменьшает некоторые сложности GCL, но в основном попадает в той же категории. Для CUE компромисс заключался в добавлении набора текста и уменьшении сложности. (для людей и машин) за счет отказа от гибкости.
HCL
HCL имеет поразительное сходство с GCL. Но было ли это совпадением или преднамеренным, это удаляет ядро источник сложности GCL: наследование.
Он вводит версию наследования для бедняков: файловые оверлеи. Поля могут быть определены в нескольких файлах, которые перезаписываются в определенный момент времени. порядок имен файлов. Хотя он и не такой сложный, как GCL, у него есть некоторые из тех же проблем.
Кроме того, было ли удаление наследства случайным или великим прозрением, взамен нет конструкции, которая может понадобиться для большего масштаба управление конфигурацией. Это означает, что использование HCL может достичь потолка для средних и больших установок.
Итак, что CUE может предложить пользователям HCL: набор текста, лучшие перспективы роста к более масштабным операциям и устранению особенностей файловых наложений.
CUE заимствует одну конструкцию из HCL: свертывание объектов с одним полем на одну строку был напрямую вдохновлен очень похожим подходом HCL.
Последнее изменение 26 февраля 2022 г.: Вернуть «документы/использования/конфигурация: исправить опечатку (# 227)» (# 232) (b7548d7)
Перейти | CUE
Как CUE интегрируется с языком программирования Go.
CUE не относится к Go или облачным приложениям, но, как и многие другие новые облачные технологии, CUE написан на Go. Имеет богатый набор API доступен разработчикам Go и взаимодействует с CUE различными способами.
API-интерфейсы CUE
API-интерфейсы CUE в основном репозитории организованы следующим образом:
- cmd : Инструмент командной строки CUE.
- реплика : основные API, связанные с разбором, форматированием, загрузкой и запуском программ CUE. Эти пакеты используются всеми другими пакетами, включая инструмент командной строки.
- кодировка : Пакеты для преобразования в CUE и из него, включая адаптеры для YAML, JSON, Go, Protobuf и OpenAPI.
- упак. : Встроенные пакеты, доступные из программ CUE . Обычно они не используются в коде Go.
Загрузка определений CUE из пакетов Go
Многие современные облачные проекты написаны на Go.
Сигнал get go
извлекает пакеты Go с помощью менеджера пакетов Go.
и делает их определения доступными через модуль CUE pkg
каталог
используя те же соглашения об именах пакетов, что и в Go.
Например, чтобы загрузить определения CUE для основных типов Kubernetes, запустите
cue get go k8s.io/api/core/v1
В корне вашего модуля CUE вы увидите ./pkg/k8s.io/api/core
, заполненный извлеченными определениями CUE.
Такие проекты, как Kubernetes, не обязаны поддерживать такие преобразования.
CUE выводит интерпретацию, анализируя, как типы Go преобразуются
с кодировка/json
.
Сгенерированный пакет можно использовать в CUE, используя тот же путь импорта.
В этом файле CUE мы импортируем сгенерированные определения и указываем, что
все сервисы в нашей конфигурации имеют тип v1.Service
.
импорт "k8s.io/api/core/v1" services: [string]: v1.#Service
Вы можете скачать определения из любого проекта Go, как здесь.
Например, попробуйте k8s.io/api/extensions/v1beta1
или github.com/prometheus/prometheus/pkg/rulefmt
.
Обработка CUE в Go
Загрузка CUE в Go
Существует два основных способа загрузки CUE в Go.
Чтобы загрузить целые пакеты в соответствии с инструментом cue
,
использовать cuelang.org/go/cue/load
упаковка.
Чтобы загрузить деревья синтаксического анализа CUE или необработанный текст CUE, используйте cuelang.org/go/cue.Время выполнения
.
Использовать одну среду выполнения
Для любой операции, включающей два значения CUE, эти два значения должны иметь был создан с использованием той же среды выполнения.Следующий код загружает встроенную конфигурацию CUE, оценивает одно из своих полей и печатает результат.
константная конфигурация = ` msg: "Привет \(место)!" место: строка | *"мир" // "мир" по умолчанию. ` var r cue.Время выполнения экземпляр, _ := r.Compile("тест", конфиг) str, _ := instance.Lookup("msg").String() fmt.Println(str) // Выход: // Привет, мир!
Имена, переданные в Compile, записываются как ссылки в позициях токенов.
Проверка значений Go
Тип кодека
в упаковке cuelang.org/go/encoding/gocode/gocodec
предоставляет Проверка
метод проверки значений Go.
var codec = gocodec.New(r, nil) var myValueConstraints cue.Value func (x *MyValue) Ошибка Validate() { вернуть codec.Validate(myValueConstraints, x) }
Пакет cuelang.org/go/encoding/gocode
,
обсуждается ниже,
может генерировать такие заглушки, чтобы немного облегчить жизнь.
Полные значения Go
A gocodec.Codec
также определяет метод Complete
, аналогичный методу Подтвердить
, но заполнить отсутствующие значения, если они могут быть получены из
Определения CUE.
Объединить значения CUE
Метод cue.Value
Unify
можно использовать для объединения двух значений.
Это программный эквивалент операции и
на языке CUE.
С помощью Unify
можно программно комбинировать ограничения из нескольких источников.
Например, можно добавить некоторые ограничения политики, зависящие от контекста, в
набор базовых ограничений.
Копировать значения CUE в значения Go
Самый простой способ установить значение Go на содержимое значения CUE заключается в использовании метода декодирования более позднего.
тип ab struct { A, B int } var r cue.Время выполнения вар х аб i, _ := r.Compile("тест", `{A: 2, B: 4}`) _ = i. Value(). Декодировать(&x) fmt.Println(x) i, _ = r.Compile("test", `{B: "foo"}`) _ = i.Value(). Декодировать(&x) fmt.Println(x) // Выход: // {2 4} // json: невозможно разобрать строку в поле структуры Go ab.B типа int
Пакет cuelang.com/go/encoding/gocode/gocodec
дает немного больше контроля
над кодированием и позволяет включать теги поля Go с ограничениями, такими как
а также получение неуказанных значений из ограничений.
Изменить значения CUE
Поле в экземпляре CUE может быть установлено на значение Go, которое соответствует
ограничения этого экземпляра с помощью метода Fill
.
На примере раздела «Загрузить CUE в Go» можно написать
inst, _ := instance.Fill("you", "place") ул, _ = inst.Lookup("msg").String() fmt.Println(str) // Выход: // Привет тебе!
Чтобы обеспечить целостность ссылок с экземпляром CUE, модификации разрешены только на уровне всего экземпляра.
Сгенерировать код Go
Программно
Сгенерировать
функция в упаковке cuelang.