provider/atlas: Add a Atlas Artifact Data Source (#7419)

* small doc update

* provider/atlas: Add docs for Artifact Data Source

* provider/atlas: Remove a test method that isn't used

* provider/atlas: Add Data Source for Atlas Artifact

* provider/atlas: Show deprecation error on atlas_artifact resource
This commit is contained in:
Clint 2016-07-01 10:29:53 -05:00 committed by GitHub
parent 5547a54048
commit 98fd603bdf
9 changed files with 417 additions and 33 deletions

View File

@ -0,0 +1,149 @@
package atlas
import (
"fmt"
"github.com/hashicorp/atlas-go/v1"
"github.com/hashicorp/terraform/helper/schema"
)
func dataSourceAtlasArtifact() *schema.Resource {
return &schema.Resource{
Read: dataSourceArtifactRead,
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"type": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"build": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"version": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"metadata_keys": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
"metadata": &schema.Schema{
Type: schema.TypeMap,
Optional: true,
ForceNew: true,
},
"file_url": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"metadata_full": &schema.Schema{
Type: schema.TypeMap,
Computed: true,
},
"slug": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"version_real": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
},
}
}
func dataSourceArtifactRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*atlas.Client)
// Parse the slug from the name given of the artifact since the API
// expects these to be split.
user, name, err := atlas.ParseSlug(d.Get("name").(string))
if err != nil {
return err
}
// Filter by version or build if given
var build, version string
if v, ok := d.GetOk("version"); ok {
version = v.(string)
} else if b, ok := d.GetOk("build"); ok {
build = b.(string)
}
// If we have neither, default to latest version
if build == "" && version == "" {
version = "latest"
}
// Compile the metadata search params
md := make(map[string]string)
for _, v := range d.Get("metadata_keys").(*schema.Set).List() {
md[v.(string)] = atlas.MetadataAnyValue
}
for k, v := range d.Get("metadata").(map[string]interface{}) {
md[k] = v.(string)
}
// Do the search!
vs, err := client.ArtifactSearch(&atlas.ArtifactSearchOpts{
User: user,
Name: name,
Type: d.Get("type").(string),
Build: build,
Version: version,
Metadata: md,
})
if err != nil {
return fmt.Errorf(
"Error searching for artifact '%s/%s': %s",
user, name, err)
}
if len(vs) == 0 {
return fmt.Errorf("No matching artifact for '%s/%s'", user, name)
} else if len(vs) > 1 {
return fmt.Errorf(
"Got %d results for '%s/%s', only one is allowed",
len(vs), user, name)
}
v := vs[0]
d.SetId(v.ID)
if v.ID == "" {
d.SetId(fmt.Sprintf("%s %d", v.Tag, v.Version))
}
d.Set("version_real", v.Version)
d.Set("metadata_full", cleanMetadata(v.Metadata))
d.Set("slug", v.Slug)
d.Set("file_url", "")
if u, err := client.ArtifactFileURL(v); err != nil {
return fmt.Errorf(
"Error reading file URL: %s", err)
} else if u != nil {
d.Set("file_url", u.String())
}
return nil
}

View File

