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

Terraform provider ProfitBricks - Data Sources #11520

Merged
merged 25 commits into from
Feb 2, 2017
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
fa0b8fc
Terraform ProfitBricks Builder
Aug 3, 2016
3b907d6
Merge remote-tracking branch 'upstream/master' into terraform-provide…
Sep 7, 2016
940b3f6
make fmt
Sep 7, 2016
5d63bd9
Merge remote-tracking branch 'upstream/master' into terraform-provide…
Sep 14, 2016
9c82c60
Merge remote-tracking branch 'upstream/master' into terraform-provide…
Sep 14, 2016
5996086
Merge remote-tracking branch 'upstream/master' into terraform-provide…
Nov 21, 2016
ac2f78f
Merge remote-tracking branch 'upstream/master' into terraform-provide…
Dec 1, 2016
5a6dd69
Merge remote-tracking branch 'upstream/master' into terraform-provide…
Dec 20, 2016
379a6cc
Addressing PR remarks
Dec 20, 2016
afabb26
Merge remote-tracking branch 'upstream/master' into terraform-provide…
Jan 4, 2017
21831c0
Merge remote-tracking branch 'upstream/master' into terraform-provide…
Jan 18, 2017
cff8e3f
Removed importers
Jan 18, 2017
62c0b04
Merge remote-tracking branch 'upstream/master' into terraform-provide…
Jan 18, 2017
501e606
Merge remote-tracking branch 'upstream/master' into terraform-provide…
Jan 25, 2017
e1fc5e0
Added ProfitBricks Data Sources
Jan 30, 2017
2f6a702
Added documentation
Jan 30, 2017
db4afee
Merge remote-tracking branch 'upstream/master' into terraform-provide…
Jan 31, 2017
41b73d6
Updated to REST v3:
Jan 31, 2017
68e7ddb
Minor code clean up
Jan 31, 2017
2e3618d
Fixed typo in volume documentation
Jan 31, 2017
9107784
make fmt
Jan 31, 2017
c0910a4
Addressing requested changes
Feb 1, 2017
80c650e
Added a step in load balancer tests in CheckDestroy where we are maki…
Feb 1, 2017
1cf5f09
Changed expected image name
Feb 2, 2017
913f0d1
Fixed data center test
Feb 2, 2017
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
76 changes: 76 additions & 0 deletions builtin/providers/profitbricks/data_source_datacenter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package profitbricks

import (
"fmt"
"github.com/hashicorp/terraform/helper/schema"
"github.com/profitbricks/profitbricks-sdk-go"
"log"
"strings"
)

func dataSourceDataCenter() *schema.Resource {
return &schema.Resource{
Read: dataSourceDataCenterRead,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
},
"location": {
Type: schema.TypeString,
Optional: true,
},
"id": {
Copy link
Contributor

Choose a reason for hiding this comment

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

We actually don't need to expose Id as a param - it's there by default

Type: schema.TypeString,
Computed: true,
},
},
}
}

func dataSourceDataCenterRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
profitbricks.SetAuth(config.Username, config.Password)

datacenters := profitbricks.ListDatacenters()

if datacenters.StatusCode > 299 {
return fmt.Errorf("An error occured while fetching datacenters %s", datacenters.Response)
}

name, _ := d.GetOk("name")
Copy link
Contributor

Choose a reason for hiding this comment

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

as it's a required field we can guarantee it's there so we can write

name := d.Get("name").(string)

location, locationOk := d.GetOk("location")

results := []profitbricks.Datacenter{}

for _, dc := range datacenters.Items {
if dc.Properties.Name == name.(string) || strings.Contains(dc.Properties.Name, name.(string)) {
results = append(results, dc)
}
}

if locationOk {
log.Printf("[INFO] searching dcs by location***********")
locationResults := []profitbricks.Datacenter{}
for _, dc := range results {
if dc.Properties.Location == location.(string) {
locationResults = append(locationResults, dc)
}
}
results = locationResults
}
log.Printf("[INFO] Results length %d *************", len(results))

if len(results) > 1 {
log.Printf("[INFO] Results length greater than 1")
return fmt.Errorf("There is more than one datacenters that match the search criteria")
}

if len(results) == 0 {
return fmt.Errorf("There are no datacenters that match the search criteria")
}

d.SetId(results[0].Id)

return nil
}
31 changes: 31 additions & 0 deletions builtin/providers/profitbricks/data_source_datacenter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package profitbricks

