pulumi / pulumi-converter-terraform

Apache License 2.0
9 stars 3 forks source link

State converter doesn't always get the right import strings #43

Open Frassle opened 1 year ago

Frassle commented 1 year ago

Hello!

Issue details

Currently the terraform state converter assumes that the import string for each resource is that resources ID. This is not actually true, for example @jaxxstorm tried to import an "aws:ec2:Route":

 aws:ec2:Route (public_internet_gateway-0):
    error: Preview failed: importing r-rtb-02a2262371ebeb7311080289494: unexpected format of ID ("r-rtb-02a2262371ebeb7311080289494"), expected ROUTETABLEID_DESTINATION

We should work out how to cover resources like this in the converter, probably requiring new information in the mapping files.

Affected area/feature

justinvp commented 1 year ago

For reference, some of these special cases are noted here:

Frassle commented 1 year ago

For now the state converter is copying those hardcoded lists https://github.com/pulumi/pulumi-terraform-bridge/pull/677/commits/ad76640ab09509dc37f7d92cc0ffd3616d3fb227

GeoffMillerAZ commented 12 months ago

I was building the following sample terraform codebase to propose a change in import naming. However, I experienced this same error on my sample codebase and had to use different resources for my example.

provider "aws" {
  profile = var.aws_profile
  region  = "us-west-2"
}

resource "random_string" "default" {
  length  = 16
  numeric = false
  special = false
  upper   = false
  lower   = true
}

resource "aws_ssm_parameter" "s3" {
  name  = format("/%s/foo", random_string.default.result)
  type  = "String"
  value = "bar"
}

resource "aws_s3_bucket" "s3" {
  bucket = format("example-bucket-%s", random_string.s3.result)
}

resource "aws_s3_bucket_object" "s3" {
  bucket = aws_s3_bucket.s3.id
  key    = "my-object"
  source = "main.tf"
}

resource "aws_s3_access_point" "s3" {
  name   = "my-access-point"
  bucket = aws_s3_bucket.s3.id
}

pulumi import --from terraform terraform.tfstate

error: Preview failed: importing my-object: id my-object should be in format <bucket>/<key> or s3://<bucket>/<key>
ill-eye commented 11 months ago

Just a thought here, could those mappings be go-templates? E.g. for this

case "aws_ecs_service":
    cluster, err := getString(resource.Addr.Resource, obj, "cluster")
    if err != nil {
        return nil, err
    }
    name, err := getString(resource.Addr.Resource, obj, "name")
    if err != nil {
        return nil, err
    }
    parts := strings.Split(cluster, "/")
    id = fmt.Sprintf("%s/%s", parts[len(parts)-1], name)`

it could be something like:

aws_ecs_service = `{{ $s := (split .cluster "/") }}{{ index $s (sub (len $s) 1) }}/{{ .name }}`

With split and sub and other useful functions added with a funcMap.

This is a working test program

package main

import (
    "os"
    "strings"
    "text/template"
)

func main() {
    var funcMap = template.FuncMap{
        "split": strings.Split,
        "sub": func(x int, y int) int {
            return x - y
        },
    }
    var obj = map[string]interface{}{
        "cluster": "useless/part/prefix",
        "name":    "cluster-name",
    }
    var tpl, err = template.New("test").Funcs(funcMap).Parse(`{{ $s := (split .cluster "/") }}{{ index $s (sub (len $s) 1) }}/{{ .name }}`)
    if err != nil {
        panic(err)
    }
    err = tpl.Execute(os.Stdout, obj)
    if err != nil {
        panic(err)
    }
}
Frassle commented 11 months ago

could those mappings be go-templates?

Probably, that was my first thought for this as well.