我有一个Kubernetes Pod的json文档,下面是一个示例:
https://github.com/itaysk/kubectl-neat/blob/master/test/fixtures/pod-1-raw.json

我想遍历spec.containers[i].volumeMounts并删除那些.name"default-token-"开头的volumeMount对象。注意containersvolumeMounts都是数组。

使用jq,我花了1分钟来编写以下1行:try del(.spec.containers[].volumeMounts[] | select(.name | startswith("default-token-")))。我正在尝试用Go重写它。

在寻找一个好的json库时,我选择了gjson / sjson。
由于sjson doesn't support array accessors(即#语法)和gjson不支持获取结果的路径,因此我寻找了解决方法。
我尝试使用Result.Index直接从字节 slice 中删除结果,并成功了,但是对于我编写的查询(spec.containers.#.volumeMounts.#(name%\"default-token-*\")|0),索引始终为0(我尝试了它的不同变体,结果相同)。
因此,目前我有一些代码25行代码,这些代码使用gjson获取spec.containers.#.volumeMounts并遍历结构,最后使用sjson.Delete进行删除。
它可以工作,但是感觉比我预期的要复杂得多。

Go中有更好的方法吗?我愿意在需要时切换json库。

编辑:我宁愿避免使用类型化的架构,因为我可能需要对不同的类型执行此操作,因为有些我没有完整的架构。
(还删除了一些有关我当前实现的分散注意力的细节)

最佳答案

最简单的方法是将JSON解析为一个对象,使用该对象,然后序列化回JSON。

Kubernetes提供了一个Go客户端库,该库定义了可以使用stdlib编码/ json解组到的v1.Pod struct:

// import "k8s.io/api/core/v1"
var pod v1.Pod
if err := json.Unmarshal(podBody, &pod); err != nil {
    log.Fatalf("parsing pod json: %s", err)
}

从那里您可以阅读pod.Spec.Containers及其VolumeMounts:
// Modify.
for c := range pod.Spec.Containers {
    container := &pod.Spec.Containers[c]
    for i, vol := range container.VolumeMounts {
        if strings.HasPrefix(vol.Name, "default-token-") {
            // Remove the VolumeMount at index i.
            container.VolumeMounts = append(container.VolumeMounts[:i], container.VolumeMounts[i+1:]...)
        }
    }
}

https://play.golang.org/p/3r5-XKIazhK

如果您担心丢失一些可能出现在输入中的JSON,则可以改定义var pod map[string]interface{},然后将其中的每个属性都类型转换为spec, ok := pod["spec"].(map[string]interface{})containers, ok := spec["containers"].([]map[string]interface)等。

希望能有所帮助。

ps。 “删除”是在https://github.com/golang/go/wiki/SliceTricks#delete之后

07-28 09:21