diff --git a/builtin/providers/profitbricks/config.go b/builtin/providers/profitbricks/config.go index 957bc137c93b..d3b74f2fe1c3 100644 --- a/builtin/providers/profitbricks/config.go +++ b/builtin/providers/profitbricks/config.go @@ -7,6 +7,7 @@ import ( type Config struct { Username string Password string + Endpoint string Retries int } @@ -14,6 +15,8 @@ type Config struct { func (c *Config) Client() (*Config, error) { profitbricks.SetAuth(c.Username, c.Password) profitbricks.SetDepth("5") - + if len(c.Endpoint) > 0 { + profitbricks.SetEndpoint(c.Endpoint) + } return c, nil } diff --git a/builtin/providers/profitbricks/data_source_datacenter.go b/builtin/providers/profitbricks/data_source_datacenter.go new file mode 100644 index 000000000000..4e3cf00d4ff7 --- /dev/null +++ b/builtin/providers/profitbricks/data_source_datacenter.go @@ -0,0 +1,69 @@ +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, + }, + }, + } +} + +func dataSourceDataCenterRead(d *schema.ResourceData, meta interface{}) error { + datacenters := profitbricks.ListDatacenters() + + if datacenters.StatusCode > 299 { + return fmt.Errorf("An error occured while fetching datacenters %s", datacenters.Response) + } + + name := d.Get("name").(string) + location, locationOk := d.GetOk("location") + + results := []profitbricks.Datacenter{} + + for _, dc := range datacenters.Items { + if dc.Properties.Name == name || strings.Contains(dc.Properties.Name, name) { + 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 +} diff --git a/builtin/providers/profitbricks/data_source_datacenter_test.go b/builtin/providers/profitbricks/data_source_datacenter_test.go new file mode 100644 index 000000000000..7295313cc687 --- /dev/null +++ b/builtin/providers/profitbricks/data_source_datacenter_test.go @@ -0,0 +1,48 @@ +package profitbricks + +import ( + "github.com/hashicorp/terraform/helper/resource" + "testing" +) + +func TestAccDataSourceDatacenter_matching(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + + Config: testAccDataSourceProfitBricksDataCenter_matching, + }, + { + + Config: testAccDataSourceProfitBricksDataCenter_matchingWithDataSource, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.profitbricks_datacenter.foobar", "name", "test_name"), + resource.TestCheckResourceAttr("data.profitbricks_datacenter.foobar", "location", "us/las"), + ), + }, + }, + }) + +} + +const testAccDataSourceProfitBricksDataCenter_matching = ` +resource "profitbricks_datacenter" "foobar" { + name = "test_name" + location = "us/las" +} +` + +const testAccDataSourceProfitBricksDataCenter_matchingWithDataSource = ` +resource "profitbricks_datacenter" "foobar" { + name = "test_name" + location = "us/las" +} + +data "profitbricks_datacenter" "foobar" { + name = "${profitbricks_datacenter.foobar.name}" + location = "us/las" +}` diff --git a/builtin/providers/profitbricks/data_source_image.go b/builtin/providers/profitbricks/data_source_image.go new file mode 100644 index 000000000000..61d542b5bb6a --- /dev/null +++ b/builtin/providers/profitbricks/data_source_image.go @@ -0,0 +1,102 @@ +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, + }, + }, + } +} + +func dataSourceImageRead(d *schema.ResourceData, meta interface{}) error { + 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.Get("name").(string) + 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, 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)) { + 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) + + d.SetId(results[0].Id) + + return nil +} diff --git a/builtin/providers/profitbricks/data_source_image_test.go b/builtin/providers/profitbricks/data_source_image_test.go new file mode 100644 index 000000000000..3efe6d32594e --- /dev/null +++ b/builtin/providers/profitbricks/data_source_image_test.go @@ -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-02-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" + } + ` diff --git a/builtin/providers/profitbricks/data_source_location.go b/builtin/providers/profitbricks/data_source_location.go new file mode 100644 index 000000000000..f55d60872b23 --- /dev/null +++ b/builtin/providers/profitbricks/data_source_location.go @@ -0,0 +1,73 @@ +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, + }, + }, + } +} + +func dataSourceLocationRead(d *schema.ResourceData, meta interface{}) error { + 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 +} diff --git a/builtin/providers/profitbricks/data_source_location_test.go b/builtin/providers/profitbricks/data_source_location_test.go new file mode 100644 index 000000000000..f1411f354007 --- /dev/null +++ b/builtin/providers/profitbricks/data_source_location_test.go @@ -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" + } + ` diff --git a/builtin/providers/profitbricks/provider.go b/builtin/providers/profitbricks/provider.go index e53b79521a64..dc0c782a0f58 100644 --- a/builtin/providers/profitbricks/provider.go +++ b/builtin/providers/profitbricks/provider.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/terraform" + "github.com/profitbricks/profitbricks-sdk-go" ) // Provider returns a schema.Provider for DigitalOcean. @@ -22,6 +23,12 @@ func Provider() terraform.ResourceProvider { DefaultFunc: schema.EnvDefaultFunc("PROFITBRICKS_PASSWORD", nil), Description: "Profitbricks password for API operations.", }, + "endpoint": { + Type: schema.TypeString, + Optional: true, + DefaultFunc: schema.EnvDefaultFunc("PROFITBRICKS_API_URL", profitbricks.Endpoint), + Description: "Profitbricks REST API URL.", + }, "retries": { Type: schema.TypeInt, Optional: true, @@ -39,7 +46,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, } } @@ -57,6 +68,7 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) { config := Config{ Username: d.Get("username").(string), Password: d.Get("password").(string), + Endpoint: d.Get("endpoint").(string), Retries: d.Get("retries").(int), } diff --git a/builtin/providers/profitbricks/resource_profitbricks_datacenter.go b/builtin/providers/profitbricks/resource_profitbricks_datacenter.go index c5a42ec40ba8..d402b57dc423 100644 --- a/builtin/providers/profitbricks/resource_profitbricks_datacenter.go +++ b/builtin/providers/profitbricks/resource_profitbricks_datacenter.go @@ -5,6 +5,7 @@ import ( "github.com/hashicorp/terraform/helper/schema" "github.com/profitbricks/profitbricks-sdk-go" "log" + "regexp" "runtime" "strings" "time" @@ -38,9 +39,6 @@ func resourceProfitBricksDatacenter() *schema.Resource { } func resourceProfitBricksDatacenterCreate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - datacenter := profitbricks.Datacenter{ Properties: profitbricks.DatacenterProperties{ Name: d.Get("name").(string), @@ -69,9 +67,6 @@ func resourceProfitBricksDatacenterCreate(d *schema.ResourceData, meta interface } func resourceProfitBricksDatacenterRead(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - profitbricks.SetAuth(config.Username, config.Password) datacenter := profitbricks.GetDatacenter(d.Id()) if datacenter.StatusCode > 299 { return fmt.Errorf("Error while fetching a data center ID %s %s", d.Id(), datacenter.Response) @@ -84,10 +79,6 @@ func resourceProfitBricksDatacenterRead(d *schema.ResourceData, meta interface{} } func resourceProfitBricksDatacenterUpdate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - profitbricks.SetAuth(config.Username, config.Password) - obj := profitbricks.DatacenterProperties{} if d.HasChange("name") { @@ -107,9 +98,6 @@ func resourceProfitBricksDatacenterUpdate(d *schema.ResourceData, meta interface } func resourceProfitBricksDatacenterDelete(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - - profitbricks.SetAuth(config.Username, config.Password) dcid := d.Id() resp := profitbricks.DeleteDatacenter(dcid) @@ -126,9 +114,12 @@ func resourceProfitBricksDatacenterDelete(d *schema.ResourceData, meta interface func waitTillProvisioned(meta interface{}, path string) error { config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) + waitCount := 50 - for i := 0; i < config.Retries; i++ { + if config.Retries != 0 { + waitCount = config.Retries + } + for i := 0; i < waitCount; i++ { request := profitbricks.GetRequestStatus(path) pc, _, _, ok := runtime.Caller(1) details := runtime.FuncForPC(pc) @@ -182,3 +173,8 @@ func getImageId(dcId string, imageName string, imageType string) string { } return "" } + +func IsValidUUID(uuid string) bool { + r := regexp.MustCompile("^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$") + return r.MatchString(uuid) +} diff --git a/builtin/providers/profitbricks/resource_profitbricks_firewall.go b/builtin/providers/profitbricks/resource_profitbricks_firewall.go index e4fcd24bfcfc..4559a0428ad2 100644 --- a/builtin/providers/profitbricks/resource_profitbricks_firewall.go +++ b/builtin/providers/profitbricks/resource_profitbricks_firewall.go @@ -81,9 +81,6 @@ func resourceProfitBricksFirewall() *schema.Resource { } func resourceProfitBricksFirewallCreate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - fw := profitbricks.FirewallRule{ Properties: profitbricks.FirewallruleProperties{ Protocol: d.Get("protocol").(string), @@ -131,9 +128,6 @@ func resourceProfitBricksFirewallCreate(d *schema.ResourceData, meta interface{} } func resourceProfitBricksFirewallRead(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - fw := profitbricks.GetFirewallRule(d.Get("datacenter_id").(string), d.Get("server_id").(string), d.Get("nic_id").(string), d.Id()) if fw.StatusCode > 299 { @@ -155,9 +149,6 @@ func resourceProfitBricksFirewallRead(d *schema.ResourceData, meta interface{}) } func resourceProfitBricksFirewallUpdate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - properties := profitbricks.FirewallruleProperties{} if d.HasChange("name") { @@ -215,9 +206,6 @@ func resourceProfitBricksFirewallUpdate(d *schema.ResourceData, meta interface{} } func resourceProfitBricksFirewallDelete(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - resp := profitbricks.DeleteFirewallRule(d.Get("datacenter_id").(string), d.Get("server_id").(string), d.Get("nic_id").(string), d.Id()) if resp.StatusCode > 299 { diff --git a/builtin/providers/profitbricks/resource_profitbricks_ipblock.go b/builtin/providers/profitbricks/resource_profitbricks_ipblock.go index 008a1205008b..7ba2fdab753a 100644 --- a/builtin/providers/profitbricks/resource_profitbricks_ipblock.go +++ b/builtin/providers/profitbricks/resource_profitbricks_ipblock.go @@ -34,9 +34,6 @@ func resourceProfitBricksIPBlock() *schema.Resource { } func resourceProfitBricksIPBlockCreate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - ipblock := profitbricks.IpBlock{ Properties: profitbricks.IpBlockProperties{ Size: d.Get("size").(int), @@ -59,9 +56,6 @@ func resourceProfitBricksIPBlockCreate(d *schema.ResourceData, meta interface{}) } func resourceProfitBricksIPBlockRead(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - ipblock := profitbricks.GetIpBlock(d.Id()) if ipblock.StatusCode > 299 { @@ -78,9 +72,6 @@ func resourceProfitBricksIPBlockRead(d *schema.ResourceData, meta interface{}) e } func resourceProfitBricksIPBlockDelete(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - resp := profitbricks.ReleaseIpBlock(d.Id()) if resp.StatusCode > 299 { return fmt.Errorf("An error occured while releasing an ipblock ID: %s %s", d.Id(), string(resp.Body)) diff --git a/builtin/providers/profitbricks/resource_profitbricks_lan.go b/builtin/providers/profitbricks/resource_profitbricks_lan.go index 28849928dfd9..3a3725bd0d4b 100644 --- a/builtin/providers/profitbricks/resource_profitbricks_lan.go +++ b/builtin/providers/profitbricks/resource_profitbricks_lan.go @@ -5,6 +5,7 @@ import ( "github.com/hashicorp/terraform/helper/schema" "github.com/profitbricks/profitbricks-sdk-go" "log" + "time" ) func resourceProfitBricksLan() *schema.Resource { @@ -32,9 +33,6 @@ func resourceProfitBricksLan() *schema.Resource { } func resourceProfitBricksLanCreate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - profitbricks.SetDepth("5") request := profitbricks.Lan{ Properties: profitbricks.LanProperties{ Public: d.Get("public").(bool), @@ -64,9 +62,6 @@ func resourceProfitBricksLanCreate(d *schema.ResourceData, meta interface{}) err } func resourceProfitBricksLanRead(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - lan := profitbricks.GetLan(d.Get("datacenter_id").(string), d.Id()) if lan.StatusCode > 299 { @@ -80,9 +75,6 @@ func resourceProfitBricksLanRead(d *schema.ResourceData, meta interface{}) error } func resourceProfitBricksLanUpdate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - properties := &profitbricks.LanProperties{} if d.HasChange("public") { _, newValue := d.GetChange("public") @@ -107,10 +99,15 @@ func resourceProfitBricksLanUpdate(d *schema.ResourceData, meta interface{}) err } func resourceProfitBricksLanDelete(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - resp := profitbricks.DeleteLan(d.Get("datacenter_id").(string), d.Id()) + if resp.StatusCode > 299 { + //try again in 20 seconds + time.Sleep(60 * time.Second) + resp = profitbricks.DeleteLan(d.Get("datacenter_id").(string), d.Id()) + if resp.StatusCode > 299 && resp.StatusCode != 404 { + return fmt.Errorf("An error occured while deleting a lan dcId %s ID %s %s", d.Get("datacenter_id").(string), d.Id(), string(resp.Body)) + } + } if resp.Headers.Get("Location") != "" { err := waitTillProvisioned(meta, resp.Headers.Get("Location")) diff --git a/builtin/providers/profitbricks/resource_profitbricks_loadbalancer.go b/builtin/providers/profitbricks/resource_profitbricks_loadbalancer.go index c58af3e339c7..a905831c4ccc 100644 --- a/builtin/providers/profitbricks/resource_profitbricks_loadbalancer.go +++ b/builtin/providers/profitbricks/resource_profitbricks_loadbalancer.go @@ -40,9 +40,6 @@ func resourceProfitBricksLoadbalancer() *schema.Resource { } func resourceProfitBricksLoadbalancerCreate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - lb := profitbricks.Loadbalancer{ Properties: profitbricks.LoadbalancerProperties{ Name: d.Get("name").(string), @@ -86,9 +83,6 @@ func resourceProfitBricksLoadbalancerRead(d *schema.ResourceData, meta interface } func resourceProfitBricksLoadbalancerUpdate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - properties := profitbricks.LoadbalancerProperties{} if d.HasChange("name") { _, new := d.GetChange("name") @@ -129,9 +123,6 @@ func resourceProfitBricksLoadbalancerUpdate(d *schema.ResourceData, meta interfa } func resourceProfitBricksLoadbalancerDelete(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - resp := profitbricks.DeleteLoadbalancer(d.Get("datacenter_id").(string), d.Id()) if resp.StatusCode > 299 { diff --git a/builtin/providers/profitbricks/resource_profitbricks_loadbalancer_test.go b/builtin/providers/profitbricks/resource_profitbricks_loadbalancer_test.go index 3c7a5702697c..4fd3a1b022cb 100644 --- a/builtin/providers/profitbricks/resource_profitbricks_loadbalancer_test.go +++ b/builtin/providers/profitbricks/resource_profitbricks_loadbalancer_test.go @@ -48,7 +48,11 @@ func testAccCheckDProfitBricksLoadbalancerDestroyCheck(s *terraform.State) error resp := profitbricks.GetLoadbalancer(rs.Primary.Attributes["datacenter_id"], rs.Primary.ID) if resp.StatusCode < 299 { - return fmt.Errorf("Firewall still exists %s %s", rs.Primary.ID, resp.Response) + resp := profitbricks.DeleteDatacenter(rs.Primary.Attributes["datacenter_id"]) + + if resp.StatusCode > 299 { + return fmt.Errorf("Firewall still exists %s %s", rs.Primary.ID, string(resp.Body)) + } } } diff --git a/builtin/providers/profitbricks/resource_profitbricks_nic.go b/builtin/providers/profitbricks/resource_profitbricks_nic.go index 2000282a8cf8..a2f914cb016b 100644 --- a/builtin/providers/profitbricks/resource_profitbricks_nic.go +++ b/builtin/providers/profitbricks/resource_profitbricks_nic.go @@ -16,15 +16,15 @@ func resourceProfitBricksNic() *schema.Resource { Delete: resourceProfitBricksNicDelete, Schema: map[string]*schema.Schema{ - "lan": &schema.Schema{ + "lan": { Type: schema.TypeInt, Required: true, }, - "name": &schema.Schema{ + "name": { Type: schema.TypeString, Optional: true, }, - "dhcp": &schema.Schema{ + "dhcp": { Type: schema.TypeBool, Optional: true, }, @@ -32,10 +32,19 @@ func resourceProfitBricksNic() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "ips": { + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Computed: true, + }, "firewall_active": { Type: schema.TypeBool, Optional: true, }, + "nat": { + Type: schema.TypeBool, + Optional: true, + }, "server_id": { Type: schema.TypeString, Required: true, @@ -49,9 +58,6 @@ func resourceProfitBricksNic() *schema.Resource { } func resourceProfitBricksNicCreate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - nic := profitbricks.Nic{ Properties: profitbricks.NicProperties{ Lan: d.Get("lan").(int), @@ -69,6 +75,14 @@ func resourceProfitBricksNicCreate(d *schema.ResourceData, meta interface{}) err ips := strings.Split(raw, ",") nic.Properties.Ips = ips } + if _, ok := d.GetOk("firewall_active"); ok { + raw := d.Get("firewall_active").(bool) + nic.Properties.FirewallActive = raw + } + if _, ok := d.GetOk("nat"); ok { + raw := d.Get("nat").(bool) + nic.Properties.Nat = raw + } nic = profitbricks.CreateNic(d.Get("datacenter_id").(string), d.Get("server_id").(string), nic) if nic.StatusCode > 299 { @@ -93,27 +107,20 @@ func resourceProfitBricksNicCreate(d *schema.ResourceData, meta interface{}) err } func resourceProfitBricksNicRead(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - profitbricks.SetDepth("5") - nic := profitbricks.GetNic(d.Get("datacenter_id").(string), d.Get("server_id").(string), d.Id()) if nic.StatusCode > 299 { return fmt.Errorf("Error occured while fetching a nic ID %s %s", d.Id(), nic.Response) } - log.Printf("[INFO] LAN ON NIC: %q", nic.Properties.Lan) + log.Printf("[INFO] LAN ON NIC: %d", nic.Properties.Lan) d.Set("dhcp", nic.Properties.Dhcp) d.Set("lan", nic.Properties.Lan) d.Set("name", nic.Properties.Name) - d.Set("ip", nic.Properties.Ips) + d.Set("ips", nic.Properties.Ips) return nil } func resourceProfitBricksNicUpdate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - properties := profitbricks.NicProperties{} if d.HasChange("name") { @@ -134,6 +141,11 @@ func resourceProfitBricksNicUpdate(d *schema.ResourceData, meta interface{}) err ips := strings.Split(raw.(string), ",") properties.Ips = ips } + if d.HasChange("nat") { + _, raw := d.GetChange("nat") + nat := raw.(bool) + properties.Nat = nat + } nic := profitbricks.PatchNic(d.Get("datacenter_id").(string), d.Get("server_id").(string), d.Id(), properties) @@ -148,9 +160,6 @@ func resourceProfitBricksNicUpdate(d *schema.ResourceData, meta interface{}) err } func resourceProfitBricksNicDelete(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - resp := profitbricks.DeleteNic(d.Get("datacenter_id").(string), d.Get("server_id").(string), d.Id()) err := waitTillProvisioned(meta, resp.Headers.Get("Location")) if err != nil { diff --git a/builtin/providers/profitbricks/resource_profitbricks_server.go b/builtin/providers/profitbricks/resource_profitbricks_server.go index b3f7078544f8..d81c2d45da9e 100644 --- a/builtin/providers/profitbricks/resource_profitbricks_server.go +++ b/builtin/providers/profitbricks/resource_profitbricks_server.go @@ -66,6 +66,10 @@ func resourceProfitBricksServer() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "primary_ip": { + Type: schema.TypeString, + Computed: true, + }, "datacenter_id": { Type: schema.TypeString, Required: true, @@ -97,7 +101,8 @@ func resourceProfitBricksServer() *schema.Resource { Optional: true, }, "ssh_key_path": { - Type: schema.TypeString, + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, }, "bus": { @@ -108,6 +113,10 @@ func resourceProfitBricksServer() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "availability_zone": { + Type: schema.TypeString, + Optional: true, + }, }, }, }, @@ -133,6 +142,15 @@ func resourceProfitBricksServer() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "ips": { + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Computed: true, + }, + "nat": { + Type: schema.TypeBool, + Optional: true, + }, "firewall_active": { Type: schema.TypeBool, Optional: true, @@ -167,6 +185,11 @@ func resourceProfitBricksServer() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "ips": { + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + }, "port_range_start": { Type: schema.TypeInt, Optional: true, @@ -207,9 +230,6 @@ func resourceProfitBricksServer() *schema.Resource { } func resourceProfitBricksServerCreate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - request := profitbricks.Server{ Properties: profitbricks.ServerProperties{ Name: d.Get("name").(string), @@ -233,15 +253,21 @@ func resourceProfitBricksServerCreate(d *schema.ResourceData, meta interface{}) for _, raw := range volumeRaw { rawMap := raw.(map[string]interface{}) - var imagePassword, sshkey_path string - var image, licenceType string + var imagePassword string + //Can be one file or a list of files + var sshkey_path []interface{} + var image, licenceType, availabilityZone string if rawMap["image_name"] != nil { - image = getImageId(d.Get("datacenter_id").(string), rawMap["image_name"].(string), rawMap["disk_type"].(string)) - if image == "" { - dc := profitbricks.GetDatacenter(d.Get("datacenter_id").(string)) - return fmt.Errorf("Image '%s' doesn't exist. in location %s", rawMap["image_name"], dc.Properties.Location) + if !IsValidUUID(rawMap["image_name"].(string)) { + image = getImageId(d.Get("datacenter_id").(string), rawMap["image_name"].(string), rawMap["disk_type"].(string)) + if image == "" { + dc := profitbricks.GetDatacenter(d.Get("datacenter_id").(string)) + return fmt.Errorf("Image '%s' doesn't exist. in location %s", rawMap["image_name"], dc.Properties.Location) + } + } else { + image = rawMap["image_name"].(string) } } if rawMap["licence_type"] != nil { @@ -252,24 +278,27 @@ func resourceProfitBricksServerCreate(d *schema.ResourceData, meta interface{}) imagePassword = rawMap["image_password"].(string) } if rawMap["ssh_key_path"] != nil { - sshkey_path = rawMap["ssh_key_path"].(string) + sshkey_path = rawMap["ssh_key_path"].([]interface{}) } if rawMap["image_name"] != nil { - if imagePassword == "" && sshkey_path == "" { - return fmt.Errorf("'image_password' and 'ssh_key_path' are not provided.") + if imagePassword == "" && len(sshkey_path) == 0 { + return fmt.Errorf("Either 'image_password' or 'ssh_key_path' must be provided.") } } - var publicKey string - var err error - if sshkey_path != "" { - log.Println("[DEBUG] GETTING THE KEY") - _, publicKey, err = getSshKey(d, sshkey_path) - if err != nil { - return fmt.Errorf("Error fetching sshkeys (%s)", err) + var publicKeys []string + if len(sshkey_path) != 0 { + for _, path := range sshkey_path { + log.Printf("[DEBUG] Reading file %s", path) + publicKey, err := readPublicKey(path.(string)) + if err != nil { + return fmt.Errorf("Error fetching sshkey from file (%s) (%s)", path, err.Error()) + } + publicKeys = append(publicKeys, publicKey) } - d.Set("sshkey", publicKey) } - + if rawMap["availability_zone"] != nil { + availabilityZone = rawMap["availability_zone"].(string) + } if image == "" && licenceType == "" { return fmt.Errorf("Either 'image', or 'licenceType' must be set.") } @@ -277,27 +306,26 @@ func resourceProfitBricksServerCreate(d *schema.ResourceData, meta interface{}) request.Entities = &profitbricks.ServerEntities{ Volumes: &profitbricks.Volumes{ Items: []profitbricks.Volume{ - profitbricks.Volume{ + { Properties: profitbricks.VolumeProperties{ - Name: rawMap["name"].(string), - Size: rawMap["size"].(int), - Type: rawMap["disk_type"].(string), - ImagePassword: imagePassword, - Image: image, - Bus: rawMap["bus"].(string), - LicenceType: licenceType, + Name: rawMap["name"].(string), + Size: rawMap["size"].(int), + Type: rawMap["disk_type"].(string), + ImagePassword: imagePassword, + Image: image, + Bus: rawMap["bus"].(string), + LicenceType: licenceType, + AvailabilityZone: availabilityZone, }, }, }, }, } - log.Printf("[DEBUG] PUBLIC KEY %s", publicKey) - - if publicKey == "" { + if len(publicKeys) == 0 { request.Entities.Volumes.Items[0].Properties.SshKeys = nil } else { - request.Entities.Volumes.Items[0].Properties.SshKeys = []string{publicKey} + request.Entities.Volumes.Items[0].Properties.SshKeys = publicKeys } } @@ -328,6 +356,9 @@ func resourceProfitBricksServerCreate(d *schema.ResourceData, meta interface{}) nic.Properties.Ips = ips } } + if rawMap["nat"] != nil { + nic.Properties.Nat = rawMap["nat"].(bool) + } request.Entities.Nics = &profitbricks.Nics{ Items: []profitbricks.Nic{ nic, @@ -416,9 +447,6 @@ func resourceProfitBricksServerCreate(d *schema.ResourceData, meta interface{}) } func resourceProfitBricksServerRead(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - dcId := d.Get("datacenter_id").(string) server := profitbricks.GetServer(dcId, d.Id()) @@ -456,9 +484,6 @@ func resourceProfitBricksServerRead(d *schema.ResourceData, meta interface{}) er } func resourceProfitBricksServerUpdate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - dcId := d.Get("datacenter_id").(string) request := profitbricks.ServerProperties{} @@ -484,7 +509,6 @@ func resourceProfitBricksServerUpdate(d *schema.ResourceData, meta interface{}) request.CpuFamily = n.(string) } server := profitbricks.PatchServer(dcId, d.Id(), request) - log.Println("[INFO] hlab hlab", request) //Volume stuff if d.HasChange("volume") { @@ -508,7 +532,6 @@ func resourceProfitBricksServerUpdate(d *schema.ResourceData, meta interface{}) } volume = profitbricks.PatchVolume(d.Get("datacenter_id").(string), server.Entities.Volumes.Items[0].Id, properties) - log.Println("[INFO] blah blah", properties) if volume.StatusCode > 299 { return fmt.Errorf("Error patching volume (%s) (%s)", d.Id(), volume.Response) @@ -553,10 +576,12 @@ func resourceProfitBricksServerUpdate(d *schema.ResourceData, meta interface{}) if rawMap["dhcp"] != nil { properties.Dhcp = rawMap["dhcp"].(bool) } + if rawMap["nat"] != nil { + properties.Nat = rawMap["nat"].(bool) + } } nic = profitbricks.PatchNic(d.Get("datacenter_id").(string), server.Id, server.Entities.Nics.Items[0].Id, properties) - log.Println("[INFO] blah blah", properties) if nic.StatusCode > 299 { return fmt.Errorf( @@ -577,9 +602,6 @@ func resourceProfitBricksServerUpdate(d *schema.ResourceData, meta interface{}) } func resourceProfitBricksServerDelete(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - dcId := d.Get("datacenter_id").(string) server := profitbricks.GetServer(dcId, d.Id()) @@ -605,6 +627,19 @@ func resourceProfitBricksServerDelete(d *schema.ResourceData, meta interface{}) return nil } +//Reads public key from file and returns key string iff valid +func readPublicKey(path string) (key string, err error) { + bytes, err := ioutil.ReadFile(path) + if err != nil { + return "", err + } + pubKey, _, _, _, err := ssh.ParseAuthorizedKey(bytes) + if err != nil { + return "", err + } + return string(ssh.MarshalAuthorizedKey(pubKey)[:]), nil +} + func getSshKey(d *schema.ResourceData, path string) (privatekey string, publickey string, err error) { pemBytes, err := ioutil.ReadFile(path) @@ -623,7 +658,6 @@ func getSshKey(d *schema.ResourceData, path string) (privatekey string, publicke if err != nil { return "", "", err } - priv_blk := pem.Block{ Type: "RSA PRIVATE KEY", Headers: nil, diff --git a/builtin/providers/profitbricks/resource_profitbricks_server_test.go b/builtin/providers/profitbricks/resource_profitbricks_server_test.go index d4891ec5ca06..c14fc39e2c3d 100644 --- a/builtin/providers/profitbricks/resource_profitbricks_server_test.go +++ b/builtin/providers/profitbricks/resource_profitbricks_server_test.go @@ -141,6 +141,12 @@ resource "profitbricks_datacenter" "foobar" { location = "us/las" } +resource "profitbricks_lan" "webserver_lan" { + datacenter_id = "${profitbricks_datacenter.foobar.id}" + public = true + name = "public" +} + resource "profitbricks_server" "webserver" { name = "updated" datacenter_id = "${profitbricks_datacenter.foobar.id}" @@ -156,7 +162,7 @@ resource "profitbricks_server" "webserver" { image_password = "test1234" } nic { - lan = "1" + lan = "${profitbricks_lan.webserver_lan.id}" dhcp = true firewall_active = true firewall { diff --git a/builtin/providers/profitbricks/resource_profitbricks_volume.go b/builtin/providers/profitbricks/resource_profitbricks_volume.go index afc2a72973a0..6efed8e84511 100644 --- a/builtin/providers/profitbricks/resource_profitbricks_volume.go +++ b/builtin/providers/profitbricks/resource_profitbricks_volume.go @@ -1,7 +1,6 @@ package profitbricks import ( - "encoding/json" "fmt" "github.com/hashicorp/terraform/helper/schema" "github.com/profitbricks/profitbricks-sdk-go" @@ -37,7 +36,8 @@ func resourceProfitBricksVolume() *schema.Resource { Optional: true, }, "ssh_key_path": { - Type: schema.TypeString, + Type: schema.TypeList, + Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, }, "sshkey": { @@ -52,6 +52,10 @@ func resourceProfitBricksVolume() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "availability_zone": { + Type: schema.TypeString, + Optional: true, + }, "server_id": { Type: schema.TypeString, Required: true, @@ -65,20 +69,17 @@ func resourceProfitBricksVolume() *schema.Resource { } func resourceProfitBricksVolumeCreate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - var err error + var ssh_keypath []interface{} dcId := d.Get("datacenter_id").(string) serverId := d.Get("server_id").(string) - imagePassword := d.Get("image_password").(string) - sshkey := d.Get("ssh_key_path").(string) + ssh_keypath = d.Get("ssh_key_path").([]interface{}) image_name := d.Get("image_name").(string) if image_name != "" { - if imagePassword == "" && sshkey == "" { - return fmt.Errorf("'image_password' and 'sshkey' are not provided.") + if imagePassword == "" && len(ssh_keypath) == 0 { + return fmt.Errorf("Either 'image_password' or 'sshkey' must be provided.") } } @@ -88,19 +89,24 @@ func resourceProfitBricksVolumeCreate(d *schema.ResourceData, meta interface{}) return fmt.Errorf("Either 'image_name', or 'licenceType' must be set.") } - var publicKey string - - if sshkey != "" { - _, publicKey, err = getSshKey(d, sshkey) - if err != nil { - return fmt.Errorf("Error fetching sshkeys (%s)", err) + var publicKeys []string + if len(ssh_keypath) != 0 { + for _, path := range ssh_keypath { + log.Printf("[DEBUG] Reading file %s", path) + publicKey, err := readPublicKey(path.(string)) + if err != nil { + return fmt.Errorf("Error fetching sshkey from file (%s) (%s)", path, err.Error()) + } + publicKeys = append(publicKeys, publicKey) } - d.Set("sshkey", publicKey) } - log.Printf("[INFO] public key: %s", publicKey) - - image := getImageId(d.Get("datacenter_id").(string), image_name, d.Get("disk_type").(string)) + var image string + if !IsValidUUID(image_name) { + image = getImageId(d.Get("datacenter_id").(string), image_name, d.Get("disk_type").(string)) + } else { + image = image_name + } volume := profitbricks.Volume{ Properties: profitbricks.VolumeProperties{ @@ -114,14 +120,17 @@ func resourceProfitBricksVolumeCreate(d *schema.ResourceData, meta interface{}) }, } - if publicKey != "" { - volume.Properties.SshKeys = []string{publicKey} + if len(publicKeys) != 0 { + volume.Properties.SshKeys = publicKeys } else { volume.Properties.SshKeys = nil } - jsn, _ := json.Marshal(volume) - log.Printf("[INFO] volume: %s", string(jsn)) + + if _, ok := d.GetOk("availability_zone"); ok { + raw := d.Get("availability_zone").(string) + volume.Properties.AvailabilityZone = raw + } volume = profitbricks.CreateVolume(dcId, volume) @@ -169,9 +178,6 @@ func resourceProfitBricksVolumeRead(d *schema.ResourceData, meta interface{}) er } func resourceProfitBricksVolumeUpdate(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - properties := profitbricks.VolumeProperties{} dcId := d.Get("datacenter_id").(string) @@ -191,6 +197,10 @@ func resourceProfitBricksVolumeUpdate(d *schema.ResourceData, meta interface{}) _, newValue := d.GetChange("bus") properties.Bus = newValue.(string) } + if d.HasChange("availability_zone") { + _, newValue := d.GetChange("availability_zone") + properties.AvailabilityZone = newValue.(string) + } volume := profitbricks.PatchVolume(dcId, d.Id(), properties) err := waitTillProvisioned(meta, volume.Headers.Get("Location")) @@ -216,9 +226,6 @@ func resourceProfitBricksVolumeUpdate(d *schema.ResourceData, meta interface{}) } func resourceProfitBricksVolumeDelete(d *schema.ResourceData, meta interface{}) error { - config := meta.(*Config) - profitbricks.SetAuth(config.Username, config.Password) - dcId := d.Get("datacenter_id").(string) resp := profitbricks.DeleteVolume(dcId, d.Id()) diff --git a/builtin/providers/profitbricks/resource_profitbricks_volume_test.go b/builtin/providers/profitbricks/resource_profitbricks_volume_test.go index e1586f024f89..50ced0e4ff39 100644 --- a/builtin/providers/profitbricks/resource_profitbricks_volume_test.go +++ b/builtin/providers/profitbricks/resource_profitbricks_volume_test.go @@ -151,6 +151,12 @@ resource "profitbricks_datacenter" "foobar" { location = "us/las" } +resource "profitbricks_lan" "webserver_lan" { + datacenter_id = "${profitbricks_datacenter.foobar.id}" + public = true + name = "public" +} + resource "profitbricks_server" "webserver" { name = "webserver" datacenter_id = "${profitbricks_datacenter.foobar.id}" @@ -166,7 +172,7 @@ resource "profitbricks_server" "webserver" { image_password = "test1234" } nic { - lan = "1" + lan = "${profitbricks_lan.webserver_lan.id}" dhcp = true firewall_active = true firewall { diff --git a/vendor/github.com/profitbricks/profitbricks-sdk-go/config.go b/vendor/github.com/profitbricks/profitbricks-sdk-go/config.go index 5671089519f9..0df1841cfb74 100644 --- a/vendor/github.com/profitbricks/profitbricks-sdk-go/config.go +++ b/vendor/github.com/profitbricks/profitbricks-sdk-go/config.go @@ -1,7 +1,7 @@ package profitbricks -// Endpoint is the base url for REST requests . -var Endpoint = "https://api.profitbricks.com/rest/v2" +// Endpoint is the base url for REST requests. +var Endpoint = "https://api.profitbricks.com/cloudapi/v3" // Username for authentication . var Username string @@ -21,3 +21,7 @@ func SetAuth(u, p string) { Username = u Passwd = p } + +func SetUserAgent(userAgent string) { + AgentHeader = userAgent +} diff --git a/vendor/github.com/profitbricks/profitbricks-sdk-go/location.go b/vendor/github.com/profitbricks/profitbricks-sdk-go/location.go index 279429464123..9a222ca13e09 100644 --- a/vendor/github.com/profitbricks/profitbricks-sdk-go/location.go +++ b/vendor/github.com/profitbricks/profitbricks-sdk-go/location.go @@ -27,7 +27,8 @@ type Locations struct { } type Properties struct { - Name string `json:"name,omitempty"` + Name string `json:"name,omitempty"` + Features []string `json:"features,omitempty"` } // ListLocations returns location collection data diff --git a/vendor/github.com/profitbricks/profitbricks-sdk-go/nic.go b/vendor/github.com/profitbricks/profitbricks-sdk-go/nic.go index 74764f56b716..1d082a64d142 100644 --- a/vendor/github.com/profitbricks/profitbricks-sdk-go/nic.go +++ b/vendor/github.com/profitbricks/profitbricks-sdk-go/nic.go @@ -25,6 +25,7 @@ type NicProperties struct { Dhcp bool `json:"dhcp,omitempty"` Lan int `json:"lan,omitempty"` FirewallActive bool `json:"firewallActive,omitempty"` + Nat bool `json:"nat,omitempty"` } type NicEntities struct { diff --git a/vendor/github.com/profitbricks/profitbricks-sdk-go/paths.go b/vendor/github.com/profitbricks/profitbricks-sdk-go/paths.go index 3b3c7f50dfaa..a4ba71822be9 100644 --- a/vendor/github.com/profitbricks/profitbricks-sdk-go/paths.go +++ b/vendor/github.com/profitbricks/profitbricks-sdk-go/paths.go @@ -45,31 +45,11 @@ func location_path(locid string) string { return location_col_path() + slash(locid) } -// request_col_path returns the string "/requests" -func request_col_path() string { - return slash("requests") -} - -// request_path returns the string "/requests/" -func request_path(requestid string) string { - return request_col_path() + slash(requestid) -} - -// request_status_path returns the string "/requests/status" -func request_status_path(requestid string) string { - return request_path(requestid) + slash("status") -} - // snapshot_col_path returns the string "/snapshots" func snapshot_col_path() string { return slash("snapshots") } -// snapshot_path returns the string "/snapshots/" -func snapshot_path(snapid string) string { - return snapshot_col_path() + slash(snapid) -} - // lan_col_path returns the string "/datacenters//lans" func lan_col_path(dcid string) string { return dc_path(dcid) + slash("lans") @@ -115,12 +95,6 @@ func volume_path(dcid, volid string) string { return volume_col_path(dcid) + slash(volid) } -// lan_nic_col_path returns the string /datacenters//lans//nics -func lan_nic_col(dcid, lanid string) string { - return lan_path(dcid, lanid) + slash("nics") - -} - // balnic_col_path returns the string "/loadbalancers//balancednics" func balnic_col_path(dcid, lbalid string) string { return lbal_path(dcid, lbalid) + slash("balancednics") diff --git a/vendor/github.com/profitbricks/profitbricks-sdk-go/req.go b/vendor/github.com/profitbricks/profitbricks-sdk-go/req.go index b5f21c17d069..e1038affc912 100644 --- a/vendor/github.com/profitbricks/profitbricks-sdk-go/req.go +++ b/vendor/github.com/profitbricks/profitbricks-sdk-go/req.go @@ -9,10 +9,12 @@ import ( ) //FullHeader is the standard header to include with all http requests except is_patch and is_command -const FullHeader = "application/vnd.profitbricks.resource+json" +const FullHeader = "application/json" + +var AgentHeader = "profitbricks-sdk-go/3.0.1" //PatchHeader is used with is_patch . -const PatchHeader = "application/vnd.profitbricks.partial-properties+json" +const PatchHeader = "application/json" //CommandHeader is used with is_command const CommandHeader = "application/x-www-form-urlencoded" @@ -32,7 +34,8 @@ func SetDepth(newdepth string) string { func mk_url(path string) string { if strings.HasPrefix(path, "http") { //REMOVE AFTER TESTING - path := strings.Replace(path, "https://api.profitbricks.com/rest/v2", Endpoint, 1) + //FIXME @jasmin Is this still relevant? + path := strings.Replace(path, "https://api.profitbricks.com/cloudapi/v3", Endpoint, 1) // END REMOVE return path } @@ -48,6 +51,7 @@ func mk_url(path string) string { func do(req *http.Request) Resp { client := &http.Client{} req.SetBasicAuth(Username, Passwd) + req.Header.Add("User-Agent", AgentHeader) resp, err := client.Do(req) if err != nil { panic(err) @@ -67,6 +71,7 @@ func is_delete(path string) Resp { url := mk_url(path) req, _ := http.NewRequest("DELETE", url, nil) req.Header.Add("Content-Type", FullHeader) + req.Header.Add("User-Agent", AgentHeader) return do(req) } @@ -76,5 +81,6 @@ func is_command(path string, jason string) Resp { body := json.RawMessage(jason) req, _ := http.NewRequest("POST", url, bytes.NewBuffer(body)) req.Header.Add("Content-Type", CommandHeader) + req.Header.Add("User-Agent", AgentHeader) return do(req) } diff --git a/vendor/github.com/profitbricks/profitbricks-sdk-go/resp.go b/vendor/github.com/profitbricks/profitbricks-sdk-go/resp.go index 12d68e0d247e..20975d4e19f7 100644 --- a/vendor/github.com/profitbricks/profitbricks-sdk-go/resp.go +++ b/vendor/github.com/profitbricks/profitbricks-sdk-go/resp.go @@ -15,13 +15,6 @@ func MkJson(i interface{}) string { return string(jason) } -// MetaData is a map for metadata returned in a Resp.Body -type StringMap map[string]string - -type StringIfaceMap map[string]interface{} - -type StringCollectionMap map[string]Collection - // Resp is the struct returned by all Rest request functions type Resp struct { Req *http.Request @@ -36,26 +29,4 @@ func (r *Resp) PrintHeaders() { fmt.Println(key, " : ", value[0]) } -} - -type Id_Type_Href struct { - Id string `json:"id"` - Type string `json:"type"` - Href string `json:"href"` -} - -type MetaData StringIfaceMap - -type Instance struct { - Id_Type_Href - MetaData StringMap `json:"metaData,omitempty"` - Properties StringIfaceMap `json:"properties,omitempty"` - Entities StringCollectionMap `json:"entities,omitempty"` - Resp Resp `json:"-"` -} - -type Collection struct { - Id_Type_Href - Items []Instance `json:"items,omitempty"` - Resp Resp `json:"-"` -} +} \ No newline at end of file diff --git a/vendor/github.com/profitbricks/profitbricks-sdk-go/test_helpers.go b/vendor/github.com/profitbricks/profitbricks-sdk-go/test_helpers.go index 35df1f929172..91f01027ccd2 100644 --- a/vendor/github.com/profitbricks/profitbricks-sdk-go/test_helpers.go +++ b/vendor/github.com/profitbricks/profitbricks-sdk-go/test_helpers.go @@ -3,6 +3,8 @@ package profitbricks import ( "fmt" "time" + "strings" + "os" ) func mkdcid(name string) string { @@ -55,18 +57,49 @@ func mknic(lbal_dcid, serverid string) string { fmt.Println("created a nic with id " + resp.Id) fmt.Println(resp.StatusCode) fmt.Println("===========================") + waitTillProvisioned(resp.Headers.Get("Location")) return resp.Id } func waitTillProvisioned(path string) { - waitCount := 20 + waitCount := 120 fmt.Println(path) for i := 0; i < waitCount; i++ { request := GetRequestStatus(path) if request.Metadata.Status == "DONE" { break } - time.Sleep(10 * time.Second) + time.Sleep(1 * time.Second) i++ } } + +func getImageId(location string, imageName string, imageType string) string { + if imageName == "" { + return "" + } + + SetAuth(os.Getenv("PROFITBRICKS_USERNAME"), os.Getenv("PROFITBRICKS_PASSWORD")) + + images := ListImages() + if images.StatusCode > 299 { + fmt.Printf("Error while fetching the list of images %s", images.Response) + } + + if len(images.Items) > 0 { + for _, i := range images.Items { + imgName := "" + if i.Properties.Name != "" { + imgName = i.Properties.Name + } + + if imageType == "SSD" { + imageType = "HDD" + } + if imgName != "" && strings.Contains(strings.ToLower(imgName), strings.ToLower(imageName)) && i.Properties.ImageType == imageType && i.Properties.Location == location && i.Properties.Public == true { + return i.Id + } + } + } + return "" +} diff --git a/vendor/github.com/profitbricks/profitbricks-sdk-go/volume.go b/vendor/github.com/profitbricks/profitbricks-sdk-go/volume.go index 2982448d7324..1f22eba32088 100644 --- a/vendor/github.com/profitbricks/profitbricks-sdk-go/volume.go +++ b/vendor/github.com/profitbricks/profitbricks-sdk-go/volume.go @@ -21,6 +21,7 @@ type VolumeProperties struct { Name string `json:"name,omitempty"` Type string `json:"type,omitempty"` Size int `json:"size,omitempty"` + AvailabilityZone string `json:"availabilityZone,omitempty"` Image string `json:"image,omitempty"` ImagePassword string `json:"imagePassword,omitempty"` SshKeys []string `json:"sshKeys,omitempty"` diff --git a/vendor/vendor.json b/vendor/vendor.json index 9eff8e41cca1..cf48a61680db 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -2331,10 +2331,10 @@ "revisionTime": "2016-10-29T09:36:37Z" }, { - "checksumSHA1": "atkFfe1CrxF+Cz4p4Z78RMXC0Kg=", + "checksumSHA1": "WPDz/Ed0OwaP7F/HvzZQ8OwT3fM=", "path": "github.com/profitbricks/profitbricks-sdk-go", - "revision": "ccbdd70b24ec5c6cd000a34aba264d708c106af9", - "revisionTime": "2016-07-28T11:13:56Z" + "revision": "b279e1adcaf1c9cae4d6520c1bdbbf4674e7806e", + "revisionTime": "2017-01-11T22:35:15Z" }, { "checksumSHA1": "hcyoctYs0NjsvAXXVRc4mVt+FBg=", diff --git a/website/source/docs/providers/profitbricks/d/profitbricks_datacenter.html.markdown b/website/source/docs/providers/profitbricks/d/profitbricks_datacenter.html.markdown new file mode 100644 index 000000000000..fab58ad2ae10 --- /dev/null +++ b/website/source/docs/providers/profitbricks/d/profitbricks_datacenter.html.markdown @@ -0,0 +1,29 @@ +--- +layout: "profitbricks" +page_title: "ProfitBricks : profitbricks_datacenter" +sidebar_current: "docs-profitbricks-datasource-datacenter" +description: |- + Get information on a ProfitBricks Data Centers +--- + +# profitbricks\_datacenter + +The data centers data source can be used to search for and return an existing Virtual Data Center. You can provide a string for the name and location parameters which will be compared with provisioned Virtual Data Centers. If a single match is found, it will be returned. If your search results in multiple matches, an error will be generated. When this happens, please refine your search string so that it is specific enough to return only one result. + +## Example Usage + +``` +data "profitbricks_datacenter" "dc_example" { + name = "test_dc" + location = "us" +} +``` + +## Argument Reference + + * `name` - (Required) Name or part of the name of an existing Virtual Data Center that you want to search for. + * `location` - (Optional) Id of the existing Virtual Data Center's location. + +## Attributes Reference + + * `id` - UUID of the Virtual Data Center diff --git a/website/source/docs/providers/profitbricks/d/profitbricks_image.html.markdown b/website/source/docs/providers/profitbricks/d/profitbricks_image.html.markdown new file mode 100644 index 000000000000..378c507ed1b4 --- /dev/null +++ b/website/source/docs/providers/profitbricks/d/profitbricks_image.html.markdown @@ -0,0 +1,35 @@ +--- +layout: "profitbricks" +page_title: "ProfitBricks : profitbrick_image" +sidebar_current: "docs-profitbricks-datasource-image" +description: |- + Get information on a ProfitBricks Images +--- + +# profitbricks\_image + +The images data source can be used to search for and return an existing image which can then be used to provision a server. + +## Example Usage + +``` +data "profitbricks_image" "image_example" { + name = "Ubuntu" + type = "HDD" + version = "14" + location = "location_id" +} +``` + +## Argument Reference + + * `name` - (Required) Name or part of the name of an existing image that you want to search for. + * `version` - (Optional) Version of the image (see details below). + * `location` - (Optional) Id of the existing image's location. + * `type` - (Optional) The image type, HDD or CD-ROM. + +If both "name" and "version" are provided the plugin will concatenate the two strings in this format [name]-[version]. + +## Attributes Reference + + * `id` - UUID of the image diff --git a/website/source/docs/providers/profitbricks/d/profitbricks_location.html.markdown b/website/source/docs/providers/profitbricks/d/profitbricks_location.html.markdown new file mode 100644 index 000000000000..42949113e761 --- /dev/null +++ b/website/source/docs/providers/profitbricks/d/profitbricks_location.html.markdown @@ -0,0 +1,29 @@ +--- +layout: "profitbricks" +page_title: "ProfitBricks : profitbrick_location" +sidebar_current: "docs-profitbricks-datasource-location" +description: |- + Get information on a ProfitBricks Locations +--- + +# profitbricks\_location + +The locations data source can be used to search for and return an existing location which can then be used elsewhere in the configuration. + +## Example Usage + +``` +data "profitbricks_location" "loc1" { + name = "karlsruhe" + feature = "SSD" +} +``` + +## Argument Reference + + * `name` - (Required) Name or part of the location name to search for. + * `feature` - (Optional) A desired feature that the location must be able to provide. + +## Attributes Reference + + * `id` - UUID of the location diff --git a/website/source/docs/providers/profitbricks/r/profitbricks_nic.html.markdown b/website/source/docs/providers/profitbricks/r/profitbricks_nic.html.markdown index 8c2ed01dc1c6..96ff0e2d90dd 100644 --- a/website/source/docs/providers/profitbricks/r/profitbricks_nic.html.markdown +++ b/website/source/docs/providers/profitbricks/r/profitbricks_nic.html.markdown @@ -31,4 +31,4 @@ resource "profitbricks_nic" "example" { * `dhcp` - (Optional) [boolean] * `ip` - (Optional) [string] IP assigned to the NIC. * `firewall_active` - (Optional) [boolean] If this resource is set to true and is nested under a server resource firewall, with open SSH port, resource must be nested under the nic. - \ No newline at end of file +* `nat` - (Optional) [boolean] Boolean value indicating if the private IP address has outbound access to the public internet. diff --git a/website/source/docs/providers/profitbricks/r/profitbricks_volume.html.markdown b/website/source/docs/providers/profitbricks/r/profitbricks_volume.html.markdown index df3549946a48..34ff5bfb3774 100644 --- a/website/source/docs/providers/profitbricks/r/profitbricks_volume.html.markdown +++ b/website/source/docs/providers/profitbricks/r/profitbricks_volume.html.markdown @@ -21,7 +21,7 @@ resource "profitbricks_volume" "example" { image_name = "${var.ubuntu}" size = 5 disk_type = "HDD" - sshkey_path = "${var.private_key_path}" + ssh_key_path = "${var.private_key_path}" bus = "VIRTIO" } ``` @@ -33,7 +33,9 @@ resource "profitbricks_volume" "example" { * `disk_type` - (Required) [string] The volume type, HDD or SSD. * `bus` - (Required) [boolean] The bus type of the volume. * `size` - (Required)[integer] The size of the volume in GB. +* `ssh_key_path` - (Required)[list] List of paths to files containing a public SSH key that will be injected into ProfitBricks provided Linux images. Required if `image_password` is not provided. * `image_password` - [string] Required if `sshkey_path` is not provided. * `image_name` - [string] The image or snapshot ID. It is required if `licence_type` is not provided. * `licence_type` - [string] Required if `image_name` is not provided. -* `name` - (Optional) [string] The name of the volume. \ No newline at end of file +* `name` - (Optional) [string] The name of the volume. +* `availability_zone` - (Optional) [string] The storage availability zone assigned to the volume. AUTO, ZONE_1, ZONE_2, or ZONE_3 \ No newline at end of file