@ -0,0 +1,150 @@
package atlas
import (
"fmt"
"testing"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccDataSourceArtifact_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDataArtifact_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckDataArtifactState("name", "hashicorp/tf-provider-test"),
),
},
},
})
}
func TestAccDataSourceArtifact_metadata(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDataArtifact_metadata,
Check: resource.ComposeTestCheckFunc(
testAccCheckDataArtifactState("name", "hashicorp/tf-provider-test"),
testAccCheckDataArtifactState("id", "x86"),
testAccCheckDataArtifactState("metadata_full.arch", "x86"),
),
},
},
})
}
func TestAccDataSourceArtifact_metadataSet(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDataArtifact_metadataSet,
Check: resource.ComposeTestCheckFunc(
testAccCheckDataArtifactState("name", "hashicorp/tf-provider-test"),
testAccCheckDataArtifactState("id", "x64"),
testAccCheckDataArtifactState("metadata_full.arch", "x64"),
),
},
},
})
}
func TestAccDataSourceArtifact_buildLatest(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDataArtifact_buildLatest,
Check: resource.ComposeTestCheckFunc(
testAccCheckDataArtifactState("name", "hashicorp/tf-provider-test"),
),
},
},
})
}
func TestAccDataSourceArtifact_versionAny(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDataArtifact_versionAny,
Check: resource.ComposeTestCheckFunc(
testAccCheckDataArtifactState("name", "hashicorp/tf-provider-test"),
),
},
},
})
}
func testAccCheckDataArtifactState(key, value string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources["data.atlas_artifact.foobar"]
if !ok {
return fmt.Errorf("Not found: %s", "data.atlas_artifact.foobar")
}
if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}
p := rs.Primary
if p.Attributes[key] != value {
return fmt.Errorf(
"%s != %s (actual: %s)", key, value, p.Attributes[key])
}
return nil
}
}
const testAccDataArtifact_basic = `
data "atlas_artifact" "foobar" {
name = "hashicorp/tf-provider-test"
type = "foo"
}`
const testAccDataArtifact_metadata = `
data "atlas_artifact" "foobar" {
name = "hashicorp/tf-provider-test"
type = "foo"
metadata {
arch = "x86"
}
version = "any"
}`
const testAccDataArtifact_metadataSet = `
data "atlas_artifact" "foobar" {
name = "hashicorp/tf-provider-test"
type = "foo"
metadata_keys = ["arch"]
version = "any"
}`
const testAccDataArtifact_buildLatest = `
data "atlas_artifact" "foobar" {
name = "hashicorp/tf-provider-test"
type = "foo"
build = "latest"
metadata {
arch = "x86"
}
}`
const testAccDataArtifact_versionAny = `
data "atlas_artifact" "foobar" {
name = "hashicorp/tf-provider-test"
type = "foo"
version = "any"
}`

View File

@ -31,6 +31,10 @@ func Provider() terraform.ResourceProvider {
},
},
DataSourcesMap: map[string]*schema.Resource{
"atlas_artifact": dataSourceAtlasArtifact(),
},
ResourcesMap: map[string]*schema.Resource{
"atlas_artifact": resourceArtifact(),
},

View File

