如何在Terraform中排序/合并两个地图

时间:2020-09-04 06:20:45

标签: sorting merge maps terraform

有人可以帮我解决这个问题吗?我正在使用Terraform 12.28。

我有两张看起来像这样的地图:

instances = { 
  "instance1" = "us-east-1a"
  "instance2" = "us-east-1a"
  "instance3" = "us-east-1c"
  "instance4" = "us-east-1b"
  "instance5" = "us-east-1b"
  "instance6" = "us-east-1c"
}

snapshots = {
  "snap1" = "us-east-1c"
  "snap2" = "us-east-1b"
  "snap3" = "us-east-1b"
  "snap4" = "us-east-1c"
  "snap5" = "us-east-1a"
  "snap6" = "us-east-1a"
}

我想从中得到的是:

desired_result = {
  "instance1" = "snap5"
  "instance2" = "snap6"
  "instnace3" = "snap1"
  "instance4" = "snap2"
  "instance5" = "snap3" 
  "instance6" = "snap4"
}

我只需要确保实例具有来自同一Az的快照即可。任何想法将不胜感激!

2 个答案:

答案 0 :(得分:0)

您描述的结果是不可能的,因为您的查找值重叠。 Instance1instance2都可能导致snap5snap6,因为它们都位于us-east-1a中。其他可用区也是如此。获得实际结果的一种方法是反转列表之一并将值分组。之后,您可以使用该列表在另一个列表中查找相应的值。这是我的示例:

locals {
  instances = {
    "instance1" = "us-east-1a"
    "instance2" = "us-east-1a"
    "instance3" = "us-east-1c"
    "instance4" = "us-east-1b"
    "instance5" = "us-east-1b"
    "instance6" = "us-east-1c"
  }
  snapshots = {
    "snap1" = "us-east-1c"
    "snap2" = "us-east-1b"
    "snap3" = "us-east-1b"
    "snap4" = "us-east-1c"
    "snap5" = "us-east-1a"
    "snap6" = "us-east-1a"
  }
  # Reverse and group (...)
  reversed_snapshots = {
    for key, value in local.snapshots:
    value => key...
  }
}

output "result" {
  value = {
    for key, value in local.instances:
    # Match instance to snapshots by looking up az
    key => lookup(local.reversed_snapshots, value, null)
  }
}

结果与原始问题中的结果有些不同,因为每个实例基本上都可以具有位于同一AZ中的两个快照之一。公用标识符AZ具有重复的值,因此也许您可以找到另一个唯一的标识符,例如snapshotID或类似名称。或者,将两个快照与一个实例相关联不是一个问题。

result = {
  "instance1" = [
    "snap5",
    "snap6",
  ]
  "instance2" = [
    "snap5",
    "snap6",
  ]
  "instance3" = [
    "snap1",
    "snap4",
  ]
  "instance4" = [
    "snap2",
    "snap3",
  ]
  "instance5" = [
    "snap2",
    "snap3",
  ]
  "instance6" = [
    "snap1",
    "snap4",
  ]
}

答案 1 :(得分:0)

您可能会说,我正在尝试将卷映射到灾难恢复terraform脚本的同一Availability_zone中的实例。原始(灾难前)群集在3个可用区之间分布了相等数量的实例。在发生灾难的情况下,我需要在相同数量的可用区中还原群集,以将节点保留为可用区组组合。

我不确定这是否是解决此问题的最干净的方法,但这就是我最终要做的事情。如果有人有更好/更干净的方法,我仍然可以提出建议,但我很高兴至少现在可以这样做。

首先,我最终根据像这样的可用区创建了字符串映射图元组:

instance_az = [
  flatten([for instance in aws_instance.cassandra: 
    map(
      instance.availability_zone,
      zipmap(
        matchkeys(
          tolist(aws_instance.cassandra.*.id),
          tolist(aws_instance.cassandra.*.availability_zone),  
          [instance.availability_zone]
        ),
        matchkeys(
          tolist(aws_ebs_volume.data.*.id),
          tolist(aws_ebs_volume.data.*.availability_zone),        
          [instance.availability_zone]
        )
      )
    )
  ])
]

示例输出:

