From cdd3b075d17198dc4707859907d31ad6dad28843 Mon Sep 17 00:00:00 2001 From: Olivier Cano Date: Tue, 3 Dec 2019 14:43:29 +0100 Subject: [PATCH] feat: data source security group (#346) --- scaleway/data_source_account_ssh_key.go | 2 +- scaleway/data_source_helpers.go | 73 +++++++++++++++++++ .../data_source_instance_security_group.go | 61 ++++++++++++++++ ...ata_source_instance_security_group_test.go | 59 +++++++++++++++ scaleway/provider.go | 11 +-- website/docs/d/account_ssh_key.html.markdown | 2 +- .../d/instance_security_group.html.markdown | 60 +++++++++++++++ .../r/instance_security_group.html.markdown | 4 +- website/scaleway.erb | 12 ++- 9 files changed, 274 insertions(+), 10 deletions(-) create mode 100644 scaleway/data_source_helpers.go create mode 100644 scaleway/data_source_instance_security_group.go create mode 100644 scaleway/data_source_instance_security_group_test.go create mode 100644 website/docs/d/instance_security_group.html.markdown diff --git a/scaleway/data_source_account_ssh_key.go b/scaleway/data_source_account_ssh_key.go index 8ae47acc5..7cc670b20 100644 --- a/scaleway/data_source_account_ssh_key.go +++ b/scaleway/data_source_account_ssh_key.go @@ -22,7 +22,7 @@ func dataSourceScalewayAccountSSHKey() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, - Description: "The name of the SSH key", + Description: "The ID of the SSH key", ValidateFunc: validationUUIDorUUIDWithLocality(), }, "public_key": { diff --git a/scaleway/data_source_helpers.go b/scaleway/data_source_helpers.go new file mode 100644 index 000000000..644aa8d04 --- /dev/null +++ b/scaleway/data_source_helpers.go @@ -0,0 +1,73 @@ +package scaleway + +// source: https://github.com/terraform-providers/terraform-provider-google/blob/master/google/datasource_helpers.go + +import "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + +// datasourceSchemaFromResourceSchema is a recursive func that +// converts an existing Resource schema to a Datasource schema. +// All schema elements are copied, but certain attributes are ignored or changed: +// - all attributes have Computed = true +// - all attributes have ForceNew, Required = false +// - Validation funcs and attributes (e.g. MaxItems) are not copied +func datasourceSchemaFromResourceSchema(rs map[string]*schema.Schema) map[string]*schema.Schema { + ds := make(map[string]*schema.Schema, len(rs)) + for k, v := range rs { + dv := &schema.Schema{ + Computed: true, + ForceNew: false, + Required: false, + Description: v.Description, + Type: v.Type, + } + + switch v.Type { + case schema.TypeSet: + dv.Set = v.Set + fallthrough + case schema.TypeList: + // List & Set types are generally used for 2 cases: + // - a list/set of simple primitive values (e.g. list of strings) + // - a sub resource + if elem, ok := v.Elem.(*schema.Resource); ok { + // handle the case where the Element is a sub-resource + dv.Elem = &schema.Resource{ + Schema: datasourceSchemaFromResourceSchema(elem.Schema), + } + } else { + // handle simple primitive case + dv.Elem = v.Elem + } + + default: + // Elem of all other types are copied as-is + dv.Elem = v.Elem + + } + ds[k] = dv + + } + return ds +} + +// fixDatasourceSchemaFlags is a convenience func that toggles the Computed, +// Optional + Required flags on a schema element. This is useful when the schema +// has been generated (using `datasourceSchemaFromResourceSchema` above for +// example) and therefore the attribute flags were not set appropriately when +// first added to the schema definition. Currently only supports top-level +// schema elements. +func fixDatasourceSchemaFlags(schema map[string]*schema.Schema, required bool, keys ...string) { + for _, v := range keys { + schema[v].Computed = false + schema[v].Optional = !required + schema[v].Required = required + } +} + +func addRequiredFieldsToSchema(schema map[string]*schema.Schema, keys ...string) { + fixDatasourceSchemaFlags(schema, true, keys...) +} + +func addOptionalFieldsToSchema(schema map[string]*schema.Schema, keys ...string) { + fixDatasourceSchemaFlags(schema, false, keys...) +} diff --git a/scaleway/data_source_instance_security_group.go b/scaleway/data_source_instance_security_group.go new file mode 100644 index 000000000..da8ab00d2 --- /dev/null +++ b/scaleway/data_source_instance_security_group.go @@ -0,0 +1,61 @@ +package scaleway + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/scaleway/scaleway-sdk-go/api/instance/v1" +) + +func dataSourceScalewayInstanceSecurityGroup() *schema.Resource { + // Generate datasource schema from resource + dsSchema := datasourceSchemaFromResourceSchema(resourceScalewayInstanceSecurityGroup().Schema) + + // Set 'Optional' schema elements + addOptionalFieldsToSchema(dsSchema, "name", "organization_id", "zone") + + dsSchema["name"].ConflictsWith = []string{"security_group_id"} + dsSchema["security_group_id"] = &schema.Schema{ + Type: schema.TypeString, + Optional: true, + Description: "The ID of the security group", + ValidateFunc: validationUUIDorUUIDWithLocality(), + ConflictsWith: []string{"name"}, + } + + return &schema.Resource{ + Read: dataSourceScalewayInstanceSecurityGroupRead, + + Schema: dsSchema, + } +} + +func dataSourceScalewayInstanceSecurityGroupRead(d *schema.ResourceData, m interface{}) error { + meta := m.(*Meta) + instanceApi, zone, err := getInstanceAPIWithZone(d, meta) + if err != nil { + return err + } + + securityGroupID, ok := d.GetOk("security_group_id") + if !ok { + res, err := instanceApi.ListSecurityGroups(&instance.ListSecurityGroupsRequest{ + Zone: zone, + Name: String(d.Get("name").(string)), + }) + if err != nil { + return err + } + if len(res.SecurityGroups) == 0 { + return fmt.Errorf("no security group found with the name %s", d.Get("name")) + } + if len(res.SecurityGroups) > 1 { + return fmt.Errorf("%d security groups found with the same name %s", len(res.SecurityGroups), d.Get("name")) + } + securityGroupID = res.SecurityGroups[0].ID + } + + d.SetId(newZonedId(zone, expandID(securityGroupID))) + d.Set("security_group_id", d.Id()) + return resourceScalewayInstanceSecurityGroupRead(d, m) +} diff --git a/scaleway/data_source_instance_security_group_test.go b/scaleway/data_source_instance_security_group_test.go new file mode 100644 index 000000000..d9c995f10 --- /dev/null +++ b/scaleway/data_source_instance_security_group_test.go @@ -0,0 +1,59 @@ +package scaleway + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" +) + +func TestAccScalewayDataSourceInstanceSecurityGroup_Basic(t *testing.T) { + securityGroupName := acctest.RandString(10) + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckScalewayInstanceSecurityGroupDestroy, + Steps: []resource.TestStep{ + { + Config: ` +resource "scaleway_instance_security_group" "main" { + name = "` + securityGroupName + `" +} + +data "scaleway_instance_security_group" "prod" { + name = "${scaleway_instance_security_group.main.name}" +} + +data "scaleway_instance_security_group" "stg" { + security_group_id = "${scaleway_instance_security_group.main.id}" +}`, + Check: resource.ComposeTestCheckFunc( + testAccCheckScalewayInstanceSecurityGroupExists("data.scaleway_instance_security_group.prod"), + resource.TestCheckResourceAttr("data.scaleway_instance_security_group.prod", "name", securityGroupName), + testAccCheckScalewayInstanceSecurityGroupExists("data.scaleway_instance_security_group.stg"), + resource.TestCheckResourceAttr("data.scaleway_instance_security_group.stg", "name", securityGroupName), + ), + }, + { + Config: ` +resource "scaleway_instance_security_group" "main" { + name = "` + securityGroupName + `" +} + +data "scaleway_instance_security_group" "prod" { + security_group_id = "${scaleway_instance_security_group.main.id}" +} + +data "scaleway_instance_security_group" "stg" { + name = "${scaleway_instance_security_group.main.name}" +}`, + Check: resource.ComposeTestCheckFunc( + testAccCheckScalewayInstanceSecurityGroupExists("data.scaleway_instance_security_group.prod"), + resource.TestCheckResourceAttr("data.scaleway_instance_security_group.prod", "name", securityGroupName), + testAccCheckScalewayInstanceSecurityGroupExists("data.scaleway_instance_security_group.stg"), + resource.TestCheckResourceAttr("data.scaleway_instance_security_group.stg", "name", securityGroupName), + ), + }, + }, + }) +} diff --git a/scaleway/provider.go b/scaleway/provider.go index 777e0d3df..3e71b597f 100644 --- a/scaleway/provider.go +++ b/scaleway/provider.go @@ -216,11 +216,12 @@ func Provider() terraform.ResourceProvider { }, DataSourcesMap: map[string]*schema.Resource{ - "scaleway_bootscript": dataSourceScalewayBootscript(), - "scaleway_image": dataSourceScalewayImage(), - "scaleway_security_group": dataSourceScalewaySecurityGroup(), - "scaleway_volume": dataSourceScalewayVolume(), - "scaleway_account_ssh_key": dataSourceScalewayAccountSSHKey(), + "scaleway_bootscript": dataSourceScalewayBootscript(), + "scaleway_image": dataSourceScalewayImage(), + "scaleway_security_group": dataSourceScalewaySecurityGroup(), + "scaleway_volume": dataSourceScalewayVolume(), + "scaleway_account_ssh_key": dataSourceScalewayAccountSSHKey(), + "scaleway_instance_security_group": dataSourceScalewayInstanceSecurityGroup(), }, } diff --git a/website/docs/d/account_ssh_key.html.markdown b/website/docs/d/account_ssh_key.html.markdown index 191e71a2d..83391e33d 100644 --- a/website/docs/d/account_ssh_key.html.markdown +++ b/website/docs/d/account_ssh_key.html.markdown @@ -34,5 +34,5 @@ data "scaleway_account_ssh_key" "my_key" { In addition to all above arguments, the following attributes are exported: -- `id` - The ID of the server. +- `id` - The ID of the SSH public key. - `public_key` - The SSH public key string diff --git a/website/docs/d/instance_security_group.html.markdown b/website/docs/d/instance_security_group.html.markdown new file mode 100644 index 000000000..d321de07f --- /dev/null +++ b/website/docs/d/instance_security_group.html.markdown @@ -0,0 +1,60 @@ +--- +layout: "scaleway" +page_title: "Scaleway: scaleway_security_group" +description: |- + Gets information about a Security Group. +--- + +# scaleway_security_group + +Gets information about a Security Group. + +## Example Usage + +```hcl +// Get info by security group name +data "scaleway_instance_security_group" "my_key" { + name = "my-security-group-name" +} + +// Get info by security group id +data "scaleway_instance_security_group" "my_key" { + security_group_id = "11111111-1111-1111-1111-111111111111" +} +``` + +## Argument Reference + +- `name` - (Optional) The security group name. Only one of `name` and `security_group_id` should be specified. + +- `security_group_id` - (Optional) The security group id. Only one of `name` and `security_group_id` should be specified. + +- `zone` - (Defaults to [provider](../index.html#zone) `zone`) The [zone](../guides/regions_and_zones.html#zones) in which the security group should be created. + +- `organization_id` - (Defaults to [provider](../index.html#organization_id) `organization_id`) The ID of the organization the security group is associated with. + +## Attributes Reference + +In addition to all above arguments, the following attributes are exported: + +- `id` - The ID of the security group. + +- `inbound_default_policy` - The default policy on incoming traffic. Possible values are: `accept` or `drop`. + +- `outbound_default_policy` - The default policy on outgoing traffic. Possible values are: `accept` or `drop`. + +- `inbound_rule` - A list of inbound rule to add to the security group. (Structure is documented below.) + +- `outbound_rule` - A list of outbound rule to add to the security group. (Structure is documented below.) + +The `inbound_rule` and `outbound_rule` block supports: + +- `action` - The action to take when rule match. Possible values are: `accept` or `drop`. + +- `protocol`- The protocol this rule apply to. Possible values are: `TCP`, `UDP`, `ICMP` or `ANY`. + +- `port`- The port this rule apply to. If no port is specified, rule will apply to all port. + +- `ip`- The ip this rule apply to. + +- `ip_range`- The ip range (e.g `192.168.1.0/24`) this rule apply to. diff --git a/website/docs/r/instance_security_group.html.markdown b/website/docs/r/instance_security_group.html.markdown index 69ca9c39f..86f47c248 100644 --- a/website/docs/r/instance_security_group.html.markdown +++ b/website/docs/r/instance_security_group.html.markdown @@ -104,9 +104,9 @@ The following arguments are supported: - `outbound_rule` - (Optional) A list of outbound rule to add to the security group. (Structure is documented below.) -- `zone` - (Defaults to [provider](../index.html#zone) `zone`) The [zone](../guides/regions_and_zones.html#zones) in which the server should be created. +- `zone` - (Defaults to [provider](../index.html#zone) `zone`) The [zone](../guides/regions_and_zones.html#zones) in which the security group should be created. -- `organization_id` - (Defaults to [provider](../index.html#organization_id) `organization_id`) The ID of the project the server is associated with. +- `organization_id` - (Defaults to [provider](../index.html#organization_id) `organization_id`) The ID of the project the security group is associated with. The `inbound_rule` and `outbound_rule` block supports: diff --git a/website/scaleway.erb b/website/scaleway.erb index 9780408cb..9dc38c51a 100644 --- a/website/scaleway.erb +++ b/website/scaleway.erb @@ -71,7 +71,7 @@ scaleway_image
  • - scaleway_security_group + scaleway_instance_security_group
  • scaleway_volume @@ -168,6 +168,16 @@
  • + +
  • + Deprecated Data Sources + +
  • + <% end %>