1
1
Fork 0
mirror of https://github.com/mcuadros/ascode synced 2024-05-08 08:36:15 +02:00

starlark/types: ResourceCollection documentation and exmaples

This commit is contained in:
Máximo Cuadros 2020-03-24 08:40:53 +01:00
parent 9f59c34ce6
commit df4f8b77fb
No known key found for this signature in database
GPG Key ID: 17A5DFEDC735AE4B
7 changed files with 167 additions and 48 deletions

View File

@ -9,6 +9,51 @@ import (
"go.starlark.net/syntax"
)
// ResourceCollection stores and instantiates resources for specific provider
// and resource.
//
// outline: types
// types:
// ResourceCollection
// ResourceCollection stores and instantiates resources for specific
// provider and resource. The resources can be accessed by indexing or
// using the built-in method of `dict`.
//
// fields:
// __provider__ Provider
// Provider of this resource collection.
// __kind__ string
// Kind of the resource collection. Eg.: `data`
// __type__ string
// Type of the resource collection. Eg.: `aws_instance`
//
// methods:
// __call__(name="", values="") Resource
// Returns a new resourced with the given name and values.
//
// examples:
// resource_collection_call.star
// Resource instantiation using values, dicts or kwargs.
//
// params:
// name string
// Local name of the resource, if `None` is provided it's
// autogenerated.
// values dict
// List of arguments and nested blocks to be set in the new
// resource, this values can be also defined using `kwargs`.
// search(key="id", value) list
// Return all the Resources with the given value in the given key.
//
// examples:
// resource_collection_search.star
//
// params:
// name string
// Key to search. The default value is `id`.
// value <any>
// Value to match in the given key.
//
type ResourceCollection struct {
typ string
kind Kind
@ -201,8 +246,18 @@ func (c *ResourceCollection) Attr(name string) (starlark.Value, error) {
switch name {
case "search":
return starlark.NewBuiltin("search", c.search), nil
case "__dict__":
return c.toDict(), nil
case "__provider__":
if c.kind.IsProviderRelated() {
if c.provider == nil {
return starlark.None, nil
}
return c.provider, nil
}
case "__kind__":
return starlark.String(c.kind), nil
case "__type__":
return starlark.String(c.typ), nil
}
return c.List.Attr(name)
@ -210,7 +265,8 @@ func (c *ResourceCollection) Attr(name string) (starlark.Value, error) {
// AttrNames honors the starlark.HasAttrs interface.
func (c *ResourceCollection) AttrNames() []string {
return append(c.List.AttrNames(), "search", "__dict__")
return append(c.List.AttrNames(),
"search", "__provider__", "__kind__", "__type__")
}
func (c *ResourceCollection) search(_ *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, _ []starlark.Tuple) (starlark.Value, error) {

View File

@ -13,43 +13,6 @@ import (
"go.starlark.net/syntax"
)
func BuiltinProvider(pm *terraform.PluginManager) starlark.Value {
return starlark.NewBuiltin("provider", func(_ *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
var typ, version, name starlark.String
switch len(args) {
case 3:
var ok bool
name, ok = args.Index(2).(starlark.String)
if !ok {
return nil, fmt.Errorf("expected string, got %s", args.Index(2).Type())
}
fallthrough
case 2:
var ok bool
version, ok = args.Index(1).(starlark.String)
if !ok {
return nil, fmt.Errorf("expected string, got %s", args.Index(1).Type())
}
fallthrough
case 1:
var ok bool
typ, ok = args.Index(0).(starlark.String)
if !ok {
return nil, fmt.Errorf("expected string, got %s", args.Index(0).Type())
}
default:
return nil, fmt.Errorf("unexpected positional arguments count")
}
p, err := NewProvider(pm, typ.GoString(), version.GoString(), name.GoString())
if err != nil {
return nil, err
}
return p, p.loadKeywordArgs(kwargs)
})
}
// Provider represents a provider as a starlark.Value.
//
// outline: types
@ -181,6 +144,26 @@ func (x *Provider) CompareSameType(op syntax.Token, y_ starlark.Value, depth int
}
}
// ResourceCollectionGroup represents a group by kind (resource or data resource)
// of ResourceCollections for a given provider.
//
// outline: types
// types:
// ResourceCollectionGroup
// ResourceCollectionGroup represents a group by kind (resource or data
// resource) of ResourceCollections for a given provider.
//
// fields:
// __provider__ Provider
// Provider of this group.
// __kind__ string
// Kind of the resources (`data` or `resource`).
// <resource-name> ResourceCollection
// It returns a ResourceCollection if the resource name is valid for
// the schema of the provider. The resource name should be provided
// without the provider prefix, `aws_instance` becomes
// just `instance`.
//
type ResourceCollectionGroup struct {
provider *Provider
kind Kind
@ -191,11 +174,13 @@ type ResourceCollectionGroup struct {
var _ starlark.Value = &ResourceCollectionGroup{}
var _ starlark.HasAttrs = &ResourceCollectionGroup{}
func NewResourceCollectionGroup(p *Provider, k Kind, schemas map[string]providers.Schema) *ResourceCollectionGroup {
// NewResourceCollectionGroup returns a new ResourceCollectionGroup for a given
// provider and kind based on the given schema.
func NewResourceCollectionGroup(p *Provider, k Kind, schema map[string]providers.Schema) *ResourceCollectionGroup {
return &ResourceCollectionGroup{
provider: p,
kind: k,
schemas: schemas,
schemas: schema,
collections: make(map[string]*ResourceCollection),
}
}
@ -228,8 +213,14 @@ func (g *ResourceCollectionGroup) Hash() (uint32, error) {
// Attr honors the starlark.HasAttrs interface.
func (g *ResourceCollectionGroup) Attr(name string) (starlark.Value, error) {
name = g.provider.typ + "_" + name
switch name {
case "__provider__":
return g.provider, nil
case "__kind__":
return starlark.String(g.kind), nil
}
name = g.provider.typ + "_" + name
if c, ok := g.collections[name]; ok {
return c, nil
}
@ -253,5 +244,5 @@ func (g *ResourceCollectionGroup) AttrNames() []string {
i++
}
return names
return append(names, "__kind__", "__provider__")
}

View File

@ -11,7 +11,7 @@ provider.region = "us-central1"
print_provider_info(provider)
# Output:
# Provider google[id_1] (3.13.0)
# Defines Data Sources: 58
# Defines Resources: 261
# Defines Data Sources: 60
# Defines Resources: 263
# Configuration: {"project": "acme-app", "region": "us-central1"}

View File

@ -0,0 +1,27 @@
aws = tf.provider("aws")
# Resources can be defined in different ways...
# you can set the resource attributes...
v = aws.resource.instance()
v.instance_type = "t2.micro"
v.tags = {"name": "HelloWorld"}
# or using a dict in the constructor...
d = aws.resource.instance({
"instance_type": "t2.micro",
"tags": {"name": "HelloWorld"},
})
# or even using kwargs
k = aws.resource.instance(instance_type="t2.micro", tags={"name": "HelloWorld"})
# and all the resources are equivalent:
print(v.__dict__)
print(d.__dict__)
print(k.__dict__)
# Output:
# {"instance_type": "t2.micro", "tags": {"name": "HelloWorld"}}
# {"instance_type": "t2.micro", "tags": {"name": "HelloWorld"}}
# {"instance_type": "t2.micro", "tags": {"name": "HelloWorld"}}

View File

@ -0,0 +1,14 @@
aws = tf.provider("aws")
aws.resource.instance("foo", instance_type="t2.micro")
aws.resource.instance("bar", instance_type="a1.medium")
aws.resource.instance("qux", instance_type="t2.micro")
r = aws.resource.instance.search("bar")
print("Instance type of `bar`: %s" % r[0].instance_type)
r = aws.resource.instance.search("instance_type", "t2.micro")
print("Instances with 't2.micro`: %d" % len(r))
# Output:
# Instance type of `bar`: a1.medium
# Instances with 't2.micro`: 2

View File

@ -15,8 +15,8 @@ assert.eq("data" in dir(p), True)
assert.eq("resource" in dir(p), True)
# attr
assert.eq(len(dir(p.data)), 131)
assert.eq(len(dir(p.resource)), 506)
assert.eq(len(dir(p.data)), 133)
assert.eq(len(dir(p.resource)), 508)
resources = dir(p.resource)
assert.contains(resources, "instance")
@ -48,6 +48,12 @@ assert.eq(alias.__version__, "2.13.0")
kwargs = tf.provider("aws", region="foo")
assert.eq(kwargs.region, "foo")
# ResourceCollectionGroup
assert.eq("__kind__" in dir(p.resource), True)
assert.eq(p.resource.__kind__, "resource")
assert.eq("__provider__" in dir(p.resource), True)
assert.eq(p.resource.__provider__, p)
# compare
assert.ne(p, kwargs)
assert.ne(p, kwargs)

View File

@ -2,6 +2,8 @@ load("assert.star", "assert")
ignition = tf.provider("ignition", "1.1.0")
# attr
qux = ignition.data.user()
qux.uid = 42
@ -73,6 +75,10 @@ group.mixed_instances_policy = {
assert.eq(group.mixed_instances_policy.launch_template.launch_template_specification.launch_template_id, "bar")
# attr collections
assert.eq("__provider__" in dir(web.network_interface), True)
assert.eq("__type__" in dir(web.network_interface), True)
assert.eq("__kind__" in dir(web.network_interface), True)
web.network_interface = [
{"network_interface_id": "foo"},
{"network_interface_id": "bar"},
@ -217,18 +223,37 @@ assert.eq(web.__provider__, aws)
assert.eq(baz.__provider__, ignition)
assert.eq(instanceA.__provider__, aws)
assert.eq(home.__provider__, ignition)
assert.eq(aws.resource.instance.__provider__, aws)
# __kind__
assert.eq(ignition.data.user().__kind__, "data")
assert.eq(aws.resource.instance.__kind__, "resource")
assert.eq(aws.resource.instance().__kind__, "resource")
assert.eq(aws.resource.autoscaling_group().mixed_instances_policy.__kind__, "nested")
assert.eq(web.network_interface.__kind__, "nested")
# __type__
assert.eq(ignition.data.user().__type__, "ignition_user")
assert.eq(aws.resource.instance.__type__, "aws_instance")
assert.eq(aws.resource.instance().__type__, "aws_instance")
assert.eq(aws.resource.autoscaling_group().mixed_instances_policy.__type__, "mixed_instances_policy")
assert.eq(web.network_interface.__type__, "network_interface")
# __name__
assert.eq(ignition.data.user().__name__, "id_30")
assert.eq(aws.resource.instance().__name__, "id_31")
assert.eq(ignition.data.user("given").__name__, "given")
# __call__
assert.eq(ignition.data.user().__name__, "id_32")
assert.eq(ignition.data.user("foo").__name__, "foo")
assert.eq(ignition.data.user(uid=42).uid, 42)
assert.eq(ignition.data.user({"uid": 42}).uid, 42)
foo = ignition.data.user("foo", {"uid": 42})
assert.eq(foo.__name__, "foo")
assert.eq(foo.uid, 42)
foo = ignition.data.user("foo", uid=42)
assert.eq(foo.__name__, "foo")
assert.eq(foo.uid, 42)