Skip to content

Commit 6f18f35

Browse files
committed
feat(project): add the projects datasource
1 parent 942001a commit 6f18f35

File tree

5 files changed

+447
-3
lines changed

5 files changed

+447
-3
lines changed

docs/data-sources/account_projects.md

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
---
2+
subcategory: "Account"
3+
page_title: "Scaleway: scaleway_account_projects"
4+
---
5+
6+
# scaleway_account_projects
7+
8+
The `scaleway_account_projects` data source is used to list all Scaleway projects in an Organization.
9+
10+
Refer to the Organizations and Projects [documentation](https://www.scaleway.com/en/docs/organizations-and-projects/) and [API documentation](https://www.scaleway.com/en/developers/api/account/project-api/) for more information.
11+
12+
13+
## Retrieve a Scaleway Projects
14+
15+
The following commands allow you to:
16+
17+
- retrieve all Projects in an Organization
18+
19+
```hcl
20+
# Get all Projects in an Organization
21+
data scaleway_account_projects "all" {
22+
organization_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
23+
}
24+
```
25+
26+
## Example Usage
27+
28+
### Deploy an SSH key in all your organization's projects
29+
30+
```hcl
31+
data scaleway_account_projects "all" {}
32+
33+
resource "scaleway_account_ssh_key" "main" {
34+
name = "main"
35+
public_key = local.public_key
36+
count = length(data.scaleway_account_projects.all.projects)
37+
project_id = data.scaleway_account_projects.all.projects[count.index].id
38+
}
39+
```
40+
41+
## Argument Reference
42+
43+
- `organization_id` - (Optional) The unique identifier of the Organization with which the Projects are associated.
44+
If no default `organization_id` is set, one must be set explicitly in this datasource
45+
46+
47+
## Attribute reference
48+
49+
The `scaleway_account_projects` data source exports the following attributes:
50+
51+
- `projects` - (Computed) A list of projects. Each project has the following attributes:
52+
- `id` - (Computed) The unique identifier of the project.
53+
- `name` - (Computed) The name of the project.
54+
- `organization_id` - (Computed) The unique identifier of the organization with which the project is associated.
55+
- `created_at` - (Computed) The date and time when the project was created.
56+
- `updated_at` - (Computed) The date and time when the project was updated.
57+
- `description` - (Computed) The description of the project.

internal/provider/provider.go

+1
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ func Provider(config *Config) plugin.ProviderFunc {
245245

246246
DataSourcesMap: map[string]*schema.Resource{
247247
"scaleway_account_project": account.DataSourceProject(),
248+
"scaleway_account_projects": account.DataSourceProjects(),
248249
"scaleway_account_ssh_key": iam.DataSourceSSHKey(),
249250
"scaleway_availability_zones": az.DataSourceAvailabilityZones(),
250251
"scaleway_baremetal_offer": baremetal.DataSourceOffer(),

internal/services/account/project_data_source.go

+104-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package account
33
import (
44
"context"
55

6+
"github.com/google/uuid"
67
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
78
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
89
accountSDK "github.com/scaleway/scaleway-sdk-go/api/account/v3"
@@ -22,7 +23,7 @@ func DataSourceProject() *schema.Resource {
2223
Type: schema.TypeString,
2324
Computed: true,
2425
Optional: true,
25-
Description: "The ID of the SSH key",
26+
Description: "The ID of the project",
2627
ValidateDiagFunc: verify.IsUUID(),
2728
}
2829

@@ -85,3 +86,105 @@ func DataSourceAccountProjectRead(ctx context.Context, d *schema.ResourceData, m
8586

8687
return nil
8788
}
89+
90+
func DataSourceProjects() *schema.Resource {
91+
dsSchema := datasource.SchemaFromResourceSchema(ResourceProject().Schema)
92+
datasource.AddOptionalFieldsToSchema(dsSchema, "organization_id")
93+
94+
dsSchema["organization_id"] = &schema.Schema{
95+
Type: schema.TypeString,
96+
Computed: true,
97+
Optional: true,
98+
Description: "The ID of the organization",
99+
ValidateDiagFunc: verify.IsUUID(),
100+
}
101+
dsSchema["projects"] = &schema.Schema{
102+
Type: schema.TypeList,
103+
Computed: true,
104+
Description: "The list of projects",
105+
Elem: &schema.Resource{
106+
Schema: map[string]*schema.Schema{
107+
"id": {
108+
Type: schema.TypeString,
109+
Computed: true,
110+
Description: "ID of the Project",
111+
},
112+
"name": {
113+
Type: schema.TypeString,
114+
Computed: true,
115+
Description: "Name of the Project",
116+
},
117+
"organization_id": {
118+
Type: schema.TypeString,
119+
Computed: true,
120+
Description: "Organization ID of the Project",
121+
},
122+
"created_at": {
123+
Type: schema.TypeString,
124+
Computed: true,
125+
Description: "Creation date of the Project",
126+
},
127+
"updated_at": {
128+
Type: schema.TypeString,
129+
Computed: true,
130+
Description: "Update date of the Project",
131+
},
132+
"description": {
133+
Type: schema.TypeString,
134+
Computed: true,
135+
Description: "Description of the Project",
136+
},
137+
},
138+
},
139+
}
140+
141+
return &schema.Resource{
142+
ReadContext: DataSourceAccountProjectsRead,
143+
Schema: dsSchema,
144+
}
145+
}
146+
147+
func DataSourceAccountProjectsRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
148+
accountAPI := NewProjectAPI(m)
149+
150+
var orgID *string
151+
152+
if v, orgIDExists := d.GetOk("organization_id"); orgIDExists {
153+
orgID = types.ExpandStringPtr(v)
154+
} else {
155+
orgID = GetOrganizationID(m, d)
156+
}
157+
158+
if orgID == nil {
159+
return diag.Errorf("organization_id was not specified nor found in the provider configuration")
160+
}
161+
162+
res, err := accountAPI.ListProjects(&accountSDK.ProjectAPIListProjectsRequest{
163+
OrganizationID: *orgID,
164+
}, scw.WithContext(ctx))
165+
if err != nil {
166+
return diag.FromErr(err)
167+
}
168+
169+
d.SetId(uuid.New().String())
170+
_ = d.Set("projects", flattenProjects(res.Projects))
171+
_ = d.Set("organization_id", orgID)
172+
173+
return nil
174+
}
175+
176+
func flattenProjects(projects []*accountSDK.Project) []map[string]interface{} {
177+
flattenedProjects := make([]map[string]interface{}, len(projects))
178+
for i, project := range projects {
179+
flattenedProjects[i] = map[string]interface{}{
180+
"id": project.ID,
181+
"name": project.Name,
182+
"organization_id": project.OrganizationID,
183+
"created_at": types.FlattenTime(project.CreatedAt),
184+
"updated_at": types.FlattenTime(project.UpdatedAt),
185+
"description": project.Description,
186+
}
187+
}
188+
189+
return flattenedProjects
190+
}

internal/services/account/project_data_source_test.go

+37-2
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ import (
88
"github.com/scaleway/terraform-provider-scaleway/v2/internal/acctest"
99
)
1010

11+
const dummyOrgID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
12+
1113
func TestAccDataSourceProject_Basic(t *testing.T) {
1214
tt := acctest.NewTestTools(t)
1315
defer tt.Cleanup()
1416

1517
orgID, orgIDExists := tt.Meta.ScwClient().GetDefaultOrganizationID()
1618
if !orgIDExists {
17-
orgID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
19+
orgID = dummyOrgID
1820
}
1921

2022
resource.ParallelTest(t, resource.TestCase{
@@ -55,7 +57,7 @@ func TestAccDataSourceProject_Default(t *testing.T) {
5557

5658
orgID, orgIDExists := tt.Meta.ScwClient().GetDefaultOrganizationID()
5759
if !orgIDExists {
58-
orgID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
60+
orgID = dummyOrgID
5961
}
6062

6163
resource.ParallelTest(t, resource.TestCase{
@@ -116,3 +118,36 @@ func TestAccDataSourceProject_Extract(t *testing.T) {
116118
},
117119
})
118120
}
121+
122+
func TestAccDataSourceProject_List(t *testing.T) {
123+
tt := acctest.NewTestTools(t)
124+
defer tt.Cleanup()
125+
126+
orgID, orgIDExists := tt.Meta.ScwClient().GetDefaultOrganizationID()
127+
if !orgIDExists {
128+
orgID = dummyOrgID
129+
}
130+
131+
resource.ParallelTest(t, resource.TestCase{
132+
PreCheck: func() { acctest.PreCheck(t) },
133+
ProviderFactories: tt.ProviderFactories,
134+
CheckDestroy: resource.ComposeTestCheckFunc(
135+
isProjectDestroyed(tt),
136+
),
137+
Steps: []resource.TestStep{
138+
{
139+
Config: fmt.Sprintf(`
140+
data scaleway_account_projects "projects" {
141+
organization_id = "%s"
142+
}`, orgID),
143+
Check: resource.ComposeTestCheckFunc(
144+
resource.TestCheckResourceAttr("data.scaleway_account_projects.projects", "projects.#", "8"),
145+
resource.TestCheckResourceAttr("data.scaleway_account_projects.projects", "projects.0.id", "6867048b-fe12-4e96-835e-41c79a39604b"),
146+
resource.TestCheckResourceAttr("data.scaleway_account_projects.projects", "projects.1.id", "8cc8dd4d-a094-407a-89a3-9d004674e936"),
147+
resource.TestCheckResourceAttr("data.scaleway_account_projects.projects", "projects.0.name", "default"),
148+
resource.TestCheckResourceAttr("data.scaleway_account_projects.projects", "projects.1.name", "tf_tests_container_trigger_sqs"),
149+
),
150+
},
151+
},
152+
})
153+
}

0 commit comments

Comments
 (0)