Skip to content

Commit 93859f4

Browse files
authored
feat(cockpit): add data source for source (#2856)
* feat(cockpit): add data source for source * feat(cockpit): fix lint * feat(cockpit): fix test * feat(cockpit): refacto fetch all
1 parent 4c8866c commit 93859f4

8 files changed

+2795
-62
lines changed

docs/data-sources/cockpit_source.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
---
2+
subcategory: "Cockpit"
3+
page_title: "Scaleway: scaleway_cockpit_source"
4+
---
5+
6+
# Data Source: scaleway_cockpit_source
7+
8+
The `scaleway_cockpit_source` data source allows you to retrieve information about a specific [data source](https://www.scaleway.com/en/docs/observability/cockpit/concepts/#data-sources) in Scaleway's Cockpit.
9+
10+
Refer to Cockpit's [product documentation](https://www.scaleway.com/en/docs/observability/cockpit/concepts/) and [API documentation](https://www.scaleway.com/en/developers/api/cockpit/regional-api) for more information.
11+
12+
## Example Usage
13+
14+
### Retrieve a specific data source by ID
15+
16+
The following example retrieves a Cockpit data source by its unique ID.
17+
18+
```terraform
19+
data "scaleway_cockpit_source" "example" {
20+
id = "fr-par/11111111-1111-1111-1111-111111111111"
21+
}
22+
```
23+
24+
### Retrieve a data source by filters
25+
26+
You can also retrieve a data source by specifying filtering criteria such as `name`, `type`, and `origin`.
27+
28+
```terraform
29+
data "scaleway_cockpit_source" "filtered" {
30+
project_id = "11111111-1111-1111-1111-111111111111"
31+
region = "fr-par"
32+
name = "my-data-source"
33+
}
34+
```
35+
36+
## Argument Reference
37+
38+
This section lists the arguments that are supported:
39+
40+
- `id` - (Optional) The unique identifier of the Cockpit data source in the `{region}/{id}` format. If specified, other filters are ignored.
41+
42+
- `region` - (Optional) The [region](../guides/regions_and_zones.md#regions) where the data source is located. Defaults to the region specified in the [provider configuration](../index.md#region).
43+
44+
- `project_id` - (Required unless `id` is specified) The ID of the Project the data source is associated with. Defaults to the Project ID specified in the [provider configuration](../index.md#project_id).
45+
46+
- `name` - (Optional) The name of the data source.
47+
48+
- `type` - (Optional) The [type](https://www.scaleway.com/en/docs/observability/cockpit/concepts/#data-types) of data source. Possible values are: `metrics`, `logs`, or `traces`.
49+
50+
- `origin` - (Optional) The origin of the data source. Possible values are:
51+
- `scaleway` - Data source managed by Scaleway.
52+
- `external` - Data source created by the user.
53+
- `custom` - User-defined custom data source.
54+
55+
## Attributes Reference
56+
57+
In addition to all arguments above, the following attributes are exported:
58+
59+
- `id` - The unique identifier of the data source in the `{region}/{id}` format.
60+
61+
- `url` - The URL of the Cockpit data source.
62+
63+
- `created_at` - The date and time the data source was created (in RFC 3339 format).
64+
65+
- `updated_at` - The date and time the data source was last updated (in RFC 3339 format).
66+
67+
- `origin` - The origin of the data source.
68+
69+
- `synchronized_with_grafana` - Indicates whether the data source is synchronized with Grafana.
70+
71+
- `retention_days` - The number of days the data is retained in the data source.
72+
73+
## Import
74+
75+
You can import a Cockpit data source using its unique ID in the `{region}/{id}` format.
76+
77+
```bash
78+
terraform import scaleway_cockpit_source.example fr-par/11111111-1111-1111-1111-111111111111
79+
```

internal/provider/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ func Provider(config *Config) plugin.ProviderFunc {
239239
"scaleway_block_volume": block.DataSourceVolume(),
240240
"scaleway_cockpit": cockpit.DataSourceCockpit(),
241241
"scaleway_cockpit_plan": cockpit.DataSourcePlan(),
242+
"scaleway_cockpit_source": cockpit.DataSourceCockpitSource(),
242243
"scaleway_config": scwconfig.DataSourceConfig(),
243244
"scaleway_container": container.DataSourceContainer(),
244245
"scaleway_container_namespace": container.DataSourceNamespace(),
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
package cockpit
2+
3+
import (
4+
"context"
5+
6+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
8+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
9+
"github.com/scaleway/scaleway-sdk-go/api/cockpit/v1"
10+
"github.com/scaleway/scaleway-sdk-go/scw"
11+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/regional"
12+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/services/account"
13+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/types"
14+
)
15+
16+
func DataSourceCockpitSource() *schema.Resource {
17+
return &schema.Resource{
18+
ReadContext: dataSourceCockpitSourceRead,
19+
Schema: map[string]*schema.Schema{
20+
"id": {
21+
Type: schema.TypeString,
22+
Optional: true,
23+
Computed: true,
24+
Description: "ID of the data source.",
25+
},
26+
"region": {
27+
Type: schema.TypeString,
28+
Computed: true,
29+
Description: "The region of the data source.",
30+
},
31+
"project_id": account.ProjectIDSchema(),
32+
"name": {
33+
Type: schema.TypeString,
34+
Optional: true,
35+
Computed: true,
36+
Description: "The name of the data source.",
37+
},
38+
"type": {
39+
Type: schema.TypeString,
40+
Optional: true,
41+
Computed: true,
42+
Description: "The type of the data source (e.g., 'metrics', 'logs', 'traces').",
43+
ValidateFunc: validation.StringInSlice([]string{
44+
"metrics", "logs", "traces",
45+
}, false),
46+
},
47+
"origin": {
48+
Type: schema.TypeString,
49+
Optional: true,
50+
Computed: true,
51+
Description: "The origin of the data source (e.g., 'scaleway', 'external', 'custom').",
52+
ValidateFunc: validation.StringInSlice([]string{
53+
"scaleway", "external", "custom",
54+
}, false),
55+
},
56+
"url": {
57+
Type: schema.TypeString,
58+
Computed: true,
59+
Description: "The URL of the data source.",
60+
},
61+
"created_at": {
62+
Type: schema.TypeString,
63+
Computed: true,
64+
Description: "The creation date of the data source.",
65+
},
66+
"updated_at": {
67+
Type: schema.TypeString,
68+
Computed: true,
69+
Description: "The last update date of the data source.",
70+
},
71+
"synchronized_with_grafana": {
72+
Type: schema.TypeBool,
73+
Computed: true,
74+
Description: "Whether the data source is synchronized with Grafana.",
75+
},
76+
"retention_days": {
77+
Type: schema.TypeInt,
78+
Computed: true,
79+
Description: "The retention period of the data source in days.",
80+
},
81+
},
82+
}
83+
}
84+
85+
func dataSourceCockpitSourceRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
86+
if _, ok := d.GetOk("id"); ok {
87+
return fetchDataSourceByID(ctx, d, meta)
88+
}
89+
return fetchDataSourceByFilters(ctx, d, meta)
90+
}
91+
92+
func fetchDataSourceByID(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
93+
regionalID := d.Get("id").(string)
94+
api, region, id, err := NewAPIWithRegionAndID(meta, regionalID)
95+
if err != nil {
96+
return diag.FromErr(err)
97+
}
98+
d.SetId(id)
99+
res, err := api.GetDataSource(&cockpit.RegionalAPIGetDataSourceRequest{
100+
Region: region,
101+
DataSourceID: id,
102+
}, scw.WithContext(ctx))
103+
if err != nil {
104+
return diag.FromErr(err)
105+
}
106+
flattenDataSource(d, res)
107+
return nil
108+
}
109+
110+
func fetchDataSourceByFilters(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
111+
api, region, err := cockpitAPIWithRegion(d, meta)
112+
if err != nil {
113+
return diag.FromErr(err)
114+
}
115+
116+
req := &cockpit.RegionalAPIListDataSourcesRequest{
117+
Region: region,
118+
ProjectID: d.Get("project_id").(string),
119+
}
120+
121+
if v, ok := d.GetOk("type"); ok {
122+
req.Types = []cockpit.DataSourceType{cockpit.DataSourceType(v.(string))}
123+
}
124+
if v, ok := d.GetOk("origin"); ok {
125+
req.Origin = cockpit.DataSourceOrigin(v.(string))
126+
}
127+
128+
res, err := api.ListDataSources(req, scw.WithContext(ctx), scw.WithAllPages())
129+
if err != nil {
130+
return diag.FromErr(err)
131+
}
132+
133+
if res.TotalCount == 0 {
134+
return diag.Errorf("no data source found matching the specified criteria")
135+
}
136+
137+
if name, ok := d.GetOk("name"); ok {
138+
for _, ds := range res.DataSources {
139+
if ds.Name == name.(string) {
140+
flattenDataSource(d, ds)
141+
return nil
142+
}
143+
}
144+
return diag.Errorf("no data source found with name '%s'", name.(string))
145+
}
146+
147+
flattenDataSource(d, res.DataSources[0])
148+
return nil
149+
}
150+
151+
func flattenDataSource(d *schema.ResourceData, ds *cockpit.DataSource) {
152+
d.SetId(regional.NewIDString(ds.Region, ds.ID))
153+
_ = d.Set("project_id", ds.ProjectID)
154+
_ = d.Set("name", ds.Name)
155+
_ = d.Set("url", ds.URL)
156+
_ = d.Set("type", ds.Type.String())
157+
_ = d.Set("origin", ds.Origin.String())
158+
_ = d.Set("created_at", types.FlattenTime(ds.CreatedAt))
159+
_ = d.Set("updated_at", types.FlattenTime(ds.UpdatedAt))
160+
_ = d.Set("synchronized_with_grafana", ds.SynchronizedWithGrafana)
161+
_ = d.Set("retention_days", int(ds.RetentionDays))
162+
_ = d.Set("region", ds.Region.String())
163+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package cockpit_test
2+
3+
import (
4+
"fmt"
5+
"testing"
6+
7+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
8+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/acctest"
9+
)
10+
11+
func TestAccCockpitSource_DataSource_ByID(t *testing.T) {
12+
tt := acctest.NewTestTools(t)
13+
defer tt.Cleanup()
14+
15+
resource.ParallelTest(t, resource.TestCase{
16+
PreCheck: func() { acctest.PreCheck(t) },
17+
ProviderFactories: tt.ProviderFactories,
18+
CheckDestroy: isSourceDestroyed(tt),
19+
Steps: []resource.TestStep{
20+
{
21+
Config: `
22+
resource "scaleway_account_project" "project" {
23+
name = "tf_tests_cockpit_datasource_by_id"
24+
}
25+
26+
resource "scaleway_cockpit_source" "main" {
27+
project_id = scaleway_account_project.project.id
28+
name = "source-by-id"
29+
type = "metrics"
30+
retention_days = 30
31+
}
32+
33+
data "scaleway_cockpit_source" "by_id" {
34+
id = scaleway_cockpit_source.main.id
35+
}
36+
`,
37+
Check: resource.ComposeTestCheckFunc(
38+
resource.TestCheckResourceAttrPair("data.scaleway_cockpit_source.by_id", "id", "scaleway_cockpit_source.main", "id"),
39+
resource.TestCheckResourceAttr("data.scaleway_cockpit_source.by_id", "name", "source-by-id"),
40+
resource.TestCheckResourceAttr("data.scaleway_cockpit_source.by_id", "type", "metrics"),
41+
),
42+
},
43+
},
44+
})
45+
}
46+
47+
func TestAccCockpitSource_DataSource_ByName(t *testing.T) {
48+
tt := acctest.NewTestTools(t)
49+
defer tt.Cleanup()
50+
51+
resource.ParallelTest(t, resource.TestCase{
52+
PreCheck: func() { acctest.PreCheck(t) },
53+
ProviderFactories: tt.ProviderFactories,
54+
CheckDestroy: isSourceDestroyed(tt),
55+
Steps: []resource.TestStep{
56+
{
57+
Config: `
58+
resource "scaleway_account_project" "project" {
59+
name = "tf_tests_cockpit_datasource_by_name"
60+
}
61+
62+
resource "scaleway_cockpit_source" "main" {
63+
project_id = scaleway_account_project.project.id
64+
name = "source-by-name"
65+
type = "logs"
66+
retention_days = 30
67+
}
68+
69+
data "scaleway_cockpit_source" "by_name" {
70+
project_id = scaleway_account_project.project.id
71+
name = "source-by-name"
72+
depends_on = [scaleway_cockpit_source.main]
73+
}
74+
`,
75+
Check: resource.ComposeTestCheckFunc(
76+
resource.TestCheckResourceAttrPair("data.scaleway_cockpit_source.by_name", "id", "scaleway_cockpit_source.main", "id"),
77+
resource.TestCheckResourceAttr("data.scaleway_cockpit_source.by_name", "name", "source-by-name"),
78+
resource.TestCheckResourceAttr("data.scaleway_cockpit_source.by_name", "type", "logs"),
79+
),
80+
},
81+
},
82+
})
83+
}
84+
85+
func TestAccCockpitSource_DataSource_Defaults(t *testing.T) {
86+
tt := acctest.NewTestTools(t)
87+
defer tt.Cleanup()
88+
orgID, orgIDExists := tt.Meta.ScwClient().GetDefaultOrganizationID()
89+
if !orgIDExists {
90+
orgID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
91+
}
92+
resource.ParallelTest(t, resource.TestCase{
93+
PreCheck: func() { acctest.PreCheck(t) },
94+
ProviderFactories: tt.ProviderFactories,
95+
96+
Steps: []resource.TestStep{
97+
{
98+
Config: fmt.Sprintf(`
99+
100+
data scaleway_account_project "by_name" {
101+
name = "default"
102+
organization_id = "%s"
103+
}
104+
105+
106+
data "scaleway_cockpit_source" "default_metrics" {
107+
project_id = data.scaleway_account_project.by_name.id
108+
type = "metrics"
109+
origin = "scaleway"
110+
}
111+
112+
data "scaleway_cockpit_source" "default_logs" {
113+
project_id = data.scaleway_account_project.by_name.id
114+
type = "logs"
115+
origin = "scaleway"
116+
}
117+
`, orgID),
118+
Check: resource.ComposeTestCheckFunc(
119+
resource.TestCheckResourceAttr("data.scaleway_cockpit_source.default_metrics", "name", "Scaleway Metrics"),
120+
resource.TestCheckResourceAttr("data.scaleway_cockpit_source.default_metrics", "type", "metrics"),
121+
resource.TestCheckResourceAttrSet("data.scaleway_cockpit_source.default_metrics", "url"),
122+
resource.TestCheckResourceAttr("data.scaleway_cockpit_source.default_logs", "name", "Scaleway Logs"),
123+
resource.TestCheckResourceAttr("data.scaleway_cockpit_source.default_logs", "type", "logs"),
124+
resource.TestCheckResourceAttrSet("data.scaleway_cockpit_source.default_logs", "url"),
125+
),
126+
},
127+
},
128+
})
129+
}

0 commit comments

Comments
 (0)