Custom provider flatten problem

Hello,

I’m trying write custom provider and faced with next error

Error: roles: must be a map

I have the next field in the schema

"roles" : &schema.Schema {
    Type          : schema.TypeMap,
        Computed      : true,
        Elem : &schema.Resource {
          Schema : datasourceRoleSchema(),
    },
 },

and next code to setup

tmp := flattenRoles(value.([]Roles))
if len(tmp) > 0 {
    err = d.Set(fieldName, tmp)
}

flattenRoles looks like

func flattenRoles(roles []Roles) []map[string]interface{} {
  flattened := make([]map[string]interface{}, len(roles))

  for i, v := range roles {
    m := make(map[string]interface{})
    m["role"] = flattenRole(v.Role)

    flattened[i] = m
  }

  return flattened
}

func flattenRole(role *Role) map[string]interface{} {
  m := make(map[string]interface{})

  m["id"]           = role.ID
  m["label"]        = role.Label
  m["identifier"]   = role.Identifier

  return m
}

JSON input looks like:

"roles": [
                {
                    "role": {
                        "created_at": "2020-03-10T14:34:27.000+02:00",
                        "id": 3,
                        "identifier": "locations_manager",
                        "label": "Cloud Locations Manager",
                        "permissions": [
                            {
                                "permission": {
                                    "created_at": "2020-03-10T14:34:19.000+02:00",
                                    "id": 137,
                                    "identifier": "cdn_locations",
                                    "updated_at": "2020-03-10T14:34:19.000+02:00"
                                }
                            },
                            {
                                "permission": {
                                    "created_at": "2020-03-10T14:34:21.000+02:00",
                                    "id": 450,
                                    "identifier": "location_groups",
                                    "updated_at": "2020-03-10T14:34:21.000+02:00"
                                }
                            }
                        ],
                        "system": false,
                        "updated_at": "2020-03-10T14:34:27.000+02:00",
                        "users_count": 1
                    }
                }
            ],

In the future please use subjects for your topics which actually express the problem or issue you are having. If you don’t many people will just skip over them since they have no idea whether they can provide any assistance.

It appears that your ‘roles’ element is not a map, it’s a list. That would explain why you are getting an error, if a map is required.

Okay, thank you.

But previously I declare roles as TypeList and got error:

2020/03/13 16:58:16 [ERROR] <root>: eval: *terraform.EvalReadData, err: Invalid address to set: []string{"roles", "0", "role"}
2020/03/13 16:58:16 [ERROR] <root>: eval: *terraform.EvalSequence, err: Invalid address to set: []string{"roles", "0", "role"}

I can’t find problem… the schema is the same like Permissions but don’t work.

Also, there is a dedicated category in this forum for discussion of Terraform Providers, and it tends to be used for discussion of provider development. You may want to move this topic to that category.

Okay, I found my mistake, schema must looks like:

  "roles" : &schema.Schema {
    Type          : schema.TypeList,
    Computed      : true,
    Elem : &schema.Resource {
      Schema: map[string]*schema.Schema{
        "role": &schema.Schema {
          Type:        schema.TypeMap,
          Optional:    true,
          Elem: &schema.Resource{
            Schema : datasourceRoleSchema(),
          },
        },
      },
    },
  },

But I got another error

roles.0.role.permissions: '' expected type 'string', got unconvertible type '[]map[string]interface {}'

func datasourceRoleSchema() map[string]*schema.Schema {
  return map[string]*schema.Schema {
    ...
    "permissions" : datasourcePermissionsSchema(),
  }
}

func datasourcePermissionsSchema() *schema.Schema {
  return &schema.Schema {
    Type          : schema.TypeList,
    Computed      : true,
    Elem : &schema.Resource {
      Schema : map[string]*schema.Schema {
        "permission" : &schema.Schema {
          Type      : schema.TypeMap,
          Computed  : true,
          Elem : &schema.Resource {
            Schema : map[string]*schema.Schema {
              "id" : &schema.Schema {
                Type      : schema.TypeInt,
                Computed  : true,
              },
              "identifier" : &schema.Schema {
                Type      : schema.TypeString,
                Computed  : true,
              },
            },
          },
        },
      },
    },
  }
}

Anyone? I can’t understand where is error…

Hello,

Seems I found where is the problem, maybe it is related to the terraform restriction about simple type in the map, as described early field “role” is a TypeMap, so field “permissions” can be only simple type, but not TypeList

So someone could help me figure out how to describe complex type in this situation?