Skip to content
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

New Data Source: aws_glue_script #4481

Merged
merged 2 commits into from
May 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
184 changes: 184 additions & 0 deletions aws/data_source_aws_glue_script.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package aws

import (
"errors"
"fmt"
"log"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/glue"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
)

func dataSourceAwsGlueScript() *schema.Resource {
return &schema.Resource{
Read: dataSourceAwsGlueScriptRead,
Schema: map[string]*schema.Schema{
"dag_edge": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"source": {
Type: schema.TypeString,
Required: true,
},
"target": {
Type: schema.TypeString,
Required: true,
},
"target_parameter": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
"dag_node": {
Type: schema.TypeList,
Required: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"args": {
Type: schema.TypeList,
Required: true,
MinItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"param": {
Type: schema.TypeBool,
Optional: true,
},
"value": {
Type: schema.TypeString,
Required: true,
},
},
},
},
"id": {
Type: schema.TypeString,
Required: true,
},
"line_number": {
Type: schema.TypeInt,
Optional: true,
},
"node_type": {
Type: schema.TypeString,
Required: true,
},
},
},
},
"language": {
Type: schema.TypeString,
Optional: true,
Default: glue.LanguagePython,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would this be better as Required with no default set?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It defaults to Python if you do not provide a value 😉

ValidateFunc: validation.StringInSlice([]string{
glue.LanguagePython,
glue.LanguageScala,
}, false),
},
"python_script": {
Type: schema.TypeString,
Computed: true,
},
"scala_code": {
Type: schema.TypeString,
Computed: true,
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could argue these could be one field, in case additional languages are added in the future?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why the Glue API distinguishes between the return values. It only returns one of them at a time currently 😕 Maybe it will return multiple in the future. We tend to opt for sticking with API rather than making our own choices for UX due to past maintenance issues. I'm tempted to leave this as-is hoping that AWS has a good reason for this API design decision.

},
}
}

func dataSourceAwsGlueScriptRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).glueconn

dagEdge := d.Get("dag_edge").([]interface{})
dagNode := d.Get("dag_node").([]interface{})

input := &glue.CreateScriptInput{
DagEdges: expandGlueCodeGenEdges(dagEdge),
DagNodes: expandGlueCodeGenNodes(dagNode),
}

if v, ok := d.GetOk("language"); ok && v.(string) != "" {
input.Language = aws.String(v.(string))
}

log.Printf("[DEBUG] Creating Glue Script: %s", input)
output, err := conn.CreateScript(input)
if err != nil {
return fmt.Errorf("error creating Glue script: %s", err)
}

if output == nil {
return errors.New("script not created")
}

d.SetId(time.Now().UTC().String())
d.Set("python_script", output.PythonScript)
d.Set("scala_code", output.ScalaCode)

return nil
}

func expandGlueCodeGenNodeArgs(l []interface{}) []*glue.CodeGenNodeArg {
args := []*glue.CodeGenNodeArg{}

for _, mRaw := range l {
m := mRaw.(map[string]interface{})
arg := &glue.CodeGenNodeArg{
Name: aws.String(m["name"].(string)),
Param: aws.Bool(m["param"].(bool)),
Value: aws.String(m["value"].(string)),
}
args = append(args, arg)
}

return args
}

func expandGlueCodeGenEdges(l []interface{}) []*glue.CodeGenEdge {
edges := []*glue.CodeGenEdge{}

for _, mRaw := range l {
m := mRaw.(map[string]interface{})
edge := &glue.CodeGenEdge{
Source: aws.String(m["source"].(string)),
Target: aws.String(m["target"].(string)),
}
if v, ok := m["target_parameter"]; ok && v.(string) != "" {
edge.TargetParameter = aws.String(v.(string))
}
edges = append(edges, edge)
}

return edges
}

func expandGlueCodeGenNodes(l []interface{}) []*glue.CodeGenNode {
nodes := []*glue.CodeGenNode{}

for _, mRaw := range l {
m := mRaw.(map[string]interface{})
node := &glue.CodeGenNode{
Args: expandGlueCodeGenNodeArgs(m["args"].([]interface{})),
Id: aws.String(m["id"].(string)),
NodeType: aws.String(m["node_type"].(string)),
}
if v, ok := m["line_number"]; ok && v.(int) != 0 {
node.LineNumber = aws.Int64(int64(v.(int)))
}
nodes = append(nodes, node)
}

return nodes
}
52 changes: 52 additions & 0 deletions aws/data_source_aws_glue_script_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package aws