import (
"github.com/hashicorp/terraform/helper/resource"
"regexp"
"testing"
)

func TestAccDataSourceDatacenter_basic(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd like to see a test that matches a datacenter name here :)

Copy link
Author

@jasmingacic jasmingacic Feb 1, 2017

Choose a reason for hiding this comment

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

This one is tricky in order to get a match we need to have a data center. I'm not sure how to accomplish that?

Copy link
Contributor

Choose a reason for hiding this comment

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

In the test, have 2 steps, the first as a setup to create the datacenter, then the second will include a datacenter and a lookup

have a look at this test as an example https://github.com/hashicorp/terraform/blob/master/builtin/providers/aws/data_source_aws_autoscaling_groups_test.go#L15

Copy link
Author

@jasmingacic jasmingacic Feb 1, 2017

Choose a reason for hiding this comment

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

I tried something similar:

In first step I do this:

resource "profitbricks_datacenter" "foobar" {
	name       =  "datacenter-test"
	location = "us/las"
}

and then this.

resource "profitbricks_datacenter" "foobar" {
	name       =  "datacenter-test-updated"
	location = "us/las"
}

data "profitbricks_datacenter" "data_source"{
	name = "datacenter-test-updated"
	location= "us/las"
}

Each time I do this it simply doesn't work.
How do you want me to proceed?

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{

Config: testAccDataSourceProfitBricksDataCenter_basic,
ExpectError: regexp.MustCompile(`There are no datacenters that match the search criteria`),
},
},
})

}

const testAccDataSourceProfitBricksDataCenter_basic = `
data "profitbricks_datacenter" "dc_example" {
name = "test_name"
location = "us/las"
}
`
107 changes: 107 additions & 0 deletions builtin/providers/profitbricks/data_source_image.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package profitbricks

import (
"fmt"
"github.com/hashicorp/terraform/helper/schema"
"github.com/profitbricks/profitbricks-sdk-go"
"strings"
)

func dataSourceImage() *schema.Resource {
return &schema.Resource{
Read: dataSourceImageRead,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Optional: true,
},
"type": {
Type: schema.TypeString,
Optional: true,
},
"location": {
Type: schema.TypeString,
Optional: true,
},
"version": {
Type: schema.TypeString,
Optional: true,
},
"id": {
Copy link
Contributor

Choose a reason for hiding this comment

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

We actually don't need to expose Id as a param - it's there by default

Type: schema.TypeString,
Computed: true,
},
},
}
}

func dataSourceImageRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
profitbricks.SetAuth(config.Username, config.Password)
profitbricks.SetDepth("5")

images := profitbricks.ListImages()

if images.StatusCode > 299 {
return fmt.Errorf("An error occured while fetching ProfitBricks locations %s", images.Response)
}

name, _ := d.GetOk("name")
Copy link
Contributor

Choose a reason for hiding this comment

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

Name isn't required, so we should check it's ok before using it

imageType, imageTypeOk := d.GetOk("type")
location, locationOk := d.GetOk("location")
version, versionOk := d.GetOk("version")

results := []profitbricks.Image{}

// if version value is present then concatenate name - version
// otherwise search by name or part of the name
if versionOk {
name_ver := fmt.Sprintf("%s-%s", name.(string), version.(string))
for _, img := range images.Items {
if strings.Contains(strings.ToLower(img.Properties.Name), strings.ToLower(name_ver)) {
results = append(results, img)
}
}
} else {
for _, img := range images.Items {
if strings.Contains(strings.ToLower(img.Properties.Name), strings.ToLower(name.(string))) {
results = append(results, img)
}
}
}

if imageTypeOk {
imageTypeResults := []profitbricks.Image{}
for _, img := range results {
if img.Properties.ImageType == imageType.(string) {
imageTypeResults = append(imageTypeResults, img)
}

}
results = imageTypeResults
}

if locationOk {
locationResults := []profitbricks.Image{}
for _, img := range results {
if img.Properties.Location == location.(string) {
locationResults = append(locationResults, img)
}

}
results = locationResults
}

if len(results) > 1 {
return fmt.Errorf("There is more than one image that match the search criteria")
}

if len(results) == 0 {
return fmt.Errorf("There are no images that match the search criteria")
}

d.Set("name", results[0].Properties.Name)
Copy link
Contributor

Choose a reason for hiding this comment

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

should we check that Properties != nil ? Otherwise we could panic here

Copy link
Author

Choose a reason for hiding this comment

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

