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:
parent
5547a54048
commit
98fd603bdf
|
@ -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
|
||||
}
|
|
@ -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"
|
||||
}`
|
|
@ -31,6 +31,10 @@ func Provider() terraform.ResourceProvider {
|
|||
},
|
||||
},
|
||||
|
||||
DataSourcesMap: map[string]*schema.Resource{
|
||||
"atlas_artifact": dataSourceAtlasArtifact(),
|
||||
},
|
||||
|
||||
ResourcesMap: map[string]*schema.Resource{
|
||||
"atlas_artifact": resourceArtifact(),
|
||||
},
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
---
|
||||
|
|
|
@ -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">« Documentation Home</a>
|
||||
</li>
|
||||
|
||||
<a href="/docs/providers/index.html">« 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 %>
|
||||
|
||||
|
|
Loading…
Reference in New Issue