Repository: ovh/terraform-provider-ovh

Issue:
[FEATURE] expose kubeconfig and kubeconfig_attributes through ovh_cloud_project_kube data source
### Description

When using cloud-project-kube data source, it would be useful to expose the kubeconfig and kubeconfig_attributes attributes so we can auth in project that did not create a cluster but need to add resources into it (without copying kubeconfig files).

### Affected Data Source

* ovh_cloud_project_kube

### Potential Terraform Configuration

Just like the actual data source.

``` terraform
data "ovh_cloud_project_kube" "kube_project" {
   service_name = "my_service_name"
   kube_id = "my_kube_id"
}
```


Hints from issue comments:
@ridwan-b: There is my PR proposal for this feature https://github.com/ovh/terraform-provider-ovh/pull/1059.

Solution patch:
diff --git a/.cds/terraform-provider-ovh.pip.yml b/.cds/terraform-provider-ovh.pip.yml
index 4552dc3a..566da64b 100644
--- a/.cds/terraform-provider-ovh.pip.yml
+++ b/.cds/terraform-provider-ovh.pip.yml
@@ -70,3 +70,6 @@ parameters:
   skipthistest.storageefs:
     type: boolean
     description: Skip Storage EFS tests
+  skipthistest.location:
+    type: boolean
+    description: Skip Location tests
\ No newline at end of file
diff --git a/.cds/terraform-provider-ovh.yml b/.cds/terraform-provider-ovh.yml
index efed4e8e..6288f99d 100644
--- a/.cds/terraform-provider-ovh.yml
+++ b/.cds/terraform-provider-ovh.yml
@@ -821,6 +821,18 @@ workflow:
     pipeline: terraform-provider-ovh-testacc
     when:
     - success
+  Tests_Location:
+    application: terraform-provider-ovh
+    depends_on:
+    - terraform-provider-ovh-pre-sweepers
+    environment: acctests
+    one_at_a_time: true
+    parameters:
+      testargs: -run Location
+      skipthispipeline: "{{.workflow.terraform-provider-ovh.pip.skipthistest.location}}"
+    pipeline: terraform-provider-ovh-testacc
+    when:
+    - success
   terraform-provider-ovh:
     application: terraform-provider-ovh
     parameters:
@@ -907,6 +919,7 @@ workflow:
     - Tests_DedicatedCloud
     - Tests_VMwareCloudDirector
     - Tests_StorageEfs
+    - Tests_Location
     environment: acctests
     one_at_a_time: true
     pipeline: terraform-provider-ovh-run-sweepers
diff --git a/.gitignore b/.gitignore
index b9a3c95d..0516ac8e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,4 +36,7 @@ terraform-provider-ovh
 examples/kube-nodepool-deployment/.terraform.lock.hcl
 examples/kube-nodepool-deployment/.terraform.tfstate.lock.info
 examples/kube-nodepool-deployment/logs
