此对象没有名为 yaml 结构的属性
Posted
技术标签:
【中文标题】此对象没有名为 yaml 结构的属性【英文标题】:This object does not have an attribute named yaml structures 【发布时间】:2022-01-22 02:28:25 【问题描述】:我想在一个 yaml 文件中构建我的组织结构,供 github 提供者管理团队、成员,有些团队包含子元素,如子团队,有些不包含,for 循环错误时出现“此对象没有命名的属性” yaml 中的结构不一样,我尝试使用 lookup()、contains()、if() 但我刚刚开始使用 terraform,所以也许你可以帮助我如何实现这一目标?
# cat locals.tf
locals
teams = yamldecode(file("teams.yaml"))["teams"]
teams_flatten = flatten([
for team in local.teams :
team_name = team.name
description = lookup(team, "description", "")
privacy = lookup(team, "privacy", "closed")
])
subteams_flatten = flatten([
for team in local.teams : [
for subteam in team.subteams :
team_name = team.name
subteam_name = subteam.name
description = lookup(subteam, "description", "")
privacy = lookup(subteam, "privacy", "closed")
]
])
│ on locals.tf line 16, in locals:
│ 16: for subteam in team.subteams :
│
│ This object does not have an attribute named "subteams".
# cat teams.yaml
---
teams:
# Parent team
- name: Engineering
# This team has sub-teams
subteams:
- name: access
members:
- member: alex
role: maintainer
- member: bob
role: maintainer
- name: payments
members:
- member: alice
role: maintainer
# Parent team
- name: Marketing
# This team does not have any sub-teams
members:
- member: bob
role: maintainer
- member: alex
role: maintainer
# cat teams.tf
resource "github_team" "teams"
for_each =
for team in local.teams_flatten : team.team_name => team
name = each.value.team_name
description = each.value.description
privacy = each.value.privacy
resource "github_team" "subteams"
depends_on = [github_team.teams]
for_each =
for subteam in local.subteams_flatten : subteam.subteam_name => subteam
name = each.value.subteam_name
parent_team_id = lookup(github_team.teams, each.value.team_name)["id"]
description = each.value.description
privacy = each.value.privacy
【问题讨论】:
通常这就是 lambda 迭代器在几乎所有语言中的作用方式。如果要迭代特定的嵌套键,则该键必须存在于每个迭代器的结构中。 是的,但是但是 :) 有时您可能想尝试在元素存在时使事情正常工作,有时不,因此试图弄清楚如何使其工作:) 【参考方案1】:在使用这种结构不一定一致的原始人工编辑文件时,有时可以先将数据结构明确规范化为一个单独的步骤,然后在其他地方使用更一致的数据结构。然后将密集的条件代码隔离在一个地方,因此希望使模块的其余部分更易于阅读。
例如:
locals
teams_raw = yamldecode(file("$path.module/teams.yaml"))["teams"]
teams =
for team_raw in local.teams_raw : tostring(team_raw.name) =>
name = tostring(team_raw.name)
subteams = tomap(
for subteam_raw in try(team_raw.subteams, []) :
tostring(subteam_raw.name) =>
name = tostring(subteam_raw.name)
members = tomap(
for member_raw in subteam_raw.members :
tostring(member_raw.member) =>
name = tostring(member_raw.member)
role = tostring(member_raw.role)
)
)
members = tomap(
for member_raw in try(team_raw.members, []) :
tostring(member_raw.member) =>
name = tostring(member_raw.member)
role = tostring(member_raw.role)
)
上述local.teams
定义的两个主要相关特征是:
try
来为特定键不可用时提供备用值。这意味着生成的数据结构将始终具有该类型的属性,但它可能引用一个空映射,这比可能根本不存在的属性更容易处理。
它大量使用tomap
和tostring
来断言每个属性的预期类型。因此,如果给定值不适合这些约束之一,这将允许 Terraform 提早引发错误,并确保 Terraform 可以为此数据结构推断出合适的静态类型,您可以在其他地方依赖它。
使用这种新的规范化数据结构,您可以在所有元素上引用 members
和 subteams
,并且知道它始终会被设置,但可能会被设置为空映射。
【讨论】:
│ Error: Invalid reference
│ on locals.tf line 5, in locals:
│ 5: for team_raw in teams_raw : tostring(team_raw.name) =>
│ A reference to a resource type must be followed by at least one attribute access, specifying the resource name.
我试着把它改成for team_raw in local.teams_raw : tostring(team_raw.name) =>
│ Error: Invalid function argument
│ │ local.teams_raw is tuple with 2 elements
│ Invalid value for "v" parameter: cannot convert object to map of any single type
嗯是的...我没有让他的子团队结构完全正确(错过了name
和members
的额外对象级别)并且这个数据结构对于当前来说似乎有点太复杂了Terraform 能够弄清楚如何自动将***结构转换为地图。我在这里修复了这两件事;现在应该可以了。
现在我使用了两个单独的文件,因为我更容易理解和管理,但我不确定我应该在这里使用tomap()
以上是关于此对象没有名为 yaml 结构的属性的主要内容,如果未能解决你的问题,请参考以下文章
Go语言之读取yaml配置文件,转换成struct结构,json形式输出