我应该如何在 YAML 中编写和解组 byte64 编码值

How should I write and unmarshal a byte64 encoded value in YAML

我的 Yaml 文件的一部分

rules:
- action:
    count: {}
  name: rulenumbertwo
  priority: 123
  statement:
    bytematchstatement:
      fieldtomatch:
        singleheader:
          name: foobar
      positionalconstraint: CONTAINS
      searchstring: [103, 105, 122, 122, 98, 117, 122, 122]

上面的结果是搜索字符串值对应的 ASCII 字符串(“fizzbuzz”)。但是我怎样才能把它写成人类可读的格式呢? manual 表示应该“自动”转换搜索字符串,但如果我不将其写为 ASCII 码数组,它会抛出错误。

我的代码(试图解组它,如果我直接写数组但它不是人类可读的,它会起作用):

d := &wafv2.UpdateRuleGroupInput{}
err = yaml.Unmarshal(buf, d)

我想简单的写YAML如下

rules:
- action:
    count: {}
  name: rulenumbertwo
  priority: 123
  statement:
    bytematchstatement:
      fieldtomatch:
        singleheader:
          name: foobar
      positionalconstraint: CONTAINS
      searchstring: fizzbuzz

或者可能使用模板(但为什么什么时候应该很容易)

searchstring: {{ convertStringToByteArray "fizzbuzz" }}

包含 SearchString 的类型 ByteMatchStatement 没有声明任何自定义从 YAML 加载的方式,因此它无法从 YAML 标量加载 []byte。您 link 的手册描述了类型的语义,但没有定义数据的存储方式(取决于用例,将 string 的内容存储给用户确实有意义[]byte) 也不知道如何从 YAML 加载它。通常,(反)序列化往往会暴露有关数据模型的事实,否则这些事实将成为实现细节,这就是您在这里遇到的问题。

简单的解决方法是声明一些 type SearchStringType []byte,将其用于 SearchString 字段并在那里声明一个自定义 UnmarshalYAML 方法来处理到 []byte 的转换.但是,这在您的代码中是不可能的,因为您无法控制类型。

一种可能的修复方法是预处理 YAML 输入:

type LoadableUpdateRuleGroupInput wafv2.UpdateRuleGroupInput

func (l *LoadableUpdateRuleGroupInput) UnmarshalYAML(n *yaml.Node) error {
    preprocSearchString(n)
    return n.Decode((*wafv2.UpdateRuleGroupInput)(l))
}

func preprocSearchString(n *yaml.Node) {
    switch n.Kind {
    case yaml.SequenceNode:
        for _, item := range n.Content {
            preprocSearchString(item)
        }
    case yaml.MappingNode:
        for i := 0; i < len(n.Content); i += 2 {
            if n.Content[i].Kind == yaml.ScalarNode &&
                n.Content[i].Value == "searchstring" {
                toByteSequence(n.Content[i+1])
            } else {
                preprocSearchString(n.Content[i+1])
            }
        }
    }
}

func toByteSequence(n *yaml.Node) {
    n.Kind = yaml.SequenceNode
    raw := []byte(n.Value)
    n.Content = make([]*yaml.Node, len(raw))
    for i := range raw {
        n.Content[i] = &yaml.Node{Kind: yaml.ScalarNode, Value: strconv.Itoa(int(raw[i]))}
    }
}

通过在解组时使用这个新的子类型,searchstring 的 YAML 标量值将被转换为您编写的 YAML 序列节点。当您加载 YAML 节点时,它将正确加载到 []byte:

d := &LoadableUpdateRuleGroupInput{}
err = yaml.Unmarshal(buf, d)

此代码需要 gopkg.in/yaml.v3v2 无法让您对解组进行尽可能多的控制。