1
1
mirror of https://github.com/mcuadros/ascode synced 2024-11-22 17:02:03 +01:00

starlark/types: Resource.depends_on support

Signed-off-by: Máximo Cuadros <mcuadros@gmail.com>
This commit is contained in:
Máximo Cuadros 2019-07-23 21:12:55 +02:00
parent 5eee1fa944
commit d25c7b32a2
4 changed files with 94 additions and 11 deletions

@ -4,6 +4,7 @@ import (
"fmt"
"github.com/hashicorp/hcl2/hcl"
"github.com/hashicorp/hcl2/hcl/hclsyntax"
"github.com/hashicorp/hcl2/hclwrite"
"github.com/zclconf/go-cty/cty"
"go.starlark.net/starlark"
@ -69,12 +70,14 @@ func (r *Resource) ToHCL(b *hclwrite.Body) {
body := block.Body()
if r.parent.kind == ProviderKind {
body.SetAttributeTraversal("provider", hcl.Traversal{hcl.TraverseRoot{
Name: fmt.Sprintf("%s.%s", r.parent.typ, r.parent.Name()),
}})
body.SetAttributeTraversal("provider", hcl.Traversal{
hcl.TraverseRoot{Name: r.parent.typ},
hcl.TraverseAttr{Name: r.parent.Name()},
})
}
r.doToHCLAttributes(body)
r.doToHCLDependencies(body)
}
func (r *Resource) doToHCLAttributes(body *hclwrite.Body) {
@ -84,11 +87,10 @@ func (r *Resource) doToHCLAttributes(body *hclwrite.Body) {
continue
}
// TODO(mcuadros): I don't know how to do this properly, meanwhile, this works.
if c, ok := v.v.(*Computed); ok {
body.SetAttributeTraversal(k, hcl.Traversal{hcl.TraverseRoot{
Name: c.String(),
}})
body.SetAttributeTraversal(k, hcl.Traversal{
hcl.TraverseRoot{Name: c.String()},
})
continue
}
@ -107,3 +109,44 @@ func (r *Resource) doToHCLAttributes(body *hclwrite.Body) {
}
}
}
func (r *Resource) doToHCLDependencies(body *hclwrite.Body) {
if len(r.dependenies) == 0 {
return
}
toks := []*hclwrite.Token{}
toks = append(toks, &hclwrite.Token{
Type: hclsyntax.TokenIdent,
Bytes: []byte("depends_on"),
})
toks = append(toks, &hclwrite.Token{
Type: hclsyntax.TokenEqual, Bytes: []byte{'='},
}, &hclwrite.Token{
Type: hclsyntax.TokenOBrack, Bytes: []byte{'['},
})
l := len(r.dependenies)
for i, dep := range r.dependenies {
name := fmt.Sprintf("%s.%s", dep.typ, dep.Name())
toks = append(toks, &hclwrite.Token{
Type: hclsyntax.TokenIdent, Bytes: []byte(name),
})
if i+1 == l {
break
}
toks = append(toks, &hclwrite.Token{
Type: hclsyntax.TokenComma, Bytes: []byte{','},
})
}
toks = append(toks, &hclwrite.Token{
Type: hclsyntax.TokenCBrack, Bytes: []byte{']'},
})
body.AppendUnstructuredTokens(toks)
body.AppendNewline()
}

@ -37,8 +37,10 @@ type Resource struct {
typ string
kind Kind
block *configschema.Block
parent *Resource
values map[string]*Value
parent *Resource
dependenies []*Resource
}
// MakeResource returns a new resource of the given kind, type based on the
@ -121,6 +123,8 @@ func (r *Resource) Hash() (uint32, error) {
// Attr honors the starlark.HasAttrs interface.
func (r *Resource) Attr(name string) (starlark.Value, error) {
switch name {
case "depends_on":
return starlark.NewBuiltin("depends_on", r.dependsOn), nil
case "__dict__":
return r.toDict(), nil
}
@ -233,6 +237,25 @@ func (r *Resource) toDict() *starlark.Dict {
return d
}
func (r *Resource) dependsOn(_ *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, _ []starlark.Tuple) (starlark.Value, error) {
resources := make([]*Resource, len(args))
for i, arg := range args {
resource, ok := arg.(*Resource)
if !ok || resource.kind != DataSourceKind && resource.kind != ResourceKind {
return nil, fmt.Errorf("expected Resource<[data|resource].*>, got %s", arg.Type())
}
if r == resource {
return nil, fmt.Errorf("can't depend on itself")
}
resources[i] = resource
}
r.dependenies = append(r.dependenies, resources...)
return starlark.None, nil
}
// CompareSameType honors starlark.Comprable interface.
func (x *Resource) CompareSameType(op syntax.Token, y_ starlark.Value, depth int) (bool, error) {
y := y_.(*Resource)

@ -9,10 +9,12 @@ ubuntu.filter(name = "name", values = ["ubuntu/images/hvm-ssd/ubuntu-trusty-14.0
ubuntu.filter(name = "virtualization-type", values = ["hvm"])
ubuntu.owners = ["099720109477"]
fedora = aws.data.ami("fedora")
web = aws.resource.instance(instance_type = "t2.micro")
web.depends_on(ubuntu, fedora)
#web.instance_type = "t2.micro"
#web.ami = ami.id
web.instance_type = "t2.micro"
web.ami = ubuntu.id
template = aws.resource.launch_template()
template.name_prefix = "example"

@ -125,4 +125,19 @@ assert.eq(disk.__dict__, {
"size": 4194304,
"label": "home"
}]
})
})
# depends_on
userA = p.data.user()
userB = p.data.user()
userA.depends_on(userB)
def dependsOnNonResource(): userA.depends_on(42)
assert.fails(dependsOnNonResource, "expected Resource<\\[data|resource\\].\\*>, got int")
def dependsOnNestedResource(): userA.depends_on(disk.partition())
assert.fails(dependsOnNestedResource, "expected Resource<\\[data|resource\\].\\*>, got Resource<nested.partition>")
def dependsOnItself(): userA.depends_on(userA)
assert.fails(dependsOnItself, "can't depend on itself")