New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
interpolation variable #81
Conversation
provider/import.go
Outdated
@@ -130,6 +134,16 @@ func Import(ctx context.Context, p Provider, hcl, tfstate writer.Writer, f *filt | |||
return errors.Wrapf(err, "error while calculating the satate of resource %q", t) | |||
} | |||
} | |||
// we construct a map[string]string to perform | |||
// interpolation later. By default, the value to interpolate is the ID | |||
// but in some case (ex: google), it can be different. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Different how?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually the comment is misleading. I modified it consequently.
it can be different
resource key could be self_link
with Google.
provider/resource.go
Outdated
@@ -35,6 +35,13 @@ type Resource interface { | |||
// Type is the type of resource (ex: aws_instance) | |||
Type() string | |||
|
|||
// InstanceState is the Terraform state of the resource | |||
// it contains important elements likes `Attributes` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
like*
b7ac476
to
e678986
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall it's ok, I've commented some changes and also some divagations over the implementation haha.
provider/import.go
Outdated
// google special case | ||
// sometimes, the resource is referred by its self_link (https://...) | ||
// so we need to identify if we reference the ressource by its ID or its selfLink (the key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better add it to the actual comment of the function.
provider/import.go
Outdated
if _, ok := hcl.(*h.Writer); ok { | ||
err := util.Interpolate(hcl.(*h.Writer), interpolation) | ||
if err != nil { | ||
return errors.Wrapf(err, "error while Interpolate Config") | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I was reading the util.Interpolate
I already thought that it should go to the hcl
pkg, and now even more so the implementation is the one that tries to convert to the specific type even with that I don't like that as the Interface was ment to avoid knowing the implementation behind it, and this brakes it.
Ways to solve this:
- Have the
util
be the one that converts so it expects awrite.Writer
not anhcl.Writer
(still not good IMO) - Move it to
hcl
pkg - Add it to the
write.Wiriter
interface - Make the
Sync()
expect themap[string]string
.
The last 2 are the ones I prefer as they delay the implementation to the actual one (State will do nothing as no Interpolation is needed and HCL will do something).
provider/import.go
Outdated
if _, ok := s.Attributes["self_link"]; ok { | ||
return "self_link" | ||
} | ||
return "id" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've commented it to @tormath1 on PM that this could be much more things than just the id
, on an aws_instance
the relations could be done with https://www.terraform.io/docs/providers/aws/r/instance.html#attributes-reference any of those. But maybe for now only the ID it's the important one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Among the list we want for sure - and that we already widely use (some services I can think of):
id
(general reference), arn
(iam,alb,etc), name
(iam,r53), fqdn
(r53)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, my current thought would be to have an AttributesReference
associated to a Resource
. This attribute would be simply feed by https://github.com/cycloidio/tfdocs.
Interpolation would now be made there:
terracognita/provider/import.go
Line 92 in 5709caa
for i, re := range resources { |
resources
.
Then looping on the resources, if a value of resources.AttributesReferences[*] match with a value in the resources
, we interpolate.
WDYT ?
Impletemented: 9460151
@@ -65,6 +67,8 @@ func Import(ctx context.Context, p Provider, hcl, tfstate writer.Writer, f *filt | |||
fmt.Fprintf(out, "Importing with filters: %s", f) | |||
logger.Log("filters", f.String()) | |||
|
|||
interpolation := make(map[string]string) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add documentations on what it holds and why is it used.
provider/import.go
Outdated
state := r.InstanceState() | ||
if state != nil { | ||
key := getKey(state) | ||
value := state.Attributes[key] | ||
interpolatedValue := fmt.Sprintf("${%s.%s.%s}", r.Type(), r.Name(), key) | ||
interpolation[value] = interpolatedValue | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also all this logic could be done on the r.HCL
for example as it has all the logic and the actual scope for all this information (state and Name and all of them)
Maybe better have a method on the Resource
that actually returns all the possible interpolated values (right now just ID but potentially more) as the Resource has access to the schema and could potentially know them.
But maybe for now it's ok this way.
c7b6303
to
2f3e972
Compare
@xescugc I'm not really convinced by this solution and it increases the running time. On |
808c787
to
bdd2262
Compare
@xescugc ready for review. In the latest commit, I totally modified the way I was updating the resources. At the beginning I was trying to simply To summarize:
I tried out with a large infra (security groups and instances) and it works as expected. |
01587da
to
bb2cd72
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM it's a good implementation.
hcl/writer.go
Outdated
src := reflect.ValueOf(block) | ||
// this will store the updated block | ||
dest := reflect.New(src.Type()).Elem() | ||
// walk through the resources to interpolate the good values | ||
walk(dest, src, i, name, rt) | ||
// remove reflect.Value wrapper from dest | ||
resources.(map[string]map[string]interface{})[rt][name] = dest.Interface() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you space up this part a bit? Comment+Code+\n so it's easy to read if not it's too dense.
hcl/writer.go
Outdated
// walk through a resource block. it's easier since we do not how the block is made | ||
func walk(dest, src reflect.Value, interpolate map[string]string, name string, resourceType string) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improve the docs, what does it actually do? It goes though all the src
and put it on dest
, so instead of "returning" the result is the "dest". (better wording ofc hehe).
|
||
// what we want to interpolate is a string | ||
// we do not interpolate a custom tag (like cycloid.io) since it's key. | ||
case reflect.String: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented on PM with you already but to keep the record, could it be anything else than String no? Int, bool etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IDK why I forgot to review that code/commit.
res, err = awsdocs.GetResource(r.resourceType) | ||
case "google": | ||
res, err = googledocs.GetResource(r.resourceType) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Return the errors first, basically check them after the end of the switch
provider/resource.go
Outdated
case "aws": | ||
res, err = awsdocs.GetResource(r.resourceType) | ||
case "google": | ||
res, err = googledocs.GetResource(r.resourceType) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could also be done by having an static map where the key is the r.provider.String()
and the value func (r string) (*tfdocresource.Resource, error)
, this way is an static map, and easy to add more instead of having to add a new case
to the switch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Rebase ans squash the commits that you want.
7dc9363
to
6689ba3
Compare
hcl/writer.go
Outdated
resources.(map[string]map[string]interface{})[rt][name] = dest.Interface() | ||
} | ||
} | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why return an error, if it never will?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeh it could be removed now as it's using a different logic.
hcl/writer.go
Outdated
return nil | ||
} | ||
|
||
// walk through a resource block. it's easier since we do not how the block is made |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do not know how* ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
provider/resource.go
Outdated
providerResources = map[string]func(string) (*tfdocs.Resource, error){ | ||
"aws": func(rt string) (*tfdocs.Resource, error) { | ||
return awsdocs.GetResource(rt) | ||
}, | ||
"google": func(rt string) (*tfdocs.Resource, error) { | ||
return googledocs.GetResource(rt) | ||
}, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok a better way:
- Define a function type
func(rt string) (*tfdocs.Resource, error)
- Then the map just have to have
"google" googledocs.GetResource
Which make is much more simpler (that was my first intention but IDK why I read it wrong on the implementation).
Or actually the way you have it now you can still directly use the format without defining the function actually 😄
hcl/writer.go
Outdated
resources.(map[string]map[string]interface{})[rt][name] = dest.Interface() | ||
} | ||
} | ||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeh it could be removed now as it's using a different logic.
we need to be able to get this name in order to construct the complete path of the resource <type>.<name>.<key>
6689ba3
to
891d5d2
Compare
@xescugc final rebase has been made :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just one comment :) Rebase it directly.
provider/resource.go
Outdated
@@ -119,6 +132,21 @@ func NewResource(id, rt string, p Provider) Resource { | |||
} | |||
} | |||
|
|||
func (r *resource) AttributesReference() ([]string, error) { | |||
resourceFunc := providerResources[r.provider.String()] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check the ok
also, as it could not exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
9ac8fef
to
92fe28e
Compare
this function will be used to identify which fields have the ability to be interpolated. For each resource, the attributes will be provided by tfdocs
we first iterate on block resources then for each block we walk through it and for each isolated string, we try to find its interpolation value from the `interpolate` array.
In this PR:
I added a function
Interpolate
with two args: the HCL writer (since there's no interpolation with state AFAIK) and an interpolation map which map a value with its interpolation name. (<resource_type>.<resource_name>.(id|self_link)
)Feel free to test it.
example of output:
Close #37