import (
"fmt"
"testing"

"github.com/hashicorp/terraform/helper/resource"
)

func TestAccDataSourceAWSGlueScript_Language_Python(t *testing.T) {
dataSourceName := "data.aws_glue_script.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAWSGlueScriptConfig_Language("PYTHON"),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrSet(dataSourceName, "python_script"),
),
},
},
})
}

func TestAccDataSourceAWSGlueScript_Language_Scala(t *testing.T) {
dataSourceName := "data.aws_glue_script.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAWSGlueScriptConfig_Language("SCALA"),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrSet(dataSourceName, "scala_code"),
),
},
},
})
}

func testAccDataSourceAWSGlueScriptConfig_Language(language string) string {
return fmt.Sprintf(`
data "aws_glue_script" "test" {
dag_edge = []
dag_node = []
language = "%s"
}
`, language)
}
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ func Provider() terraform.ResourceProvider {
"aws_elasticache_replication_group": dataSourceAwsElasticacheReplicationGroup(),
"aws_elb_hosted_zone_id": dataSourceAwsElbHostedZoneId(),
"aws_elb_service_account": dataSourceAwsElbServiceAccount(),
"aws_glue_script": dataSourceAwsGlueScript(),
"aws_iam_account_alias": dataSourceAwsIamAccountAlias(),
"aws_iam_group": dataSourceAwsIAMGroup(),
"aws_iam_instance_profile": dataSourceAwsIAMInstanceProfile(),
Expand Down
3 changes: 3 additions & 0 deletions website/aws.erb
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@
<li<%= sidebar_current("docs-aws-datasource-elb-service-account") %>>
<a href="/docs/providers/aws/d/elb_service_account.html">aws_elb_service_account</a>
</li>
<li<%= sidebar_current("docs-aws-datasource-glue-script") %>>
<a href="/docs/providers/aws/d/glue_script.html">aws_glue_script</a>
</li>
<li<%= sidebar_current("docs-aws-datasource-iam-account-alias") %>>
<a href="/docs/providers/aws/d/iam_account_alias.html">aws_iam_account_alias</a>
</li>
Expand Down
83 changes: 83 additions & 0 deletions website/docs/d/glue_script.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
---
layout: "aws"
page_title: "AWS: aws_glue_script"
sidebar_current: "docs-aws-datasource-glue-script"
description: |-
Generate Glue script from Directed Acyclic Graph
---

# Data Source: aws_glue_script

Use this data source to generate a Glue script from a Directed Acyclic Graph (DAG).

## Example Usage

### Generate Python Script

```hcl
data "aws_glue_script" "example" {
language = "PYTHON"

dag_edge = [
# ...
]

dag_node = [
# ...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it'd be good to give a working example here imo

]
}

output "python_script" {
value = "${data.aws_glue_script.example.python_script}"
}
```

### Generate Scala Code

```hcl
data "aws_glue_script" "example" {
language = "SCALA"

dag_edge = [
# ...
]

dag_node = [
# ...
]
}

output "scala_code" {
value = "${data.aws_glue_script.example.scala_code}"
}
```

## Argument Reference

* `dag_edge` - (Required) A list of the edges in the DAG. Defined below.
* `dag_node` - (Required) A list of the nodes in the DAG. Defined below.
* `language` - (Optional) The programming language of the resulting code from the DAG. Defaults to `PYTHON`. Valid values are `PYTHON` and `SCALA`.

### dag_edge Argument Reference

* `source` - (Required) The ID of the node at which the edge starts.
* `target` - (Required) The ID of the node at which the edge ends.
* `target_parameter` - (Optional) The target of the edge.

### dag_node Argument Reference

* `args` - (Required) Nested configuration an argument or property of a node. Defined below.
* `id` - (Required) A node identifier that is unique within the node's graph.
* `node_type` - (Required) The type of node this is.
* `line_number` - (Optional) The line number of the node.

#### args Argument Reference

* `name` - (Required) The name of the argument or property.
* `value` - (Required) The value of the argument or property.
* `param` - (Optional) Boolean if the value is used as a parameter. Defaults to `false`.

## Attributes Reference

* `python_script` - The Python script generated from the DAG when the `language` argument is set to `PYTHON`.
* `scala_code` - The Scala code generated from the DAG when the `language` argument is set to `SCALA`.