Skip to content

Commit 2b770fe

Browse files
authored
feat: Generate component IDs before applying new resources (#142)
* Generate component ID * Test component func * test id change * add license * lint: package comment
1 parent d64b7c8 commit 2b770fe

11 files changed

+115
-18
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ require (
88
github.com/hashicorp/go-version v1.7.0
99
github.com/hashicorp/terraform-plugin-sdk/v2 v2.29.0
1010
github.com/observiq/bindplane-op-enterprise v1.86.0
11+
github.com/oklog/ulid/v2 v2.1.0
1112
github.com/stretchr/testify v1.10.0
1213
github.com/testcontainers/testcontainers-go v0.35.0
1314
go.uber.org/zap v1.27.0
@@ -135,7 +136,6 @@ require (
135136
github.com/nats-io/nuid v1.0.1 // indirect
136137
github.com/observiq/stanza v1.6.1 // indirect
137138
github.com/oklog/run v1.0.0 // indirect
138-
github.com/oklog/ulid/v2 v2.1.0 // indirect
139139
github.com/olekukonko/tablewriter v0.0.5 // indirect
140140
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/golden v0.118.0 // indirect
141141
github.com/open-telemetry/opentelemetry-collector-contrib/pkg/pdatatest v0.118.0 // indirect

internal/component/component.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright observIQ, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Package component provides functions for defining bindplane
16+
// component values.
17+
package component
18+
19+
import (
20+
"fmt"
21+
22+
"github.com/observiq/bindplane-op-enterprise/model"
23+
)
24+
25+
// NewResourceID wraps model.NewResourceID and returns
26+
// a new resource ID with the `tf` prefix to indicate
27+
// that it was created by the Terraform provider.
28+
func NewResourceID() string {
29+
return fmt.Sprintf("tf-%s", model.NewResourceID())
30+
}

internal/component/component_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright observIQ, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package component
16+
17+
import (
18+
"strings"
19+
"testing"
20+
21+
"github.com/oklog/ulid/v2"
22+
"github.com/stretchr/testify/require"
23+
)
24+
25+
func TestNewResourceID(t *testing.T) {
26+
id := NewResourceID()
27+
require.True(t, strings.HasPrefix(id, "tf-"))
28+
_, err := ulid.Parse(strings.TrimPrefix(id, "tf-"))
29+
require.NoError(t, err)
30+
}

internal/resource/resource.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import (
2828
// configurations, use AnyResourceFromConfigurationV1.
2929
//
3030
// rParameters and rProcessors can be nil.
31-
func AnyResourceV1(rName, rType string, rKind model.Kind, rParameters []model.Parameter, rProcessors []model.ResourceConfiguration) (model.AnyResource, error) {
31+
func AnyResourceV1(id, rName, rType string, rKind model.Kind, rParameters []model.Parameter, rProcessors []model.ResourceConfiguration) (model.AnyResource, error) {
3232
procs := []map[string]string{}
3333
for _, p := range rProcessors {
3434
proc := map[string]string{}
@@ -47,6 +47,7 @@ func AnyResourceV1(rName, rType string, rKind model.Kind, rParameters []model.Pa
4747
APIVersion: "bindplane.observiq.com/v1",
4848
Kind: rKind,
4949
Metadata: model.Metadata{
50+
ID: id,
5051
Name: rName,
5152
},
5253
},

internal/resource/resource_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
func TestAnyResourceV1(t *testing.T) {
2525
cases := []struct {
2626
name string
27+
id string
2728
rName string
2829
rType string
2930
rkind model.Kind
@@ -33,6 +34,7 @@ func TestAnyResourceV1(t *testing.T) {
3334
}{
3435
{
3536
"source",
37+
"tf-source",
3638
"my-host",
3739
"host",
3840
model.KindSource,
@@ -51,6 +53,7 @@ func TestAnyResourceV1(t *testing.T) {
5153
},
5254
{
5355
"destination",
56+
"tf-destination",
5457
"my-destination",
5558
"googlecloud",
5659
model.KindDestination,
@@ -65,6 +68,7 @@ func TestAnyResourceV1(t *testing.T) {
6568
},
6669
{
6770
"processor",
71+
"tf-processor",
6872
"my-filter",
6973
"filter",
7074
model.KindProcessor,
@@ -74,6 +78,7 @@ func TestAnyResourceV1(t *testing.T) {
7478
},
7579
{
7680
"extension",
81+
"tf-extension",
7782
"my-extension",
7883
"pprof",
7984
model.KindExtension,
@@ -83,6 +88,7 @@ func TestAnyResourceV1(t *testing.T) {
8388
},
8489
{
8590
"invalid-kind",
91+
"tf-resource",
8692
"my-resource",
8793
"resource",
8894
model.KindAgent,
@@ -92,6 +98,7 @@ func TestAnyResourceV1(t *testing.T) {
9298
},
9399
{
94100
"valid-processors",
101+
"tf-bundle",
95102
"my-bundle",
96103
"bundle",
97104
model.KindProcessor,
@@ -110,7 +117,7 @@ func TestAnyResourceV1(t *testing.T) {
110117

111118
for _, tc := range cases {
112119
t.Run(tc.name, func(t *testing.T) {
113-
_, err := AnyResourceV1(tc.rName, tc.rType, tc.rkind, tc.rParameters, tc.rProcessors)
120+
_, err := AnyResourceV1(tc.id, tc.rName, tc.rType, tc.rkind, tc.rParameters, tc.rProcessors)
114121
if tc.expectErr != "" {
115122
require.Error(t, err)
116123
require.ErrorContains(t, err, tc.expectErr)

provider/resource_destination.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
2323
"github.com/observiq/bindplane-op-enterprise/model"
2424
"github.com/observiq/terraform-provider-bindplane/client"
25+
"github.com/observiq/terraform-provider-bindplane/internal/component"
2526
"github.com/observiq/terraform-provider-bindplane/internal/parameter"
2627
"github.com/observiq/terraform-provider-bindplane/internal/resource"
2728
)
@@ -87,8 +88,14 @@ func resourceDestinationCreate(d *schema.ResourceData, meta any) error {
8788
if c != nil {
8889
return fmt.Errorf("destination with name '%s' already exists with id '%s'", name, c.ID())
8990
}
91+
92+
// If a source does not already exist with this name
93+
// and an ID is not set, generate and ID.
94+
d.SetId(component.NewResourceID())
9095
}
9196

97+
id := d.Id()
98+
9299
parameters := []model.Parameter{}
93100
if s := d.Get("parameters_json").(string); s != "" {
94101
params, err := parameter.StringToParameter(s)
@@ -98,7 +105,7 @@ func resourceDestinationCreate(d *schema.ResourceData, meta any) error {
98105
parameters = params
99106
}
100107

101-
r, err := resource.AnyResourceV1(name, destType, model.KindDestination, parameters, nil)
108+
r, err := resource.AnyResourceV1(id, name, destType, model.KindDestination, parameters, nil)
102109
if err != nil {
103110
return err
104111
}

provider/resource_extension.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
2323
"github.com/observiq/bindplane-op-enterprise/model"
2424
"github.com/observiq/terraform-provider-bindplane/client"
25+
"github.com/observiq/terraform-provider-bindplane/internal/component"
2526
"github.com/observiq/terraform-provider-bindplane/internal/parameter"
2627
"github.com/observiq/terraform-provider-bindplane/internal/resource"
2728
)
@@ -87,8 +88,14 @@ func resourceExtensionCreate(d *schema.ResourceData, meta any) error {
8788
if c != nil {
8889
return fmt.Errorf("extension with name '%s' already exists with id '%s'", name, c.ID())
8990
}
91+
92+
// If a source does not already exist with this name
93+
// and an ID is not set, generate and ID.
94+
d.SetId(component.NewResourceID())
9095
}
9196

97+
id := d.Id()
98+
9299
parameters := []model.Parameter{}
93100
if s := d.Get("parameters_json").(string); s != "" {
94101
params, err := parameter.StringToParameter(s)
@@ -98,7 +105,7 @@ func resourceExtensionCreate(d *schema.ResourceData, meta any) error {
98105
parameters = params
99106
}
100107

101-
r, err := resource.AnyResourceV1(name, extensionType, model.KindExtension, parameters, nil)
108+
r, err := resource.AnyResourceV1(id, name, extensionType, model.KindExtension, parameters, nil)
102109
if err != nil {
103110
return err
104111
}

provider/resource_generic.go

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,27 +39,21 @@ func genericResourceRead(rKind model.Kind, d *schema.ResourceData, meta any) err
3939
// A nil return from GenericResource indicates that the resource
4040
// did not exist. Terraform read operations should always set the
4141
// ID to "" and return a nil error. This will allow Terraform to
42-
// re-create the resource or comfirm that it was deleted.
42+
// re-create the resource or confirm that it was deleted.
4343
if g == nil {
4444
d.SetId("")
4545
return nil
4646
}
4747

48-
// Save values returned by bindplane to Terraform's state
49-
50-
d.SetId(g.ID)
51-
5248
// If the state ID is set but differs from the ID returned by,
5349
// bindplane, mark the resource to be re-created by unsetting
5450
// the ID. This will cause Terraform to attempt to create the resource
5551
// instead of updating it. The creation step will fail because
5652
// the resource already exists. This behavior is desirable, it will
5753
// prevent Terraform from modifying resources created by other means.
58-
if id := d.Id(); id != "" {
59-
if g.ID != d.Id() {
60-
d.SetId("")
61-
return nil
62-
}
54+
if g.ID != d.Id() {
55+
d.SetId("")
56+
return nil
6357
}
6458

6559
if err := d.Set("name", g.Name); err != nil {

provider/resource_processor.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
2323
"github.com/observiq/bindplane-op-enterprise/model"
2424
"github.com/observiq/terraform-provider-bindplane/client"
25+
"github.com/observiq/terraform-provider-bindplane/internal/component"
2526
"github.com/observiq/terraform-provider-bindplane/internal/parameter"
2627
"github.com/observiq/terraform-provider-bindplane/internal/resource"
2728
)
@@ -87,8 +88,14 @@ func resourceProcessorCreate(d *schema.ResourceData, meta any) error {
8788
if c != nil {
8889
return fmt.Errorf("processor with name '%s' already exists with id '%s'", name, c.ID())
8990
}
91+
92+
// If a source does not already exist with this name
93+
// and an ID is not set, generate and ID.
94+
d.SetId(component.NewResourceID())
9095
}
9196

97+
id := d.Id()
98+
9299
parameters := []model.Parameter{}
93100
if s := d.Get("parameters_json").(string); s != "" {
94101
params, err := parameter.StringToParameter(s)
@@ -98,7 +105,7 @@ func resourceProcessorCreate(d *schema.ResourceData, meta any) error {
98105
parameters = params
99106
}
100107

101-
r, err := resource.AnyResourceV1(name, processorType, model.KindProcessor, parameters, nil)
108+
r, err := resource.AnyResourceV1(id, name, processorType, model.KindProcessor, parameters, nil)
102109
if err != nil {
103110
return err
104111
}

provider/resource_processor_bundle.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
2424
"github.com/observiq/bindplane-op-enterprise/model"
2525
"github.com/observiq/terraform-provider-bindplane/client"
26+
"github.com/observiq/terraform-provider-bindplane/internal/component"
2627
"github.com/observiq/terraform-provider-bindplane/internal/resource"
2728
)
2829

@@ -107,8 +108,14 @@ func resourceProcessorBundleCreate(d *schema.ResourceData, meta any) error {
107108
if c != nil {
108109
return fmt.Errorf("processor with name '%s' already exists with id '%s'", name, c.ID())
109110
}
111+
112+
// If a source does not already exist with this name
113+
// and an ID is not set, generate and ID.
114+
d.SetId(component.NewResourceID())
110115
}
111116

117+
id := d.Id()
118+
112119
// Using resource configuration instead of []string (names)
113120
// to allow for future use of type + parameters_json.
114121
processors := []model.ResourceConfiguration{}
@@ -131,7 +138,7 @@ func resourceProcessorBundleCreate(d *schema.ResourceData, meta any) error {
131138
}
132139
}
133140

134-
r, err := resource.AnyResourceV1(name, processorType, model.KindProcessor, nil, processors)
141+
r, err := resource.AnyResourceV1(id, name, processorType, model.KindProcessor, nil, processors)
135142
if err != nil {
136143
return err
137144
}

provider/resource_source.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
2323
"github.com/observiq/bindplane-op-enterprise/model"
2424
"github.com/observiq/terraform-provider-bindplane/client"
25+
"github.com/observiq/terraform-provider-bindplane/internal/component"
2526
"github.com/observiq/terraform-provider-bindplane/internal/parameter"
2627
"github.com/observiq/terraform-provider-bindplane/internal/resource"
2728
)
@@ -88,8 +89,14 @@ func resourceSourceCreate(d *schema.ResourceData, meta any) error {
8889
if c != nil {
8990
return fmt.Errorf("source with name '%s' already exists with id '%s'", name, c.ID())
9091
}
92+
93+
// If a source does not already exist with this name
94+
// and an ID is not set, generate and ID.
95+
d.SetId(component.NewResourceID())
9196
}
9297

98+
id := d.Id()
99+
93100
parameters := []model.Parameter{}
94101
if s := d.Get("parameters_json").(string); s != "" {
95102
params, err := parameter.StringToParameter(s)
@@ -99,7 +106,7 @@ func resourceSourceCreate(d *schema.ResourceData, meta any) error {
99106
parameters = params
100107
}
101108

102-
r, err := resource.AnyResourceV1(name, sourceType, model.KindSource, parameters, nil)
109+
r, err := resource.AnyResourceV1(id, name, sourceType, model.KindSource, parameters, nil)
103110
if err != nil {
104111
return err
105112
}

0 commit comments

Comments
 (0)