-examples/kube-nodepool-deployment/my-kube-cluster-*.yml
\ No newline at end of file
+examples/kube-nodepool-deployment/my-kube-cluster-*.yml
+
+# Documentation exclusions
+docs/resources/dedicated_server_networking.md
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4844bbc4..3743f5d2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,45 @@
+## 2.6.0 (July 25, 2025)
+
+⚙️ General:
+
+* Bump dependencies ([#1052](https://github.com/ovh/terraform-provider-ovh/pull/1052))
+
+🎉 Features:
+
+* New resource: `ovh_cloud_project_region` ([#1044](https://github.com/ovh/terraform-provider-ovh/pull/1044))
+
+* New datasource: `ovh_cloud_project_gateway` ([#1061](https://github.com/ovh/terraform-provider-ovh/pull/1061))
+* New datasource: `ovh_location` ([#1063](https://github.com/ovh/terraform-provider-ovh/pull/1063))
+
+💪 Improvements:
+
+* `r/ovh_dbaas_logs_token`: Resource can now be imported ([#1045](https://github.com/ovh/terraform-provider-ovh/pull/1045))
+* Ensure all resources have an ID ([#1047](https://github.com/ovh/terraform-provider-ovh/pull/1047))
+
+⚠️ Deprecations:
+
+* `r/ovh_dedicated_server_update`: Resource is now deprecated ([#1036](https://github.com/ovh/terraform-provider-ovh/pull/1036))
+
+🐜 Bug fixes:
+
+* `r/ovh_dedicated_server`: Changing `service_name` forces recreation of the resource ([#1033](https://github.com/ovh/terraform-provider-ovh/pull/1033))
+* `r/ovh_dedicated_server_update`: Changing `service_name` forces recreation of the resource ([#1033](https://github.com/ovh/terraform-provider-ovh/pull/1033))
+* `r/ovh_savings_plan`: Perform an exact match when searching for a product code ([#1040](https://github.com/ovh/terraform-provider-ovh/pull/1040))
+* `r/ovh_dbaas_logs_input`: Fix fields in example ([#1053](https://github.com/ovh/terraform-provider-ovh/pull/1053))
+* `r/ovh_cloud_project_failover_ip_attach`: Correctly check errors and improve error messages ([#1056](https://github.com/ovh/terraform-provider-ovh/pull/1056))
+* `r/ovh_cloud_project_containerregistry_oidc`: Attribute `oidc_verify_cert` is computed when not input by the user ([#1057](https://github.com/ovh/terraform-provider-ovh/pull/1057))
+* `r/ovh_cloud_project_containerregistry_oidc`: Recreate OIDC config when removed outside Terraform ([#1058](https://github.com/ovh/terraform-provider-ovh/pull/1058))
+* `r/ovh_cloud_project_storage`: Set the right type for replication tags ([#1060](https://github.com/ovh/terraform-provider-ovh/pull/1060))
+
+📚 Documentation:
+
+* Update subcategories of several public cloud resources ([#1035](https://github.com/ovh/terraform-provider-ovh/pull/1035))
+* `r/ovh_cloud_project_containerregistry_user`: Fix resource documentation ([#1037](https://github.com/ovh/terraform-provider-ovh/pull/1037))
+* Ensure naming convention in examples ([#1046](https://github.com/ovh/terraform-provider-ovh/pull/1046))
+* `r/ovh_vps`: Add clarifications on image selection ([#1055](https://github.com/ovh/terraform-provider-ovh/pull/1055))
+
+❤️ Thanks for your contributions ❤️
+
 ## 2.5.0 (July 1, 2025)
 
 ⚙️ General:
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f606f5f0..6e2d98dc 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,3 +1,5 @@
+# Contributing to `terraform-provider-ovh`
+
 Thanks for wanting to contribute to this project ❤️.
 
 This project accepts contributions. In order to contribute, you should pay attention to a few things:
@@ -5,9 +7,10 @@ This project accepts contributions. In order to contribute, you should pay atten
 1. Your code must follow the coding style rules
 2. Your code must be fully documented
 3. Your code must have acceptance test
-4. Your new resource need to be imported by the user
-5. Please test your new resources, datasources and acceptance tests
-6. GitHub Pull Requests
+4. Every Terraform resource added must be importable by the end-user
+5. Your work must be signed (see below)
+6. Please test your new resources, datasources and acceptance tests
+7. Use GitHub Pull Requests to contribute
 
 ## Coding and documentation Style:
 
@@ -16,6 +19,7 @@ This project accepts contributions. In order to contribute, you should pay atten
 - The examples of resources and datasources in the documentation must follow the [Terraform style guidelines](https://developer.hashicorp.com/terraform/language/style)
 - Check your documentation through [Terraform Doc Preview Tool](https://registry.terraform.io/tools/doc-preview)
 - When adding a documentation page, use the `subcategory:` tag in the [YAML Frontmatter](https://developer.hashicorp.com/terraform/registry/providers/docs#yaml-frontmatter) with a value equals to the product name defined in the OVHcloud [product map](https://www.product-map.ovh/)
+- New documentation pages should be added first in the directory `templates/`, with the examples being placed in the `examples/` directory. Once this is done, the content in `docs/` directory must be generated with [tfplugindocs](https://github.com/hashicorp/terraform-plugin-docs?tab=readme-ov-file#usage).
 
 ## Acceptance tests:
 
@@ -26,8 +30,59 @@ This project accepts contributions. In order to contribute, you should pay atten
 
 ## Submitting Modifications:
 
-The contributions should be submitted through new GitHub Pull Requests.
+The contributions should be submitted through Github Pull Requests
+and follow the DCO which is defined below.
+
+## Licensing for new files
+
+terraform-provider-ovh is licensed under the Mozilla Public License 2.0. Anything
+contributed to terraform-provider-ovh must be released under this license.
 
 ## Submiting an Issue:
 
 In addition to contributions, we welcome [bug reports](https://github.com/ovh/terraform-provider-ovh/issues/new?template=report-a-bug.md), [resource or datasource requests](https://github.com/ovh/terraform-provider-ovh/issues/new?template=request-a-new-resource-and-or-datasource.md), [documentation errors reports](https://github.com/ovh/terraform-provider-ovh/issues/new?template=report-a-documentation-error.md) and [feature requests](https://github.com/ovh/terraform-provider-ovh/issues/new?template=request-a-feature.md).
+
+
+## Developer Certificate of Origin (DCO)
+
+To improve tracking of contributions to this project we will use a
+process modeled on the modified DCO 1.1 and use a "sign-off" procedure
+on patches that are being emailed around or contributed in any other
+way.
+
+The sign-off is a simple line at the end of the explanation for the
+patch, which certifies that you wrote it or otherwise have the right
+to pass it on as an open-source patch.  The rules are pretty simple:
+if you can certify the below:
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I have
+    the right to submit it under the open source license indicated in
+    the file; or
+
+(b) The contribution is based upon previous work that, to the best of
+    my knowledge, is covered under an appropriate open source License
+    and I have the right under that license to submit that work with
+    modifications, whether created in whole or in part by me, under
+    the same open source license (unless I am permitted to submit
+    under a different license), as indicated in the file; or
+
+(c) The contribution was provided directly to me by some other person
+    who certified (a), (b) or (c) and I have not modified it.
+
+(d) The contribution is made free of any other party's intellectual
+    property claims or rights.
+
+(e) I understand and agree that this project and the contribution are
+    public and that a record of the contribution (including all
+    personal information I submit with it, including my sign-off) is
+    maintained indefinitely and may be redistributed consistent with
+    this project or the open source license(s) involved.
+
+
+then you just add a line saying
+
+    Signed-off-by: Random J Developer <random@example.org>
+
+using your real name (sorry, no pseudonyms or anonymous contributions.)
diff --git a/docs/data-sources/cloud_project_gateway.md b/docs/data-sources/cloud_project_gateway.md
new file mode 100644
index 00000000..aabee1d3
--- /dev/null
+++ b/docs/data-sources/cloud_project_gateway.md
@@ -0,0 +1,62 @@
+---
+subcategory: "Gateway"
+---
+
+# ovh_cloud_project_gateway (Data Source)
+
+Get gateway
+
+## Example Usage
+
+```terraform
+data "ovh_cloud_project_gateway" "gateway" {
+    service_name = "<public cloud project ID>"
+    region       = "GRA11"
+    id           = "<gateway ID>"
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `id` (String) Id
+- `region` (String) Gateway region
+- `service_name` (String) Service name
+
+### Read-Only
+
+- `external_information` (Attributes) External information (see [below for nested schema](#nestedatt--external_information))
+- `interfaces` (Attributes List) Interfaces list of the gateway (see [below for nested schema](#nestedatt--interfaces))
+- `model` (String) Model of the gateway
+- `name` (String) Name of the gateway
+- `status` (String) Status of the gateway
+
+<a id="nestedatt--external_information"></a>
+### Nested Schema for `external_information`
+
+Read-Only:
+
+- `ips` (Attributes List) External ips of the gateway (see [below for nested schema](#nestedatt--external_information--ips))
+- `network_id` (String) External network ID of the gateway
+
+<a id="nestedatt--external_information--ips"></a>
+### Nested Schema for `external_information.ips`
+
+Read-Only:
+
+- `ip` (String) External IP of the gateway
+- `subnet_id` (String) Subnet ID of the ip
+
+
+
+<a id="nestedatt--interfaces"></a>
+### Nested Schema for `interfaces`
+
+Read-Only:
+
+- `id` (String) ID of the interface
+- `ip` (String) IP of the interface
+- `network_id` (String) Network ID of the interface
+- `subnet_id` (String) Subnet ID of the interface
diff --git a/docs/data-sources/cloud_project_kube.md b/docs/data-sources/cloud_project_kube.md
index 235eaeae..a61d12b6 100644
--- a/docs/data-sources/cloud_project_kube.md
+++ b/docs/data-sources/cloud_project_kube.md
@@ -17,6 +17,15 @@ data "ovh_cloud_project_kube" "my_kube_cluster" {
 output "version" {
   value = data.ovh_cloud_project_kube.my_kube_cluster.version
 }
+
+output "kubeconfig" {
+  value = data.ovh_cloud_project_kube.my_kube_cluster.kubeconfig
+  sensitive = true
+}
+
+output "kube_host" {
+  value = data.ovh_cloud_project_kube.my_kube_cluster.kubeconfig_attributes[0].host
+}
 ```
 
 ## Argument Reference
@@ -35,6 +44,7 @@ The following attributes are exported:
 * `name` - The name of the managed kubernetes cluster.
 * `region` - The OVHcloud public cloud region ID of the managed kubernetes cluster.
 * `version` - Kubernetes version of the managed kubernetes cluster.
+* `plan` - Plan of the managed kubernetes cluster.
 * `private_network_id` - OpenStack private network (or vrack) ID to use.
 * `load_balancers_subnet_id` - Openstack private network (or vRack) ID to use for load balancers.
 * `nodes_subnet_id` - Openstack private network (or vRack) ID to use for nodes.
@@ -45,6 +55,12 @@ The following attributes are exported:
 * `status` - Cluster status. Should be normally set to 'READY'.
 * `update_policy` - Cluster update policy. Choose between [ALWAYS_UPDATE,MINIMAL_DOWNTIME,NEVER_UPDATE]'.
 * `url` - Management URL of your cluster.
+* `kubeconfig` - (Sensitive) Raw kubeconfig file content for connecting to the cluster.
+* `kubeconfig_attributes` - (Sensitive) Structured kubeconfig data for connecting to the cluster.
+  * `host` - Kubernetes API server endpoint.
+  * `cluster_ca_certificate` - (Sensitive) Cluster certificate authority data.
+  * `client_certificate` - (Sensitive) Client certificate data for authentication.
+  * `client_key` - (Sensitive) Client private key data for authentication.
 * `kube_proxy_mode` - Selected mode for kube-proxy.
 * `customization` - **Deprecated** (Optional) Use `customization_apiserver` and `customization_kube_proxy` instead. Kubernetes cluster customization
   * `apiserver` - Kubernetes API server customization
diff --git a/docs/data-sources/dbaas_logs_output_graylog_stream.md b/docs/data-sources/dbaas_logs_output_graylog_stream.md
index 6ff0371a..0a724aa8 100644
--- a/docs/data-sources/dbaas_logs_output_graylog_stream.md
+++ b/docs/data-sources/dbaas_logs_output_graylog_stream.md
@@ -18,7 +18,7 @@ data "ovh_dbaas_logs_output_graylog_stream" "stream" {
 ## Argument Reference
 
 * `service_name` - The service name. It's the ID of your Logs Data Platform instance.
-* `title` - Stream description
+* `title` - Stream name
 
 ## Attributes Reference
 
diff --git a/docs/data-sources/dbaas_logs_output_graylog_stream_url.md b/docs/data-sources/dbaas_logs_output_graylog_stream_url.md
new file mode 100644
index 00000000..aae20b2b
--- /dev/null
+++ b/docs/data-sources/dbaas_logs_output_graylog_stream_url.md
@@ -0,0 +1,29 @@
+---
+subcategory : "Logs Data Platform"
+---
+
+# ovh_dbaas_logs_output_graylog_stream_url (Data Source)
+
+Use this data source to retrieve the list of URLs for a DBaas logs output Graylog stream.
+
+## Example Usage
+
+```terraform
+data "ovh_dbaas_logs_output_graylog_stream_url" "urls" {
+  service_name = "ldp-xx-xxxxx"
+  stream_id    = "STREAM_ID"
+}
+```
+
+## Argument Reference
+
+* `service_name` - The service name. It's the ID of your Logs Data Platform instance.
+* `stream_id` - Stream ID.
+
+## Attributes Reference
+
+The following attributes are exported:
+
+* `url` - List of URLs. Each element contains:
+  * `address` - URL address
+  * `type` - URL type (e.g. `GRAYLOG_WEBUI`, `WEB_SOCKET`)
\ No newline at end of file
diff --git a/docs/data-sources/domain_zone.md b/docs/data-sources/domain_zone.md
index d5e59d22..00881d7c 100644
--- a/docs/data-sources/domain_zone.md
+++ b/docs/data-sources/domain_zone.md
@@ -22,8 +22,8 @@ data "ovh_domain_zone" "root_zone" {
 
 `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
 * `dnssec_supported` - Is DNSSEC supported by this zone
+* `urn` - URN of the DNS Zone to be used inside an IAM policy
diff --git a/docs/data-sources/location.md b/docs/data-sources/location.md
new file mode 100644
index 00000000..fc422328
--- /dev/null
+++ b/docs/data-sources/location.md
@@ -0,0 +1,40 @@
+---
+subcategory: "Location"
+---
+
+# ovh_location (Data Source)
+
+Get available regions and their availability zones
+
+## Example Usage
+
+```terraform
+data "ovh_location" "paris" {
+    name = "eu-west-par"
+}
+```
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `name` (String) Name
+
+### Read-Only
+
+- `availability_zones` (List of String) List of availability zones for the region
+- `cardinal_point` (String) Cardinal direction where the region is located
+- `city_code` (String) ISO code of the city
+- `city_latitude` (Number) Geographical latitude of the city
+- `city_longitude` (Number) Geographical longitude of the city
+- `city_name` (String) Full name of the city
+- `code` (String) Region's short code
+- `country_code` (String) ISO code of the country
+- `country_name` (String) Full name of the country
+- `geography_code` (String) Short code representing the geographical area
+- `geography_name` (String) Name of the geographical area
+- `location` (String) Location of the region
+- `opening_year` (Number) Year the region was opened
+- `specific_type` (String) Specific typology of the region
+- `type` (String) General typology of the region
diff --git a/docs/data-sources/me_api_oauth2_client.md b/docs/data-sources/me_api_oauth2_client.md
index 7f5cdf8e..64d7de84 100644
--- a/docs/data-sources/me_api_oauth2_client.md
+++ b/docs/data-sources/me_api_oauth2_client.md
@@ -25,5 +25,6 @@ data "ovh_me_api_oauth2_client" "my_oauth2_client" {
 * `description` - OAuth2 client description.
 * `flow` - The OAuth2 flow to use. `AUTHORIZATION_CODE` or `CLIENT_CREDENTIALS` are supported at the moment.
 * `callback_urls` - List of callback urls when configuring the `AUTHORIZATION_CODE` flow.
+* `identity` - Identity URN of the service account to be used inside an IAM policy.
 
 The `client_secret` attribute is not supported in the Data Source. If you need this attribute to be in the state, see how to import a `ovh_me_api_oauth2_client` resource instead.
diff --git a/docs/resources/cloud_project_kube.md b/docs/resources/cloud_project_kube.md
index c470df53..1ad9bc01 100644
--- a/docs/resources/cloud_project_kube.md
+++ b/docs/resources/cloud_project_kube.md
@@ -8,7 +8,7 @@ Creates a OVHcloud Managed Kubernetes Service cluster in a public cloud project.
 
 ## Example Usage
 
-Create a simple Kubernetes cluster in `GRA11` region:
+Create a simple Kubernetes Free cluster in `GRA11` region:
 
 ```terraform
 resource "ovh_cloud_project_kube" "my_cluster" {
@@ -26,7 +26,7 @@ resource "ovh_cloud_project_kube_nodepool" "node_pool_1" {
 }
 ```
 
-Create a simple Kubernetes cluster in `GRA11` region and export its kubeconfig file:
+Create a simple Kubernetes Free cluster in `GRA11` region and export its kubeconfig file:
 
 ```terraform
 resource "ovh_cloud_project_kube" "my_cluster" {
@@ -41,7 +41,7 @@ output "kubeconfig_file" {
 }
 ```
 
-Create a simple Kubernetes cluster in `GRA11` region and read kubeconfig attributes:
+Create a simple Kubernetes Free cluster in `GRA11` region and read kubeconfig attributes:
 
 -> Sensitive attributes cannot be displayed using `terraform output` command. You need to specify the output's name: `terraform output my_cluster_host`.
 
@@ -73,7 +73,7 @@ output "my_cluster_client_key" {
 }
 ```
 
-Create a simple Kubernetes cluster in `GRA11` region and use kubeconfig with [Helm provider](https://registry.terraform.io/providers/hashicorp/helm/latest/docs):
+Create a simple Kubernetes Free cluster in `GRA11` region and use kubeconfig with [Helm provider](https://registry.terraform.io/providers/hashicorp/helm/latest/docs):
 
 ```terraform
 resource "ovh_cloud_project_kube" "my_cluster" {
@@ -94,7 +94,7 @@ provider "helm" {
 # Ready to use Helm provider
 ```
 
-Create a Kubernetes cluster in `GRA11` region with API Server AdmissionPlugins configuration:
+Create a Kubernetes Free cluster in `GRA11` region with API Server AdmissionPlugins configuration:
 
 ```terraform
 resource "ovh_cloud_project_kube" "my_cluster" {
@@ -110,7 +110,7 @@ resource "ovh_cloud_project_kube" "my_cluster" {
 }
 ```
 
-Create a Kubernetes cluster in `GRA11` region with Kube proxy configuration, by specifying iptables or ipvs configurations:
+Create a Kubernetes Free cluster in `GRA11` region with Kube proxy configuration, by specifying iptables or ipvs configurations:
 
 ```terraform
 resource "ovh_cloud_project_kube" "my_cluster" {
@@ -137,7 +137,7 @@ resource "ovh_cloud_project_kube" "my_cluster" {
 }
 ```
 
-Kubernetes cluster creation on a private network / subnet in `GRA11` region with a managed gateway:
+Kubernetes Free cluster creation on a private network / subnet in `GRA11` region with a managed gateway:
 
 ```terraform
 resource "ovh_cloud_project_network_private" "network" {
@@ -183,7 +183,7 @@ resource "ovh_cloud_project_kube" "my_cluster" {
 }
 ```
 
-Create a multi-zone Kubernetes cluster (on 3 availability zones):
+Create a multi-zone Kubernetes Standard cluster (on 3 availability zones):
 
 ```terraform
 resource "ovh_cloud_project_network_private" "network" {
@@ -219,6 +219,7 @@ resource "ovh_cloud_project_kube" "my_multizone_cluster" {
   service_name  = ovh_cloud_project_network_private.network.service_name
   name          = "multi-zone-mks"
   region        = "EU-WEST-PAR"
+  plan          = "standard"
 
   private_network_id = tolist(ovh_cloud_project_network_private.network.regions_attributes[*].openstackid)[0]
   nodes_subnet_id    = ovh_cloud_project_network_private_subnet.subnet.id
@@ -267,6 +268,7 @@ The following arguments are supported:
 * `name` - (Optional) The name of the kubernetes cluster.
 * `region` - a valid OVHcloud public cloud region ID in which the kubernetes cluster will be available. Ex.: "GRA9". Defaults to all public cloud regions. **Changing this value recreates the resource.**
 * `version` - (Optional) kubernetes version to use. Changing this value updates the resource. Defaults to the latest available.
+* `plan` - (Optional) Plan of the MKS cluster `free` or `standard`. Default to `free`. Migration to another plan is not implemented yet.
 * `kube_proxy_mode` - (Optional) Selected mode for kube-proxy. **Changing this value recreates the resource, including ETCD user data.** Defaults to `iptables`.
 * `customization` - **Deprecated** (Optional) Use `customization_apiserver` and `customization_kube_proxy` instead. Kubernetes cluster customization
   * `apiserver` - Kubernetes API server customization
diff --git a/docs/resources/cloud_project_storage.md b/docs/resources/cloud_project_storage.md
index 9d088606..48fa01c7 100644
--- a/docs/resources/cloud_project_storage.md
+++ b/docs/resources/cloud_project_storage.md
@@ -100,16 +100,7 @@ Optional:
 Optional:
 
 - `prefix` (String) Prefix filter
-- `tags` (Attributes List) Tags filter (see [below for nested schema](#nestedatt--replication--rules--filter--tags))
-
-<a id="nestedatt--replication--rules--filter--tags"></a>
-
-### Nested Schema for `replication.rules.filter.tags`
-
-Required:
-
-- `key` (String) Tag key
-- `value` (String) Tag value
+- `tags` (String to String Map) Tags filter
 
 <a id="nestedatt--versioning"></a>
 
diff --git a/docs/resources/cloud_project_user.md b/docs/resources/cloud_project_user.md
index 0e8a7554..2c6b4842 100644
--- a/docs/resources/cloud_project_user.md
+++ b/docs/resources/cloud_project_user.md
@@ -37,7 +37,6 @@ The following arguments are supported:
 * `role_name` - The name of a role. See `role_names`.
 
 * `role_names` - A list of role names. Values can be:
-  - admin
   - administrator
   - ai_training_operator
   - ai_training_read
diff --git a/docs/resources/dbaas_logs_output_graylog_stream.md b/docs/resources/dbaas_logs_output_graylog_stream.md
index 60161750..3ba43ff0 100644
--- a/docs/resources/dbaas_logs_output_graylog_stream.md
+++ b/docs/resources/dbaas_logs_output_graylog_stream.md
@@ -37,8 +37,8 @@ resource "ovh_dbaas_logs_output_graylog_stream" "stream" {
 
 The following arguments are supported:
 * `service_name` - (Required) The service name
+* `title` - (Required) Stream name
 * `description` - (Required) Stream description
-* `title` - (Required) Stream description
 * `parent_stream_id` - Parent stream ID
 * `retention_id` - Retention ID
 * `cold_storage_compression` - Cold storage compression method. One of "LZMA", "GZIP", "DEFLATED", "ZSTD"
@@ -50,7 +50,7 @@ The following arguments are supported:
 * `indexing_enabled` - Enable ES indexing
 * `indexing_max_size` - Maximum indexing size (in GB)
 * `indexing_notify_enabled` - If set, notify when size is near 80, 90 or 100 % of the maximum configured setting
-* `pause_indexing_on_max_size` - If set, pause indexing when maximum size is reach
+* `pause_indexing_on_max_size` - If set, pause indexing when maximum size is reached
 * `web_socket_enabled` - Enable Websocket
 
 ## Attributes Reference
@@ -66,3 +66,11 @@ Id is set to the output stream Id. In addition, the following attributes are exp
 * `stream_id` - Stream ID
 * `updated_at` - Stream last updater
 * `write_token` - Write token of the stream (empty if the caller is not the owner of the stream)
+
+## Import
+
+DBaas logs output Graylog stream can be imported using the `service_name` of the cluster and `stream_id` of the graylog output stream, separated by "/" E.g.,
+
+```bash
+$ terraform import ovh_dbaas_logs_output_graylog_stream.ldp ldp-az-12345/9d2f9cf8-9f92-1337-c0f3-48a0213d2c6f
+```
\ No newline at end of file
diff --git a/docs/resources/dbaas_logs_output_opensearch_alias.md b/docs/resources/dbaas_logs_output_opensearch_alias.md
index 3e721001..cd9e55d1 100644
--- a/docs/resources/dbaas_logs_output_opensearch_alias.md
+++ b/docs/resources/dbaas_logs_output_opensearch_alias.md
@@ -40,3 +40,11 @@ Id is set to the opensearch alias Id. In addition, the following attributes are
 * `nb_stream` - Number of streams linked
 * `streams` - List of attached streams id
 * `updated_at` - Input last update
+
+## Import
+
+DBaaS logs Opensearch output alias can be imported using the `service_name` and `alias_id`, separated by "/" E.g.,
+
+```bash
+$ terraform import ovh_dbaas_logs_output_opensearch_alias.this ldp-XX-NNNNN/7e2301b6-c0fe-41d9-bc58-44fd844f1e3e
+```
diff --git a/docs/resources/domain_zone.md b/docs/resources/domain_zone.md
index 63b33e60..8bce0dce 100644
--- a/docs/resources/domain_zone.md
+++ b/docs/resources/domain_zone.md
@@ -80,7 +80,7 @@ Id is set to the order Id. In addition, the following attributes are exported:
 * `last_update` - Last update date of the DNS zone
 * `name` - Zone name
 * `name_servers` - Name servers that host the DNS zone
-
+* `urn` - URN of the DNS Zone to be used inside an IAM policy
 * `order` - Details about an Order
   * `date` - date
   * `order_id` - order id
diff --git a/docs/resources/me_api_oauth2_client.md b/docs/resources/me_api_oauth2_client.md
index 01e18989..b4b5ce8e 100644
--- a/docs/resources/me_api_oauth2_client.md
+++ b/docs/resources/me_api_oauth2_client.md
@@ -44,6 +44,7 @@ resource "ovh_me_api_oauth2_client" "my_oauth2_client_client_creds" {
 * `description` - OAuth2 client description.
 * `flow` - The OAuth2 flow to use. `AUTHORIZATION_CODE` or `CLIENT_CREDENTIALS` are supported at the moment.
 * `callback_urls` - List of callback urls when configuring the `AUTHORIZATION_CODE` flow.
+* `identity` - Identity URN of the service account to be used inside an IAM policy.
 
 ## Import
 
diff --git a/docs/resources/vps.md b/docs/resources/vps.md
index 23cda7cb..a317e01a 100644
--- a/docs/resources/vps.md
+++ b/docs/resources/vps.md
@@ -12,7 +12,7 @@ Creates an OVHcloud Virtual Private Server (VPS).
 
 ~> **WARNING** `BANK_ACCOUNT` is not supported anymore, please update your default payment method to `SEPA_DIRECT_DEBIT`
 
-~> **NOTE** During VPS creation, the OS must be configured through the `plan.configuration` argument, using `vps_os` as key, and values from [catalog](https://eu.api.ovh.com/console/?section=%2Forder&branch=v1#get-/order/catalog/public/vps) data). The `image_id` argument should be used only when reinstalling a server.
+~> **NOTE** During VPS creation, the OS must be configured through the `plan.configuration` argument, using `vps_os` as key, and values from [catalog](https://eu.api.ovh.com/console/?section=%2Forder&branch=v1#get-/order/catalog/public/vps) data). The `image_id` argument should be used only when reinstalling a server. The available values for `image_id` can be found using this [API call](https://eu.api.ovh.com/console/?section=%2Fvps&branch=v1#get-/vps/-serviceName-/images/available)
 
 ## Example Usage
 
@@ -68,7 +68,7 @@ output "vps_display_name" {
 The following arguments are supported:
 
 * `display_name` - Custom display name
-* `image_id` - (String) Id of the image to install on the VPS. This attribute is only useful to trigger a VPS reinstallation.
+* `image_id` - (String) Id of the image to install on the VPS. This attribute is only useful to trigger a VPS reinstallation. The available values can be found using this [API call](https://eu.api.ovh.com/console/?section=%2Fvps&branch=v1#get-/vps/-serviceName-/images/available)
 * `netboot_mode` - VPS netboot mode (local┃rescue)
 * `ovh_subsidiary` - (Required) OVHcloud Subsidiary. Country of OVHcloud legal entity you'll be billed by. List of supported subsidiaries available on API at [/1.0/me.json](https://eu.api.ovh.com/console-preview/?section=%2Fme&branch=v1#get-/me)
 * `plan` - (Required) Product Plan to order
diff --git a/examples/data-sources/cloud_project_kube/example_1.tf b/examples/data-sources/cloud_project_kube/example_1.tf
index c4eda9e0..f5a1f062 100644
--- a/examples/data-sources/cloud_project_kube/example_1.tf
+++ b/examples/data-sources/cloud_project_kube/example_1.tf
@@ -6,3 +6,12 @@ data "ovh_cloud_project_kube" "my_kube_cluster" {
 output "version" {
   value = data.ovh_cloud_project_kube.my_kube_cluster.version
 }
+
+output "kubeconfig" {
+  value = data.ovh_cloud_project_kube.my_kube_cluster.kubeconfig
+  sensitive = true
+}
+
+output "kube_host" {
+  value = data.ovh_cloud_project_kube.my_kube_cluster.kubeconfig_attributes[0].host
+}
\ No newline at end of file
diff --git a/examples/data-sources/ovh_cloud_project_gateway/data-source.tf b/examples/data-sources/ovh_cloud_project_gateway/data-source.tf
new file mode 100644
index 00000000..18b2ca3e
--- /dev/null
+++ b/examples/data-sources/ovh_cloud_project_gateway/data-source.tf
@@ -0,0 +1,5 @@
+data "ovh_cloud_project_gateway" "gateway" {
+    service_name = "<public cloud project ID>"
+    region       = "GRA11"
+    id           = "<gateway ID>"
+}
\ No newline at end of file
diff --git a/examples/data-sources/ovh_location/data-source.tf b/examples/data-sources/ovh_location/data-source.tf
new file mode 100644
index 00000000..3fceddcc
--- /dev/null
+++ b/examples/data-sources/ovh_location/data-source.tf
@@ -0,0 +1,3 @@
+data "ovh_location" "paris" {
+    name = "eu-west-par"
+}
\ No newline at end of file
diff --git a/examples/resources/cloud_project_kube/example_10.tf b/examples/resources/cloud_project_kube/example_10.tf
index dadb32e1..0ac66784 100644
--- a/examples/resources/cloud_project_kube/example_10.tf
+++ b/examples/resources/cloud_project_kube/example_10.tf
@@ -32,6 +32,7 @@ resource "ovh_cloud_project_kube" "my_multizone_cluster" {
   service_name  = ovh_cloud_project_network_private.network.service_name
   name          = "multi-zone-mks"
   region        = "EU-WEST-PAR"
+  plan          = "standard"
 
   private_network_id = tolist(ovh_cloud_project_network_private.network.regions_attributes[*].openstackid)[0]
   nodes_subnet_id    = ovh_cloud_project_network_private_subnet.subnet.id
diff --git a/examples/resources/cloud_project_kube/example_9.tf b/examples/resources/cloud_project_kube/example_9.tf
index 68c5fb9c..f20c1459 100644
--- a/examples/resources/cloud_project_kube/example_9.tf
+++ b/examples/resources/cloud_project_kube/example_9.tf
@@ -2,6 +2,7 @@ resource "ovh_cloud_project_kube" "my_multizone_cluster" {
   service_name       = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
   name               = "terraform-multi-zone-cluster"
   region             = "EU-WEST-PAR"
+  plan               = "standard"
 
   private_network_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
   nodes_subnet_id    = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" //Subnet must has a OVHcloud Gateway/OpenStack router
diff --git a/ovh/data_cloud_project_gateway.go b/ovh/data_cloud_project_gateway.go
new file mode 100644
index 00000000..127c0762
--- /dev/null
+++ b/ovh/data_cloud_project_gateway.go
@@ -0,0 +1,69 @@
+package ovh
+
+import (
+	"context"
+	"fmt"
+	"net/url"
+
+	"github.com/hashicorp/terraform-plugin-framework/datasource"
+)
+
+var _ datasource.DataSourceWithConfigure = (*cloudProjectGatewayDataSource)(nil)
+
+func NewCloudProjectGatewayDataSource() datasource.DataSource {
+	return &cloudProjectGatewayDataSource{}
+}
+
+type cloudProjectGatewayDataSource struct {
+	config *Config
+}
+
+func (d *cloudProjectGatewayDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_cloud_project_gateway"
+}
+
+func (d *cloudProjectGatewayDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
+	if req.ProviderData == nil {
+		return
+	}
+
+	config, ok := req.ProviderData.(*Config)
+	if !ok {
+		resp.Diagnostics.AddError(
+			"Unexpected Data Source Configure Type",
+			fmt.Sprintf("Expected *Config, got: %T. Please report this issue to the provider developers.", req.ProviderData),
+		)
+		return
+	}
+
+	d.config = config
+}
+
+func (d *cloudProjectGatewayDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+	resp.Schema = CloudProjectGatewayDataSourceSchema(ctx)
+}
+
+func (d *cloudProjectGatewayDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
+	var data CloudProjectGatewayModel
+
+	// Read Terraform configuration data into the model
+	resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
+
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	// Read API call logic
+	endpoint := "/cloud/project/" + url.PathEscape(data.ServiceName.ValueString()) + "/region/" + url.PathEscape(data.Region.ValueString()) + "/gateway/" + url.PathEscape(data.Id.ValueString())
+
+	if err := d.config.OVHClient.Get(endpoint, &data); err != nil {
+		resp.Diagnostics.AddError(
+			fmt.Sprintf("Error calling Get %s", endpoint),
+			err.Error(),
+		)
+		return
+	}
+
+	// Save data into Terraform state
+	resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
diff --git a/ovh/data_cloud_project_gateway_gen.go b/ovh/data_cloud_project_gateway_gen.go
new file mode 100644
index 00000000..2764c7d9
--- /dev/null
+++ b/ovh/data_cloud_project_gateway_gen.go
@@ -0,0 +1,1535 @@
+// Code generated by terraform-plugin-framework-generator DO NOT EDIT.
+
+package ovh
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"strings"
+
+	"github.com/hashicorp/terraform-plugin-framework/attr"
+	"github.com/hashicorp/terraform-plugin-framework/diag"
+	"github.com/hashicorp/terraform-plugin-framework/types"
+	"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
+	"github.com/hashicorp/terraform-plugin-go/tftypes"
+	ovhtypes "github.com/ovh/terraform-provider-ovh/v2/ovh/types"
+
+	"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+)
+
+func CloudProjectGatewayDataSourceSchema(ctx context.Context) schema.Schema {
+	attrs := map[string]schema.Attribute{
+		"external_information": schema.SingleNestedAttribute{
+			Attributes: map[string]schema.Attribute{
+				"ips": schema.ListNestedAttribute{
+					NestedObject: schema.NestedAttributeObject{
+						Attributes: map[string]schema.Attribute{
+							"ip": schema.StringAttribute{
+								CustomType:          ovhtypes.TfStringType{},
+								Computed:            true,
+								Description:         "External IP of the gateway",
+								MarkdownDescription: "External IP of the gateway",
+							},
+							"subnet_id": schema.StringAttribute{
+								CustomType:          ovhtypes.TfStringType{},
+								Computed:            true,
+								Description:         "Subnet ID of the ip",
+								MarkdownDescription: "Subnet ID of the ip",
+							},
+						},
+						CustomType: ExternalInformationIpsType{
+							ObjectType: types.ObjectType{
+								AttrTypes: ExternalInformationIpsValue{}.AttributeTypes(ctx),
+							},
+						},
+					},
+					CustomType:          ovhtypes.NewTfListNestedType[ExternalInformationIpsValue](ctx),
+					Computed:            true,
+					Description:         "External ips of the gateway",
+					MarkdownDescription: "External ips of the gateway",
+				},
+				"network_id": schema.StringAttribute{
+					CustomType:          ovhtypes.TfStringType{},
+					Computed:            true,
+					Description:         "External network ID of the gateway",
+					MarkdownDescription: "External network ID of the gateway",
+				},
+			},
+			CustomType: ExternalInformationType{
+				ObjectType: types.ObjectType{
+					AttrTypes: ExternalInformationValue{}.AttributeTypes(ctx),
+				},
+			},
+			Computed:            true,
+			Description:         "External information",
+			MarkdownDescription: "External information",
+		},
+		"id": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Required:            true,
+			Description:         "Id",
+			MarkdownDescription: "Id",
+		},
+		"interfaces": schema.ListNestedAttribute{
+			NestedObject: schema.NestedAttributeObject{
+				Attributes: map[string]schema.Attribute{
+					"id": schema.StringAttribute{
+						CustomType:          ovhtypes.TfStringType{},
+						Computed:            true,
+						Description:         "ID of the interface",
+						MarkdownDescription: "ID of the interface",
+					},
+					"ip": schema.StringAttribute{
+						CustomType:          ovhtypes.TfStringType{},
+						Computed:            true,
+						Description:         "IP of the interface",
+						MarkdownDescription: "IP of the interface",
+					},
+					"network_id": schema.StringAttribute{
+						CustomType:          ovhtypes.TfStringType{},
+						Computed:            true,
+						Description:         "Network ID of the interface",
+						MarkdownDescription: "Network ID of the interface",
+					},
+					"subnet_id": schema.StringAttribute{
+						CustomType:          ovhtypes.TfStringType{},
+						Computed:            true,
+						Description:         "Subnet ID of the interface",
+						MarkdownDescription: "Subnet ID of the interface",
+					},
+				},
+				CustomType: InterfacesType{
+					ObjectType: types.ObjectType{
+						AttrTypes: InterfacesValue{}.AttributeTypes(ctx),
+					},
+				},
+			},
+			CustomType:          ovhtypes.NewTfListNestedType[InterfacesValue](ctx),
+			Computed:            true,
+			Description:         "Interfaces list of the gateway",
+			MarkdownDescription: "Interfaces list of the gateway",
+		},
+		"model": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Computed:            true,
+			Description:         "Model of the gateway",
+			MarkdownDescription: "Model of the gateway",
+		},
+		"name": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Computed:            true,
+			Description:         "Name of the gateway",
+			MarkdownDescription: "Name of the gateway",
+		},
+		"region": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Required:            true,
+			Description:         "Gateway region",
+			MarkdownDescription: "Gateway region",
+		},
+		"service_name": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Required:            true,
+			Description:         "Service name",
+			MarkdownDescription: "Service name",
+		},
+		"status": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Computed:            true,
+			Description:         "Status of the gateway",
+			MarkdownDescription: "Status of the gateway",
+		},
+	}
+
+	return schema.Schema{
+		Description: "Get gateway",
+		Attributes:  attrs,
+	}
+}
+
+type CloudProjectGatewayModel struct {
+	ExternalInformation ExternalInformationValue                    `tfsdk:"external_information" json:"externalInformation"`
+	Id                  ovhtypes.TfStringValue                      `tfsdk:"id" json:"id"`
+	Interfaces          ovhtypes.TfListNestedValue[InterfacesValue] `tfsdk:"interfaces" json:"interfaces"`
+	Model               ovhtypes.TfStringValue                      `tfsdk:"model" json:"model"`
+	Name                ovhtypes.TfStringValue                      `tfsdk:"name" json:"name"`
+	Region              ovhtypes.TfStringValue                      `tfsdk:"region" json:"region"`
+	ServiceName         ovhtypes.TfStringValue                      `tfsdk:"service_name" json:"serviceName"`
+	Status              ovhtypes.TfStringValue                      `tfsdk:"status" json:"status"`
+}
+
+func (v *CloudProjectGatewayModel) MergeWith(other *CloudProjectGatewayModel) {
+
+	if (v.ExternalInformation.IsUnknown() || v.ExternalInformation.IsNull()) && !other.ExternalInformation.IsUnknown() {
+		v.ExternalInformation = other.ExternalInformation
+	}
+
+	if (v.Id.IsUnknown() || v.Id.IsNull()) && !other.Id.IsUnknown() {
+		v.Id = other.Id
+	}
+
+	if (v.Interfaces.IsUnknown() || v.Interfaces.IsNull()) && !other.Interfaces.IsUnknown() {
+		v.Interfaces = other.Interfaces
+	}
+
+	if (v.Model.IsUnknown() || v.Model.IsNull()) && !other.Model.IsUnknown() {
+		v.Model = other.Model
+	}
+
+	if (v.Name.IsUnknown() || v.Name.IsNull()) && !other.Name.IsUnknown() {
+		v.Name = other.Name
+	}
+
+	if (v.Region.IsUnknown() || v.Region.IsNull()) && !other.Region.IsUnknown() {
+		v.Region = other.Region
+	}
+
+	if (v.ServiceName.IsUnknown() || v.ServiceName.IsNull()) && !other.ServiceName.IsUnknown() {
+		v.ServiceName = other.ServiceName
+	}
+
+	if (v.Status.IsUnknown() || v.Status.IsNull()) && !other.Status.IsUnknown() {
+		v.Status = other.Status
+	}
+
+}
+
+var _ basetypes.ObjectTypable = ExternalInformationType{}
+
+type ExternalInformationType struct {
+	basetypes.ObjectType
+}
+
+func (t ExternalInformationType) Equal(o attr.Type) bool {
+	other, ok := o.(ExternalInformationType)
+
+	if !ok {
+		return false
+	}
+
+	return t.ObjectType.Equal(other.ObjectType)
+}
+
+func (t ExternalInformationType) String() string {
+	return "ExternalInformationType"
+}
+
+func (t ExternalInformationType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) {
+	var diags diag.Diagnostics
+
+	attributes := in.Attributes()
+
+	ipsAttribute, ok := attributes["ips"]
+
+	if !ok {
+		diags.AddError(
+			"Attribute Missing",
+			`ips is missing from object`)
+
+		return nil, diags
+	}
+
+	ipsVal, ok := ipsAttribute.(ovhtypes.TfListNestedValue[ExternalInformationIpsValue])
+
+	if !ok {
+		diags.AddError(
+			"Attribute Wrong Type",
+			fmt.Sprintf(`ips expected to be ovhtypes.TfListNestedValue[ExternalInformationIpsValue], was: %T`, ipsAttribute))
+	}
+
+	networkIdAttribute, ok := attributes["network_id"]
+
+	if !ok {
+		diags.AddError(
+			"Attribute Missing",
+			`network_id is missing from object`)
+
+		return nil, diags
+	}
+
+	networkIdVal, ok := networkIdAttribute.(ovhtypes.TfStringValue)
+
+	if !ok {
+		diags.AddError(
+			"Attribute Wrong Type",
+			fmt.Sprintf(`network_id expected to be ovhtypes.TfStringValue, was: %T`, networkIdAttribute))
+	}
+
+	if diags.HasError() {
+		return nil, diags
+	}
+
+	return ExternalInformationValue{
+		Ips:       ipsVal,
+		NetworkId: networkIdVal,
+		state:     attr.ValueStateKnown,
+	}, diags
+}
+
+func NewExternalInformationValueNull() ExternalInformationValue {
+	return ExternalInformationValue{
+		state: attr.ValueStateNull,
+	}
+}
+
+func NewExternalInformationValueUnknown() ExternalInformationValue {
+	return ExternalInformationValue{
+		state: attr.ValueStateUnknown,
+	}
+}
+
+func NewExternalInformationValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (ExternalInformationValue, diag.Diagnostics) {
+	var diags diag.Diagnostics
+
+	// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521
+	ctx := context.Background()
+
+	for name, attributeType := range attributeTypes {
+		attribute, ok := attributes[name]
+
+		if !ok {
+			diags.AddError(
+				"Missing ExternalInformationValue Attribute Value",
+				"While creating a ExternalInformationValue value, a missing attribute value was detected. "+
+					"A ExternalInformationValue must contain values for all attributes, even if null or unknown. "+
+					"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
+					fmt.Sprintf("ExternalInformationValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()),
+			)
+
+			continue
+		}
+
+		if !attributeType.Equal(attribute.Type(ctx)) {
+			diags.AddError(
+				"Invalid ExternalInformationValue Attribute Type",
+				"While creating a ExternalInformationValue value, an invalid attribute value was detected. "+
+					"A ExternalInformationValue must use a matching attribute type for the value. "+
+					"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
+					fmt.Sprintf("ExternalInformationValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+
+					fmt.Sprintf("ExternalInformationValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)),
+			)
+		}
+	}
+
+	for name := range attributes {
+		_, ok := attributeTypes[name]
+
+		if !ok {
+			diags.AddError(
+				"Extra ExternalInformationValue Attribute Value",
+				"While creating a ExternalInformationValue value, an extra attribute value was detected. "+
+					"A ExternalInformationValue must not contain values beyond the expected attribute types. "+
+					"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
+					fmt.Sprintf("Extra ExternalInformationValue Attribute Name: %s", name),
+			)
+		}
+	}
+
+	if diags.HasError() {
+		return NewExternalInformationValueUnknown(), diags
+	}
+
+	ipsAttribute, ok := attributes["ips"]
+
+	if !ok {
+		diags.AddError(
+			"Attribute Missing",
+			`ips is missing from object`)
+
+		return NewExternalInformationValueUnknown(), diags
+	}
+
+	ipsVal, ok := ipsAttribute.(ovhtypes.TfListNestedValue[ExternalInformationIpsValue])
+
+	if !ok {
+		diags.AddError(
+			"Attribute Wrong Type",
+			fmt.Sprintf(`ips expected to be ovhtypes.TfListNestedValue[ExternalInformationIpsValue], was: %T`, ipsAttribute))
+	}
+
+	networkIdAttribute, ok := attributes["network_id"]
+
+	if !ok {
+		diags.AddError(
+			"Attribute Missing",
+			`network_id is missing from object`)
+
+		return NewExternalInformationValueUnknown(), diags
+	}
+
+	networkIdVal, ok := networkIdAttribute.(ovhtypes.TfStringValue)
+
+	if !ok {
+		diags.AddError(
+			"Attribute Wrong Type",
+			fmt.Sprintf(`network_id expected to be ovhtypes.TfStringValue, was: %T`, networkIdAttribute))
+	}
+
+	if diags.HasError() {
+		return NewExternalInformationValueUnknown(), diags
+	}
+
+	return ExternalInformationValue{
+		Ips:       ipsVal,
+		NetworkId: networkIdVal,
+		state:     attr.ValueStateKnown,
+	}, diags
+}
+
+func NewExternalInformationValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) ExternalInformationValue {
+	object, diags := NewExternalInformationValue(attributeTypes, attributes)
+
+	if diags.HasError() {
+		// This could potentially be added to the diag package.
+		diagsStrings := make([]string, 0, len(diags))
+
+		for _, diagnostic := range diags {
+			diagsStrings = append(diagsStrings, fmt.Sprintf(
+				"%s | %s | %s",
+				diagnostic.Severity(),
+				diagnostic.Summary(),
+				diagnostic.Detail()))
+		}
+
+		panic("NewExternalInformationValueMust received error(s): " + strings.Join(diagsStrings, "\n"))
+	}
+
+	return object
+}
+
+func (t ExternalInformationType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) {
+	if in.Type() == nil {
+		return NewExternalInformationValueNull(), nil
+	}
+
+	if !in.Type().Equal(t.TerraformType(ctx)) {
+		return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type())
+	}
+
+	if !in.IsKnown() {
+		return NewExternalInformationValueUnknown(), nil
+	}
+
+	if in.IsNull() {
+		return NewExternalInformationValueNull(), nil
+	}
+
+	attributes := map[string]attr.Value{}
+
+	val := map[string]tftypes.Value{}
+
+	err := in.As(&val)
+
+	if err != nil {
+		return nil, err
+	}
+
+	for k, v := range val {
+		a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v)
+
+		if err != nil {
+			return nil, err
+		}
+
+		attributes[k] = a
+	}
+
+	return NewExternalInformationValueMust(ExternalInformationValue{}.AttributeTypes(ctx), attributes), nil
+}
+
+func (t ExternalInformationType) ValueType(ctx context.Context) attr.Value {
+	return ExternalInformationValue{}
+}
+
+var _ basetypes.ObjectValuable = ExternalInformationValue{}
+
+type ExternalInformationValue struct {
+	Ips       ovhtypes.TfListNestedValue[ExternalInformationIpsValue] `tfsdk:"ips" json:"ips"`
+	NetworkId ovhtypes.TfStringValue                                  `tfsdk:"network_id" json:"networkId"`
+	state     attr.ValueState
+}
+
+func (v *ExternalInformationValue) UnmarshalJSON(data []byte) error {
+	type JsonExternalInformationValue ExternalInformationValue
+
+	var tmp JsonExternalInformationValue
+	if err := json.Unmarshal(data, &tmp); err != nil {
+		return err
+	}
+	v.Ips = tmp.Ips
+	v.NetworkId = tmp.NetworkId
+
+	v.state = attr.ValueStateKnown
+
+	return nil
+}
+
+func (v *ExternalInformationValue) MergeWith(other *ExternalInformationValue) {
+
+	if (v.Ips.IsUnknown() || v.Ips.IsNull()) && !other.Ips.IsUnknown() {
+		v.Ips = other.Ips
+	}
+
+	if (v.NetworkId.IsUnknown() || v.NetworkId.IsNull()) && !other.NetworkId.IsUnknown() {
+		v.NetworkId = other.NetworkId
+	}
+
+	if (v.state == attr.ValueStateUnknown || v.state == attr.ValueStateNull) && other.state != attr.ValueStateUnknown {
+		v.state = other.state
+	}
+}
+
+func (v ExternalInformationValue) Attributes() map[string]attr.Value {
+	return map[string]attr.Value{
+		"ips":       v.Ips,
+		"networkId": v.NetworkId,
+	}
+}
+func (v ExternalInformationValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) {
+	attrTypes := make(map[string]tftypes.Type, 2)
+
+	var val tftypes.Value
+	var err error
+
+	attrTypes["ips"] = basetypes.ListType{
+		ElemType: ExternalInformationIpsValue{}.Type(ctx),
+	}.TerraformType(ctx)
+	attrTypes["network_id"] = basetypes.StringType{}.TerraformType(ctx)
+
+	objectType := tftypes.Object{AttributeTypes: attrTypes}
+
+	switch v.state {
+	case attr.ValueStateKnown:
+		vals := make(map[string]tftypes.Value, 2)
+
+		val, err = v.Ips.ToTerraformValue(ctx)
+
+		if err != nil {
+			return tftypes.NewValue(objectType, tftypes.UnknownValue), err
+		}
+
+		vals["ips"] = val
+
+		val, err = v.NetworkId.ToTerraformValue(ctx)
+
+		if err != nil {
+			return tftypes.NewValue(objectType, tftypes.UnknownValue), err
+		}
+
+		vals["network_id"] = val
+
+		if err := tftypes.ValidateValue(objectType, vals); err != nil {
+			return tftypes.NewValue(objectType, tftypes.UnknownValue), err
+		}
+
+		return tftypes.NewValue(objectType, vals), nil
+	case attr.ValueStateNull:
+		return tftypes.NewValue(objectType, nil), nil
+	case attr.ValueStateUnknown:
+		return tftypes.NewValue(objectType, tftypes.UnknownValue), nil
+	default:
+		panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state))
+	}
+}
+
+func (v ExternalInformationValue) IsNull() bool {
+	return v.state == attr.ValueStateNull
+}
+
+func (v ExternalInformationValue) IsUnknown() bool {
+	return v.state == attr.ValueStateUnknown
+}
+
+func (v ExternalInformationValue) String() string {
+	return "ExternalInformationValue"
+}
+
+func (v ExternalInformationValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) {
+	var diags diag.Diagnostics
+
+	objVal, diags := types.ObjectValue(
+		map[string]attr.Type{
+			"ips":        ovhtypes.NewTfListNestedType[ExternalInformationIpsValue](ctx),
+			"network_id": ovhtypes.TfStringType{},
+		},
+		map[string]attr.Value{
+			"ips":        v.Ips,
+			"network_id": v.NetworkId,
+		})
+
+	return objVal, diags
+}
+
+func (v ExternalInformationValue) Equal(o attr.Value) bool {
+	other, ok := o.(ExternalInformationValue)
+
+	if !ok {
+		return false
+	}
+
+	if v.state != other.state {
+		return false
+	}
+
+	if v.state != attr.ValueStateKnown {
+		return true
+	}
+
+	if !v.Ips.Equal(other.Ips) {
+		return false
+	}
+
+	if !v.NetworkId.Equal(other.NetworkId) {
+		return false
+	}
+
+	return true
+}
+
+func (v ExternalInformationValue) Type(ctx context.Context) attr.Type {
+	return ExternalInformationType{
+		basetypes.ObjectType{
+			AttrTypes: v.AttributeTypes(ctx),
+		},
+	}
+}
+
+func (v ExternalInformationValue) AttributeTypes(ctx context.Context) map[string]attr.Type {
+	return map[string]attr.Type{
+		"ips":        ovhtypes.NewTfListNestedType[ExternalInformationIpsValue](ctx),
+		"network_id": ovhtypes.TfStringType{},
+	}
+}
+
+var _ basetypes.ObjectTypable = ExternalInformationIpsType{}
+
+type ExternalInformationIpsType struct {
+	basetypes.ObjectType
+}
+
+func (t ExternalInformationIpsType) Equal(o attr.Type) bool {
+	other, ok := o.(ExternalInformationIpsType)
+
+	if !ok {
+		return false
+	}
+
+	return t.ObjectType.Equal(other.ObjectType)
+}
+
+func (t ExternalInformationIpsType) String() string {
+	return "ExternalInformationIpsType"
+}
+
+func (t ExternalInformationIpsType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) {
+	var diags diag.Diagnostics
+
+	attributes := in.Attributes()
+
+	ipAttribute, ok := attributes["ip"]
+
+	if !ok {
+		diags.AddError(
+			"Attribute Missing",
+			`ip is missing from object`)
+
+		return nil, diags
+	}
+
+	ipVal, ok := ipAttribute.(ovhtypes.TfStringValue)
+
+	if !ok {
+		diags.AddError(
+			"Attribute Wrong Type",
+			fmt.Sprintf(`ip expected to be ovhtypes.TfStringValue, was: %T`, ipAttribute))
+	}
+
+	subnetIdAttribute, ok := attributes["subnet_id"]
+
+	if !ok {
+		diags.AddError(
+			"Attribute Missing",
+			`subnet_id is missing from object`)
+
+		return nil, diags
+	}
+
+	subnetIdVal, ok := subnetIdAttribute.(ovhtypes.TfStringValue)
+
+	if !ok {
+		diags.AddError(
+			"Attribute Wrong Type",
+			fmt.Sprintf(`subnet_id expected to be ovhtypes.TfStringValue, was: %T`, subnetIdAttribute))
+	}
+
+	if diags.HasError() {
+		return nil, diags
+	}
+
+	return ExternalInformationIpsValue{
+		Ip:       ipVal,
+		SubnetId: subnetIdVal,
+		state:    attr.ValueStateKnown,
+	}, diags
+}
+
+func NewExternalInformationIpsValueNull() ExternalInformationIpsValue {
+	return ExternalInformationIpsValue{
+		state: attr.ValueStateNull,
+	}
+}
+
+func NewExternalInformationIpsValueUnknown() ExternalInformationIpsValue {
+	return ExternalInformationIpsValue{
+		state: attr.ValueStateUnknown,
+	}
+}
+
+func NewExternalInformationIpsValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (ExternalInformationIpsValue, diag.Diagnostics) {
+	var diags diag.Diagnostics
+
+	// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521
+	ctx := context.Background()
+
+	for name, attributeType := range attributeTypes {
+		attribute, ok := attributes[name]
+
+		if !ok {
+			diags.AddError(
+				"Missing ExternalInformationIpsValue Attribute Value",
+				"While creating a ExternalInformationIpsValue value, a missing attribute value was detected. "+
+					"A ExternalInformationIpsValue must contain values for all attributes, even if null or unknown. "+
+					"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
+					fmt.Sprintf("ExternalInformationIpsValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()),
+			)
+
+			continue
+		}
+
+		if !attributeType.Equal(attribute.Type(ctx)) {
+			diags.AddError(
+				"Invalid ExternalInformationIpsValue Attribute Type",
+				"While creating a ExternalInformationIpsValue value, an invalid attribute value was detected. "+
+					"A ExternalInformationIpsValue must use a matching attribute type for the value. "+
+					"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
+					fmt.Sprintf("ExternalInformationIpsValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+
+					fmt.Sprintf("ExternalInformationIpsValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)),
+			)
+		}
+	}
+
+	for name := range attributes {
+		_, ok := attributeTypes[name]
+
+		if !ok {
+			diags.AddError(
+				"Extra ExternalInformationIpsValue Attribute Value",
+				"While creating a ExternalInformationIpsValue value, an extra attribute value was detected. "+
+					"A ExternalInformationIpsValue must not contain values beyond the expected attribute types. "+
+					"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
+					fmt.Sprintf("Extra ExternalInformationIpsValue Attribute Name: %s", name),
+			)
+		}
+	}
+
+	if diags.HasError() {
+		return NewExternalInformationIpsValueUnknown(), diags
+	}
+
+	ipAttribute, ok := attributes["ip"]
+
+	if !ok {
+		diags.AddError(
+			"Attribute Missing",
+			`ip is missing from object`)
+
+		return NewExternalInformationIpsValueUnknown(), diags
+	}
+
+	ipVal, ok := ipAttribute.(ovhtypes.TfStringValue)
+
+	if !ok {
+		diags.AddError(
+			"Attribute Wrong Type",
+			fmt.Sprintf(`ip expected to be ovhtypes.TfStringValue, was: %T`, ipAttribute))
+	}
+
+	subnetIdAttribute, ok := attributes["subnet_id"]
+
+	if !ok {
+		diags.AddError(
+			"Attribute Missing",
+			`subnet_id is missing from object`)
+
+		return NewExternalInformationIpsValueUnknown(), diags
+	}
+
+	subnetIdVal, ok := subnetIdAttribute.(ovhtypes.TfStringValue)
+
+	if !ok {
+		diags.AddError(
+			"Attribute Wrong Type",
+			fmt.Sprintf(`subnet_id expected to be ovhtypes.TfStringValue, was: %T`, subnetIdAttribute))
+	}
+
+	if diags.HasError() {
+		return NewExternalInformationIpsValueUnknown(), diags
+	}
+
+	return ExternalInformationIpsValue{
+		Ip:       ipVal,
+		SubnetId: subnetIdVal,
+		state:    attr.ValueStateKnown,
+	}, diags
+}
+
+func NewExternalInformationIpsValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) ExternalInformationIpsValue {
+	object, diags := NewExternalInformationIpsValue(attributeTypes, attributes)
+
+	if diags.HasError() {
+		// This could potentially be added to the diag package.
+		diagsStrings := make([]string, 0, len(diags))
+
+		for _, diagnostic := range diags {
+			diagsStrings = append(diagsStrings, fmt.Sprintf(
+				"%s | %s | %s",
+				diagnostic.Severity(),
+				diagnostic.Summary(),
+				diagnostic.Detail()))
+		}
+
+		panic("NewExternalInformationIpsValueMust received error(s): " + strings.Join(diagsStrings, "\n"))
+	}
+
+	return object
+}
+
+func (t ExternalInformationIpsType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) {
+	if in.Type() == nil {
+		return NewExternalInformationIpsValueNull(), nil
+	}
+
+	if !in.Type().Equal(t.TerraformType(ctx)) {
+		return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type())
+	}
+
+	if !in.IsKnown() {
+		return NewExternalInformationIpsValueUnknown(), nil
+	}
+
+	if in.IsNull() {
+		return NewExternalInformationIpsValueNull(), nil
+	}
+
+	attributes := map[string]attr.Value{}
+
+	val := map[string]tftypes.Value{}
+
+	err := in.As(&val)
+
+	if err != nil {
+		return nil, err
+	}
+
+	for k, v := range val {
+		a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v)
+
+		if err != nil {
+			return nil, err
+		}
+
+		attributes[k] = a
+	}
+
+	return NewExternalInformationIpsValueMust(ExternalInformationIpsValue{}.AttributeTypes(ctx), attributes), nil
+}
+
+func (t ExternalInformationIpsType) ValueType(ctx context.Context) attr.Value {
+	return ExternalInformationIpsValue{}
+}
+
+var _ basetypes.ObjectValuable = ExternalInformationIpsValue{}
+
+type ExternalInformationIpsValue struct {
+	Ip       ovhtypes.TfStringValue `tfsdk:"ip" json:"ip"`
+	SubnetId ovhtypes.TfStringValue `tfsdk:"subnet_id" json:"subnetId"`
+	state    attr.ValueState
+}
+
+func (v *ExternalInformationIpsValue) UnmarshalJSON(data []byte) error {
+	type JsonExternalInformationIpsValue ExternalInformationIpsValue
+
+	var tmp JsonExternalInformationIpsValue
+	if err := json.Unmarshal(data, &tmp); err != nil {
+		return err
+	}
+	v.Ip = tmp.Ip
+	v.SubnetId = tmp.SubnetId
+
+	v.state = attr.ValueStateKnown
+
+	return nil
+}
+
+func (v *ExternalInformationIpsValue) MergeWith(other *ExternalInformationIpsValue) {
+
+	if (v.Ip.IsUnknown() || v.Ip.IsNull()) && !other.Ip.IsUnknown() {
+		v.Ip = other.Ip
+	}
+
+	if (v.SubnetId.IsUnknown() || v.SubnetId.IsNull()) && !other.SubnetId.IsUnknown() {
+		v.SubnetId = other.SubnetId
+	}
+
+	if (v.state == attr.ValueStateUnknown || v.state == attr.ValueStateNull) && other.state != attr.ValueStateUnknown {
+		v.state = other.state
+	}
+}
+
+func (v ExternalInformationIpsValue) Attributes() map[string]attr.Value {
+	return map[string]attr.Value{
+		"ip":       v.Ip,
+		"subnetId": v.SubnetId,
+	}
+}
+func (v ExternalInformationIpsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) {
+	attrTypes := make(map[string]tftypes.Type, 2)
+
+	var val tftypes.Value
+	var err error
+
+	attrTypes["ip"] = basetypes.StringType{}.TerraformType(ctx)
+	attrTypes["subnet_id"] = basetypes.StringType{}.TerraformType(ctx)
+
+	objectType := tftypes.Object{AttributeTypes: attrTypes}
+
+	switch v.state {
+	case attr.ValueStateKnown:
+		vals := make(map[string]tftypes.Value, 2)
+
+		val, err = v.Ip.ToTerraformValue(ctx)
+
+		if err != nil {
+			return tftypes.NewValue(objectType, tftypes.UnknownValue), err
+		}
+
+		vals["ip"] = val
+
+		val, err = v.SubnetId.ToTerraformValue(ctx)
+
+		if err != nil {
+			return tftypes.NewValue(objectType, tftypes.UnknownValue), err
+		}
+
+		vals["subnet_id"] = val
+
+		if err := tftypes.ValidateValue(objectType, vals); err != nil {
+			return tftypes.NewValue(objectType, tftypes.UnknownValue), err
+		}
+
+		return tftypes.NewValue(objectType, vals), nil
+	case attr.ValueStateNull:
+		return tftypes.NewValue(objectType, nil), nil
+	case attr.ValueStateUnknown:
+		return tftypes.NewValue(objectType, tftypes.UnknownValue), nil
+	default:
+		panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state))
+	}
+}
+
+func (v ExternalInformationIpsValue) IsNull() bool {
+	return v.state == attr.ValueStateNull
+}
+
+func (v ExternalInformationIpsValue) IsUnknown() bool {
+	return v.state == attr.ValueStateUnknown
+}
+
+func (v ExternalInformationIpsValue) String() string {
+	return "ExternalInformationIpsValue"
+}
+
+func (v ExternalInformationIpsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) {
+	var diags diag.Diagnostics
+
+	objVal, diags := types.ObjectValue(
+		map[string]attr.Type{
+			"ip":        ovhtypes.TfStringType{},
+			"subnet_id": ovhtypes.TfStringType{},
+		},
+		map[string]attr.Value{
+			"ip":        v.Ip,
+			"subnet_id": v.SubnetId,
+		})
+
+	return objVal, diags
+}
+
+func (v ExternalInformationIpsValue) Equal(o attr.Value) bool {
+	other, ok := o.(ExternalInformationIpsValue)
+
+	if !ok {
+		return false
+	}
+
+	if v.state != other.state {
+		return false
+	}
+
+	if v.state != attr.ValueStateKnown {
+		return true
+	}
+
+	if !v.Ip.Equal(other.Ip) {
+		return false
+	}
+
+	if !v.SubnetId.Equal(other.SubnetId) {
+		return false
+	}
+
+	return true
+}
+
+func (v ExternalInformationIpsValue) Type(ctx context.Context) attr.Type {
+	return ExternalInformationIpsType{
+		basetypes.ObjectType{
+			AttrTypes: v.AttributeTypes(ctx),
+		},
+	}
+}
+
+func (v ExternalInformationIpsValue) AttributeTypes(ctx context.Context) map[string]attr.Type {
+	return map[string]attr.Type{
+		"ip":        ovhtypes.TfStringType{},
+		"subnet_id": ovhtypes.TfStringType{},
+	}
+}
+
+var _ basetypes.ObjectTypable = InterfacesType{}
+
+type InterfacesType struct {
+	basetypes.ObjectType
+}
+
+func (t InterfacesType) Equal(o attr.Type) bool {
+	other, ok := o.(InterfacesType)
+
+	if !ok {
+		return false
+	}
+
+	return t.ObjectType.Equal(other.ObjectType)
+}
+
+func (t InterfacesType) String() string {
+	return "InterfacesType"
+}
+
+func (t InterfacesType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) {
+	var diags diag.Diagnostics
+
+	attributes := in.Attributes()
+
+	idAttribute, ok := attributes["id"]
+
+	if !ok {
+		diags.AddError(
+			"Attribute Missing",
+			`id is missing from object`)
+
+		return nil, diags
+	}
+
+	idVal, ok := idAttribute.(ovhtypes.TfStringValue)
+
+	if !ok {
+		diags.AddError(
+			"Attribute Wrong Type",
+			fmt.Sprintf(`id expected to be ovhtypes.TfStringValue, was: %T`, idAttribute))
+	}
+
+	ipAttribute, ok := attributes["ip"]
+
+	if !ok {
+		diags.AddError(
+			"Attribute Missing",
+			`ip is missing from object`)
+
+		return nil, diags
+	}
+
+	ipVal, ok := ipAttribute.(ovhtypes.TfStringValue)
+
+	if !ok {
+		diags.AddError(
+			"Attribute Wrong Type",
+			fmt.Sprintf(`ip expected to be ovhtypes.TfStringValue, was: %T`, ipAttribute))
+	}
+
+	networkIdAttribute, ok := attributes["network_id"]
+
+	if !ok {
+		diags.AddError(
+			"Attribute Missing",
+			`network_id is missing from object`)
+
+		return nil, diags
+	}
+
+	networkIdVal, ok := networkIdAttribute.(ovhtypes.TfStringValue)
+
+	if !ok {
+		diags.AddError(
+			"Attribute Wrong Type",
+			fmt.Sprintf(`network_id expected to be ovhtypes.TfStringValue, was: %T`, networkIdAttribute))
+	}
+
+	subnetIdAttribute, ok := attributes["subnet_id"]
+
+	if !ok {
+		diags.AddError(
+			"Attribute Missing",
+			`subnet_id is missing from object`)
+
+		return nil, diags
+	}
+
+	subnetIdVal, ok := subnetIdAttribute.(ovhtypes.TfStringValue)
+
+	if !ok {
+		diags.AddError(
+			"Attribute Wrong Type",
+			fmt.Sprintf(`subnet_id expected to be ovhtypes.TfStringValue, was: %T`, subnetIdAttribute))
+	}
+
+	if diags.HasError() {
+		return nil, diags
+	}
+
+	return InterfacesValue{
+		Id:        idVal,
+		Ip:        ipVal,
+		NetworkId: networkIdVal,
+		SubnetId:  subnetIdVal,
+		state:     attr.ValueStateKnown,
+	}, diags
+}
+
+func NewInterfacesValueNull() InterfacesValue {
+	return InterfacesValue{
+		state: attr.ValueStateNull,
+	}
+}
+
+func NewInterfacesValueUnknown() InterfacesValue {
+	return InterfacesValue{
+		state: attr.ValueStateUnknown,
+	}
+}
+
+func NewInterfacesValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (InterfacesValue, diag.Diagnostics) {
+	var diags diag.Diagnostics
+
+	// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521
+	ctx := context.Background()
+
+	for name, attributeType := range attributeTypes {
+		attribute, ok := attributes[name]
+
+		if !ok {
+			diags.AddError(
+				"Missing InterfacesValue Attribute Value",
+				"While creating a InterfacesValue value, a missing attribute value was detected. "+
+					"A InterfacesValue must contain values for all attributes, even if null or unknown. "+
+					"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
+					fmt.Sprintf("InterfacesValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()),
+			)
+
+			continue
+		}
+
+		if !attributeType.Equal(attribute.Type(ctx)) {
+			diags.AddError(
+				"Invalid InterfacesValue Attribute Type",
+				"While creating a InterfacesValue value, an invalid attribute value was detected. "+
+					"A InterfacesValue must use a matching attribute type for the value. "+
+					"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
+					fmt.Sprintf("InterfacesValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+
+					fmt.Sprintf("InterfacesValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)),
+			)
+		}
+	}
+
+	for name := range attributes {
+		_, ok := attributeTypes[name]
+
+		if !ok {
+			diags.AddError(
+				"Extra InterfacesValue Attribute Value",
+				"While creating a InterfacesValue value, an extra attribute value was detected. "+
+					"A InterfacesValue must not contain values beyond the expected attribute types. "+
+					"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
+					fmt.Sprintf("Extra InterfacesValue Attribute Name: %s", name),
+			)
+		}
+	}
+
+	if diags.HasError() {
+		return NewInterfacesValueUnknown(), diags
+	}
+
+	idAttribute, ok := attributes["id"]
+
+	if !ok {
+		diags.AddError(
+			"Attribute Missing",
+			`id is missing from object`)
+
+		return NewInterfacesValueUnknown(), diags
+	}
+
+	idVal, ok := idAttribute.(ovhtypes.TfStringValue)
+
+	if !ok {
+		diags.AddError(
+			"Attribute Wrong Type",
+			fmt.Sprintf(`id expected to be ovhtypes.TfStringValue, was: %T`, idAttribute))
+	}
+
+	ipAttribute, ok := attributes["ip"]
+
+	if !ok {
+		diags.AddError(
+			"Attribute Missing",
+			`ip is missing from object`)
+
+		return NewInterfacesValueUnknown(), diags
+	}
+
+	ipVal, ok := ipAttribute.(ovhtypes.TfStringValue)
+
+	if !ok {
+		diags.AddError(
+			"Attribute Wrong Type",
+			fmt.Sprintf(`ip expected to be ovhtypes.TfStringValue, was: %T`, ipAttribute))
+	}
+
+	networkIdAttribute, ok := attributes["network_id"]
+
+	if !ok {
+		diags.AddError(
+			"Attribute Missing",
+			`network_id is missing from object`)
+
+		return NewInterfacesValueUnknown(), diags
+	}
+
+	networkIdVal, ok := networkIdAttribute.(ovhtypes.TfStringValue)
+
+	if !ok {
+		diags.AddError(
+			"Attribute Wrong Type",
+			fmt.Sprintf(`network_id expected to be ovhtypes.TfStringValue, was: %T`, networkIdAttribute))
+	}
+
+	subnetIdAttribute, ok := attributes["subnet_id"]
+
+	if !ok {
+		diags.AddError(
+			"Attribute Missing",
+			`subnet_id is missing from object`)
+
+		return NewInterfacesValueUnknown(), diags
+	}
+
+	subnetIdVal, ok := subnetIdAttribute.(ovhtypes.TfStringValue)
+
+	if !ok {
+		diags.AddError(
+			"Attribute Wrong Type",
+			fmt.Sprintf(`subnet_id expected to be ovhtypes.TfStringValue, was: %T`, subnetIdAttribute))
+	}
+
+	if diags.HasError() {
+		return NewInterfacesValueUnknown(), diags
+	}
+
+	return InterfacesValue{
+		Id:        idVal,
+		Ip:        ipVal,
+		NetworkId: networkIdVal,
+		SubnetId:  subnetIdVal,
+		state:     attr.ValueStateKnown,
+	}, diags
+}
+
+func NewInterfacesValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) InterfacesValue {
+	object, diags := NewInterfacesValue(attributeTypes, attributes)
+
+	if diags.HasError() {
+		// This could potentially be added to the diag package.
+		diagsStrings := make([]string, 0, len(diags))
+
+		for _, diagnostic := range diags {
+			diagsStrings = append(diagsStrings, fmt.Sprintf(
+				"%s | %s | %s",
+				diagnostic.Severity(),
+				diagnostic.Summary(),
+				diagnostic.Detail()))
+		}
+
+		panic("NewInterfacesValueMust received error(s): " + strings.Join(diagsStrings, "\n"))
+	}
+
+	return object
+}
+
+func (t InterfacesType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) {
+	if in.Type() == nil {
+		return NewInterfacesValueNull(), nil
+	}
+
+	if !in.Type().Equal(t.TerraformType(ctx)) {
+		return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type())
+	}
+
+	if !in.IsKnown() {
+		return NewInterfacesValueUnknown(), nil
+	}
+
+	if in.IsNull() {
+		return NewInterfacesValueNull(), nil
+	}
+
+	attributes := map[string]attr.Value{}
+
+	val := map[string]tftypes.Value{}
+
+	err := in.As(&val)
+
+	if err != nil {
+		return nil, err
+	}
+
+	for k, v := range val {
+		a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v)
+
+		if err != nil {
+			return nil, err
+		}
+
+		attributes[k] = a
+	}
+
+	return NewInterfacesValueMust(InterfacesValue{}.AttributeTypes(ctx), attributes), nil
+}
+
+func (t InterfacesType) ValueType(ctx context.Context) attr.Value {
+	return InterfacesValue{}
+}
+
+var _ basetypes.ObjectValuable = InterfacesValue{}
+
+type InterfacesValue struct {
+	Id        ovhtypes.TfStringValue `tfsdk:"id" json:"id"`
+	Ip        ovhtypes.TfStringValue `tfsdk:"ip" json:"ip"`
+	NetworkId ovhtypes.TfStringValue `tfsdk:"network_id" json:"networkId"`
+	SubnetId  ovhtypes.TfStringValue `tfsdk:"subnet_id" json:"subnetId"`
+	state     attr.ValueState
+}
+
+func (v *InterfacesValue) UnmarshalJSON(data []byte) error {
+	type JsonInterfacesValue InterfacesValue
+
+	var tmp JsonInterfacesValue
+	if err := json.Unmarshal(data, &tmp); err != nil {
+		return err
+	}
+	v.Id = tmp.Id
+	v.Ip = tmp.Ip
+	v.NetworkId = tmp.NetworkId
+	v.SubnetId = tmp.SubnetId
+
+	v.state = attr.ValueStateKnown
+
+	return nil
+}
+
+func (v *InterfacesValue) MergeWith(other *InterfacesValue) {
+
+	if (v.Id.IsUnknown() || v.Id.IsNull()) && !other.Id.IsUnknown() {
+		v.Id = other.Id
+	}
+
+	if (v.Ip.IsUnknown() || v.Ip.IsNull()) && !other.Ip.IsUnknown() {
+		v.Ip = other.Ip
+	}
+
+	if (v.NetworkId.IsUnknown() || v.NetworkId.IsNull()) && !other.NetworkId.IsUnknown() {
+		v.NetworkId = other.NetworkId
+	}
+
+	if (v.SubnetId.IsUnknown() || v.SubnetId.IsNull()) && !other.SubnetId.IsUnknown() {
+		v.SubnetId = other.SubnetId
+	}
+
+	if (v.state == attr.ValueStateUnknown || v.state == attr.ValueStateNull) && other.state != attr.ValueStateUnknown {
+		v.state = other.state
+	}
+}
+
+func (v InterfacesValue) Attributes() map[string]attr.Value {
+	return map[string]attr.Value{
+		"id":        v.Id,
+		"ip":        v.Ip,
+		"networkId": v.NetworkId,
+		"subnetId":  v.SubnetId,
+	}
+}
+func (v InterfacesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) {
+	attrTypes := make(map[string]tftypes.Type, 4)
+
+	var val tftypes.Value
+	var err error
+
+	attrTypes["id"] = basetypes.StringType{}.TerraformType(ctx)
+	attrTypes["ip"] = basetypes.StringType{}.TerraformType(ctx)
+	attrTypes["network_id"] = basetypes.StringType{}.TerraformType(ctx)
+	attrTypes["subnet_id"] = basetypes.StringType{}.TerraformType(ctx)
+
+	objectType := tftypes.Object{AttributeTypes: attrTypes}
+
+	switch v.state {
+	case attr.ValueStateKnown:
+		vals := make(map[string]tftypes.Value, 4)
+
+		val, err = v.Id.ToTerraformValue(ctx)
+
+		if err != nil {
+			return tftypes.NewValue(objectType, tftypes.UnknownValue), err
+		}
+
+		vals["id"] = val
+
+		val, err = v.Ip.ToTerraformValue(ctx)
+
+		if err != nil {
+			return tftypes.NewValue(objectType, tftypes.UnknownValue), err
+		}
+
+		vals["ip"] = val
+
+		val, err = v.NetworkId.ToTerraformValue(ctx)
+
+		if err != nil {
+			return tftypes.NewValue(objectType, tftypes.UnknownValue), err
+		}
+
+		vals["network_id"] = val
+
+		val, err = v.SubnetId.ToTerraformValue(ctx)
+
+		if err != nil {
+			return tftypes.NewValue(objectType, tftypes.UnknownValue), err
+		}
+
+		vals["subnet_id"] = val
+
+		if err := tftypes.ValidateValue(objectType, vals); err != nil {
+			return tftypes.NewValue(objectType, tftypes.UnknownValue), err
+		}
+
+		return tftypes.NewValue(objectType, vals), nil
+	case attr.ValueStateNull:
+		return tftypes.NewValue(objectType, nil), nil
+	case attr.ValueStateUnknown:
+		return tftypes.NewValue(objectType, tftypes.UnknownValue), nil
+	default:
+		panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state))
+	}
+}
+
+func (v InterfacesValue) IsNull() bool {
+	return v.state == attr.ValueStateNull
+}
+
+func (v InterfacesValue) IsUnknown() bool {
+	return v.state == attr.ValueStateUnknown
+}
+
+func (v InterfacesValue) String() string {
+	return "InterfacesValue"
+}
+
+func (v InterfacesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) {
+	var diags diag.Diagnostics
+
+	objVal, diags := types.ObjectValue(
+		map[string]attr.Type{
+			"id":         ovhtypes.TfStringType{},
+			"ip":         ovhtypes.TfStringType{},
+			"network_id": ovhtypes.TfStringType{},
+			"subnet_id":  ovhtypes.TfStringType{},
+		},
+		map[string]attr.Value{
+			"id":         v.Id,
+			"ip":         v.Ip,
+			"network_id": v.NetworkId,
+			"subnet_id":  v.SubnetId,
+		})
+
+	return objVal, diags
+}
+
+func (v InterfacesValue) Equal(o attr.Value) bool {
+	other, ok := o.(InterfacesValue)
+
+	if !ok {
+		return false
+	}
+
+	if v.state != other.state {
+		return false
+	}
+
+	if v.state != attr.ValueStateKnown {
+		return true
+	}
+
+	if !v.Id.Equal(other.Id) {
+		return false
+	}
+
+	if !v.Ip.Equal(other.Ip) {
+		return false
+	}
+
+	if !v.NetworkId.Equal(other.NetworkId) {
+		return false
+	}
+
+	if !v.SubnetId.Equal(other.SubnetId) {
+		return false
+	}
+
+	return true
+}
+
+func (v InterfacesValue) Type(ctx context.Context) attr.Type {
+	return InterfacesType{
+		basetypes.ObjectType{
+			AttrTypes: v.AttributeTypes(ctx),
+		},
+	}
+}
+
+func (v InterfacesValue) AttributeTypes(ctx context.Context) map[string]attr.Type {
+	return map[string]attr.Type{
+		"id":         ovhtypes.TfStringType{},
+		"ip":         ovhtypes.TfStringType{},
+		"network_id": ovhtypes.TfStringType{},
+		"subnet_id":  ovhtypes.TfStringType{},
+	}
+}
diff --git a/ovh/data_cloud_project_kube.go b/ovh/data_cloud_project_kube.go
index 9803d6a7..a1eac64f 100644
--- a/ovh/data_cloud_project_kube.go
+++ b/ovh/data_cloud_project_kube.go
@@ -30,6 +30,13 @@ func dataSourceCloudProjectKube() *schema.Resource {
 				Type:     schema.TypeString,
 				Optional: true,
 			},
+			"plan": {
+				Type:         schema.TypeString,
+				Optional:     true,
+				ForceNew:     false,
+				Default:      "free",
+				ValidateFunc: helpers.ValidateEnum([]string{"standard", "free"}),
+			},
 			kubeClusterProxyModeKey: {
 				Type:         schema.TypeString,
 				Optional:     true,
@@ -266,6 +273,40 @@ func dataSourceCloudProjectKube() *schema.Resource {
 				Type:     schema.TypeString,
 				Computed: true,
 			},
+			"kubeconfig": {
+				Type:      schema.TypeString,
+				Computed:  true,
+				Sensitive: true,
+			},
+			"kubeconfig_attributes": {
+				Type:        schema.TypeList,
+				Computed:    true,
+				Sensitive:   true,
+				Description: "The kubeconfig configuration file of the Kubernetes cluster",
+				Elem: &schema.Resource{
+					Schema: map[string]*schema.Schema{
+						"host": {
+							Type:     schema.TypeString,
+							Computed: true,
+						},
+						"cluster_ca_certificate": {
+							Type:      schema.TypeString,
+							Computed:  true,
+							Sensitive: true,
+						},
+						"client_certificate": {
+							Type:      schema.TypeString,
+							Computed:  true,
+							Sensitive: true,
+						},
+						"client_key": {
+							Type:      schema.TypeString,
+							Computed:  true,
+							Sensitive: true,
+						},
+					},
+				},
+			},
 		},
 	}
 }
@@ -295,5 +336,44 @@ func dataSourceCloudProjectKubeRead(d *schema.ResourceData, meta interface{}) er
 		}
 	}
 
+	// add kubeconfig in state
+	if err := dataSourceKubeconfig(d, meta); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func dataSourceKubeconfig(d *schema.ResourceData, meta interface{}) error {
+	serviceName := d.Get("service_name").(string)
+	var kubeId string
+
+	// For data source, use kube_id instead of d.Id()
+	if id := d.Get("kube_id"); id != nil {
+		kubeId = id.(string)
+	} else {
+		kubeId = d.Id()
+	}
+
+	kubeConfig, err := getKubeconfig(meta.(*Config), serviceName, kubeId)
+	if err != nil {
+		return err
+	}
+
+	if len(kubeConfig.Clusters) == 0 || len(kubeConfig.Users) == 0 {
+		return fmt.Errorf("kubeconfig is invalid")
+	}
+
+	// raw kubeconfig
+	d.Set("kubeconfig", kubeConfig.Raw)
+
+	// kubeconfig attributes
+	kubeconf := map[string]interface{}{}
+	kubeconf["host"] = kubeConfig.Clusters[0].Cluster.Server
+	kubeconf["cluster_ca_certificate"] = kubeConfig.Clusters[0].Cluster.CertificateAuthorityData
+	kubeconf["client_certificate"] = kubeConfig.Users[0].User.ClientCertificateData
+	kubeconf["client_key"] = kubeConfig.Users[0].User.ClientKeyData
+	d.Set("kubeconfig_attributes", []map[string]interface{}{kubeconf})
+
 	return nil
 }
diff --git a/ovh/data_dbaas_logs_output_graylog_stream.go b/ovh/data_dbaas_logs_output_graylog_stream.go
index 346fcbf9..85d7281d 100644
--- a/ovh/data_dbaas_logs_output_graylog_stream.go
+++ b/ovh/data_dbaas_logs_output_graylog_stream.go
@@ -22,7 +22,7 @@ func dataSourceDbaasLogsOutputGraylogStream() *schema.Resource {
 			},
 			"title": {
 				Type:        schema.TypeString,
-				Description: "Stream description",
+				Description: "Stream name",
 				Required:    true,
 			},
 
diff --git a/ovh/data_dbaas_logs_output_graylog_stream_url.go b/ovh/data_dbaas_logs_output_graylog_stream_url.go
new file mode 100644
index 00000000..4b482f48
--- /dev/null
+++ b/ovh/data_dbaas_logs_output_graylog_stream_url.go
@@ -0,0 +1,83 @@
+package ovh
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"net/url"
+
+	"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
+	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+)
+
+// dataSourceDbaasLogsOutputGraylogStreamURL returns the list of URLs for a Graylog stream.
+func dataSourceDbaasLogsOutputGraylogStreamURL() *schema.Resource {
+	return &schema.Resource{
+		ReadContext: dataSourceDbaasLogsOutputGraylogStreamURLRead,
+		Schema: map[string]*schema.Schema{
+			"service_name": {
+				Type:        schema.TypeString,
+				Description: "The service name",
+				Required:    true,
+			},
+			"stream_id": {
+				Type:        schema.TypeString,
+				Description: "Stream ID",
+				Required:    true,
+			},
+			"url": {
+				Type:     schema.TypeList,
+				Computed: true,
+				Elem: &schema.Resource{
+					Schema: map[string]*schema.Schema{
+						"address": {
+							Type:        schema.TypeString,
+							Computed:    true,
+							Description: "URL address",
+						},
+						"type": {
+							Type:        schema.TypeString,
+							Computed:    true,
+							Description: "URL type",
+						},
+					},
+				},
+			},
+		},
+	}
+}
+
+func dataSourceDbaasLogsOutputGraylogStreamURLRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
+	config := meta.(*Config)
+
+	serviceName := d.Get("service_name").(string)
+	streamID := d.Get("stream_id").(string)
+
+	log.Printf("[DEBUG] Will read URLs for dbaas logs output graylog stream: %s/%s", serviceName, streamID)
+	endpoint := fmt.Sprintf(
+		"/dbaas/logs/%s/output/graylog/stream/%s/url",
+		url.PathEscape(serviceName),
+		url.PathEscape(streamID),
+	)
+
+	var urls []DbaasLogsOutputGraylogStreamURL
+	if err := config.OVHClient.Get(endpoint, &urls); err != nil {
+		return diag.Errorf("Error calling Get %s:\n\t %q", endpoint, err)
+	}
+
+	list := make([]map[string]interface{}, len(urls))
+	for i, u := range urls {
+		m := map[string]interface{}{
+			"address": u.Address,
+			"type":    u.Type,
+		}
+		list[i] = m
+	}
+
+	if err := d.Set("url", list); err != nil {
+		return diag.FromErr(err)
+	}
+
+	d.SetId(fmt.Sprintf("%s/%s", serviceName, streamID))
+	return nil
+}
diff --git a/ovh/data_location.go b/ovh/data_location.go
new file mode 100644
index 00000000..25a998b8
--- /dev/null
+++ b/ovh/data_location.go
@@ -0,0 +1,69 @@
+package ovh
+
+import (
+	"context"
+	"fmt"
+	"net/url"
+
+	"github.com/hashicorp/terraform-plugin-framework/datasource"
+)
+
+var _ datasource.DataSourceWithConfigure = (*locationDataSource)(nil)
+
+func NewLocationDataSource() datasource.DataSource {
+	return &locationDataSource{}
+}
+
+type locationDataSource struct {
+	config *Config
+}
+
+func (d *locationDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+	resp.TypeName = req.ProviderTypeName + "_location"
+}
+
+func (d *locationDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
+	if req.ProviderData == nil {
+		return
+	}
+
+	config, ok := req.ProviderData.(*Config)
+	if !ok {
+		resp.Diagnostics.AddError(
+			"Unexpected Data Source Configure Type",
+			fmt.Sprintf("Expected *Config, got: %T. Please report this issue to the provider developers.", req.ProviderData),
+		)
+		return
+	}
+
+	d.config = config
+}
+
+func (d *locationDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+	resp.Schema = LocationDataSourceSchema(ctx)
+}
+
+func (d *locationDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
+	var data LocationModel
+
+	// Read Terraform configuration data into the model
+	resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
+
+	if resp.Diagnostics.HasError() {
+		return
+	}
+
+	// Read API call logic
+	endpoint := "/v2/location/" + url.PathEscape(data.Name.ValueString())
+
+	if err := d.config.OVHClient.Get(endpoint, &data); err != nil {
+		resp.Diagnostics.AddError(
+			fmt.Sprintf("Error calling Get %s", endpoint),
+			err.Error(),
+		)
+		return
+	}
+
+	// Save data into Terraform state
+	resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+}
diff --git a/ovh/data_location_gen.go b/ovh/data_location_gen.go
new file mode 100644
index 00000000..c828c5d8
--- /dev/null
+++ b/ovh/data_location_gen.go
@@ -0,0 +1,204 @@
+// Code generated by terraform-plugin-framework-generator DO NOT EDIT.
+
+package ovh
+
+import (
+	"context"
+
+	ovhtypes "github.com/ovh/terraform-provider-ovh/v2/ovh/types"
+
+	"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+)
+
+func LocationDataSourceSchema(ctx context.Context) schema.Schema {
+	attrs := map[string]schema.Attribute{
+		"availability_zones": schema.ListAttribute{
+			CustomType:          ovhtypes.NewTfListNestedType[ovhtypes.TfStringValue](ctx),
+			Computed:            true,
+			Description:         "List of availability zones for the region",
+			MarkdownDescription: "List of availability zones for the region",
+		},
+		"cardinal_point": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Computed:            true,
+			Description:         "Cardinal direction where the region is located",
+			MarkdownDescription: "Cardinal direction where the region is located",
+		},
+		"city_code": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Computed:            true,
+			Description:         "ISO code of the city",
+			MarkdownDescription: "ISO code of the city",
+		},
+		"city_latitude": schema.NumberAttribute{
+			CustomType:          ovhtypes.TfNumberType{},
+			Computed:            true,
+			Description:         "Geographical latitude of the city",
+			MarkdownDescription: "Geographical latitude of the city",
+		},
+		"city_longitude": schema.NumberAttribute{
+			CustomType:          ovhtypes.TfNumberType{},
+			Computed:            true,
+			Description:         "Geographical longitude of the city",
+			MarkdownDescription: "Geographical longitude of the city",
+		},
+		"city_name": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Computed:            true,
+			Description:         "Full name of the city",
+			MarkdownDescription: "Full name of the city",
+		},
+		"code": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Computed:            true,
+			Description:         "Region's short code",
+			MarkdownDescription: "Region's short code",
+		},
+		"country_code": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Computed:            true,
+			Description:         "ISO code of the country",
+			MarkdownDescription: "ISO code of the country",
+		},
+		"country_name": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Computed:            true,
+			Description:         "Full name of the country",
+			MarkdownDescription: "Full name of the country",
+		},
+		"geography_code": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Computed:            true,
+			Description:         "Short code representing the geographical area",
+			MarkdownDescription: "Short code representing the geographical area",
+		},
+		"geography_name": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Computed:            true,
+			Description:         "Name of the geographical area",
+			MarkdownDescription: "Name of the geographical area",
+		},
+		"location": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Computed:            true,
+			Description:         "Location of the region",
+			MarkdownDescription: "Location of the region",
+		},
+		"name": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Required:            true,
+			Description:         "Name",
+			MarkdownDescription: "Name",
+		},
+		"opening_year": schema.Int64Attribute{
+			CustomType:          ovhtypes.TfInt64Type{},
+			Computed:            true,
+			Description:         "Year the region was opened",
+			MarkdownDescription: "Year the region was opened",
+		},
+		"specific_type": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Computed:            true,
+			Description:         "Specific typology of the region",
+			MarkdownDescription: "Specific typology of the region",
+		},
+		"type": schema.StringAttribute{
+			CustomType:          ovhtypes.TfStringType{},
+			Computed:            true,
+			Description:         "General typology of the region",
+			MarkdownDescription: "General typology of the region",
+		},
+	}
+
+	return schema.Schema{
+		Description: "Get available region and its availability zones",
+		Attributes:  attrs,
+	}
+}
+
+type LocationModel struct {
+	AvailabilityZones ovhtypes.TfListNestedValue[ovhtypes.TfStringValue] `tfsdk:"availability_zones" json:"availabilityZones"`
+	CardinalPoint     ovhtypes.TfStringValue                             `tfsdk:"cardinal_point" json:"cardinalPoint"`
+	CityCode          ovhtypes.TfStringValue                             `tfsdk:"city_code" json:"cityCode"`
+	CityLatitude      ovhtypes.TfNumberValue                             `tfsdk:"city_latitude" json:"cityLatitude"`
+	CityLongitude     ovhtypes.TfNumberValue                             `tfsdk:"city_longitude" json:"cityLongitude"`
+	CityName          ovhtypes.TfStringValue                             `tfsdk:"city_name" json:"cityName"`
+	Code              ovhtypes.TfStringValue                             `tfsdk:"code" json:"code"`
+	CountryCode       ovhtypes.TfStringValue                             `tfsdk:"country_code" json:"countryCode"`
+	CountryName       ovhtypes.TfStringValue                             `tfsdk:"country_name" json:"countryName"`
+	GeographyCode     ovhtypes.TfStringValue                             `tfsdk:"geography_code" json:"geographyCode"`
+	GeographyName     ovhtypes.TfStringValue                             `tfsdk:"geography_name" json:"geographyName"`
+	Location          ovhtypes.TfStringValue                             `tfsdk:"location" json:"location"`
+	Name              ovhtypes.TfStringValue                             `tfsdk:"name" json:"name"`
+	OpeningYear       ovhtypes.TfInt64Value                              `tfsdk:"opening_year" json:"openingYear"`
+	SpecificType      ovhtypes.TfStringValue                             `tfsdk:"specific_type" json:"specificType"`
+	Type              ovhtypes.TfStringValue                             `tfsdk:"type" json:"type"`
+}
+
+func (v *LocationModel) MergeWith(other *LocationModel) {
+
+	if (v.AvailabilityZones.IsUnknown() || v.AvailabilityZones.IsNull()) && !other.AvailabilityZones.IsUnknown() {
+		v.AvailabilityZones = other.AvailabilityZones
+	}
+
+	if (v.CardinalPoint.IsUnknown() || v.CardinalPoint.IsNull()) && !other.CardinalPoint.IsUnknown() {
+		v.CardinalPoint = other.CardinalPoint
+	}
+
+	if (v.CityCode.IsUnknown() || v.CityCode.IsNull()) && !other.CityCode.IsUnknown() {
+		v.CityCode = other.CityCode
+	}
+
+	if (v.CityLatitude.IsUnknown() || v.CityLatitude.IsNull()) && !other.CityLatitude.IsUnknown() {
+		v.CityLatitude = other.CityLatitude
+	}
+
+	if (v.CityLongitude.IsUnknown() || v.CityLongitude.IsNull()) && !other.CityLongitude.IsUnknown() {
+		v.CityLongitude = other.CityLongitude
+	}
+
+	if (v.CityName.IsUnknown() || v.CityName.IsNull()) && !other.CityName.IsUnknown() {
+		v.CityName = other.CityName
+	}
+
+	if (v.Code.IsUnknown() || v.Code.IsNull()) && !other.Code.IsUnknown() {
+		v.Code = other.Code
+	}
+
+	if (v.CountryCode.IsUnknown() || v.CountryCode.IsNull()) && !other.CountryCode.IsUnknown() {
+		v.CountryCode = other.CountryCode
+	}
+
+	if (v.CountryName.IsUnknown() || v.CountryName.IsNull()) && !other.CountryName.IsUnknown() {
+		v.CountryName = other.CountryName
+	}
+
+	if (v.GeographyCode.IsUnknown() || v.GeographyCode.IsNull()) && !other.GeographyCode.IsUnknown() {
+		v.GeographyCode = other.GeographyCode
+	}
+
+	if (v.GeographyName.IsUnknown() || v.GeographyName.IsNull()) && !other.GeographyName.IsUnknown() {
+		v.GeographyName = other.GeographyName
+	}
+
+	if (v.Location.IsUnknown() || v.Location.IsNull()) && !other.Location.IsUnknown() {
+		v.Location = other.Location
+	}
+
+	if (v.Name.IsUnknown() || v.Name.IsNull()) && !other.Name.IsUnknown() {
+		v.Name = other.Name
+	}
+
+	if (v.OpeningYear.IsUnknown() || v.OpeningYear.IsNull()) && !other.OpeningYear.IsUnknown() {
+		v.OpeningYear = other.OpeningYear
+	}
+
+	if (v.SpecificType.IsUnknown() || v.SpecificType.IsNull()) && !other.SpecificType.IsUnknown() {
+		v.SpecificType = other.SpecificType
+	}
+
+	if (v.Type.IsUnknown() || v.Type.IsNull()) && !other.Type.IsUnknown() {
+		v.Type = other.Type
+	}
+
+}
diff --git a/ovh/provider.go b/ovh/provider.go
index 6e7c5cc2..be892692 100644
--- a/ovh/provider.go
+++ b/ovh/provider.go
@@ -156,6 +156,7 @@ func Provider() *schema.Provider {
 			"ovh_dbaas_logs_clusters":                                        dataSourceDbaasLogsClusters(),
 			"ovh_dbaas_logs_input_engine":                                    dataSourceDbaasLogsInputEngine(),
 			"ovh_dbaas_logs_output_graylog_stream":                           dataSourceDbaasLogsOutputGraylogStream(),
+			"ovh_dbaas_logs_output_graylog_stream_url":                       dataSourceDbaasLogsOutputGraylogStreamURL(),
 			"ovh_dbaas_logs_output_opensearch_index":                         dataSourceDbaasLogsOutputOpensearchIndex(),
 			"ovh_dedicated_ceph":                                             dataSourceDedicatedCeph(),
 			"ovh_dedicated_installation_templates":                           dataSourceDedicatedInstallationTemplates(),
diff --git a/ovh/provider_new.go b/ovh/provider_new.go
index 6bbda9ff..04381620 100644
--- a/ovh/provider_new.go
+++ b/ovh/provider_new.go
@@ -211,6 +211,7 @@ func (p *OvhProvider) DataSources(_ context.Context) []func() datasource.DataSou
 		NewCloudProjectFlavorDataSource,
 		NewCloudProjectFlavorsDataSource,
 		NewCloudProjectFloatingipsDataSource,
+		NewCloudProjectGatewayDataSource,
 		NewCloudProjectGatewayInterfaceDataSource,
 		NewCloudProjectImageDataSource,
 		NewCloudProjectImagesDataSource,
@@ -243,6 +244,7 @@ func (p *OvhProvider) DataSources(_ context.Context) []func() datasource.DataSou
 		NewIpFirewallDataSource,
 		NewIpFirewallRuleDataSource,
 		NewIpMitigationDataSource,
+		NewLocationDataSource,
 		NewOkmsCredentialDataSource,
 		NewOkmsResourceDataSource,
 		NewOkmsServiceKeyDataSource,
diff --git a/ovh/resource_cloud_project_containerregistry_oidc.go b/ovh/resource_cloud_project_containerregistry_oidc.go
index e6fc72e4..6e485183 100644
--- a/ovh/resource_cloud_project_containerregistry_oidc.go
+++ b/ovh/resource_cloud_project_containerregistry_oidc.go
@@ -7,6 +7,7 @@ import (
 	"time"
 
 	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
+	"github.com/ovh/go-ovh/ovh"
 )
 
 func resourceCloudProjectContainerRegistryOIDC() *schema.Resource {
@@ -148,6 +149,12 @@ func resourceCloudProjectContainerRegistryOIDCRead(d *schema.ResourceData, meta
 	log.Printf("[DEBUG] Will read oidc from registry %s and project: %s", registryID, serviceName)
 	err := config.OVHClient.Get(endpoint, res)
 	if err != nil {
+		if ovhErr, ok := err.(*ovh.APIError); ok && ovhErr.Code == 404 {
+			// If the resource does not exist, remove it from the state to force recreation
+			log.Printf("[DEBUG] Registry %s OIDC does not exist, removing from state", registryID)
+			d.SetId("")
+			return nil
+		}
 		return fmt.Errorf("calling get %s %w", endpoint, err)
 	}
 	for k, v := range res.ToMap() {
diff --git a/ovh/resource_cloud_project_instance.go b/ovh/resource_cloud_project_instance.go
index e6f84813..5f28b566 100644
--- a/ovh/resource_cloud_project_instance.go
+++ b/ovh/resource_cloud_project_instance.go
@@ -5,6 +5,7 @@ import (
 	"fmt"
 	"log"
 	"net/url"
+	"time"
 
 	"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
 	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -522,6 +523,8 @@ func resourceCloudProjectInstanceDelete(ctx context.Context, d *schema.ResourceD
 
 	d.SetId("")
 
+	time.Sleep(time.Second * 20) // Wait a bit to ensure the instance is deleted before returning
+
 	log.Printf("[DEBUG] Deleted Public Cloud %s Instance %s", serviceName, id)
 	return nil
 }
diff --git a/ovh/resource_cloud_project_kube.go b/ovh/resource_cloud_project_kube.go
index 6feba8fe..8e9f1aec 100644
--- a/ovh/resource_cloud_project_kube.go
+++ b/ovh/resource_cloud_project_kube.go
@@ -24,6 +24,7 @@ const (
 	kubeClusterPrivateNetworkConfigurationKey = "private_network_configuration"
 	kubeClusterUpdatePolicyKey                = "update_policy"
 	kubeClusterVersionKey                     = "version"
+	kubeClusterPlanKey                        = "plan"
 
 	kubeClusterProxyModeKey = "kube_proxy_mode"
 
@@ -69,6 +70,13 @@ func resourceCloudProjectKube() *schema.Resource {
 				Optional: true,
 				ForceNew: false,
 			},
+			kubeClusterPlanKey: {
+				Type:         schema.TypeString,
+				Computed:     true,
+				Optional:     true,
+				ForceNew:     false,
+				ValidateFunc: helpers.ValidateEnum([]string{"standard", "free"}),
+			},
 			kubeClusterCustomizationApiServerKey: {
 				Type:          schema.TypeSet,
 				Computed:      true,
@@ -624,6 +632,17 @@ func resourceCloudProjectKubeUpdate(d *schema.ResourceData, meta interface{}) er
 		log.Printf("[DEBUG] kube %s is READY", d.Id())
 	}
 
+	if d.HasChanges(kubeClusterPlanKey) {
+		oldValue, newValue := d.GetChange(kubeClusterPlanKey)
+		newPlan := newValue.(string)
+		oldPlan := oldValue.(string)
+		if oldPlan == "standard" {
+			return fmt.Errorf("you cannot migrate from %s to %s", oldPlan, newPlan)
+		}
+
+		return fmt.Errorf("migrate from %s to %s is not available yet", oldPlan, newPlan)
+	}
+
 	if d.HasChange(kubeClusterUpdatePolicyKey) {
 		_, newValue := d.GetChange(kubeClusterUpdatePolicyKey)
 		value := newValue.(string)
diff --git a/ovh/resource_cloud_project_region.go b/ovh/resource_cloud_project_region.go
index bbdea7b6..10b8b63d 100644
--- a/ovh/resource_cloud_project_region.go
+++ b/ovh/resource_cloud_project_region.go
@@ -6,6 +6,7 @@ import (
 	"net/url"
 
 	"github.com/hashicorp/terraform-plugin-framework/resource"
+	ovhtypes "github.com/ovh/terraform-provider-ovh/v2/ovh/types"
 )
 
 var _ resource.ResourceWithConfigure = (*cloudProjectRegionResource)(nil)
@@ -62,6 +63,7 @@ func (r *cloudProjectRegionResource) Create(ctx context.Context, req resource.Cr
 	}
 
 	responseData.MergeWith(&data)
+	responseData.ID = ovhtypes.NewTfStringValue(responseData.Region.ValueString())
 
 	// Save data into Terraform state
 	resp.Diagnostics.Append(resp.State.Set(ctx, &responseData)...)
diff --git a/ovh/resource_cloud_project_region_gen.go b/ovh/resource_cloud_project_region_gen.go
index dda142c5..cf62f7be 100644
--- a/ovh/resource_cloud_project_region_gen.go
+++ b/ovh/resource_cloud_project_region_gen.go
@@ -22,6 +22,11 @@ import (
 
 func CloudProjectRegionResourceSchema(ctx context.Context) schema.Schema {
 	attrs := map[string]schema.Attribute{
+		"id": schema.StringAttribute{
+			CustomType:  ovhtypes.TfStringType{},
+			Computed:    true,
+			Description: "Unique identifier for the resource",
+		},
 		"availability_zones": schema.ListAttribute{
 			CustomType:          ovhtypes.NewTfListNestedType[ovhtypes.TfStringValue](ctx),
 			Computed:            true,
@@ -136,6 +141,7 @@ func CloudProjectRegionResourceSchema(ctx context.Context) schema.Schema {
 }
 
 type CloudProjectRegionModel struct {
+	ID                 ovhtypes.TfStringValue                             `tfsdk:"id" json:"-"`
 	AvailabilityZones  ovhtypes.TfListNestedValue[ovhtypes.TfStringValue] `tfsdk:"availability_zones" json:"availabilityZones"`
 	ContinentCode      ovhtypes.TfStringValue                             `tfsdk:"continent_code" json:"continentCode"`
 	CountryCode        ovhtypes.TfStringValue                             `tfsdk:"country_code" json:"countryCode"`
@@ -151,6 +157,9 @@ type CloudProjectRegionModel struct {
 }
 
 func (v *CloudProjectRegionModel) MergeWith(other *CloudProjectRegionModel) {
+	if (v.ID.IsUnknown() || v.ID.IsNull()) && !other.ID.IsUnknown() {
+		v.ID = other.ID
+	}
 
 	if (v.AvailabilityZones.IsUnknown() || v.AvailabilityZones.IsNull()) && !other.AvailabilityZones.IsUnknown() {
 		v.AvailabilityZones = other.AvailabilityZones
diff --git a/ovh/resource_cloud_project_storage.go b/ovh/resource_cloud_project_storage.go
index 3aca06e7..df1a8072 100644
--- a/ovh/resource_cloud_project_storage.go
+++ b/ovh/resource_cloud_project_storage.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"fmt"
 	"net/url"
+	"strconv"
 	"strings"
 
 	"github.com/hashicorp/terraform-plugin-framework/path"
@@ -91,7 +92,19 @@ func (r *cloudProjectStorageResource) Read(ctx context.Context, req resource.Rea
 		return
 	}
 
-	endpoint := "/cloud/project/" + url.PathEscape(data.ServiceName.ValueString()) + "/region/" + url.PathEscape(data.RegionName.ValueString()) + "/storage/" + url.PathEscape(data.Name.ValueString())
+	// Add filters if defined
+	queryParams := url.Values{}
+	if !data.Limit.IsNull() && !data.Limit.IsUnknown() {
+		queryParams.Add("limit", strconv.FormatInt(data.Limit.ValueInt64(), 10))
+	}
+	if !data.Marker.IsNull() && !data.Marker.IsUnknown() {
+		queryParams.Add("marker", data.Marker.ValueString())
+	}
+	if !data.Prefix.IsNull() && !data.Prefix.IsUnknown() {
+		queryParams.Add("prefix", data.Prefix.ValueString())
+	}
+
+	endpoint := "/cloud/project/" + url.PathEscape(data.ServiceName.ValueString()) + "/region/" + url.PathEscape(data.RegionName.ValueString()) + "/storage/" + url.PathEscape(data.Name.ValueString()) + "?" + queryParams.Encode()
 	if err := r.config.OVHClient.Get(endpoint, &responseData); err != nil {
 		resp.Diagnostics.AddError(
 			fmt.Sprintf("Error calling Get %s", endpoint),
@@ -100,10 +113,10 @@ func (r *cloudProjectStorageResource) Read(ctx context.Context, req resource.Rea
 		return
 	}
 
-	data.MergeWith(&responseData)
+	responseData.MergeWith(&data)
 
 	// Save updated data into Terraform state
-	resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
+	resp.Diagnostics.Append(resp.State.Set(ctx, &responseData)...)
 }
 
 func (r *cloudProjectStorageResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
@@ -131,8 +144,20 @@ func (r *cloudProjectStorageResource) Update(ctx context.Context, req resource.U
 		return
 	}
 
+	// Add filters if defined
+	queryParams := url.Values{}
+	if !planData.Limit.IsNull() && !planData.Limit.IsUnknown() {
+		queryParams.Add("limit", strconv.FormatInt(planData.Limit.ValueInt64(), 10))
+	}
+	if !planData.Marker.IsNull() && !planData.Marker.IsUnknown() {
+		queryParams.Add("marker", planData.Marker.ValueString())
+	}
+	if !planData.Prefix.IsNull() && !planData.Prefix.IsUnknown() {
+		queryParams.Add("prefix", planData.Prefix.ValueString())
+	}
+
 	// Read updated resource
-	endpoint = "/cloud/project/" + url.PathEscape(data.ServiceName.ValueString()) + "/region/" + url.PathEscape(data.RegionName.ValueString()) + "/storage/" + url.PathEscape(data.Name.ValueString())
+	endpoint = "/cloud/project/" + url.PathEscape(data.ServiceName.ValueString()) + "/region/" + url.PathEscape(data.RegionName.ValueString()) + "/storage/" + url.PathEscape(data.Name.ValueString()) + "?" + queryParams.Encode()
 	if err := r.config.OVHClient.Get(endpoint, &responseData); err != nil {
 		resp.Diagnostics.AddError(
 			fmt.Sprintf("Error calling Get %s", endpoint),
diff --git a/ovh/resource_cloud_project_region_storage_gen.go b/ovh/resource_cloud_project_storage_gen.go
similarity index 88%
rename from ovh/resource_cloud_project_region_storage_gen.go
rename to ovh/resource_cloud_project_storage_gen.go
index c9427573..6649d396 100644
--- a/ovh/resource_cloud_project_region_storage_gen.go
+++ b/ovh/resource_cloud_project_storage_gen.go
@@ -246,29 +246,8 @@ func CloudProjectRegionStorageResourceSchema(ctx context.Context) schema.Schema
 										Description:         "Prefix filter",
 										MarkdownDescription: "Prefix filter",
 									},
-									"tags": schema.ListNestedAttribute{
-										NestedObject: schema.NestedAttributeObject{
-											Attributes: map[string]schema.Attribute{
-												"key": schema.StringAttribute{
-													CustomType:          ovhtypes.TfStringType{},
-													Required:            true,
-													Description:         "Tag key",
-													MarkdownDescription: "Tag key",
-												},
-												"value": schema.StringAttribute{
-													CustomType:          ovhtypes.TfStringType{},
-													Required:            true,
-													Description:         "Tag value",
-													MarkdownDescription: "Tag value",
-												},
-											},
-											CustomType: ReplicationRulesFilterTagsType{
-												ObjectType: types.ObjectType{
-													AttrTypes: ReplicationRulesFilterTagsValue{}.AttributeTypes(ctx),
-												},
-											},
-										},
-										CustomType:          ovhtypes.NewTfListNestedType[ReplicationRulesFilterTagsValue](ctx),
+									"tags": schema.MapAttribute{
+										CustomType:          ovhtypes.NewTfMapNestedType[ovhtypes.TfStringValue](ctx),
 										Optional:            true,
 										Computed:            true,
 										Description:         "Tags filter",
@@ -429,29 +408,6 @@ func (v *CloudProjectRegionStorageModel) MergeWith(other *CloudProjectRegionStor
 		v.Name = other.Name
 	}
 
-	if (v.Objects.IsUnknown() || v.Objects.IsNull()) && !other.Objects.IsUnknown() {
-		v.Objects = other.Objects
-	} else if !other.Objects.IsUnknown() {
-		newSlice := make([]attr.Value, 0)
-		elems := v.Objects.Elements()
-		newElems := other.Objects.Elements()
-
-		if len(elems) != len(newElems) {
-			v.Objects = other.Objects
-		} else {
-			for idx, e := range elems {
-				tmp := e.(ObjectsValue)
-				tmp2 := newElems[idx].(ObjectsValue)
-				tmp.MergeWith(&tmp2)
-				newSlice = append(newSlice, tmp)
-			}
-
-			v.Objects = ovhtypes.TfListNestedValue[ObjectsValue]{
-				ListValue: basetypes.NewListValueMust(ObjectsValue{}.Type(context.Background()), newSlice),
-			}
-		}
-	}
-
 	if (v.ObjectsCount.IsUnknown() || v.ObjectsCount.IsNull()) && !other.ObjectsCount.IsUnknown() {
 		v.ObjectsCount = other.ObjectsCount
 	}
@@ -1965,10 +1921,9 @@ func (v *ReplicationValue) UnmarshalJSON(data []byte) error {
 }
 
 func (v *ReplicationValue) MergeWith(other *ReplicationValue) {
-
 	if (v.Rules.IsUnknown() || v.Rules.IsNull()) && !other.Rules.IsUnknown() {
 		v.Rules = other.Rules
-	} else if !other.Rules.IsUnknown() {
+	} else if !other.Rules.IsUnknown() && !other.Rules.IsNull() {
 		newSlice := make([]attr.Value, 0)
 		elems := v.Rules.Elements()
 		newElems := other.Rules.Elements()
@@ -3396,12 +3351,12 @@ func (t ReplicationRulesFilterType) ValueFromObject(ctx context.Context, in base
 		return nil, diags
 	}
 
-	tagsVal, ok := tagsAttribute.(ovhtypes.TfListNestedValue[ReplicationRulesFilterTagsValue])
+	tagsVal, ok := tagsAttribute.(ovhtypes.TfMapNestedValue[ovhtypes.TfStringValue])
 
 	if !ok {
 		diags.AddError(
 			"Attribute Wrong Type",
-			fmt.Sprintf(`tags expected to be ovhtypes.TfListNestedValue[ReplicationRulesFilterTagsValue], was: %T`, tagsAttribute))
+			fmt.Sprintf(`tags expected to be ovhtypes.TfMapNestedValue[ovhtypes.TfStringValue], was: %T`, tagsAttribute))
 	}
 
 	if diags.HasError() {
@@ -3506,12 +3461,12 @@ func NewReplicationRulesFilterValue(attributeTypes map[string]attr.Type, attribu
 		return NewReplicationRulesFilterValueUnknown(), diags
 	}
 
-	tagsVal, ok := tagsAttribute.(ovhtypes.TfListNestedValue[ReplicationRulesFilterTagsValue])
+	tagsVal, ok := tagsAttribute.(ovhtypes.TfMapNestedValue[ovhtypes.TfStringValue])
 
 	if !ok {
 		diags.AddError(
 			"Attribute Wrong Type",
-			fmt.Sprintf(`tags expected to be ovhtypes.TfListNestedValue[ReplicationRulesFilterTagsValue], was: %T`, tagsAttribute))
+			fmt.Sprintf(`tags expected to be ovhtypes.TfMapNestedValue[ovhtypes.TfStringValue], was: %T`, tagsAttribute))
 	}
 
 	if diags.HasError() {
@@ -3593,15 +3548,15 @@ func (t ReplicationRulesFilterType) ValueType(ctx context.Context) attr.Value {
 var _ basetypes.ObjectValuable = ReplicationRulesFilterValue{}
 
 type ReplicationRulesFilterValue struct {
-	Prefix ovhtypes.TfStringValue                                      `tfsdk:"prefix" json:"prefix"`
-	Tags   ovhtypes.TfListNestedValue[ReplicationRulesFilterTagsValue] `tfsdk:"tags" json:"tags"`
+	Prefix ovhtypes.TfStringValue                            `tfsdk:"prefix" json:"prefix"`
+	Tags   ovhtypes.TfMapNestedValue[ovhtypes.TfStringValue] `tfsdk:"tags" json:"tags"`
 	state  attr.ValueState
 }
 
 type ReplicationRulesFilterWritableValue struct {
 	*ReplicationRulesFilterValue `json:"-"`
-	Prefix                       *ovhtypes.TfStringValue                                      `json:"prefix,omitempty"`
-	Tags                         *ovhtypes.TfListNestedValue[ReplicationRulesFilterTagsValue] `json:"tags,omitempty"`
+	Prefix                       *ovhtypes.TfStringValue                            `json:"prefix,omitempty"`
+	Tags                         *ovhtypes.TfMapNestedValue[ovhtypes.TfStringValue] `json:"tags,omitempty"`
 }
 
 func (v ReplicationRulesFilterValue) ToCreate() *ReplicationRulesFilterWritableValue {
@@ -3655,25 +3610,6 @@ func (v *ReplicationRulesFilterValue) MergeWith(other *ReplicationRulesFilterVal
 
 	if (v.Tags.IsUnknown() || v.Tags.IsNull()) && !other.Tags.IsUnknown() {
 		v.Tags = other.Tags
-	} else if !other.Tags.IsUnknown() {
-		newSlice := make([]attr.Value, 0)
-		elems := v.Tags.Elements()
-		newElems := other.Tags.Elements()
-
-		if len(elems) != len(newElems) {
-			v.Tags = other.Tags
-		} else {
-			for idx, e := range elems {
-				tmp := e.(ReplicationRulesFilterTagsValue)
-				tmp2 := newElems[idx].(ReplicationRulesFilterTagsValue)
-				tmp.MergeWith(&tmp2)
-				newSlice = append(newSlice, tmp)
-			}
-
-			v.Tags = ovhtypes.TfListNestedValue[ReplicationRulesFilterTagsValue]{
-				ListValue: basetypes.NewListValueMust(ReplicationRulesFilterTagsValue{}.Type(context.Background()), newSlice),
-			}
-		}
 	}
 
 	if (v.state == attr.ValueStateUnknown || v.state == attr.ValueStateNull) && other.state != attr.ValueStateUnknown {
@@ -3694,8 +3630,8 @@ func (v ReplicationRulesFilterValue) ToTerraformValue(ctx context.Context) (tfty
 	var err error
 
 	attrTypes["prefix"] = basetypes.StringType{}.TerraformType(ctx)
-	attrTypes["tags"] = basetypes.ListType{
-		ElemType: ReplicationRulesFilterTagsValue{}.Type(ctx),
+	attrTypes["tags"] = basetypes.MapType{
+		ElemType: ovhtypes.TfStringType{},
 	}.TerraformType(ctx)
 
 	objectType := tftypes.Object{AttributeTypes: attrTypes}
@@ -3752,7 +3688,7 @@ func (v ReplicationRulesFilterValue) ToObjectValue(ctx context.Context) (basetyp
 	objVal, diags := types.ObjectValue(
 		map[string]attr.Type{
 			"prefix": ovhtypes.TfStringType{},
-			"tags":   ovhtypes.NewTfListNestedType[ReplicationRulesFilterTagsValue](ctx),
+			"tags":   ovhtypes.NewTfMapNestedType[ovhtypes.TfStringValue](ctx),
 		},
 		map[string]attr.Value{
 			"prefix": v.Prefix,
@@ -3799,446 +3735,7 @@ func (v ReplicationRulesFilterValue) Type(ctx context.Context) attr.Type {
 func (v ReplicationRulesFilterValue) AttributeTypes(ctx context.Context) map[string]attr.Type {
 	return map[string]attr.Type{
 		"prefix": ovhtypes.TfStringType{},
-		"tags":   ovhtypes.NewTfListNestedType[ReplicationRulesFilterTagsValue](ctx),
-	}
-}
-
-var _ basetypes.ObjectTypable = ReplicationRulesFilterTagsType{}
-
-type ReplicationRulesFilterTagsType struct {
-	basetypes.ObjectType
-}
-
-func (t ReplicationRulesFilterTagsType) Equal(o attr.Type) bool {
-	other, ok := o.(ReplicationRulesFilterTagsType)
-
-	if !ok {
-		return false
-	}
-
-	return t.ObjectType.Equal(other.ObjectType)
-}
-
-func (t ReplicationRulesFilterTagsType) String() string {
-	return "ReplicationRulesFilterTagsType"
-}
-
-func (t ReplicationRulesFilterTagsType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) {
-	var diags diag.Diagnostics
-
-	attributes := in.Attributes()
-
-	keyAttribute, ok := attributes["key"]
-
-	if !ok {
-		diags.AddError(
-			"Attribute Missing",
-			`key is missing from object`)
-
-		return nil, diags
-	}
-
-	keyVal, ok := keyAttribute.(ovhtypes.TfStringValue)
-
-	if !ok {
-		diags.AddError(
-			"Attribute Wrong Type",
-			fmt.Sprintf(`key expected to be ovhtypes.TfStringValue, was: %T`, keyAttribute))
-	}
-
-	valueAttribute, ok := attributes["value"]
-
-	if !ok {
-		diags.AddError(
-			"Attribute Missing",
-			`value is missing from object`)
-
-		return nil, diags
-	}
-
-	valueVal, ok := valueAttribute.(ovhtypes.TfStringValue)
-
-	if !ok {
-		diags.AddError(
-			"Attribute Wrong Type",
-			fmt.Sprintf(`value expected to be ovhtypes.TfStringValue, was: %T`, valueAttribute))
-	}
-
-	if diags.HasError() {
-		return nil, diags
-	}
-
-	return ReplicationRulesFilterTagsValue{
-		Key:   keyVal,
-		Value: valueVal,
-		state: attr.ValueStateKnown,
-	}, diags
-}
-
-func NewReplicationRulesFilterTagsValueNull() ReplicationRulesFilterTagsValue {
-	return ReplicationRulesFilterTagsValue{
-		state: attr.ValueStateNull,
-	}
-}
-
-func NewReplicationRulesFilterTagsValueUnknown() ReplicationRulesFilterTagsValue {
-	return ReplicationRulesFilterTagsValue{
-		state: attr.ValueStateUnknown,
-	}
-}
-
-func NewReplicationRulesFilterTagsValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (ReplicationRulesFilterTagsValue, diag.Diagnostics) {
-	var diags diag.Diagnostics
-
-	// Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521
-	ctx := context.Background()
-
-	for name, attributeType := range attributeTypes {
-		attribute, ok := attributes[name]
-
-		if !ok {
-			diags.AddError(
-				"Missing ReplicationRulesFilterTagsValue Attribute Value",
-				"While creating a ReplicationRulesFilterTagsValue value, a missing attribute value was detected. "+
-					"A ReplicationRulesFilterTagsValue must contain values for all attributes, even if null or unknown. "+
-					"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
-					fmt.Sprintf("ReplicationRulesFilterTagsValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()),
-			)
-
-			continue
-		}
-
-		if !attributeType.Equal(attribute.Type(ctx)) {
-			diags.AddError(
-				"Invalid ReplicationRulesFilterTagsValue Attribute Type",
-				"While creating a ReplicationRulesFilterTagsValue value, an invalid attribute value was detected. "+
-					"A ReplicationRulesFilterTagsValue must use a matching attribute type for the value. "+
-					"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
-					fmt.Sprintf("ReplicationRulesFilterTagsValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+
-					fmt.Sprintf("ReplicationRulesFilterTagsValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)),
-			)
-		}
-	}
-
-	for name := range attributes {
-		_, ok := attributeTypes[name]
-
-		if !ok {
-			diags.AddError(
-				"Extra ReplicationRulesFilterTagsValue Attribute Value",
-				"While creating a ReplicationRulesFilterTagsValue value, an extra attribute value was detected. "+
-					"A ReplicationRulesFilterTagsValue must not contain values beyond the expected attribute types. "+
-					"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
-					fmt.Sprintf("Extra ReplicationRulesFilterTagsValue Attribute Name: %s", name),
-			)
-		}
-	}
-
-	if diags.HasError() {
-		return NewReplicationRulesFilterTagsValueUnknown(), diags
-	}
-
-	keyAttribute, ok := attributes["key"]
-
-	if !ok {
-		diags.AddError(
-			"Attribute Missing",
-			`key is missing from object`)
-
-		return NewReplicationRulesFilterTagsValueUnknown(), diags
-	}
-
-	keyVal, ok := keyAttribute.(ovhtypes.TfStringValue)
-
-	if !ok {
-		diags.AddError(
-			"Attribute Wrong Type",
-			fmt.Sprintf(`key expected to be ovhtypes.TfStringValue, was: %T`, keyAttribute))
-	}
-
-	valueAttribute, ok := attributes["value"]
-
-	if !ok {
-		diags.AddError(
-			"Attribute Missing",
-			`value is missing from object`)
-
-		return NewReplicationRulesFilterTagsValueUnknown(), diags
-	}
-
-	valueVal, ok := valueAttribute.(ovhtypes.TfStringValue)
-
-	if !ok {
-		diags.AddError(
-			"Attribute Wrong Type",
-			fmt.Sprintf(`value expected to be ovhtypes.TfStringValue, was: %T`, valueAttribute))
-	}
-
-	if diags.HasError() {
-		return NewReplicationRulesFilterTagsValueUnknown(), diags
-	}
-
-	return ReplicationRulesFilterTagsValue{
-		Key:   keyVal,
-		Value: valueVal,
-		state: attr.ValueStateKnown,
-	}, diags
-}
-
-func NewReplicationRulesFilterTagsValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) ReplicationRulesFilterTagsValue {
-	object, diags := NewReplicationRulesFilterTagsValue(attributeTypes, attributes)
-
-	if diags.HasError() {
-		// This could potentially be added to the diag package.
-		diagsStrings := make([]string, 0, len(diags))
-
-		for _, diagnostic := range diags {
-			diagsStrings = append(diagsStrings, fmt.Sprintf(
-				"%s | %s | %s",
-				diagnostic.Severity(),
-				diagnostic.Summary(),
-				diagnostic.Detail()))
-		}
-
-		panic("NewReplicationRulesFilterTagsValueMust received error(s): " + strings.Join(diagsStrings, "\n"))
-	}
-
-	return object
-}
-
-func (t ReplicationRulesFilterTagsType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) {
-	if in.Type() == nil {
-		return NewReplicationRulesFilterTagsValueNull(), nil
-	}
-
-	if !in.Type().Equal(t.TerraformType(ctx)) {
-		return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type())
-	}
-
-	if !in.IsKnown() {
-		return NewReplicationRulesFilterTagsValueUnknown(), nil
-	}
-
-	if in.IsNull() {
-		return NewReplicationRulesFilterTagsValueNull(), nil
-	}
-
-	attributes := map[string]attr.Value{}
-
-	val := map[string]tftypes.Value{}
-
-	err := in.As(&val)
-
-	if err != nil {
-		return nil, err
-	}
-
-	for k, v := range val {
-		a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v)
-
-		if err != nil {
-			return nil, err
-		}
-
-		attributes[k] = a
-	}
-
-	return NewReplicationRulesFilterTagsValueMust(ReplicationRulesFilterTagsValue{}.AttributeTypes(ctx), attributes), nil
-}
-
-func (t ReplicationRulesFilterTagsType) ValueType(ctx context.Context) attr.Value {
-	return ReplicationRulesFilterTagsValue{}
-}
-
-var _ basetypes.ObjectValuable = ReplicationRulesFilterTagsValue{}
-
-type ReplicationRulesFilterTagsValue struct {
-	Key   ovhtypes.TfStringValue `tfsdk:"key" json:"key"`
-	Value ovhtypes.TfStringValue `tfsdk:"value" json:"value"`
-	state attr.ValueState
-}
-
-type ReplicationRulesFilterTagsWritableValue struct {
-	*ReplicationRulesFilterTagsValue `json:"-"`
-	Key                              *ovhtypes.TfStringValue `json:"key,omitempty"`
-	Value                            *ovhtypes.TfStringValue `json:"value,omitempty"`
-}
-
-func (v ReplicationRulesFilterTagsValue) ToCreate() *ReplicationRulesFilterTagsWritableValue {
-	res := &ReplicationRulesFilterTagsWritableValue{}
-
-	if !v.Key.IsNull() {
-		res.Key = &v.Key
-	}
-
-	if !v.Value.IsNull() {
-		res.Value = &v.Value
-	}
-
-	return res
-}
-
-func (v ReplicationRulesFilterTagsValue) ToUpdate() *ReplicationRulesFilterTagsWritableValue {
-	res := &ReplicationRulesFilterTagsWritableValue{}
-
-	if !v.Key.IsNull() {
-		res.Key = &v.Key
-	}
-
-	if !v.Value.IsNull() {
-		res.Value = &v.Value
-	}
-
-	return res
-}
-
-func (v *ReplicationRulesFilterTagsValue) UnmarshalJSON(data []byte) error {
-	type JsonReplicationRulesFilterTagsValue ReplicationRulesFilterTagsValue
-
-	var tmp JsonReplicationRulesFilterTagsValue
-	if err := json.Unmarshal(data, &tmp); err != nil {
-		return err
-	}
-	v.Key = tmp.Key
-	v.Value = tmp.Value
-
-	v.state = attr.ValueStateKnown
-
-	return nil
-}
-
-func (v *ReplicationRulesFilterTagsValue) MergeWith(other *ReplicationRulesFilterTagsValue) {
-
-	if (v.Key.IsUnknown() || v.Key.IsNull()) && !other.Key.IsUnknown() {
-		v.Key = other.Key
-	}
-
-	if (v.Value.IsUnknown() || v.Value.IsNull()) && !other.Value.IsUnknown() {
-		v.Value = other.Value
-	}
-
-	if (v.state == attr.ValueStateUnknown || v.state == attr.ValueStateNull) && other.state != attr.ValueStateUnknown {
-		v.state = other.state
-	}
-}
-
-func (v ReplicationRulesFilterTagsValue) Attributes() map[string]attr.Value {
-	return map[string]attr.Value{
-		"key":   v.Key,
-		"value": v.Value,
-	}
-}
-func (v ReplicationRulesFilterTagsValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) {
-	attrTypes := make(map[string]tftypes.Type, 2)
-
-	var val tftypes.Value
-	var err error
-
-	attrTypes["key"] = basetypes.StringType{}.TerraformType(ctx)
-	attrTypes["value"] = basetypes.StringType{}.TerraformType(ctx)
-
-	objectType := tftypes.Object{AttributeTypes: attrTypes}
-
-	switch v.state {
-	case attr.ValueStateKnown:
-		vals := make(map[string]tftypes.Value, 2)
-
-		val, err = v.Key.ToTerraformValue(ctx)
-
-		if err != nil {
-			return tftypes.NewValue(objectType, tftypes.UnknownValue), err
-		}
-
-		vals["key"] = val
-
-		val, err = v.Value.ToTerraformValue(ctx)
-
-		if err != nil {
-			return tftypes.NewValue(objectType, tftypes.UnknownValue), err
-		}
-
-		vals["value"] = val
-
-		if err := tftypes.ValidateValue(objectType, vals); err != nil {
-			return tftypes.NewValue(objectType, tftypes.UnknownValue), err
-		}
-
-		return tftypes.NewValue(objectType, vals), nil
-	case attr.ValueStateNull:
-		return tftypes.NewValue(objectType, nil), nil
-	case attr.ValueStateUnknown:
-		return tftypes.NewValue(objectType, tftypes.UnknownValue), nil
-	default:
-		panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state))
-	}
-}
-
-func (v ReplicationRulesFilterTagsValue) IsNull() bool {
-	return v.state == attr.ValueStateNull
-}
-
-func (v ReplicationRulesFilterTagsValue) IsUnknown() bool {
-	return v.state == attr.ValueStateUnknown
-}
-
-func (v ReplicationRulesFilterTagsValue) String() string {
-	return "ReplicationRulesFilterTagsValue"
-}
-
-func (v ReplicationRulesFilterTagsValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) {
-	var diags diag.Diagnostics
-
-	objVal, diags := types.ObjectValue(
-		map[string]attr.Type{
-			"key":   ovhtypes.TfStringType{},
-			"value": ovhtypes.TfStringType{},
-		},
-		map[string]attr.Value{
-			"key":   v.Key,
-			"value": v.Value,
-		})
-
-	return objVal, diags
-}
-
-func (v ReplicationRulesFilterTagsValue) Equal(o attr.Value) bool {
-	other, ok := o.(ReplicationRulesFilterTagsValue)
-
-	if !ok {
-		return false
-	}
-
-	if v.state != other.state {
-		return false
-	}
-
-	if v.state != attr.ValueStateKnown {
-		return true
-	}
-
-	if !v.Key.Equal(other.Key) {
-		return false
-	}
-
-	if !v.Value.Equal(other.Value) {
-		return false
-	}
-
-	return true
-}
-
-func (v ReplicationRulesFilterTagsValue) Type(ctx context.Context) attr.Type {
-	return ReplicationRulesFilterTagsType{
-		basetypes.ObjectType{
-			AttrTypes: v.AttributeTypes(ctx),
-		},
-	}
-}
-
-func (v ReplicationRulesFilterTagsValue) AttributeTypes(ctx context.Context) map[string]attr.Type {
-	return map[string]attr.Type{
-		"key":   ovhtypes.TfStringType{},
-		"value": ovhtypes.TfStringType{},
+		"tags":   ovhtypes.NewTfMapNestedType[ovhtypes.TfStringValue](ctx),
 	}
 }
 
diff --git a/ovh/resource_dbaas_logs_output_graylog_stream.go b/ovh/resource_dbaas_logs_output_graylog_stream.go
index 202ccd1c..bebbcb55 100644
--- a/ovh/resource_dbaas_logs_output_graylog_stream.go
+++ b/ovh/resource_dbaas_logs_output_graylog_stream.go
@@ -35,7 +35,7 @@ func resourceDbaasLogsOutputGraylogStream() *schema.Resource {
 			},
 			"title": {
 				Type:        schema.TypeString,
-				Description: "Stream description",
+				Description: "Stream name",
 				Required:    true,
 			},
 
diff --git a/ovh/resource_domain_zone_record.go b/ovh/resource_domain_zone_record.go
index 8af4d1c1..bf11bd4e 100644
--- a/ovh/resource_domain_zone_record.go
+++ b/ovh/resource_domain_zone_record.go
@@ -124,7 +124,7 @@ func resourceOvhDomainZoneRecordCreate(d *schema.ResourceData, meta interface{})
 	// this is an API response BUG known by OVH team
 	// with no planned fix
 	// Workaround is to filter records matching the attributes
-	// and keep the last id if there are doublons
+	// and keep the last id if there are duplicates
 	if resultRecord.Id == 0 {
 		log.Printf("[WARN] Known OVH API Bug with Inconsistency API result (id = 0): %v", resultRecord)
 		records := make([]int, 0)
@@ -172,13 +172,14 @@ func resourceOvhDomainZoneRecordRead(d *schema.ResourceData, meta interface{}) e
 	config := meta.(*Config)
 
 	record, err := ovhDomainZoneRecord(config.OVHClient, d, d.Id(), d.IsNewResource())
-
 	if err != nil {
 		return err
 	}
 
 	if record == nil {
-		return fmt.Errorf("record %v has been deleted.", d.Id())
+		// ID already set to "", so just return
+		log.Print("record has been deleted")
+		return nil
 	}
 
 	d.Set("zone", record.Zone)
diff --git a/ovh/types_cloud_project_kube.go b/ovh/types_cloud_project_kube.go
index 77eb0941..1cd9b2ac 100644
--- a/ovh/types_cloud_project_kube.go
+++ b/ovh/types_cloud_project_kube.go
@@ -33,6 +33,7 @@ type CloudProjectKubeCreateOpts struct {
 	PrivateNetworkConfiguration *privateNetworkConfiguration `json:"privateNetworkConfiguration,omitempty"`
 	Region                      string                       `json:"region"`
 	Version                     *string                      `json:"version,omitempty"`
+	Plan                        *string                      `json:"plan,omitempty"`
 	UpdatePolicy                *string                      `json:"updatePolicy,omitempty"`
 	Customization               *Customization               `json:"customization,omitempty"`
 	KubeProxyMode               *string                      `json:"kubeProxyMode,omitempty"`
@@ -76,6 +77,7 @@ type AdmissionPlugins struct {
 func (opts *CloudProjectKubeCreateOpts) FromResource(d *schema.ResourceData) {
 	opts.Region = d.Get("region").(string)
 	opts.Version = helpers.GetNilStringPointerFromData(d, "version")
+	opts.Plan = helpers.GetNilStringPointerFromData(d, kubeClusterPlanKey)
 	opts.Name = helpers.GetNilStringPointerFromData(d, "name")
 	opts.UpdatePolicy = helpers.GetNilStringPointerFromData(d, "update_policy")
 	opts.LoadBalancersSubnetId = helpers.GetNilStringPointerFromData(d, "load_balancers_subnet_id")
@@ -275,6 +277,7 @@ type CloudProjectKubeResponse struct {
 	UpdatePolicy           string        `json:"updatePolicy"`
 	Url                    string        `json:"url"`
 	Version                string        `json:"version"`
+	Plan                   string        `json:"plan"`
 	Customization          Customization `json:"customization"`
 	KubeProxyMode          string        `json:"kubeProxyMode"`
 }
@@ -294,6 +297,7 @@ func (v *CloudProjectKubeResponse) ToMap(d *schema.ResourceData) map[string]inte
 	obj["status"] = v.Status
 	obj["update_policy"] = v.UpdatePolicy
 	obj["url"] = v.Url
+	obj[kubeClusterPlanKey] = v.Plan
 	versionPatch, err := version.NewVersion(v.Version)
 	if err != nil {
 		// if fail, return to the previous implementation
diff --git a/ovh/types_dbaas_logs_output_graylog_stream.go b/ovh/types_dbaas_logs_output_graylog_stream.go
index 95c21743..8d7ddefa 100644
--- a/ovh/types_dbaas_logs_output_graylog_stream.go
+++ b/ovh/types_dbaas_logs_output_graylog_stream.go
@@ -160,3 +160,9 @@ type DbaasLogsOutputGraylogStreamRule struct {
 	Field string `json:"field"`
 	Value string `json:"value"`
 }
+
+// DbaasLogsOutputGraylogStreamURL represents a URL entry for a Graylog stream.
+type DbaasLogsOutputGraylogStreamURL struct {
+	Address string `json:"address"`
+	Type    string `json:"type"`
+}
diff --git a/templates/data-sources/cloud_project_gateway.md.tmpl b/templates/data-sources/cloud_project_gateway.md.tmpl
new file mode 100644
index 00000000..705ebdf4
--- /dev/null
+++ b/templates/data-sources/cloud_project_gateway.md.tmpl
@@ -0,0 +1,56 @@
+---
+subcategory: "Gateway"
+---
+
+# ovh_cloud_project_gateway (Data Source)
+
+Get gateway
+
+## Example Usage
+
+{{tffile "examples/data-sources/ovh_cloud_project_gateway/data-source.tf"}}
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `id` (String) Id
+- `region` (String) Gateway region
+- `service_name` (String) Service name
+
+### Read-Only
+
+- `external_information` (Attributes) External information (see [below for nested schema](#nestedatt--external_information))
+- `interfaces` (Attributes List) Interfaces list of the gateway (see [below for nested schema](#nestedatt--interfaces))
+- `model` (String) Model of the gateway
+- `name` (String) Name of the gateway
+- `status` (String) Status of the gateway
+
+<a id="nestedatt--external_information"></a>
+### Nested Schema for `external_information`
+
+Read-Only:
+
+- `ips` (Attributes List) External ips of the gateway (see [below for nested schema](#nestedatt--external_information--ips))
+- `network_id` (String) External network ID of the gateway
+
+<a id="nestedatt--external_information--ips"></a>
+### Nested Schema for `external_information.ips`
+
+Read-Only:
+
+- `ip` (String) External IP of the gateway
+- `subnet_id` (String) Subnet ID of the ip
+
+
+
+<a id="nestedatt--interfaces"></a>
+### Nested Schema for `interfaces`
+
+Read-Only:
+
+- `id` (String) ID of the interface
+- `ip` (String) IP of the interface
+- `network_id` (String) Network ID of the interface
+- `subnet_id` (String) Subnet ID of the interface
diff --git a/templates/data-sources/cloud_project_kube.md.tmpl b/templates/data-sources/cloud_project_kube.md.tmpl
index 79eb910e..ed74c8e3 100644
--- a/templates/data-sources/cloud_project_kube.md.tmpl
+++ b/templates/data-sources/cloud_project_kube.md.tmpl
@@ -30,6 +30,7 @@ The following attributes are exported:
 * `name` - The name of the managed kubernetes cluster.
 * `region` - The OVHcloud public cloud region ID of the managed kubernetes cluster.
 * `version` - Kubernetes version of the managed kubernetes cluster.
+* `plan` - Plan of the managed kubernetes cluster.
 * `private_network_id` - OpenStack private network (or vrack) ID to use.
 * `load_balancers_subnet_id` - Openstack private network (or vRack) ID to use for load balancers.
 * `nodes_subnet_id` - Openstack private network (or vRack) ID to use for nodes.
@@ -40,6 +41,12 @@ The following attributes are exported:
 * `status` - Cluster status. Should be normally set to 'READY'.
 * `update_policy` - Cluster update policy. Choose between [ALWAYS_UPDATE,MINIMAL_DOWNTIME,NEVER_UPDATE]'.
 * `url` - Management URL of your cluster.
+* `kubeconfig` - (Sensitive) Raw kubeconfig file content for connecting to the cluster.
+* `kubeconfig_attributes` - (Sensitive) Structured kubeconfig data for connecting to the cluster.
+  * `host` - Kubernetes API server endpoint.
+  * `cluster_ca_certificate` - (Sensitive) Cluster certificate authority data.
+  * `client_certificate` - (Sensitive) Client certificate data for authentication.
+  * `client_key` - (Sensitive) Client private key data for authentication.
 * `kube_proxy_mode` - Selected mode for kube-proxy.
 * `customization` - **Deprecated** (Optional) Use `customization_apiserver` and `customization_kube_proxy` instead. Kubernetes cluster customization
   * `apiserver` - Kubernetes API server customization
diff --git a/templates/data-sources/dbaas_logs_output_graylog_stream.md.tmpl b/templates/data-sources/dbaas_logs_output_graylog_stream.md.tmpl
index 18899a2d..fb1fe423 100644
--- a/templates/data-sources/dbaas_logs_output_graylog_stream.md.tmpl
+++ b/templates/data-sources/dbaas_logs_output_graylog_stream.md.tmpl
@@ -17,7 +17,7 @@ Use this data source to retrieve information about a DBaas logs output graylog s
 ## Argument Reference
 
 * `service_name` - The service name. It's the ID of your Logs Data Platform instance.
-* `title` - Stream description
+* `title` - Stream name
 
 ## Attributes Reference
 
diff --git a/templates/data-sources/dbaas_logs_output_graylog_stream_url.md b/templates/data-sources/dbaas_logs_output_graylog_stream_url.md
new file mode 100644
index 00000000..aae20b2b
--- /dev/null
+++ b/templates/data-sources/dbaas_logs_output_graylog_stream_url.md
@@ -0,0 +1,29 @@
+---
+subcategory : "Logs Data Platform"
+---
+
+# ovh_dbaas_logs_output_graylog_stream_url (Data Source)
+
+Use this data source to retrieve the list of URLs for a DBaas logs output Graylog stream.
+
+## Example Usage
+
+```terraform
+data "ovh_dbaas_logs_output_graylog_stream_url" "urls" {
+  service_name = "ldp-xx-xxxxx"
+  stream_id    = "STREAM_ID"
+}
+```
+
+## Argument Reference
+
+* `service_name` - The service name. It's the ID of your Logs Data Platform instance.
+* `stream_id` - Stream ID.
+
+## Attributes Reference
+
+The following attributes are exported:
+
+* `url` - List of URLs. Each element contains:
+  * `address` - URL address
+  * `type` - URL type (e.g. `GRAYLOG_WEBUI`, `WEB_SOCKET`)
\ No newline at end of file
diff --git a/templates/data-sources/domain_zone.md.tmpl b/templates/data-sources/domain_zone.md.tmpl
index 81d19bbb..1338aafd 100644
--- a/templates/data-sources/domain_zone.md.tmpl
+++ b/templates/data-sources/domain_zone.md.tmpl
@@ -22,8 +22,8 @@ Use this data source to retrieve information about a domain zone.
 
 `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
 * `dnssec_supported` - Is DNSSEC supported by this zone
+* `urn` - URN of the DNS Zone to be used inside an IAM policy
diff --git a/templates/data-sources/location.md.tmpl b/templates/data-sources/location.md.tmpl
new file mode 100644
index 00000000..ade75c72
--- /dev/null
+++ b/templates/data-sources/location.md.tmpl
@@ -0,0 +1,36 @@
+---
+subcategory: "Location"
+---
+
+# ovh_location (Data Source)
+
+Get available regions and their availability zones
+
+## Example Usage
+
+{{tffile "examples/data-sources/ovh_location/data-source.tf"}}
+
+<!-- schema generated by tfplugindocs -->
+## Schema
+
+### Required
+
+- `name` (String) Name
+
+### Read-Only
+
+- `availability_zones` (List of String) List of availability zones for the region
+- `cardinal_point` (String) Cardinal direction where the region is located
+- `city_code` (String) ISO code of the city
+- `city_latitude` (Number) Geographical latitude of the city
+- `city_longitude` (Number) Geographical longitude of the city
+- `city_name` (String) Full name of the city
+- `code` (String) Region's short code
+- `country_code` (String) ISO code of the country
+- `country_name` (String) Full name of the country
+- `geography_code` (String) Short code representing the geographical area
+- `geography_name` (String) Name of the geographical area
+- `location` (String) Location of the region
+- `opening_year` (Number) Year the region was opened
+- `specific_type` (String) Specific typology of the region
+- `type` (String) General typology of the region
diff --git a/templates/data-sources/me_api_oauth2_client.md.tmpl b/templates/data-sources/me_api_oauth2_client.md.tmpl
index 987f89a8..e1aab72b 100644
--- a/templates/data-sources/me_api_oauth2_client.md.tmpl
+++ b/templates/data-sources/me_api_oauth2_client.md.tmpl
@@ -25,5 +25,6 @@ Use this data source to retrieve information about an existing OAuth2 service ac
 * `description` - OAuth2 client description.
 * `flow` - The OAuth2 flow to use. `AUTHORIZATION_CODE` or `CLIENT_CREDENTIALS` are supported at the moment.
 * `callback_urls` - List of callback urls when configuring the `AUTHORIZATION_CODE` flow.
+* `identity` - Identity URN of the service account to be used inside an IAM policy.
 
 The `client_secret` attribute is not supported in the Data Source. If you need this attribute to be in the state, see how to import a `ovh_me_api_oauth2_client` resource instead.
diff --git a/templates/resources/cloud_project_kube.md.tmpl b/templates/resources/cloud_project_kube.md.tmpl
index a3b09213..a240fd71 100644
--- a/templates/resources/cloud_project_kube.md.tmpl
+++ b/templates/resources/cloud_project_kube.md.tmpl
@@ -12,37 +12,37 @@ Creates a OVHcloud Managed Kubernetes Service cluster in a public cloud project.
 
 ## Example Usage
 
-Create a simple Kubernetes cluster in `GRA11` region:
+Create a simple Kubernetes Free cluster in `GRA11` region:
 
 {{tffile "examples/resources/cloud_project_kube/example_1.tf"}}
 
-Create a simple Kubernetes cluster in `GRA11` region and export its kubeconfig file:
+Create a simple Kubernetes Free cluster in `GRA11` region and export its kubeconfig file:
 
 {{tffile "examples/resources/cloud_project_kube/example_2.tf"}}
 
-Create a simple Kubernetes cluster in `GRA11` region and read kubeconfig attributes:
+Create a simple Kubernetes Free cluster in `GRA11` region and read kubeconfig attributes:
 
 -> Sensitive attributes cannot be displayed using `terraform output` command. You need to specify the output's name: `terraform output my_cluster_host`.
 
 {{tffile "examples/resources/cloud_project_kube/example_3.tf"}}
 
-Create a simple Kubernetes cluster in `GRA11` region and use kubeconfig with [Helm provider](https://registry.terraform.io/providers/hashicorp/helm/latest/docs):
+Create a simple Kubernetes Free cluster in `GRA11` region and use kubeconfig with [Helm provider](https://registry.terraform.io/providers/hashicorp/helm/latest/docs):
 
 {{tffile "examples/resources/cloud_project_kube/example_4.tf"}}
 
-Create a Kubernetes cluster in `GRA11` region with API Server AdmissionPlugins configuration:
+Create a Kubernetes Free cluster in `GRA11` region with API Server AdmissionPlugins configuration:
 
 {{tffile "examples/resources/cloud_project_kube/example_5.tf"}}
 
-Create a Kubernetes cluster in `GRA11` region with Kube proxy configuration, by specifying iptables or ipvs configurations:
+Create a Kubernetes Free cluster in `GRA11` region with Kube proxy configuration, by specifying iptables or ipvs configurations:
 
 {{tffile "examples/resources/cloud_project_kube/example_6.tf"}}
 
-Kubernetes cluster creation on a private network / subnet in `GRA11` region with a managed gateway:
+Kubernetes Free cluster creation on a private network / subnet in `GRA11` region with a managed gateway:
 
 {{tffile "examples/resources/cloud_project_kube/example_7.tf"}}
 
-Create a multi-zone Kubernetes cluster (on 3 availability zones):
+Create a multi-zone Kubernetes Standard cluster (on 3 availability zones):
 
 {{tffile "examples/resources/cloud_project_kube/example_10.tf"}}
 
@@ -54,6 +54,7 @@ The following arguments are supported:
 * `name` - (Optional) The name of the kubernetes cluster.
 * `region` - a valid OVHcloud public cloud region ID in which the kubernetes cluster will be available. Ex.: "GRA9". Defaults to all public cloud regions. **Changing this value recreates the resource.**
 * `version` - (Optional) kubernetes version to use. Changing this value updates the resource. Defaults to the latest available.
+* `plan` - (Optional) Plan of the MKS cluster `free` or `standard`. Default to `free`. Migration to another plan is not implemented yet.
 * `kube_proxy_mode` - (Optional) Selected mode for kube-proxy. **Changing this value recreates the resource, including ETCD user data.** Defaults to `iptables`.
 * `customization` - **Deprecated** (Optional) Use `customization_apiserver` and `customization_kube_proxy` instead. Kubernetes cluster customization
   * `apiserver` - Kubernetes API server customization
diff --git a/templates/resources/cloud_project_region.md.tmpl b/templates/resources/cloud_project_region.md.tmpl
index a763ad18..ece0c330 100644
--- a/templates/resources/cloud_project_region.md.tmpl
+++ b/templates/resources/cloud_project_region.md.tmpl
@@ -13,7 +13,7 @@ subcategory : "Cloud Project"
 
 ### Required
 
-- `region` (String) Region to add on your project
+- `region` (String) Region to add to your project
 - `service_name` (String) Service name
 
 ### Read-Only
diff --git a/templates/resources/cloud_project_storage.md.tmpl b/templates/resources/cloud_project_storage.md.tmpl
index d130a83c..4284c7a5 100644
--- a/templates/resources/cloud_project_storage.md.tmpl
+++ b/templates/resources/cloud_project_storage.md.tmpl
@@ -95,16 +95,7 @@ Optional:
 Optional:
 
 - `prefix` (String) Prefix filter
-- `tags` (Attributes List) Tags filter (see [below for nested schema](#nestedatt--replication--rules--filter--tags))
-
-<a id="nestedatt--replication--rules--filter--tags"></a>
-
-### Nested Schema for `replication.rules.filter.tags`
-
-Required:
-
-- `key` (String) Tag key
-- `value` (String) Tag value
+- `tags` (String to String Map) Tags filter
 
 <a id="nestedatt--versioning"></a>
 
diff --git a/templates/resources/cloud_project_user.md.tmpl b/templates/resources/cloud_project_user.md.tmpl
index 4e880746..1a80d0a1 100644
--- a/templates/resources/cloud_project_user.md.tmpl
+++ b/templates/resources/cloud_project_user.md.tmpl
@@ -30,7 +30,6 @@ The following arguments are supported:
 * `role_name` - The name of a role. See `role_names`.
 
 * `role_names` - A list of role names. Values can be:
-  - admin
   - administrator
   - ai_training_operator
   - ai_training_read
diff --git a/templates/resources/dbaas_logs_output_graylog_stream.md.tmpl b/templates/resources/dbaas_logs_output_graylog_stream.md.tmpl
index 187cbc5d..3cd88af3 100644
--- a/templates/resources/dbaas_logs_output_graylog_stream.md.tmpl
+++ b/templates/resources/dbaas_logs_output_graylog_stream.md.tmpl
@@ -22,8 +22,8 @@ To define the retention of the stream, you can use the following configuration:
 
 The following arguments are supported:
 * `service_name` - (Required) The service name
+* `title` - (Required) Stream name
 * `description` - (Required) Stream description
-* `title` - (Required) Stream description
 * `parent_stream_id` - Parent stream ID
 * `retention_id` - Retention ID
 * `cold_storage_compression` - Cold storage compression method. One of "LZMA", "GZIP", "DEFLATED", "ZSTD"
@@ -35,7 +35,7 @@ The following arguments are supported:
 * `indexing_enabled` - Enable ES indexing
 * `indexing_max_size` - Maximum indexing size (in GB)
 * `indexing_notify_enabled` - If set, notify when size is near 80, 90 or 100 % of the maximum configured setting
-* `pause_indexing_on_max_size` - If set, pause indexing when maximum size is reach
+* `pause_indexing_on_max_size` - If set, pause indexing when maximum size is reached
 * `web_socket_enabled` - Enable Websocket
 
 ## Attributes Reference
@@ -51,3 +51,11 @@ Id is set to the output stream Id. In addition, the following attributes are exp
 * `stream_id` - Stream ID
 * `updated_at` - Stream last updater
 * `write_token` - Write token of the stream (empty if the caller is not the owner of the stream)
+
+## Import
+
+DBaas logs output Graylog stream can be imported using the `service_name` of the cluster and `stream_id` of the graylog output stream, separated by "/" E.g.,
+
+```bash
+$ terraform import ovh_dbaas_logs_output_graylog_stream.ldp ldp-az-12345/9d2f9cf8-9f92-1337-c0f3-48a0213d2c6f
+```
\ No newline at end of file
diff --git a/templates/resources/dbaas_logs_output_opensearch_alias.md.tmpl b/templates/resources/dbaas_logs_output_opensearch_alias.md.tmpl
index 566ce9fe..96ce60f5 100644
--- a/templates/resources/dbaas_logs_output_opensearch_alias.md.tmpl
+++ b/templates/resources/dbaas_logs_output_opensearch_alias.md.tmpl
@@ -38,3 +38,11 @@ Id is set to the opensearch alias Id. In addition, the following attributes are
 * `nb_stream` - Number of streams linked
 * `streams` - List of attached streams id
 * `updated_at` - Input last update
+
+## Import
+
+DBaaS logs Opensearch output alias can be imported using the `service_name` and `alias_id`, separated by "/" E.g.,
+
+```bash
+$ terraform import ovh_dbaas_logs_output_opensearch_alias.this ldp-XX-NNNNN/7e2301b6-c0fe-41d9-bc58-44fd844f1e3e
+```
diff --git a/templates/resources/domain_zone.md.tmpl b/templates/resources/domain_zone.md.tmpl
index 9781f53f..a5129a4c 100644
--- a/templates/resources/domain_zone.md.tmpl
+++ b/templates/resources/domain_zone.md.tmpl
@@ -51,7 +51,7 @@ Id is set to the order Id. In addition, the following attributes are exported:
 * `last_update` - Last update date of the DNS zone
 * `name` - Zone name
 * `name_servers` - Name servers that host the DNS zone
-
+* `urn` - URN of the DNS Zone to be used inside an IAM policy
 * `order` - Details about an Order
   * `date` - date
   * `order_id` - order id
diff --git a/templates/resources/me_api_oauth2_client.md.tmpl b/templates/resources/me_api_oauth2_client.md.tmpl
index 817fd843..703a30d4 100644
--- a/templates/resources/me_api_oauth2_client.md.tmpl
+++ b/templates/resources/me_api_oauth2_client.md.tmpl
@@ -35,6 +35,7 @@ An OAuth2 client for an app hosted at `my-app.com`, that uses the client credent
 * `description` - OAuth2 client description.
 * `flow` - The OAuth2 flow to use. `AUTHORIZATION_CODE` or `CLIENT_CREDENTIALS` are supported at the moment.
 * `callback_urls` - List of callback urls when configuring the `AUTHORIZATION_CODE` flow.
+* `identity` - Identity URN of the service account to be used inside an IAM policy.
 
 ## Import
 



Test patch:
diff --git a/ovh/data_cloud_project_gateway_test.go b/ovh/data_cloud_project_gateway_test.go
new file mode 100644
index 00000000..a9cc84a7
--- /dev/null
+++ b/ovh/data_cloud_project_gateway_test.go
@@ -0,0 +1,73 @@
+package ovh
+
+import (
+	"fmt"
+	"os"
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccCloudProjectGatewayDataSource_basic(t *testing.T) {
+	gatewayName := acctest.RandomWithPrefix(test_prefix)
+
+	config := fmt.Sprintf(`
+			resource "ovh_cloud_project_network_private" "mypriv" {
+				service_name  = "%s"
+				vlan_id       = "%d"
+				name          = "%s"
+				regions       = ["GRA11"]
+			}
+
+			resource "ovh_cloud_project_network_private_subnet" "myprivsub" {
+				service_name  = ovh_cloud_project_network_private.mypriv.service_name
+				network_id    = ovh_cloud_project_network_private.mypriv.id
+				region        = "GRA11"
+				start         = "10.0.0.2"
+				end           = "10.0.0.8"
+				network       = "10.0.0.0/24"
+				dhcp          = true
+			}
+
+			resource "ovh_cloud_project_gateway" "gateway" {
+				service_name = ovh_cloud_project_network_private.mypriv.service_name
+				name          = "%s"
+				model         = "s"
+				region        = ovh_cloud_project_network_private_subnet.myprivsub.region
+				network_id    = tolist(ovh_cloud_project_network_private.mypriv.regions_attributes[*].openstackid)[0]
+				subnet_id     = ovh_cloud_project_network_private_subnet.myprivsub.id
+			}
+
+			data "ovh_cloud_project_gateway" "gateway" {
+				service_name = ovh_cloud_project_gateway.gateway.service_name
+				region       = ovh_cloud_project_gateway.gateway.region
+				id           = ovh_cloud_project_gateway.gateway.id
+			}
+		`,
+		os.Getenv("OVH_CLOUD_PROJECT_SERVICE_TEST"),
+		acctest.RandIntRange(100, 200),
+		acctest.RandomWithPrefix(test_prefix),
+		gatewayName,
+	)
+
+	resource.Test(t, resource.TestCase{
+		ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+		Steps: []resource.TestStep{
+			{
+				Config: config,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("data.ovh_cloud_project_gateway.gateway", "name", gatewayName),
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_gateway.gateway", "external_information.ips.#"),
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_gateway.gateway", "external_information.ips.0.ip"),
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_gateway.gateway", "external_information.ips.0.subnet_id"),
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_gateway.gateway", "interfaces.#"),
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_gateway.gateway", "interfaces.0.id"),
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_gateway.gateway", "interfaces.0.ip"),
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_gateway.gateway", "model"),
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_gateway.gateway", "status"),
+				),
+			},
+		},
+	})
+}
diff --git a/ovh/data_cloud_project_kube_test.go b/ovh/data_cloud_project_kube_test.go
index a873fd2d..2adb9129 100644
--- a/ovh/data_cloud_project_kube_test.go
+++ b/ovh/data_cloud_project_kube_test.go
@@ -37,6 +37,15 @@ func TestAccCloudProjectKubeDataSource_basic(t *testing.T) {
 					resource.TestCheckResourceAttr("data.ovh_cloud_project_kube.cluster", "region", region),
 					resource.TestCheckResourceAttr("data.ovh_cloud_project_kube.cluster", "name", name),
 					resource.TestMatchResourceAttr("data.ovh_cloud_project_kube.cluster", "version", matchVersion),
+
+					// Check kubeconfig is present and not empty
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_kube.cluster", "kubeconfig"),
+
+					// Check kubeconfig_attributes are present
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_kube.cluster", "kubeconfig_attributes.0.host"),
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_kube.cluster", "kubeconfig_attributes.0.cluster_ca_certificate"),
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_kube.cluster", "kubeconfig_attributes.0.client_certificate"),
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_kube.cluster", "kubeconfig_attributes.0.client_key"),
 				),
 			},
 		},
@@ -77,6 +86,15 @@ func TestAccCloudProjectKubeDataSource_kubeProxy(t *testing.T) {
 					resource.TestCheckResourceAttr("data.ovh_cloud_project_kube.cluster", "customization_kube_proxy.0.ipvs.0.tcp_fin_timeout", "PT30S"),
 					resource.TestCheckResourceAttr("data.ovh_cloud_project_kube.cluster", "customization_kube_proxy.0.ipvs.0.tcp_timeout", "PT30S"),
 					resource.TestCheckResourceAttr("data.ovh_cloud_project_kube.cluster", "customization_kube_proxy.0.ipvs.0.udp_timeout", "PT30S"),
+
+					// Check kubeconfig is present and not empty
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_kube.cluster", "kubeconfig"),
+
+					// Check kubeconfig_attributes are present
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_kube.cluster", "kubeconfig_attributes.0.host"),
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_kube.cluster", "kubeconfig_attributes.0.cluster_ca_certificate"),
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_kube.cluster", "kubeconfig_attributes.0.client_certificate"),
+					resource.TestCheckResourceAttrSet("data.ovh_cloud_project_kube.cluster", "kubeconfig_attributes.0.client_key"),
 				),
 			},
 		},
diff --git a/ovh/data_location_test.go b/ovh/data_location_test.go
new file mode 100644
index 00000000..b5baa1f8
--- /dev/null
+++ b/ovh/data_location_test.go
@@ -0,0 +1,29 @@
+package ovh
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+)
+
+func TestAccLocationDataSource_basic(t *testing.T) {
+	resource.Test(t, resource.TestCase{
+		PreCheck:                 func() { testAccPreCheckCredentials(t) },
+		ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+		Steps: []resource.TestStep{
+			{
+				Config: `
+					data "ovh_location" "paname" {
+						name = "eu-west-par"
+					}`,
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("data.ovh_location.paname", "code", "par"),
+					resource.TestCheckResourceAttr("data.ovh_location.paname", "type", "REGION-3-AZ"),
+					resource.TestCheckResourceAttr("data.ovh_location.paname", "city_name", "Paris"),
+					resource.TestCheckResourceAttr("data.ovh_location.paname", "country_code", "FR"),
+					resource.TestCheckResourceAttrSet("data.ovh_location.paname", "availability_zones.#"),
+				),
+			},
+		},
+	})
+}
diff --git a/ovh/resource_cloud_project_instance_test.go b/ovh/resource_cloud_project_instance_test.go
index 0832dc0d..1c1f9750 100644
--- a/ovh/resource_cloud_project_instance_test.go
+++ b/ovh/resource_cloud_project_instance_test.go
@@ -2,6 +2,7 @@ package ovh
 
 import (
 	"fmt"
+	"math/rand"
 	"net/url"
 	"os"
 	"testing"
@@ -242,6 +243,7 @@ func TestAccCloudProjectInstance_privateNetworkCreate(t *testing.T) {
 	}
 
 	networkName := acctest.RandomWithPrefix(test_prefix)
+	vlanID := rand.Intn(4000)
 
 	var testCreateInstance = fmt.Sprintf(`
 			resource "ovh_cloud_project_instance" "instance" {
@@ -262,7 +264,7 @@ func TestAccCloudProjectInstance_privateNetworkCreate(t *testing.T) {
 					private {
 						network_create {
 							name = "%s"
-							vlan_id = 1237
+							vlan_id = %d
 							subnet{
 								ip_version = 4
 								cidr = "10.0.0.1/20"
@@ -278,7 +280,8 @@ func TestAccCloudProjectInstance_privateNetworkCreate(t *testing.T) {
 		image,
 		flavor,
 		os.Getenv("OVH_CLOUD_PROJECT_SSH_NAME_TEST"),
-		networkName)
+		networkName,
+		vlanID)
 
 	resource.Test(t, resource.TestCase{
 		PreCheck: func() {
diff --git a/ovh/resource_cloud_project_kube_test.go b/ovh/resource_cloud_project_kube_test.go
index 4e2cece7..d5f6c093 100644
--- a/ovh/resource_cloud_project_kube_test.go
+++ b/ovh/resource_cloud_project_kube_test.go
@@ -1051,6 +1051,7 @@ func TestAccCloudProjectKube_basic(t *testing.T) {
 					resource.TestCheckResourceAttrSet("ovh_cloud_project_kube.cluster", "kubeconfig"),
 					resource.TestCheckResourceAttr("ovh_cloud_project_kube.cluster", kubeClusterNameKey, name),
 					resource.TestCheckResourceAttr("ovh_cloud_project_kube.cluster", "version", version),
+					resource.TestCheckResourceAttrSet("ovh_cloud_project_kube.cluster", kubeClusterPlanKey),
 					resource.TestCheckResourceAttrSet("ovh_cloud_project_kube.cluster", "kubeconfig"),
 					resource.TestCheckResourceAttrSet("ovh_cloud_project_kube.cluster", "kubeconfig_attributes.0.host"),
 					resource.TestCheckResourceAttrSet("ovh_cloud_project_kube.cluster", "kubeconfig_attributes.0.cluster_ca_certificate"),
@@ -1110,6 +1111,7 @@ func TestAccCloudProjectKubeEmptyVersion_basic(t *testing.T) {
 					resource.TestCheckResourceAttrSet("ovh_cloud_project_kube.cluster", "kubeconfig"),
 					resource.TestCheckResourceAttr("ovh_cloud_project_kube.cluster", kubeClusterNameKey, name),
 					resource.TestCheckResourceAttrSet("ovh_cloud_project_kube.cluster", "version"),
+					resource.TestCheckResourceAttrSet("ovh_cloud_project_kube.cluster", kubeClusterPlanKey),
 				),
 			},
 			{
@@ -1119,6 +1121,7 @@ func TestAccCloudProjectKubeEmptyVersion_basic(t *testing.T) {
 					resource.TestCheckResourceAttrSet("ovh_cloud_project_kube.cluster", "kubeconfig"),
 					resource.TestCheckResourceAttr("ovh_cloud_project_kube.cluster", kubeClusterNameKey, updatedName),
 					resource.TestCheckResourceAttrSet("ovh_cloud_project_kube.cluster", "version"),
+					resource.TestCheckResourceAttrSet("ovh_cloud_project_kube.cluster", kubeClusterPlanKey),
 				),
 			},
 		},
diff --git a/ovh/resource_cloud_project_storage_test.go b/ovh/resource_cloud_project_storage_test.go
index a692030b..914734f7 100644
--- a/ovh/resource_cloud_project_storage_test.go
+++ b/ovh/resource_cloud_project_storage_test.go
@@ -47,3 +47,117 @@ func TestAccCloudProjectRegionStorage_basic(t *testing.T) {
 		},
 	})
 }
+
+func TestAccCloudProjectRegionStorage_withReplication(t *testing.T) {
+	bucketName := acctest.RandomWithPrefix(test_prefix)
+	replicaBucketName := acctest.RandomWithPrefix(test_prefix)
+
+	resource.Test(t, resource.TestCase{
+		PreCheck:                 func() { testAccPreCheckCloud(t); testAccCheckCloudProjectExists(t) },
+		ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+		Steps: []resource.TestStep{
+			{
+				Config: fmt.Sprintf(`
+					resource "ovh_cloud_project_storage" "storage" {
+						service_name = "%s"
+						region_name = "GRA"
+						name = "%s"
+
+						versioning = {
+							status = "enabled"
+						}
+
+						replication = {
+							rules = [
+								{
+									id          = "test"
+									priority    = 1
+									status      = "enabled"
+									destination = {
+										name   = "%s"
+										region = "GRA"
+									}
+									filter = {
+										"prefix" = "test"
+										"tags"   = {
+											"key": "test"
+										}
+									}
+									delete_marker_replication = "disabled"
+								}
+							]
+						}
+					}`, os.Getenv("OVH_CLOUD_PROJECT_SERVICE_TEST"), bucketName, replicaBucketName),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "name", bucketName),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "region", "GRA"),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "versioning.status", "enabled"),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "encryption.sse_algorithm", "plaintext"),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "replication.rules.#", "1"),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "replication.rules.0.id", "test"),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "replication.rules.0.priority", "1"),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "replication.rules.0.status", "enabled"),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "replication.rules.0.destination.name", replicaBucketName),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "replication.rules.0.destination.region", "GRA"),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "replication.rules.0.filter.prefix", "test"),
+					resource.TestCheckResourceAttrSet("ovh_cloud_project_storage.storage", "virtual_host"),
+				),
+			},
+			{
+				Config: fmt.Sprintf(`
+					resource "ovh_cloud_project_storage" "storage" {
+						service_name = "%s"
+						region_name = "GRA"
+						name = "%s"
+
+						versioning = {
+							status = "enabled"
+						}
+
+						replication = {
+							rules = [
+								{
+									id          = "test"
+									priority    = 1
+									status      = "enabled"
+									destination = {
+										name   = "%s"
+										region = "GRA"
+									}
+									filter = {
+										"prefix" = "test-updated"
+										"tags"   = {
+											"key": "test-updated"
+										}
+									}
+									delete_marker_replication = "disabled"
+								}
+							]
+						}
+					} `, os.Getenv("OVH_CLOUD_PROJECT_SERVICE_TEST"), bucketName, replicaBucketName),
+				Check: resource.ComposeTestCheckFunc(
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "name", bucketName),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "region", "GRA"),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "versioning.status", "enabled"),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "encryption.sse_algorithm", "plaintext"),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "replication.rules.#", "1"),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "replication.rules.0.id", "test"),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "replication.rules.0.priority", "1"),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "replication.rules.0.status", "enabled"),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "replication.rules.0.destination.name", replicaBucketName),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "replication.rules.0.destination.region", "GRA"),
+					resource.TestCheckResourceAttr("ovh_cloud_project_storage.storage", "replication.rules.0.filter.prefix", "test-updated"),
+					resource.TestCheckResourceAttrSet("ovh_cloud_project_storage.storage", "virtual_host"),
+				),
+			},
+			{
+				ImportState:                          true,
+				ImportStateVerify:                    true,
+				ImportStateVerifyIdentifierAttribute: "name",
+				ResourceName:                         "ovh_cloud_project_storage.storage",
+				ImportStateId:                        fmt.Sprintf("%s/GRA/%s", os.Getenv("OVH_CLOUD_PROJECT_SERVICE_TEST"), bucketName),
+				ImportStateVerifyIgnore:              []string{"created_at"}, // Ignore created_at since its value is invalid in response of the POST.
+			},
+		},
+	})
+}
diff --git a/ovh/resource_dedicated_server_reboot_task_test.go b/ovh/resource_dedicated_server_reboot_task_test.go
index a0bdd258..e9da27bb 100644
--- a/ovh/resource_dedicated_server_reboot_task_test.go
+++ b/ovh/resource_dedicated_server_reboot_task_test.go
@@ -50,7 +50,7 @@ const testAccDedicatedServerRebootConfig_Basic = `
 data ovh_dedicated_server_boots "rescue" {
   service_name = "%s"
   boot_type    = "rescue"
-  kernel       = "rescue-customer"
+  kernel       = "rescue12-customer"
 }
 
 resource ovh_dedicated_server_update "server" {
diff --git a/ovh/resource_dedicated_server_update_test.go b/ovh/resource_dedicated_server_update_test.go
index 53d11536..ba1ab614 100644
--- a/ovh/resource_dedicated_server_update_test.go
+++ b/ovh/resource_dedicated_server_update_test.go
@@ -71,7 +71,7 @@ const testAccDedicatedServerUpdateConfig_Basic = `
 data ovh_dedicated_server_boots "rescue" {
   service_name = "%s"
   boot_type    = "rescue"
-  kernel       = "rescue-customer"
+  kernel       = "rescue12-customer"
 }
 
 resource ovh_dedicated_server_update "server" {
diff --git a/ovh/resource_vrack_dedicated_server_interface_test.go b/ovh/resource_vrack_dedicated_server_interface_test.go
index 5bc46993..9af665ae 100644
--- a/ovh/resource_vrack_dedicated_server_interface_test.go
+++ b/ovh/resource_vrack_dedicated_server_interface_test.go
@@ -2,12 +2,99 @@ package ovh
 
 import (
 	"fmt"
+	"log"
+	"net/url"
 	"os"
 	"testing"
 
 	"github.com/hashicorp/terraform-plugin-testing/helper/resource"
+	"github.com/ovh/go-ovh/ovh"
 )
 
+func init() {
+	resource.AddTestSweepers("ovh_vrack_dedicated_server_interface", &resource.Sweeper{
+		Name: "ovh_vrack_dedicated_server_interface",
+		F:    testSweepVrackDedicatedServerInterface,
+	})
+}
+
+func testSweepVrackDedicatedServerInterface(region string) error {
+	config, err := sharedConfigForRegion(region)
+	if err != nil {
+		return fmt.Errorf("error getting client: %s", err)
+	}
+
+	baremetal := os.Getenv("OVH_DEDICATED_SERVER")
+	vrack := os.Getenv("OVH_VRACK_SERVICE_TEST")
+
+	// First get vni IDs
+	vniIDs := []string{}
+	if err := config.OVHClient.Get(
+		fmt.Sprintf(
+			"/dedicated/server/%s/virtualNetworkInterface",
+			url.PathEscape(baremetal),
+		),
+		&vniIDs,
+	); err != nil {
+		return fmt.Errorf("error retrieving VNIs for dedicated server %s: %s", baremetal, err)
+	}
+
+	if len(vniIDs) == 0 {
+		log.Printf("[INFO] No VNI IDs found for dedicated server %s, nothing to sweep", baremetal)
+		return nil
+	}
+
+	// Fetch vrack interfaces
+	vnis := []*DedicatedServerVNI{}
+	for _, id := range vniIDs {
+		var vni DedicatedServerVNI
+		err := config.OVHClient.Get(
+			fmt.Sprintf("/dedicated/server/%s/virtualNetworkInterface/%s", url.PathEscape(baremetal), url.PathEscape(id)),
+			&vni,
+		)
+
+		if err != nil {
+			return fmt.Errorf("error retrieving VNI info for dedicated server %s: %s", baremetal, err)
+		}
+
+		if vni.Enabled && vni.Mode == "vrack" {
+			vnis = append(vnis, &vni)
+		}
+	}
+
+	if len(vnis) == 0 {
+		log.Printf("[INFO] No vrack interfaces found for dedicated server %s, nothing to sweep", baremetal)
+		return nil
+	}
+
+	// Check if vrack is attached to interface
+	endpoint := fmt.Sprintf("/vrack/%s/dedicatedServerInterface/%s",
+		url.PathEscape(vrack),
+		url.PathEscape(vnis[0].Uuid),
+	)
+
+	var vds VrackDedicatedServerInterface
+	if err := config.OVHClient.Get(endpoint, &vds); err != nil {
+		if errOvh, ok := err.(*ovh.APIError); ok && errOvh.Code == 404 {
+			// No vrack interface found, nothing to delete
+			return nil
+		}
+		return fmt.Errorf("error retrieving vrack dedicated server interface %s: %s", vds.DedicatedServerInterface, err)
+	}
+
+	// Remove vrack from interface
+	var task VrackTask
+	if err := config.OVHClient.Delete(endpoint, &task); err != nil {
+		return fmt.Errorf("error calling DELETE %s with %s/%s:\n\t %q", endpoint, vrack, vnis[0].Uuid, err)
+	}
+
+	if err := waitForVrackTask(&task, config.OVHClient); err != nil {
+		return fmt.Errorf("error waiting for vrack (%s) to detach dedicated server (%s): %s", vrack, vnis[0].Uuid, err)
+	}
+
+	return nil
+}
+
 var testAccVrackDedicatedServerInterfaceConfig = fmt.Sprintf(`
 data "ovh_dedicated_server" "server" {
   service_name = "%s"