@ -22,9 +22,10 @@ func resourceArtifact() *schema.Resource {
Schema: map[string]*schema.Schema{
"name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
Type: schema.TypeString,
Required: true,
ForceNew: true,
Deprecated: `atlas_artifact is now deprecated. Use the Atlas Artifact Data Source instead. See https://terraform.io/docs/providers/atlas/d/artifact.html`,
},
"type": &schema.Schema{

View File

@ -2,7 +2,6 @@ package atlas
import (
"fmt"
"reflect"
"testing"
"github.com/hashicorp/terraform/helper/resource"
@ -109,21 +108,6 @@ func testAccCheckArtifactState(key, value string) resource.TestCheckFunc {
}
}
func TestCleanMetadata(t *testing.T) {
in := map[string]string{
"region.us-east-1": "in",
"what is this?": "out",
}
exp := map[string]string{
"region-us-east-1": "in",
"what-is-this-": "out",
}
out := cleanMetadata(in)
if !reflect.DeepEqual(out, exp) {
t.Fatalf("bad: %#v", out)
}
}
const testAccArtifact_basic = `
resource "atlas_artifact" "foobar" {
name = "hashicorp/tf-provider-test"

View File

@ -0,0 +1,86 @@
---
layout: "atlas"
page_title: "Atlas: atlas_artifact"
sidebar_current: "docs-atlas-data-artifact"
description: |-
Provides a data source to deployment artifacts managed by Atlas. This can
be used to dynamically configure instantiation and provisioning
of resources.
---
# atlas\_artifact
Provides a [Data Source](/docs/configuration/data-sources.html) to access to deployment
artifacts managed by Atlas. This can be used to dynamically configure instantiation
and provisioning of resources.
## Example Usage
An artifact can be created that has metadata representing
an AMI in AWS. This AMI can be used to configure an instance. Any changes
to this artifact will trigger a change to that instance.
```
# Read the AMI
data "atlas_artifact" "web" {
name = "hashicorp/web"
type = "amazon.image"
build = "latest"
metadata {
arch = "386"
}
}
# Start our instance with the dynamic ami value
# Remember to include the AWS region as it is part of the full ID
resource "aws_instance" "app" {
ami = "${data.atlas_artifact.web.metadata_full.region-us-east-1}"
...
}
```
## Argument Reference
The following arguments are supported:
* `name` - (Required) Name of the artifact in Atlas. This is given
in slug format like "organization/artifact".
* `type` - (Required) The type of artifact to query for.
* `build` - (Optional) The build number responsible for creating
the version of the artifact to filter on. This can be "latest",
to find a matching artifact in the latest build, "any" to find a
matching artifact in any build, or a specific number to pin to that
build. If `build` and `version` are unspecified, `version` will default
to "latest". Cannot be specified with `version`. Note: `build` is only
present if Atlas builds the image.
* `version` - (Optional) The version of the artifact to filter on. This can
be "latest", to match against the latest version, "any" to find a matching artifact
in any version, or a specific number to pin to that version. Defaults to
"latest" if neither `build` or `version` is specified. Cannot be specified
with `build`.
* `metadata_keys` - (Optional) If given, only an artifact containing
the given keys will be returned. This is used to disambiguate when
multiple potential artifacts match. An example is "aws" to filter
on an AMI.
* `metadata` - (Optional) If given, only an artifact matching the
metadata filters will be returned. This is used to disambiguate when
multiple potential artifacts match. An example is "arch" = "386" to
filter on architecture.
## Attributes Reference
The following attributes are exported:
* `id` - The ID of the artifact. This could be an AMI ID, GCE Image ID, etc.
* `file_url` - For artifacts that are binaries, this is a download path.
* `metadata_full` - Contains the full metadata of the artifact. The keys are sanitized
to replace any characters that are invalid in a resource name with a hyphen.
For example, the "region.us-east-1" key will become "region-us-east-1".
* `version_real` - The matching version of the artifact
* `slug` - The artifact slug in Atlas

View File

@ -14,6 +14,9 @@ Provides access to deployment artifacts managed by Atlas. This can
be used to dynamically configure instantiation and provisioning
of resources.
~> **NOTE: This resource is deprecated.**
Please use the [Atlas Artifact Data Source](/docs/providers/atlas/d/artifact.html)
## Example Usage
An artifact can be created that has metadata representing

View File

@ -1,7 +1,7 @@
---
layout: "aws"
page_title: "AWS: aws_iam_policy_document"
sidebar_current: "docs-aws-resource-iam-policy-document"
sidebar_current: "docs-aws-datasource-iam-policy-document"
description: |-
Generates an IAM policy document in JSON format
---

View File

@ -3,24 +3,31 @@
<div class="docs-sidebar hidden-print affix-top" role="complementary">
<ul class="nav docs-sidenav">
<li<%= sidebar_current("docs-home") %>>
<a href="/docs/providers/index.html">&laquo; Documentation Home</a>
</li>
<a href="/docs/providers/index.html">&laquo; Documentation Home</a>
</li>
<li<%= sidebar_current("docs-atlas-index") %>>
<a href="/docs/providers/atlas/index.html">Atlas Provider</a>
</li>
<li<%= sidebar_current(/^docs-atlas-resource/) %>>
<a href="#">Resources</a>
<ul class="nav nav-visible">
<li<%= sidebar_current("docs-atlas-resource-artifact") %>>
<a href="/docs/providers/atlas/r/artifact.html">atlas_artifact</a>
</li>
<a href="/docs/providers/atlas/index.html">Atlas Provider</a>
</li>
<li<%= sidebar_current(/^docs-atlas-data/) %>>
<a href="#">Data</a>
<ul class="nav nav-visible">
<li<%= sidebar_current("docs-atlas-data-artifact") %>>
<a href="/docs/providers/atlas/d/artifact.html">atlas_artifact</a>
</li>
</ul>
</li>
<li<%= sidebar_current(/^docs-atlas-resource/) %>>
<a href="#">Resources</a>
<ul class="nav nav-visible">
<li<%= sidebar_current("docs-atlas-resource-artifact") %>>
<a href="/docs/providers/atlas/r/artifact.html">atlas_artifact</a>
</li>
</ul>
</li>
</ul>
</div>
<% end %>
<%= yield %>
<% end %>
<% end %>