Комплексная проверка в библиотеке Jso nnet - PullRequest
0 голосов
/ 10 апреля 2020

Я пытаюсь создать библиотеку libso nnet с некоторой сложной проверкой входных данных, но я не уверен, как реализовать это в файле libsonnet без возврата null.

Я пытаюсь сгенерировать вызовы API для API оповещений размещенного графита с использованием Jso nnet. Идея заключается в том, что мы можем хранить все наши оповещения в системе контроля версий и обновлять их в конвейере CI / CD. Я хочу предотвратить ошибки, поэтому я реализовал некоторую сложную проверку, основанную на том, что определено в приведенном выше API spe c. Я сохранил следующее как alerts.libsonnet:

local alert_criteria_types = [
  'above',
  'below',
  'missing',
  'outside_bounds',
];

local notification_types_strings = [
  'state_change',
];

local notification_types_arrays = [
  'every',
  'state_change',
];

local on_query_failure_types = [
  'ignore',
  'notify',
  null,
];

{
  local HostedGraphiteAlerts = self,

  new(
    name,
    metric,
    alert_criteria_type,
    additional_alert_criteria={},
    additional_criteria={},
    expression='a',
    scheduled_mutes=[],
    notification_channels=['Email me'],
    notification_type=null,
    info=null,
    on_query_failure='notify',
  )::

    // Simple checks
    assert std.member(alert_criteria_types, alert_criteria_type) : "Input 'alert_criteria_type' is not one of the types: %s." % std.join(', ', alert_criteria_types);
    assert std.member(on_query_failure_types, on_query_failure) : "Input 'on_query_failure_type' is not one of the types: %s." % std.join(', ', on_query_failure_types);

    // Advanced checks
    if notification_type != null && std.isString(notification_type) then
        assert std.member(notification_types_strings, notification_type) : "Input 'notification_type' is not one of the types: %s." % std.join(', ', notification_types_strings);

    if notification_type != null && std.isArray(notification_type) then
      assert std.member(notification_types_arrays, notification_type[0]) : "Input 'notification_type' is not one of the types: %s." % std.join(', ', notification_types_arrays);

    if notification_type != null && std.isArray(notification_type) then
        assert std.member(notification_types_arrays, notification_type[0]) : "Input 'notification_type' is not one of the types: %s." % std.join(', ', notification_types_arrays);

    if notification_type != null && std.isArray(notification_type) && notification_type[0] == 'every' then
        assert notification_type[1] != null : "Input 'notification_type' cannot have an empty entry for 'time_in_minutes' for notification type 'every'.";

    if notification_type != null && std.isArray(notification_type) && notification_type[0] == 'every' then
        assert std.isNumber(notification_type[1]) : "Input 'notification_type' must have a JSON 'number' type for notification type 'every'.";

    // Main
    {
      name: name,
      metric: metric,
      alert_criteria: {
        type: alert_criteria_type,
      } + additional_alert_criteria,
      additional_criteria: additional_criteria,
      expression: expression,
      scheduled_mutes: scheduled_mutes,
      notification_channels: notification_channels,
      notification_type: notification_type,
      info: info,
      on_query_failure: on_query_failure,
    },
}

Это проходит базовую проверку c jsonnetfmt, но проблема в том, когда я go использую его в файле alerts.jsonnet, например Итак:

local alerts = (import 'hosted_graphite.libsonnet').alerts;

alerts.new(
  name='something',
  metric='some.graphite.metric',
  alert_criteria_type='below',
)

Это просто возвращает null:

$ jsonnet hosted_graphite/alerts.jsonnet
null

Я знаю, это потому, что он принимает значение первого assert оператора. Но как еще это можно сделать?

Спасибо!

1 Ответ

2 голосов
/ 10 апреля 2020

Остерегайтесь того, что jsonnet не является обязательным языком, не ожидайте, что эти строки if будут оцениваться, как если бы они были частью скрипта. Думайте об утверждениях как о «виртуальном» / невидимом поле, которое всегда должно оцениваться как true

Ниже приводится описание того, что (я думаю) вы ищете:

hosted_graphite.libsonnet

local alert_criteria_types = [
  'above',
  'below',
  'missing',
  'outside_bounds',
];

local notification_types_strings = [
  'state_change',
];

local notification_types_arrays = [
  'every',
  'state_change',
];

local on_query_failure_types = [
  'ignore',
  'notify',
  null,
];

{
  local HostedGraphiteAlerts = self,

  new(
    name,
    metric,
    alert_criteria_type,
    additional_alert_criteria={},
    additional_criteria={},
    expression='a',
    scheduled_mutes=[],
    notification_channels=['Email me'],
    notification_type=null,
    info=null,
    on_query_failure='notify',
  )::

    // Main
    {
      name: name,
      metric: metric,
      alert_criteria: {
        type: alert_criteria_type,
      } + additional_alert_criteria,
      additional_criteria: additional_criteria,
      expression: expression,
      scheduled_mutes: scheduled_mutes,
      notification_channels: notification_channels,
      notification_type: notification_type,
      info: info,
      on_query_failure: on_query_failure,

      // Simple checks
      assert std.member(alert_criteria_types, self.alert_criteria.type) : (
        "Input 'alert_criteria_type' is not one of the types: %s." % std.join(', ', alert_criteria_types)
      ),
      assert std.member(on_query_failure_types, self.on_query_failure) : (
        "Input 'on_query_failure_type' is not one of the types: %s." % std.join(', ', on_query_failure_types)
      ),

      // Advanced checks:
      // - 1st line is a conditional that must be false ('A||B' construct) to get 2nd line evaluated
      // - 2nd line is the "final" type/value check, must be true
      assert (self.notification_type == null || !std.isString(self.notification_type) ||
              std.member(notification_types_strings, self.notification_type)) : (
        "Input 'notification_type' string is not one of the types: %s." % std.join(', ', notification_types_strings)
      ),
      assert (self.notification_type == null || !std.isArray(self.notification_type) ||
              std.member(notification_types_arrays, self.notification_type[0])) : (
        "Input 'notification_type' array is not one of the types: %s." % std.join(', ', notification_types_arrays)
      ),
      assert (self.notification_type == null || !std.isArray(self.notification_type) ||
              self.notification_type != ['every', null]) : (
        "Input 'notification_type' cannot have an empty entry for 'time_in_minutes' for notification type 'every'."
      ),
      assert (self.notification_type == null || !std.isArray(self.notification_type) ||
              [self.notification_type[0], std.isNumber(self.notification_type[1])] == ['every', true]) : (
        "Input 'notification_type' must have a JSON 'number' type for notification type 'every'."
      ),
    },
}

alerts.jsonnet

local alerts = (import 'hosted_graphite.libsonnet');

{
  a0: alerts.new(
    name='something',
    metric='some.graphite.metric',
    alert_criteria_type='below',
  ),
  a1: alerts.new(
    name='something',
    metric='some.graphite.metric',
    alert_criteria_type='below',
    notification_type='state_change',
  ),
  a2: alerts.new(
    name='something',
    metric='some.graphite.metric',
    alert_criteria_type='below',
    notification_type=['every', 10],
  ),
}

Обратите внимание, что я использую self.<field> вместо параметра функции, это хороший шаблон, позволяющий выводить / переопределять, в то же время оценивая утверждения.

Кстати, я бы также порекомендовал взглянуть на https://cuelang.org/, который играет в том же поле, что и jsonnet , но с проверкой типов, являющейся неотъемлемой частью языка.

...