instance_az = [
  [
    {
      "us-east-1c" = {
        "i-0a18b339d3f1ddd80" = "vol-0ace4794f40c256ed"
        "i-0bd9681b1b856c3db" = "vol-00f694635ef7b0904"
      }
    },
    {
      "us-east-1a" = {
        "i-033c004ed25dbd907" = "vol-0a31e52f2e11dfdef"
        "i-0ed01a562756800e9" = "vol-0a20cabb0ae568084"
      }
    },
    {
      "us-east-1b" = {
        "i-0400baef538ea327a" = "vol-060aff04e902f7005"
        "i-08ed6b26743a2bd95" = "vol-06917d88b07bd5d5c"
      }
    },
    {
      "us-east-1c" = {
        "i-0a18b339d3f1ddd80" = "vol-0ace4794f40c256ed"
        "i-0bd9681b1b856c3db" = "vol-00f694635ef7b0904"
      }
    },
    {
      "us-east-1a" = {
        "i-033c004ed25dbd907" = "vol-0a31e52f2e11dfdef"
        "i-0ed01a562756800e9" = "vol-0a20cabb0ae568084"
      }
    },
    {
      "us-east-1b" = {
        "i-0400baef538ea327a" = "vol-060aff04e902f7005"
        "i-08ed6b26743a2bd95" = "vol-06917d88b07bd5d5c"
      }
    },
  ],
]

该输出的问题是,每个可用区都被列出两次,且具有完全相同的instanceId-> volumeId映射。接下来,我想删除重复项,因此我将其转换为这样的集合:

  inst_vol_to_set = {
    s = toset(local.instance_az[0])
  }

现在我的输出如下:

inst_vol_to_set = {
  "s" = [
    {
      "us-east-1a" = {
        "i-033c004ed25dbd907" = "vol-0a31e52f2e11dfdef"
        "i-0ed01a562756800e9" = "vol-0a20cabb0ae568084"
      }
    },
    {
      "us-east-1b" = {
        "i-0400baef538ea327a" = "vol-060aff04e902f7005"
        "i-08ed6b26743a2bd95" = "vol-06917d88b07bd5d5c"
      }
    },
    {
      "us-east-1c" = {
        "i-0a18b339d3f1ddd80" = "vol-0ace4794f40c256ed"
        "i-0bd9681b1b856c3db" = "vol-00f694635ef7b0904"
      }
    },
  ]
}

确定看起来更像我想要完成的目标。现在,我只需要将其转换为instanceId-> VolumeId的映射即可:

  inst_vol = [
    flatten([for s in lookup(local.inst_vol_to_set, "s"): [
      for key in keys(s): [
        for idx, v in keys(s[key]): {
          "${v}" = lookup(s[key], v)
        }

      ]
    ]])
  ]

现在看起来好多了,但仍然是地图的元组:

inst_vol = [
  [
    {
      "i-033c004ed25dbd907" = "vol-0a31e52f2e11dfdef"
    },
    {
      "i-0ed01a562756800e9" = "vol-0a20cabb0ae568084"
    },
    {
      "i-0400baef538ea327a" = "vol-060aff04e902f7005"
    },
    {
      "i-08ed6b26743a2bd95" = "vol-06917d88b07bd5d5c"
    },
    {
      "i-0a18b339d3f1ddd80" = "vol-0ace4794f40c256ed"
    },
    {
      "i-0bd9681b1b856c3db" = "vol-00f694635ef7b0904"
    },
  ],
]

最后要做的是将结果展平,以便我可以查找instance_id并使其返回volume_id:

instance_to_volume_map = merge(flatten(local.inst_vol)...)

现在这正是我想要的:

instance_to_volume_map = {
  "i-033c004ed25dbd907" = "vol-0a31e52f2e11dfdef"
  "i-0400baef538ea327a" = "vol-060aff04e902f7005"
  "i-08ed6b26743a2bd95" = "vol-06917d88b07bd5d5c"
  "i-0a18b339d3f1ddd80" = "vol-0ace4794f40c256ed"
  "i-0bd9681b1b856c3db" = "vol-00f694635ef7b0904"
  "i-0ed01a562756800e9" = "vol-0a20cabb0ae568084"
}