此对象没有名为 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 来为特定键不可用时提供备用值。这意味着生成的数据结构将始终具有该类型的属性,但它可能引用一个空映射,这比可能根本不存在的属性更容易处理。 它大量使用tomaptostring 来断言每个属性的预期类型。因此,如果给定值不适合这些约束之一,这将允许 Terraform 提早引发错误,并确保 Terraform 可以为此数据结构推断出合适的静态类型,您可以在其他地方依赖它。

使用这种新的规范化数据结构,您可以在所有元素上引用 memberssubteams,并且知道它始终会被设置,但可能会被设置为空映射。

【讨论】:

│ 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 嗯是的...我没有让他的子团队结构完全正确(错过了namemembers 的额外对象级别)并且这个数据结构对于当前来说似乎有点太复杂了Terraform 能够弄清楚如何自动将***结构转换为地图。我在这里修复了这两件事;现在应该可以了。 现在我使用了两个单独的文件,因为我更容易理解和管理,但我不确定我应该在这里使用tomap()

以上是关于此对象没有名为 yaml 结构的属性的主要内容,如果未能解决你的问题,请参考以下文章

Go语言之读取yaml配置文件,转换成struct结构,json形式输出

错误:不支持的属性。此对象没有名为“nsg_name”的属性

我可以为 YAML 层次结构中的非叶节点分配值吗?

在结构的计算属性中访问环境对象属性

k8s学习-k8s资源对象与yaml结构

yaml支持的三种数据的结构及其获取(代码实战)