Properties ImageProperties `json:"properties,omitempty"
It can't be nil it is not a pointer.

Copy link
Contributor

Choose a reason for hiding this comment

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

👍 sorry - still in AWS land where everything is a pointer :)

d.SetId(results[0].Id)

return nil
}
36 changes: 36 additions & 0 deletions builtin/providers/profitbricks/data_source_image_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package profitbricks

import (
"github.com/hashicorp/terraform/helper/resource"
"testing"
)

func TestAccDataSourceImage_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{

Config: testAccDataSourceProfitBricksImage_basic,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("data.profitbricks_image.img", "location", "us/las"),
resource.TestCheckResourceAttr("data.profitbricks_image.img", "name", "Ubuntu-16.04-LTS-server-2017-01-01"),
resource.TestCheckResourceAttr("data.profitbricks_image.img", "type", "HDD"),
),
},
},
})

}

const testAccDataSourceProfitBricksImage_basic = `
data "profitbricks_image" "img" {
name = "Ubuntu"
type = "HDD"
version = "16"
location = "us/las"
}
`
81 changes: 81 additions & 0 deletions builtin/providers/profitbricks/data_source_location.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package profitbricks

import (
"fmt"
"github.com/hashicorp/terraform/helper/schema"
"github.com/profitbricks/profitbricks-sdk-go"
"log"
"strings"
)

func dataSourceLocation() *schema.Resource {
return &schema.Resource{
Read: dataSourceLocationRead,
Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Optional: true,
},
"feature": {
Type: schema.TypeString,
Optional: true,
},
"id": {
Copy link
Contributor

Choose a reason for hiding this comment

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

We actually don't need to expose Id as a param - it's there by default

Type: schema.TypeString,
Computed: true,
},
},
}
}

func dataSourceLocationRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
profitbricks.SetAuth(config.Username, config.Password)
profitbricks.SetDepth("5")

locations := profitbricks.ListLocations()

if locations.StatusCode > 299 {
return fmt.Errorf("An error occured while fetching ProfitBricks locations %s", locations.Response)
}

name, nameOk := d.GetOk("name")
feature, featureOk := d.GetOk("features")

if !nameOk && !featureOk {
return fmt.Errorf("Either 'name' or 'feature' must be provided.")
}
results := []profitbricks.Location{}

for _, loc := range locations.Items {
if loc.Properties.Name == name.(string) || strings.Contains(loc.Properties.Name, name.(string)) {
results = append(results, loc)
}
}

if featureOk {
locationResults := []profitbricks.Location{}
for _, loc := range results {
for _, f := range loc.Properties.Features {
if f == feature.(string) {
locationResults = append(locationResults, loc)
}
}
}
results = locationResults
}
log.Printf("[INFO] Results length %d *************", len(results))

if len(results) > 1 {
log.Printf("[INFO] Results length greater than 1")
return fmt.Errorf("There is more than one location that match the search criteria")
}

if len(results) == 0 {
return fmt.Errorf("There are no locations that match the search criteria")
}

d.SetId(results[0].Id)

return nil
}
32 changes: 32 additions & 0 deletions builtin/providers/profitbricks/data_source_location_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package profitbricks

import (
"github.com/hashicorp/terraform/helper/resource"
"testing"
)

func TestAccDataSourceLocation_basic(t *testing.T) {
resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
Providers: testAccProviders,
Steps: []resource.TestStep{
{

Config: testAccDataSourceProfitBricksLocation_basic,
Check: resource.ComposeTestCheckFunc(resource.TestCheckResourceAttr("data.profitbricks_location.loc", "id", "de/fkb"),
resource.TestCheckResourceAttr("data.profitbricks_location.loc", "name", "karlsruhe"),
),
},
},
})

}

const testAccDataSourceProfitBricksLocation_basic = `
data "profitbricks_location" "loc" {
name = "karlsruhe"
feature = "SSD"
}
`
6 changes: 5 additions & 1 deletion builtin/providers/profitbricks/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ func Provider() terraform.ResourceProvider {
"profitbricks_server": resourceProfitBricksServer(),
"profitbricks_volume": resourceProfitBricksVolume(),
},

DataSourcesMap: map[string]*schema.Resource{
"profitbricks_datacenter": dataSourceDataCenter(),
"profitbricks_location": dataSourceLocation(),
"profitbricks_image": dataSourceImage(),
},
ConfigureFunc: providerConfigure,
}
}
Expand Down
Loading