diff --git a/ovh/config.go b/ovh/config.go index 495fd915f..3ec77e3c2 100644 --- a/ovh/config.go +++ b/ovh/config.go @@ -4,7 +4,6 @@ import ( "fmt" "log" "sync" - "time" cleanhttp "github.com/hashicorp/go-cleanhttp" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/logging" @@ -14,6 +13,8 @@ import ( var providerVersion, providerCommit string type Config struct { + Account string + Plate string Endpoint string ApplicationKey string ApplicationSecret string @@ -24,17 +25,6 @@ type Config struct { lockAuth *sync.Mutex } -type OvhAuthCurrentCredential struct { - OvhSupport bool `json:"ovhSupport"` - Status string `json:"status"` - ApplicationId int64 `json:"applicationId"` - CredentialId int64 `json:"credentialId"` - Rules []ovh.AccessRule `json:"rules"` - Expiration time.Time `json:"expiration"` - LastUse time.Time `json:"lastUse"` - Creation time.Time `json:"creation"` -} - func clientDefault(c *Config) (*ovh.Client, error) { client, err := ovh.NewClient( c.Endpoint, @@ -63,15 +53,21 @@ func (c *Config) loadAndValidate() error { } if !c.authenticated { - var cred OvhAuthCurrentCredential - if err := c.OVHClient.Get("/auth/currentCredential", &cred); err != nil { + var details OvhAuthDetails + if err := c.OVHClient.Get("/auth/details", &details); err != nil { c.authFailed = fmt.Errorf("OVH client seems to be misconfigured: %q\n", err) return c.authFailed } log.Printf("[DEBUG] Logged in on OVH API") + c.Account = details.Account c.authenticated = true } + + if c.Plate == "" { + c.Plate = plateFromEndpoint(c.Endpoint) + } + return nil } @@ -106,3 +102,17 @@ func (c *Config) load() error { return nil } + +var plateMapping map[string]string = map[string]string{ + "ovh-eu": "eu", + "ovh-ca": "ca", + "ovh-us": "us", + "kimsufi-eu": "eu", + "kimsufi-ca": "ca", + "soyoustart-eu": "eu", + "soyoustart-ca": "ca", +} + +func plateFromEndpoint(endpoint string) string { + return plateMapping[endpoint] +} diff --git a/ovh/data_dbaas_logs_cluster.go b/ovh/data_dbaas_logs_cluster.go index babc22ecc..f48d62757 100644 --- a/ovh/data_dbaas_logs_cluster.go +++ b/ovh/data_dbaas_logs_cluster.go @@ -6,6 +6,7 @@ import ( "net/url" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/ovh/terraform-provider-ovh/ovh/helpers" ) func dataSourceDbaasLogsCluster() *schema.Resource { @@ -20,6 +21,10 @@ func dataSourceDbaasLogsCluster() *schema.Resource { Required: true, }, // Computed + "urn": { + Type: schema.TypeString, + Computed: true, + }, "cluster_type": { Type: schema.TypeString, Description: "Cluster type", @@ -114,6 +119,7 @@ func dataSourceDbaasLogsClusterRead(d *schema.ResourceData, meta interface{}) er } d.SetId(cluster_id) + d.Set("urn", helpers.ServiceURN(config.Plate, "ldp", serviceName)) endpoint := fmt.Sprintf( "/dbaas/logs/%s/cluster/%s", diff --git a/ovh/data_dedicated_ceph.go b/ovh/data_dedicated_ceph.go index e84bb0e51..0575b7537 100644 --- a/ovh/data_dedicated_ceph.go +++ b/ovh/data_dedicated_ceph.go @@ -20,6 +20,10 @@ func dataSourceDedicatedCeph() *schema.Resource { Type: schema.TypeString, }, }, + "urn": { + Type: schema.TypeString, + Computed: true, + }, "ceph_version": { Type: schema.TypeString, Optional: true, @@ -84,6 +88,7 @@ func dataSourceDedicatedCephRead(d *schema.ResourceData, meta interface{}) error } log.Printf("[DEBUG] CEPH is %v", ceph.CephMonitors) d.SetId(ceph.ServiceName) + d.Set("urn", helpers.ServiceURN(config.Plate, "dedicatedCeph", ceph.ServiceName)) d.Set("service_name", ceph.ServiceName) d.Set("ceph_mons", ceph.CephMonitors) d.Set("ceph_version", ceph.CephVersion) diff --git a/ovh/data_dedicated_nasha.go b/ovh/data_dedicated_nasha.go index 5cd052d3b..3911c4b18 100644 --- a/ovh/data_dedicated_nasha.go +++ b/ovh/data_dedicated_nasha.go @@ -3,9 +3,11 @@ package ovh import ( "context" "fmt" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "net/url" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/ovh/terraform-provider-ovh/ovh/helpers" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) @@ -20,6 +22,10 @@ func dataSourceDedicatedNasha() *schema.Resource { }, // Computed + "urn": { + Type: schema.TypeString, + Computed: true, + }, "can_create_partition": { Type: schema.TypeBool, Computed: true, @@ -86,6 +92,7 @@ func dataSourceDedicatedNashaRead(c context.Context, d *schema.ResourceData, met } d.SetId(ds.ServiceName) + d.Set("urn", helpers.ServiceURN(config.Plate, "nasHA", ds.ServiceName)) d.Set("service_name", ds.ServiceName) d.Set("monitored", ds.Monitored) d.Set("zpool_size", ds.ZpoolSize) diff --git a/ovh/data_dedicated_server.go b/ovh/data_dedicated_server.go index 5adabe1d9..730582f63 100644 --- a/ovh/data_dedicated_server.go +++ b/ovh/data_dedicated_server.go @@ -6,6 +6,7 @@ import ( "net/url" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/ovh/terraform-provider-ovh/ovh/helpers" ) func dataSourceDedicatedServer() *schema.Resource { @@ -18,6 +19,10 @@ func dataSourceDedicatedServer() *schema.Resource { }, // Computed + "urn": { + Type: schema.TypeString, + Computed: true, + }, "boot_id": { Type: schema.TypeInt, Computed: true, @@ -196,6 +201,7 @@ func dataSourceDedicatedServerRead(d *schema.ResourceData, meta interface{}) err } d.SetId(ds.Name) + d.Set("urn", helpers.ServiceURN(config.Plate, "dedicatedServer", ds.Name)) d.Set("boot_id", ds.BootId) d.Set("commercial_range", ds.CommercialRange) d.Set("datacenter", ds.Datacenter) diff --git a/ovh/data_domain_zone.go b/ovh/data_domain_zone.go index 5e47080d9..6b1c787cd 100644 --- a/ovh/data_domain_zone.go +++ b/ovh/data_domain_zone.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/ovh/terraform-provider-ovh/ovh/helpers" ) func dataSourceDomainZone() *schema.Resource { @@ -16,6 +17,10 @@ func dataSourceDomainZone() *schema.Resource { }, // Computed + "urn": { + Type: schema.TypeString, + Computed: true, + }, "has_dns_anycast": { Type: schema.TypeBool, Computed: true, @@ -55,5 +60,7 @@ func dataSourceDomainZoneRead(d *schema.ResourceData, meta interface{}) error { d.Set("last_update", dz.LastUpdate) d.Set("name_servers", dz.NameServers) + d.Set("urn", helpers.ServiceURN(config.Plate, "dnsZone", zoneName)) + return nil } diff --git a/ovh/data_hosting_privatedatabase.go b/ovh/data_hosting_privatedatabase.go index 2ee15134f..c3bb797c6 100644 --- a/ovh/data_hosting_privatedatabase.go +++ b/ovh/data_hosting_privatedatabase.go @@ -5,6 +5,7 @@ import ( "net/url" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/ovh/terraform-provider-ovh/ovh/helpers" ) func dataSourceHostingPrivateDatabase() *schema.Resource { @@ -17,6 +18,10 @@ func dataSourceHostingPrivateDatabase() *schema.Resource { }, // Computed + "urn": { + Type: schema.TypeString, + Computed: true, + }, "cpu": { Type: schema.TypeInt, Computed: true, @@ -138,6 +143,7 @@ func dataSourceHostingPrivateDatabaseRead(d *schema.ResourceData, meta interface } } d.SetId(ds.ServiceName) + d.Set("urn", helpers.ServiceURN(config.Plate, "webCloudDatabases", ds.ServiceName)) return nil } diff --git a/ovh/data_iam_policies.go b/ovh/data_iam_policies.go new file mode 100644 index 000000000..c9e1fdc68 --- /dev/null +++ b/ovh/data_iam_policies.go @@ -0,0 +1,46 @@ +package ovh + +import ( + "context" + "sort" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/ovh/terraform-provider-ovh/ovh/helpers/hashcode" +) + +func dataSourceIamPolicies() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "policies": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + ReadContext: datasourceIamPoliciesRead, + } +} + +func datasourceIamPoliciesRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + config := meta.(*Config) + + var policies []IamPolicy + err := config.OVHClient.GetWithContext(ctx, "/v2/iam/policy", &policies) + if err != nil { + return diag.FromErr(err) + } + + var polIDs []string + for _, p := range policies { + polIDs = append(polIDs, p.Id) + } + + d.Set("policies", polIDs) + + sort.Strings(polIDs) + d.SetId(hashcode.Strings(polIDs)) + return nil +} diff --git a/ovh/data_iam_policy.go b/ovh/data_iam_policy.go new file mode 100644 index 000000000..4ceb6f667 --- /dev/null +++ b/ovh/data_iam_policy.go @@ -0,0 +1,93 @@ +package ovh + +import ( + "context" + "net/url" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceIamPolicy() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "identities": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "resources": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "allow": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "except": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "owner": { + Type: schema.TypeString, + Computed: true, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + }, + "read_only": { + Type: schema.TypeBool, + Computed: true, + }, + }, + ReadContext: datasourceIamPolicyRead, + } +} + +func datasourceIamPolicyRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + config := meta.(*Config) + id := d.Get("id").(string) + + var pol IamPolicy + err := config.OVHClient.GetWithContext(ctx, "/v2/iam/policy/"+url.PathEscape(id), &pol) + if err != nil { + return diag.FromErr(err) + } + + for k, v := range pol.ToMap() { + err := d.Set(k, v) + if err != nil { + return diag.Errorf("key: %s; value: %v; err: %v", k, v, err) + } + } + d.SetId(id) + return nil +} diff --git a/ovh/data_iam_policy_test.go b/ovh/data_iam_policy_test.go new file mode 100644 index 000000000..e2be4bba7 --- /dev/null +++ b/ovh/data_iam_policy_test.go @@ -0,0 +1,145 @@ +package ovh + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccIamPolicyDataSource_basic(t *testing.T) { + usrLogin := acctest.RandomWithPrefix(test_prefix) + grpName := acctest.RandomWithPrefix(test_prefix) + + desc := "Iam policy created by Terraform Acc" + policyName1 := acctest.RandomWithPrefix(test_prefix) + policyName2 := acctest.RandomWithPrefix(test_prefix) + resource1 := "urn:v1:eu:resource:vrack:*" + resource2 := "urn:v1:eu:resource:vps:*" + allow1 := "*" + allow2 := "*" + + preSetup := fmt.Sprintf( + testAccIamPolicyDatasourceConfig_preSetup, + usrLogin, + usrLogin, + grpName, + policyName1, + desc, + resource1, + allow1, + policyName2, + desc, + resource2, + allow2, + ) + config := fmt.Sprintf( + testAccIamPolicyDatasourceConfig_keys, + usrLogin, + usrLogin, + grpName, + policyName1, + desc, + resource1, + allow1, + policyName2, + desc, + resource2, + allow2, + ) + + checks := checkIamPolicyResourceAttr("ovh_iam_policy.policy_1", policyName1, desc, resource1) + checks = append(checks, checkIamPolicyResourceAttr("ovh_iam_policy.policy_2", policyName2, desc, resource2)...) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheckCredentials(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: preSetup, + Check: resource.ComposeTestCheckFunc(checks...), + }, { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckOutput( + "keys_present", "true"), + ), + }, + }, + }) +} + +func checkIamPolicyResourceAttr(name, polName, desc, resourceURN string) []resource.TestCheckFunc { + // we are not checking identity urn because they are dynamic and depend on the test account NIC + return []resource.TestCheckFunc{ + resource.TestCheckResourceAttr(name, "name", polName), + resource.TestCheckResourceAttr(name, "description", desc), + resource.TestCheckTypeSetElemAttr(name, "resources.*", resourceURN), + } +} + +const testAccIamPolicyDatasourceConfig_preSetup = ` +resource "ovh_me_identity_user" "user_1" { + login = "%s" + email = "%s@terraform.test" + password = "qwerty123!@#" +} + +resource "ovh_me_identity_group" "group_1" { + name = "%s" +} + +resource "ovh_iam_policy" "policy_1" { + name = "%s" + description = "%s" + identities = [ovh_me_identity_user.user_1.urn] + resources = ["%s"] + allow = ["%s"] +} + +resource "ovh_iam_policy" "policy_2" { + name = "%s" + description = "%s" + identities = [ovh_me_identity_group.group_1.urn] + resources = ["%s"] + allow = ["%s"] +} +` + +const testAccIamPolicyDatasourceConfig_keys = ` +resource "ovh_me_identity_user" "user_1" { + login = "%s" + email = "%s@terraform.test" + password = "qwerty123!@#" +} + +resource "ovh_me_identity_group" "group_1" { + name = "%s" +} + +resource "ovh_iam_policy" "policy_1" { + name = "%s" + description = "%s" + identities = [ovh_me_identity_user.user_1.urn] + resources = ["%s"] + allow = ["%s"] +} + +resource "ovh_iam_policy" "policy_2" { + name = "%s" + description = "%s" + identities = [ovh_me_identity_group.group_1.urn] + resources = ["%s"] + allow = ["%s"] +} + +data "ovh_iam_policies" "policies" {} + +output "keys_present" { + value = tostring( + contains(data.ovh_iam_policies.policies.policies, ovh_iam_policy.policy_1.id) && + contains(data.ovh_iam_policies.policies.policies, ovh_iam_policy.policy_2.id) + ) +} +` diff --git a/ovh/data_iam_reference_action.go b/ovh/data_iam_reference_action.go new file mode 100644 index 000000000..ed0bb08b0 --- /dev/null +++ b/ovh/data_iam_reference_action.go @@ -0,0 +1,82 @@ +package ovh + +import ( + "context" + "log" + "net/url" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceIamReferenceActions() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIamReferenceActionRead, + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Required: true, + }, + "actions": { + Type: schema.TypeSet, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action": { + Type: schema.TypeString, + Computed: true, + }, + "categories": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "resource_type": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + Computed: true, + }, + }, + } +} + +func dataSourceIamReferenceActionRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + config := meta.(*Config) + + resType := d.Get("type").(string) + + e, err := url.Parse("/v2/iam/reference/action") + if err != nil { + return diag.Errorf("Unable to get actions:\n\t %q", err) + } + q := e.Query() + q.Add("resourceType", resType) + e.RawQuery = q.Encode() + log.Printf("[DEBUG] actions url: %+s", e.String()) + + var actions []IamReferenceAction + err = config.OVHClient.GetWithContext( + ctx, + e.String(), + &actions, + ) + if err != nil { + return diag.Errorf("Unable to get actions:\n\t %q", err) + } + log.Printf("[DEBUG] actions: %+v", actions) + + saveAct := make([]map[string]any, 0, len(actions)) + for _, a := range actions { + saveAct = append(saveAct, a.ToMap()) + } + d.SetId(resType) + d.Set("actions", saveAct) + + return nil +} diff --git a/ovh/data_iam_reference_resource_type.go b/ovh/data_iam_reference_resource_type.go new file mode 100644 index 000000000..e57f98eb3 --- /dev/null +++ b/ovh/data_iam_reference_resource_type.go @@ -0,0 +1,51 @@ +package ovh + +import ( + "context" + "log" + "net/url" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/ovh/terraform-provider-ovh/ovh/helpers/hashcode" +) + +func dataSourceIamReferenceResourceType() *schema.Resource { + return &schema.Resource{ + ReadContext: dataSourceIamReferenceResourceTypeRead, + Schema: map[string]*schema.Schema{ + "types": { + Type: schema.TypeSet, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + Computed: true, + }, + }, + } +} + +func dataSourceIamReferenceResourceTypeRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + config := meta.(*Config) + + e, err := url.Parse("/v2/iam/reference/resource/type") + if err != nil { + return diag.Errorf("Unable to get actions:\n\t %q", err) + } + + var types []string + err = config.OVHClient.GetWithContext( + ctx, + e.String(), + &types, + ) + if err != nil { + return diag.Errorf("Unable to get actions:\n\t %q", err) + } + log.Printf("[DEBUG] resource types: %+v", types) + + d.SetId(hashcode.Strings(types)) + d.Set("types", types) + + return nil +} diff --git a/ovh/data_iploadbalancing.go b/ovh/data_iploadbalancing.go index e99009369..a0373df41 100644 --- a/ovh/data_iploadbalancing.go +++ b/ovh/data_iploadbalancing.go @@ -13,6 +13,10 @@ func dataSourceIpLoadbalancing() *schema.Resource { return &schema.Resource{ Read: dataSourceIpLoadbalancingRead, Schema: map[string]*schema.Schema{ + "urn": { + Type: schema.TypeString, + Computed: true, + }, "ipv6": { Type: schema.TypeString, Optional: true, @@ -214,13 +218,13 @@ func dataSourceIpLoadbalancingRead(d *schema.ResourceData, meta interface{}) err " Please try a more specific search criteria") } - dataSourceIpLoadbalancingAttributes(d, filtered_iplbs[0]) + dataSourceIpLoadbalancingAttributes(config, d, filtered_iplbs[0]) return nil } // dataSourceIpLoadbalancingAttributes populates the fields of an ipLoadbalancing datasource. -func dataSourceIpLoadbalancingAttributes(d *schema.ResourceData, iplb *IpLoadbalancing) error { +func dataSourceIpLoadbalancingAttributes(config *Config, d *schema.ResourceData, iplb *IpLoadbalancing) error { log.Printf("[DEBUG] ovh_iploadbalancing details: %#v", iplb) if iplb.ServiceName == "" { @@ -240,6 +244,8 @@ func dataSourceIpLoadbalancingAttributes(d *schema.ResourceData, iplb *IpLoadbal } d.SetId(iplb.ServiceName) + d.Set("urn", helpers.ServiceURN(config.Plate, "loadbalancer", iplb.ServiceName)) + d.Set("ipv6", iplb.IPv6) d.Set("ipv4", iplb.IPv4) d.Set("zone", iplb.Zone) diff --git a/ovh/data_me.go b/ovh/data_me.go index eb22a63ae..6fc65db2f 100644 --- a/ovh/data_me.go +++ b/ovh/data_me.go @@ -11,6 +11,11 @@ func dataSourceMe() *schema.Resource { return &schema.Resource{ Read: dataSourceMeRead, Schema: map[string]*schema.Schema{ + "urn": { + Type: schema.TypeString, + Computed: true, + Description: "Identity URN of the account", + }, "address": { Type: schema.TypeString, Computed: true, @@ -191,5 +196,7 @@ func dataSourceMeRead(d *schema.ResourceData, meta interface{}) error { d.Set(k, v) } + d.Set("urn", fmt.Sprintf("urn:v1:%s:resource:account:%s", config.Plate, me.Nichandle)) + return nil } diff --git a/ovh/data_me_identity_user.go b/ovh/data_me_identity_user.go index 2a2a6b15e..d1dc2ffd5 100644 --- a/ovh/data_me_identity_user.go +++ b/ovh/data_me_identity_user.go @@ -16,6 +16,10 @@ func dataSourceMeIdentityUser() *schema.Resource { Required: true, Description: "User's login", }, + "urn": { + Type: schema.TypeString, + Computed: true, + }, "login": { Type: schema.TypeString, Computed: true, @@ -73,6 +77,9 @@ func dataSourceMeIdentityUserRead(d *schema.ResourceData, meta interface{}) erro if err != nil { return fmt.Errorf("Unable to find identity user %s:\n\t %q", user, err) } + + d.Set("urn", fmt.Sprintf("urn:v1:%s:identity:user:%s/%s", config.Plate, config.Account, user)) + log.Printf("[DEBUG] identity user for %s: %+v", user, identityUser) d.SetId(user) diff --git a/ovh/data_vps.go b/ovh/data_vps.go index 02c0e87fc..23482c887 100644 --- a/ovh/data_vps.go +++ b/ovh/data_vps.go @@ -5,6 +5,7 @@ import ( "net/url" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/ovh/terraform-provider-ovh/ovh/helpers" ) func dataSourceVPS() *schema.Resource { @@ -16,6 +17,10 @@ func dataSourceVPS() *schema.Resource { Required: true, }, // Here come all the computed items + "urn": { + Type: schema.TypeString, + Computed: true, + }, "type": { Type: schema.TypeString, Computed: true, @@ -107,6 +112,9 @@ func dataSourceVPSRead(d *schema.ResourceData, meta interface{}) error { } d.SetId(vps.Name) + + d.Set("urn", helpers.ServiceURN(config.Plate, helpers.VPSkind, serviceName)) + d.Set("name", vps.Name) d.Set("zone", vps.Zone) d.Set("state", vps.State) @@ -130,6 +138,9 @@ func dataSourceVPSRead(d *schema.ResourceData, meta interface{}) error { fmt.Sprintf("/vps/%s/ips", d.Id()), &ips, ) + if err != nil { + return err + } d.Set("ips", ips) @@ -138,6 +149,10 @@ func dataSourceVPSRead(d *schema.ResourceData, meta interface{}) error { fmt.Sprintf("/vps/%s/datacenter", d.Id()), &vpsDatacenter, ) + if err != nil { + return err + } + datacenter := make(map[string]string) datacenter["name"] = vpsDatacenter.Name datacenter["longname"] = vpsDatacenter.Longname diff --git a/ovh/helpers/urn.go b/ovh/helpers/urn.go new file mode 100644 index 000000000..fdff313d3 --- /dev/null +++ b/ovh/helpers/urn.go @@ -0,0 +1,11 @@ +package helpers + +import "fmt" + +const ( + VPSkind string = "vps" +) + +func ServiceURN(plate, kind, name string) string { + return fmt.Sprintf("urn:v1:%s:resource:%s:%s", plate, kind, name) +} diff --git a/ovh/provider.go b/ovh/provider.go index 78a8c020e..9a470e39d 100644 --- a/ovh/provider.go +++ b/ovh/provider.go @@ -106,6 +106,10 @@ func Provider() *schema.Provider { "ovh_hosting_privatedatabase_user_grant": dataSourceHostingPrivateDatabaseUserGrant(), "ovh_hosting_privatedatabase_whitelist": dataSourceHostingPrivateDatabaseWhitelist(), "ovh_domain_zone": dataSourceDomainZone(), + "ovh_iam_policies": dataSourceIamPolicies(), + "ovh_iam_policy": dataSourceIamPolicy(), + "ovh_iam_reference_actions": dataSourceIamReferenceActions(), + "ovh_iam_reference_resource_type": dataSourceIamReferenceResourceType(), "ovh_ip_service": dataSourceIpService(), "ovh_iploadbalancing": dataSourceIpLoadbalancing(), "ovh_iploadbalancing_vrack_network": dataSourceIpLoadbalancingVrackNetwork(), @@ -182,6 +186,7 @@ func Provider() *schema.Provider { "ovh_hosting_privatedatabase_user": resourceHostingPrivateDatabaseUser(), "ovh_hosting_privatedatabase_user_grant": resourceHostingPrivateDatabaseUserGrant(), "ovh_hosting_privatedatabase_whitelist": resourceHostingPrivateDatabaseWhitelist(), + "ovh_iam_policy": resourceIamPolicy(), "ovh_ip_reverse": resourceIpReverse(), "ovh_ip_service": resourceIpService(), "ovh_iploadbalancing": resourceIpLoadbalancing(), diff --git a/ovh/resource_cloud_project.go b/ovh/resource_cloud_project.go index e54d23756..b305e5eef 100644 --- a/ovh/resource_cloud_project.go +++ b/ovh/resource_cloud_project.go @@ -36,6 +36,10 @@ func resourceCloudProjectSchema() map[string]*schema.Schema { }, // computed + "urn": { + Type: schema.TypeString, + Computed: true, + }, "project_name": { Type: schema.TypeString, Computed: true, @@ -104,6 +108,8 @@ func resourceCloudProjectRead(d *schema.ResourceData, meta interface{}) error { return helpers.CheckDeleted(d, err, endpoint) } + d.Set("urn", helpers.ServiceURN(config.Plate, "publicCloudProject", serviceName)) + // set resource attributes for k, v := range r.ToMap() { d.Set(k, v) diff --git a/ovh/resource_domain_zone.go b/ovh/resource_domain_zone.go index ba4c7e703..cf1d34ddc 100644 --- a/ovh/resource_domain_zone.go +++ b/ovh/resource_domain_zone.go @@ -30,6 +30,10 @@ func resourceDomainZoneSchema() map[string]*schema.Schema { schema := map[string]*schema.Schema{ // computed + "urn": { + Type: schema.TypeString, + Computed: true, + }, "dnssec_supported": { Type: schema.TypeBool, Description: "Is DNSSEC supported by this zone", @@ -94,6 +98,8 @@ func resourceDomainZoneRead(d *schema.ResourceData, meta interface{}) error { d.Set(k, v) } + d.Set("urn", helpers.ServiceURN(config.Plate, "dnsZone", r.Name)) + return nil } diff --git a/ovh/resource_hosting_privatedatabase.go b/ovh/resource_hosting_privatedatabase.go index d2f75f26b..a85836575 100644 --- a/ovh/resource_hosting_privatedatabase.go +++ b/ovh/resource_hosting_privatedatabase.go @@ -36,6 +36,10 @@ func resourceHostingPrivateDatabaseSchema() map[string]*schema.Schema { }, // Computed + "urn": { + Type: schema.TypeString, + Computed: true, + }, "cpu": { Type: schema.TypeInt, Computed: true, @@ -190,6 +194,8 @@ func resourceHostingPrivateDatabaseRead(d *schema.ResourceData, meta interface{} for k, v := range ds.ToMap() { d.Set(k, v) } + d.Set("urn", helpers.ServiceURN(config.Plate, "webCloudDatabases", ds.ServiceName)) + return nil } diff --git a/ovh/resource_iam_policy.go b/ovh/resource_iam_policy.go new file mode 100644 index 000000000..9d8920c31 --- /dev/null +++ b/ovh/resource_iam_policy.go @@ -0,0 +1,170 @@ +package ovh + +import ( + "context" + "net/url" + + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceIamPolicy() *schema.Resource { + return &schema.Resource{ + Importer: &schema.ResourceImporter{ + State: func(rd *schema.ResourceData, i interface{}) ([]*schema.ResourceData, error) { + return []*schema.ResourceData{rd}, nil + }, + }, + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + }, + "identities": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "resources": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "allow": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "except": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "owner": { + Type: schema.TypeString, + Computed: true, + }, + "created_at": { + Type: schema.TypeString, + Computed: true, + }, + "updated_at": { + Type: schema.TypeString, + Computed: true, + }, + "read_only": { + Type: schema.TypeBool, + Computed: true, + }, + }, + ReadContext: resourceIamPolicyRead, + CreateContext: resourceIamPolicyCreate, + UpdateContext: resourceIamPolicyUpdate, + DeleteContext: resourceIamPolicyDelete, + } +} + +func resourceIamPolicyRead(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + config := meta.(*Config) + + var pol IamPolicy + err := config.OVHClient.GetWithContext(ctx, "/v2/iam/policy/"+url.PathEscape(d.Id()), &pol) + if err != nil { + return diag.FromErr(err) + } + + for k, v := range pol.ToMap() { + d.Set(k, v) + } + return nil +} + +func resourceIamPolicyCreate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + config := meta.(*Config) + + req := prepareIamPolicyCall(d) + + var pol IamPolicy + err := config.OVHClient.PostWithContext(ctx, "/v2/iam/policy", req, &pol) + if err != nil { + return diag.FromErr(err) + } + + for k, v := range pol.ToMap() { + d.Set(k, v) + } + + d.SetId(pol.Id) + return nil +} + +func resourceIamPolicyUpdate(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + config := meta.(*Config) + + req := prepareIamPolicyCall(d) + + var pol IamPolicy + err := config.OVHClient.PutWithContext(ctx, "/v2/iam/policy/"+url.PathEscape(d.Id()), req, &pol) + if err != nil { + return diag.FromErr(err) + } + + for k, v := range pol.ToMap() { + d.Set(k, v) + } + + return nil +} + +func resourceIamPolicyDelete(ctx context.Context, d *schema.ResourceData, meta any) diag.Diagnostics { + config := meta.(*Config) + + err := config.OVHClient.DeleteWithContext(ctx, "/v2/iam/policy/"+url.PathEscape(d.Id()), nil) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func prepareIamPolicyCall(d *schema.ResourceData) IamPolicy { + var out IamPolicy + + out.Name = d.Get("name").(string) + out.Description = d.Get("description").(string) + ids := d.Get("identities").(*schema.Set) + + for _, id := range ids.List() { + out.Identities = append(out.Identities, id.(string)) + } + + res := d.Get("resources").(*schema.Set) + for _, r := range res.List() { + out.Resources = append(out.Resources, IamResource{URN: r.(string)}) + } + + if allows, ok := d.GetOk("allow"); ok { + for _, a := range allows.(*schema.Set).List() { + out.Permissions.Allow = append(out.Permissions.Allow, IamAction{Action: a.(string)}) + } + } + + if except, ok := d.GetOk("except"); ok { + for _, e := range except.(*schema.Set).List() { + out.Permissions.Except = append(out.Permissions.Allow, IamAction{Action: e.(string)}) + } + } + return out +} diff --git a/ovh/resource_iam_policy_test.go b/ovh/resource_iam_policy_test.go new file mode 100644 index 000000000..a652ecb22 --- /dev/null +++ b/ovh/resource_iam_policy_test.go @@ -0,0 +1,100 @@ +package ovh + +import ( + "fmt" + "log" + "strings" + "testing" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func init() { + resource.AddTestSweepers("ovh_iam_policy", &resource.Sweeper{ + Name: "ovh_iam_policy", + F: testSweepIamPolicy, + }) +} + +func testSweepIamPolicy(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + + policyIds := []string{} + if err := client.Get("/v2/iam/policy", &policyIds); err != nil { + return fmt.Errorf("Error calling /v2/iam/policy:\n\t %q", err) + } + + if len(policyIds) == 0 { + log.Print("[DEBUG] No identity groups to sweep") + return nil + } + + for _, polId := range policyIds { + var polDetails IamPolicy + if err := client.Get(fmt.Sprintf("/v2/iam/policy/%s", polId), &polDetails); err != nil { + return err + } + + if !strings.HasPrefix(polDetails.Name, test_prefix) { + continue + } + + log.Printf("[DEBUG] IAM policy found %s: %s", polDetails.Name, polId) + err = resource.Retry(5*time.Minute, func() *resource.RetryError { + log.Printf("[INFO] Deleting iam policy %s: %s", polDetails.Name, polId) + if err := client.Delete(fmt.Sprintf("/v2/iam/policy/%s", polId), nil); err != nil { + return resource.RetryableError(err) + } + + // Successful delete + return nil + }) + + if err != nil { + return err + } + } + return nil +} + +func TestAccIamPolicy_basic(t *testing.T) { + name := acctest.RandomWithPrefix(test_prefix) + desc := "IAM policy created by Terraform Acc" + userName := acctest.RandomWithPrefix(test_prefix) + res := "urn:v1:eu:resource:vps:*" + config := fmt.Sprintf(testAccIamPolicyConfig, userName, userName, name, desc, res) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheckCredentials(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + checkIamPolicyResourceAttr("ovh_iam_policy.policy1", name, desc, res)..., + ), + }, + }, + }) +} + +const testAccIamPolicyConfig = ` +resource "ovh_me_identity_user" "test_user" { + login = "%s" + email = "%s@terraform.test" + password = "qwe123!@#" +} + +resource "ovh_iam_policy" "policy1" { + name = "%s" + description = "%s" + identities = [ovh_me_identity_user.test_user.urn] + resources = ["%s"] + allow = ["*"] +} +` diff --git a/ovh/resource_iploadbalancing.go b/ovh/resource_iploadbalancing.go index 5976b8118..8eb1cf4b3 100644 --- a/ovh/resource_iploadbalancing.go +++ b/ovh/resource_iploadbalancing.go @@ -55,6 +55,10 @@ func resourceIpLoadbalancingSchema() map[string]*schema.Schema { }, //computed + "urn": { + Type: schema.TypeString, + Computed: true, + }, "ipv6": { Type: schema.TypeString, Description: "The IPV6 associated to your IP load balancing. DEPRECATED.", @@ -202,6 +206,7 @@ func resourceIpLoadbalancingRead(d *schema.ResourceData, meta interface{}) error for k, v := range r.ToMap() { d.Set(k, v) } + d.Set("urn", helpers.ServiceURN(config.Plate, "loadbalancer", r.ServiceName)) return nil } diff --git a/ovh/resource_me_identity_group.go b/ovh/resource_me_identity_group.go index 3eeb009be..444a30095 100644 --- a/ovh/resource_me_identity_group.go +++ b/ovh/resource_me_identity_group.go @@ -30,6 +30,10 @@ func resourceMeIdentityGroup() *schema.Resource { ForceNew: true, Required: true, }, + "urn": { + Type: schema.TypeString, + Computed: true, + }, "description": { Type: schema.TypeString, Optional: true, @@ -73,6 +77,8 @@ func resourceMeIdentityGroupRead(ctx context.Context, d *schema.ResourceData, me d.Set("description", identityGroup.Description) d.Set("role", identityGroup.Role) + d.Set("urn", fmt.Sprintf("urn:v1:%s:identity:group:%s/%s", config.Plate, config.Account, identityGroup.Name)) + return nil } diff --git a/ovh/resource_me_identity_user.go b/ovh/resource_me_identity_user.go index 4a0a0b88b..c9ab1c1a4 100644 --- a/ovh/resource_me_identity_user.go +++ b/ovh/resource_me_identity_user.go @@ -27,6 +27,10 @@ func resourceMeIdentityUser() *schema.Resource { Optional: true, Description: "User description", }, + "urn": { + Type: schema.TypeString, + Computed: true, + }, "email": { Type: schema.TypeString, Required: true, @@ -35,6 +39,7 @@ func resourceMeIdentityUser() *schema.Resource { "group": { Type: schema.TypeString, Optional: true, + Default: "DEFAULT", Description: "User's group", }, "login": { @@ -84,6 +89,8 @@ func resourceMeIdentityUserRead(d *schema.ResourceData, meta interface{}) error return helpers.CheckDeleted(d, err, endpoint) } + d.Set("urn", fmt.Sprintf("urn:v1:%s:identity:user:%s/%s", config.Plate, config.Account, identityUser.Login)) + d.Set("login", identityUser.Login) d.Set("creation", identityUser.Creation) d.Set("description", identityUser.Description) diff --git a/ovh/resource_vrack.go b/ovh/resource_vrack.go index 4184eddf4..fdf652b23 100644 --- a/ovh/resource_vrack.go +++ b/ovh/resource_vrack.go @@ -41,6 +41,10 @@ func resourceVrackSchema() map[string]*schema.Schema { }, // computed + "urn": { + Type: schema.TypeString, + Computed: true, + }, "service_name": { Type: schema.TypeString, Description: "The internal name of your vrack", @@ -104,6 +108,7 @@ func resourceVrackRead(d *schema.ResourceData, meta interface{}) error { for k, v := range r.ToMap() { d.Set(k, v) } + d.Set("urn", helpers.ServiceURN(config.Plate, "vrack", serviceName)) return nil } diff --git a/ovh/type_auth.go b/ovh/type_auth.go new file mode 100644 index 000000000..9b530b4a5 --- /dev/null +++ b/ovh/type_auth.go @@ -0,0 +1,28 @@ +package ovh + +import ( + "time" + + "github.com/ovh/go-ovh/ovh" +) + +type OvhAuthCurrentCredential struct { + OvhSupport bool `json:"ovhSupport"` + Status string `json:"status"` + ApplicationId int64 `json:"applicationId"` + CredentialId int64 `json:"credentialId"` + Rules []ovh.AccessRule `json:"rules"` + Expiration time.Time `json:"expiration"` + LastUse time.Time `json:"lastUse"` + Creation time.Time `json:"creation"` +} + +type OvhAuthDetails struct { + Account string `json:"account"` + AllowedRoutes []ovh.AccessRule `json:"allowedRoutes"` + Description string `json:"description"` + Identities []string `json:"identities"` + Method string `json:"method"` + Roles []string `json:"roles"` + User string `json:"user"` +} diff --git a/ovh/types_iam.go b/ovh/types_iam.go new file mode 100644 index 000000000..24db8d9db --- /dev/null +++ b/ovh/types_iam.go @@ -0,0 +1,110 @@ +package ovh + +type IamReferenceAction struct { + Action string `json:"action"` + Categories []string `json:"categories"` + Description string `json:"description"` + ResourceType string `json:"resourceType"` +} + +func (a *IamReferenceAction) ToMap() map[string]any { + out := make(map[string]any, 4) + + out["action"] = a.Action + out["categories"] = a.Categories + out["description"] = a.Description + out["resource_type"] = a.ResourceType + + return out +} + +type IamPolicy struct { + Id string `json:"id,omitempty"` + Name string `json:"name"` + Description string `json:"description,omitempty"` + Identities []string `json:"identities"` + Resources []IamResource `json:"resources"` + Permissions IamPermissions `json:"permissions"` + CreatedAt string `json:"createdAt,omitempty"` + UpdatedAt string `json:"updatedAt,omitempty"` + ReadOnly bool `json:"readOnly,omitempty"` + Owner string `json:"owner,omitempty"` +} + +func (p IamPolicy) ToMap() map[string]any { + out := make(map[string]any, 0) + out["name"] = p.Name + + out["owner"] = p.Owner + out["created_at"] = p.CreatedAt + out["identities"] = p.Identities + var resources []string + for _, r := range p.Resources { + resources = append(resources, r.URN) + } + out["resources"] = resources + + // inline allow and except + allow, except := p.Permissions.ToLists() + if len(allow) != 0 { + out["allow"] = allow + } + if len(except) != 0 { + out["except"] = except + } + + if p.Description != "" { + out["description"] = p.Description + } + if p.ReadOnly { + out["read_only"] = p.ReadOnly + } + if p.UpdatedAt != "" { + out["updated_at"] = p.UpdatedAt + } + + return out +} + +type IamResource struct { + URN string `json:"urn,omitempty"` + Group *IamPolicyResourceGroup `json:"group,omitempty"` + Resource *IamResourceDetails `json:"resource,omitempty"` +} + +type IamPolicyResourceGroup struct { + Id string `json:"id"` + Name string `json:"name"` + ReadOnly bool `json:"readOnly"` +} + +type IamResourceDetails struct { + Id string `json:"id"` + Name string `json:"name"` + DisplayName string `json:"displayName"` + Owner string `json:"owner"` + Type string `json:"type"` +} + +type IamPermissions struct { + Allow []IamAction `json:"allow"` + Except []IamAction `json:"except"` +} + +func (p IamPermissions) ToLists() ([]string, []string) { + var allow []string + var except []string + + for _, r := range p.Allow { + allow = append(allow, r.Action) + } + + for _, r := range p.Except { + except = append(except, r.Action) + } + return allow, except +} + +type IamAction struct { + Action string `json:"action"` +} diff --git a/website/docs/d/dbaas_logs_cluster.html.markdown b/website/docs/d/dbaas_logs_cluster.html.markdown index 848f5feea..606e95a48 100644 --- a/website/docs/d/dbaas_logs_cluster.html.markdown +++ b/website/docs/d/dbaas_logs_cluster.html.markdown @@ -21,7 +21,8 @@ data "ovh_dbaas_logs_cluster" "logstash" { ## Attributes Reference -* `id` is set to input engine ID +* `id` is the input engine ID +* `urn` is the URN of the DBaas logs instance * `cluster_type` is type of cluster (DEDICATED, PRO or TRIAL) * `dedicated_input_pem` is PEM for dedicated inputs * `archive_allowed_networks` is allowed networks for ARCHIVE flow type diff --git a/website/docs/d/dedicated_ceph.html.markdown b/website/docs/d/dedicated_ceph.html.markdown index 8500461f4..f6c3f2cdd 100644 --- a/website/docs/d/dedicated_ceph.html.markdown +++ b/website/docs/d/dedicated_ceph.html.markdown @@ -16,12 +16,12 @@ data "ovh_dedicated_ceph" "my-ceph" { ## Argument Reference - * `service_name` - (Required) The service name of the dedicated CEPH cluster. ## Attributes Reference +* `urn` - URN of the CEPH instance * `ceph_mons` - list of CEPH monitors IPs * `ceph_version` - CEPH cluster version * `crush_tunables` - CRUSH algorithm settings. Possible values diff --git a/website/docs/d/dedicated_nasha.html.markdown b/website/docs/d/dedicated_nasha.html.markdown index 0c38c48fe..5c8774048 100644 --- a/website/docs/d/dedicated_nasha.html.markdown +++ b/website/docs/d/dedicated_nasha.html.markdown @@ -24,6 +24,7 @@ data "ovh_dedicated_nasha" "my-nas-ha" { In addition, the following attributes are exported: * `service_name` - The storage service name +* `urn` - the URN of the HA-NAS instance * `can_create_partition` - True, if partition creation is allowed on this HA-NAS * `custom_name` - The name you give to the HA-NAS * `datacenter` - area of HA-NAS diff --git a/website/docs/d/dedicated_server.html.markdown b/website/docs/d/dedicated_server.html.markdown index 99a88a8d3..63b427ed5 100644 --- a/website/docs/d/dedicated_server.html.markdown +++ b/website/docs/d/dedicated_server.html.markdown @@ -24,7 +24,8 @@ data "ovh_dedicated_server" "server" { In addition, the following attributes are exported: * `boot_id` - boot id of the server -* `commercial_range` - dedicater server commercial range +* `urn` - URN of the dedicated server instance +* `commercial_range` - dedicated server commercial range * `datacenter` - dedicated datacenter localisation (bhs1,bhs2,...) * `ip` - dedicated server ip (IPv4) * `ips` - dedicated server ip blocks diff --git a/website/docs/d/domain_zone.html.markdown b/website/docs/d/domain_zone.html.markdown index 96b6e06fa..75f52a0ea 100644 --- a/website/docs/d/domain_zone.html.markdown +++ b/website/docs/d/domain_zone.html.markdown @@ -23,6 +23,7 @@ data "ovh_domain_zone" "rootzone" { `id` is set to the domain zone name. In addition, the following attributes are exported: +* `urn` - URN of the DNS zone * `last_update` - Last update date of the DNS zone * `has_dns_anycast` - hasDnsAnycast flag of the DNS zone * `name_servers` - Name servers that host the DNS zone diff --git a/website/docs/d/hosting_privatedatabase.html.markdown b/website/docs/d/hosting_privatedatabase.html.markdown index e46b55462..9a317e053 100644 --- a/website/docs/d/hosting_privatedatabase.html.markdown +++ b/website/docs/d/hosting_privatedatabase.html.markdown @@ -22,6 +22,7 @@ data "ovh_hosting_privatedatabase" "database" { `id` is set to database service_name. In addition, the following attributes are exported. +* `urn` - URN of the private database * `cpu` - Number of CPU on your private database * `datacenter` - Datacenter where this private database is located * `display_name` - Name displayed in customer panel for your private database diff --git a/website/docs/d/iam_policies.html.markdown b/website/docs/d/iam_policies.html.markdown new file mode 100644 index 000000000..ad54ec046 --- /dev/null +++ b/website/docs/d/iam_policies.html.markdown @@ -0,0 +1,24 @@ +--- +subcategory : "Account Management" +--- + +# ovh_iam_policy (Data Source) + +Use this data source to list the existing IAM policies of an account. + +## Important +-> Using this resource requires that the account is enrolled in the OVHcloud [IAM beta](https://labs.ovhcloud.com/en/iam/) + +## Example Usage + +```hcl +data "ovh_iam_policies" "my_policies" { +} +``` + +## Argument Reference + +## Attributes Reference + +* `id` - Hash of the list of the policy IDs. +* `policies` - List of the policies IDs. diff --git a/website/docs/d/iam_policy.html.markdown b/website/docs/d/iam_policy.html.markdown new file mode 100644 index 000000000..684c26153 --- /dev/null +++ b/website/docs/d/iam_policy.html.markdown @@ -0,0 +1,35 @@ +--- +subcategory : "Account Management" +--- + +# ovh_iam_policy (Data Source) + +Use this data source to retrieve am IAM policy. + +## Important +-> Using this resource requires that the account is enrolled in the OVHcloud [IAM beta](https://labs.ovhcloud.com/en/iam/) + +## Example Usage + +```hcl +data "ovh_iam_policy" "my_policy" { + id = "my_policy_id" +} +``` + +## Argument Reference + +* `id` - UUID of the policy. + +## Attributes Reference + +* `name` - Name of the policy. +* `description` - Group description. +* `identities` - List of identities affected by the policy. +* `resources` - List of resources affected by the policy. +* `allow` - List of actions allowed by the policy. +* `except` - List of actions. +* `owner` - Owner of the policy. +* `created_at` - Creation date of this group. +* `updated_at` - Date of the last update of this group. +* `read_only` - Indicates that the policy is a default one. diff --git a/website/docs/d/iam_reference_actions.html.markdown b/website/docs/d/iam_reference_actions.html.markdown new file mode 100644 index 000000000..2bf2409bb --- /dev/null +++ b/website/docs/d/iam_reference_actions.html.markdown @@ -0,0 +1,30 @@ +--- +subcategory : "Account Management" +--- + +# ovh_iam_reference_actions (Data Source) + +Use this data source to list the IAM action associated with a resource type. + +## Important +-> Using this resource requires that the account is enrolled in the OVHcloud [IAM beta](https://labs.ovhcloud.com/en/iam/) + +## Example Usage + +```hcl +data "ovh_iam_reference_actions" "vps_actions" { + resource_type = "vps" +} +``` + +## Argument Reference + +* `type` - Kind of resource we want the actions for + +## Attributes Reference + +* `actions` - List of actions + * `action` - Name of the action + * `categories` - List of the categories of the action + * `description` - Description of the action + * `resource_type` - Resource type the action is related to \ No newline at end of file diff --git a/website/docs/d/iam_reference_resource_type.markdown b/website/docs/d/iam_reference_resource_type.markdown new file mode 100644 index 000000000..fded2e2cd --- /dev/null +++ b/website/docs/d/iam_reference_resource_type.markdown @@ -0,0 +1,24 @@ +--- +subcategory : "Account Management" +--- + +# ovh_iam_reference_resource_type (Data Source) + +Use this data source to list all the IAM resource types. + +## Important +-> Using this resource requires that the account is enrolled in the OVHcloud [IAM beta](https://labs.ovhcloud.com/en/iam/) + +## Example Usage + +```hcl +data "ovh_iam_reference_resource_type" "types" { +} +``` + +## Argument Reference + +## Attributes Reference + +* `id` - hash of the list of the resource types +* `types` - List of resource types diff --git a/website/docs/d/iploadbalancing.html.markdown b/website/docs/d/iploadbalancing.html.markdown index ac6fe343c..ed934076d 100644 --- a/website/docs/d/iploadbalancing.html.markdown +++ b/website/docs/d/iploadbalancing.html.markdown @@ -49,7 +49,7 @@ Can take any of the following value: "intermediate", "modern" `id` is set to the service_name of your IP load balancing In addition, the following attributes are exported: - +* `urn` - The URN of the load balancer, to be used in IAM policies * `metrics_token` - The metrics token associated with your IP load balancing This attribute is sensitive. diff --git a/website/docs/d/me.html.markdown b/website/docs/d/me.html.markdown index b2497ab2d..697bb2a38 100644 --- a/website/docs/d/me.html.markdown +++ b/website/docs/d/me.html.markdown @@ -20,6 +20,7 @@ There are no arguments to this datasource. The following attributes are exported: +* `urn`: The resource URN of the account, to be used when writing IAM policies * `address`: Postal address of the account * `area`: Area of the account * `birth_city`: City of birth diff --git a/website/docs/d/me_identity_group.markdown b/website/docs/d/me_identity_group.markdown index de7309c2f..7841bba9e 100644 --- a/website/docs/d/me_identity_group.markdown +++ b/website/docs/d/me_identity_group.markdown @@ -20,6 +20,7 @@ data "ovh_me_identity_group" "my_group" { ## Attributes Reference +* `urn` - Identity URN of the group. * `description` - Group description. * `role` - Role associated with the group. Valid roles are ADMIN, REGULAR, UNPRIVILEGED, and NONE. * `default_group` - Is the group a default and immutable one. diff --git a/website/docs/d/me_identity_user.markdown b/website/docs/d/me_identity_user.markdown index 6d59dfff6..b98c01393 100644 --- a/website/docs/d/me_identity_user.markdown +++ b/website/docs/d/me_identity_user.markdown @@ -20,6 +20,7 @@ data "ovh_me_identity_user" "my_user" { ## Attributes Reference +* `urn` - User's identity URN. * `login` - User's login suffix. * `creation` - Creation date of this user. * `description` - User description. diff --git a/website/docs/d/vps.html.markdown b/website/docs/d/vps.html.markdown index 8951df4c1..c7a040856 100644 --- a/website/docs/d/vps.html.markdown +++ b/website/docs/d/vps.html.markdown @@ -24,6 +24,7 @@ data "ovh_vps" "server" { In addition, the following attributes are exported: +* `urn` - The URN of the vps * `cluster` - The OVHcloud cluster the vps is in * `datacenter` - The datacenter in which the vps is located * `datacenter.longname` - The fullname of the datacenter (ex: "Strasbourg SBG1") diff --git a/website/docs/d/vracks.html.markdown b/website/docs/d/vracks.html.markdown index 03ad6792f..da86e8ae5 100644 --- a/website/docs/d/vracks.html.markdown +++ b/website/docs/d/vracks.html.markdown @@ -20,4 +20,5 @@ This datasource takes no argument. The following attributes are exported: +* `urn` - The URN of the vps * `result` - The list of vrack service name available for your OVHcloud account. diff --git a/website/docs/r/cloud_project.html.markdown b/website/docs/r/cloud_project.html.markdown index e8941d3e6..4320df59d 100644 --- a/website/docs/r/cloud_project.html.markdown +++ b/website/docs/r/cloud_project.html.markdown @@ -41,6 +41,7 @@ resource "ovh_cloud_project" "my_cloud_project" { The following arguments are supported: +* `urn` - The URN of the cloud project * `description` - A description associated with the user. * `ovh_subsidiary` - (Required) OVHcloud Subsidiary * `plan` - (Required) Product Plan to order diff --git a/website/docs/r/dbaas_logs_cluster.html.markdown b/website/docs/r/dbaas_logs_cluster.html.markdown index 7ce0c4c99..0866f7106 100644 --- a/website/docs/r/dbaas_logs_cluster.html.markdown +++ b/website/docs/r/dbaas_logs_cluster.html.markdown @@ -32,16 +32,17 @@ The following arguments are supported: ## Attributes Reference Id is set to the input Id. In addition, the following attributes are exported: -* `cluster_type` is type of cluster (DEDICATED, PRO or TRIAL) -* `dedicated_input_pem` is PEM for dedicated inputs -* `archive_allowed_networks` is allowed networks for ARCHIVE flow type -* `direct_input_allowed_networks` is allowed networks for DIRECT_INPUT flow type -* `direct_input_pem` is PEM for direct inputs -* `hostname` is cluster hostname hosting the tenant -* `is_default` is true if all content generated by given service will be placed on this cluster -* `is_unlocked` is true if given service can perform advanced operations on cluster -* `query_allowed_networks` is allowed networks for QUERY flow type -* `region` is datacenter localization +* `urn` - URN of the DBaaS +* `cluster_type` - type of cluster (DEDICATED, PRO or TRIAL) +* `dedicated_input_pem` - PEM for dedicated inputs +* `archive_allowed_networks` - allowed networks for ARCHIVE flow type +* `direct_input_allowed_networks` - allowed networks for DIRECT_INPUT flow type +* `direct_input_pem` - PEM for direct inputs +* `hostname` - cluster hostname hosting tenant +* `is_default` - true if all content generated by given service will be placed on this cluster +* `is_unlocked` - true if given service can perform advanced operations on cluster +* `query_allowed_networks` - allowed networks for QUERY flow type +* `region` - datacenter localization ## Import diff --git a/website/docs/r/hosting_privatedatabase.html.markdown b/website/docs/r/hosting_privatedatabase.html.markdown index 2266f9ccc..dfa2ca53d 100644 --- a/website/docs/r/hosting_privatedatabase.html.markdown +++ b/website/docs/r/hosting_privatedatabase.html.markdown @@ -72,6 +72,7 @@ Plan order valid values can be found on OVHcloud [APIv6](https://api.ovh.com/con The following attributes are exported: +* `urn` - URN of the private database, used when writing IAM policies * `cpu` - Number of CPU on your private database * `datacenter` - Datacenter where this private database is located * `display_name` - Name displayed in customer panel for your private database diff --git a/website/docs/r/iam_policy.html.markdown b/website/docs/r/iam_policy.html.markdown new file mode 100644 index 000000000..0883ab7c8 --- /dev/null +++ b/website/docs/r/iam_policy.html.markdown @@ -0,0 +1,54 @@ +--- +subcategory : "Account Management" +--- + +# ovh_iam_policy + +Creates an IAM policy. + +## Important +-> Using this resource requires that the account is enrolled in the OVHcloud [IAM beta](https://labs.ovhcloud.com/en/iam/) + + +## Example Usage + +```hcl +data "ovh_me" "account" {} + +resource "ovh_me_identity_group" "my_group" { + name = "my_group" + description = "my_group created in Terraform" +} + +resource "ovh_iam_policy" "manager" { + name = "allow_ovh_manager" + description = "Users are allowed to use the OVH manager" + identities = [ovh_me_identity_group.my_group.urn] + resources = [data.ovh_me.account.urn] + # these are all the actions + allow = [ + "account:apiovh:me/get", + "account:apiovh:me/supportLevel/get", + "account:apiovh:me/certificates/get", + "account:apiovh:me/tag/get", + "account:apiovh:services/get", + "account:apiovh:*", + ] +} +``` + +## Argument Reference + +* `name` - Name of the policy, must be unique +* `description` - Description of the policy +* `identities` - List of identities affected by the policy +* `resources` - List of resources affected by the policy +* `allow` - List of actions allowed on resources by identities +* `except` - List of overrides of action that must not be allowed even if they are caught by allow. Only makes sens if allow contains wildcards. + +## Attributes Reference + +* `owner` - Owner of the policy. +* `created_at` - Creation date of this group. +* `updated_at` - Date of the last update of this group. +* `read_only` - Indicates that the policy is a default one. diff --git a/website/docs/r/iploadbalancing.html.markdown b/website/docs/r/iploadbalancing.html.markdown index 6c66fb9c8..55bbe375e 100644 --- a/website/docs/r/iploadbalancing.html.markdown +++ b/website/docs/r/iploadbalancing.html.markdown @@ -83,6 +83,7 @@ The following arguments are supported: ## Attributes Reference Id is set to the order Id. In addition, the following attributes are exported: +* `urn` - URN of the load balancer, used when writing IAM policies * `ip_loadbalancing` - Your IP load balancing * `ipv4` - The IPV4 associated to your IP load balancing * `ipv6` - The IPV6 associated to your IP load balancing. DEPRECATED. diff --git a/website/docs/r/me_identity_group.html.markdown b/website/docs/r/me_identity_group.html.markdown index bbf0332d3..28fef1eb6 100644 --- a/website/docs/r/me_identity_group.html.markdown +++ b/website/docs/r/me_identity_group.html.markdown @@ -24,6 +24,7 @@ resource "ovh_me_identity_group" "my_group" { ## Attributes Reference +* `urn` - URN of the user group, used when writing IAM policies * `default_group` - Is the group a default and immutable one. * `creation` - Creation date of this group. * `last_update` - Date of the last update of this group. diff --git a/website/docs/r/me_identity_user.html.markdown b/website/docs/r/me_identity_user.html.markdown index 579c56846..7e9b00f9c 100644 --- a/website/docs/r/me_identity_user.html.markdown +++ b/website/docs/r/me_identity_user.html.markdown @@ -28,6 +28,7 @@ resource "ovh_me_identity_user" "my_user" { ## Attributes Reference +* `urn` - URN of the user, used when writing IAM policies * `creation` - Creation date of this user. * `last_update` - Last update of this user. * `password_last_update` - When the user changed his password for the last time. diff --git a/website/docs/r/vrack.html.markdown b/website/docs/r/vrack.html.markdown index 870431447..dc4e30b89 100644 --- a/website/docs/r/vrack.html.markdown +++ b/website/docs/r/vrack.html.markdown @@ -68,6 +68,7 @@ The following arguments are supported: Id is set to the order Id. In addition, the following attributes are exported: +* `urn` - The URN of the vrack, used with IAM permissions * `order` - Details about an Order * `date` - date * `order_id` - order id