Skip to content

Commit eab7a7c

Browse files
committed
New Resource: kubernetes_cluster_connection_resource
1 parent 6e405d4 commit eab7a7c

4 files changed

Lines changed: 756 additions & 0 deletions

File tree

Lines changed: 314 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package serviceconnector
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"time"
10+
11+
"github.com/hashicorp/go-azure-helpers/lang/pointer"
12+
"github.com/hashicorp/go-azure-helpers/lang/response"
13+
"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
14+
"github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2022-05-01/links"
15+
"github.com/hashicorp/go-azure-sdk/resource-manager/servicelinker/2024-04-01/servicelinker"
16+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
17+
"github.com/hashicorp/terraform-provider-azurerm/helpers/azure"
18+
"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
19+
"github.com/hashicorp/terraform-provider-azurerm/internal/services/containers/validate"
20+
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
21+
"github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation"
22+
"github.com/hashicorp/terraform-provider-azurerm/utils"
23+
)
24+
25+
var _ sdk.ResourceWithUpdate = KubernetesClusterConnectorResource{}
26+
27+
type KubernetesClusterConnectorResource struct{}
28+
29+
type KubernetesClusterConnectorResourceModel struct {
30+
Name string `tfschema:"name"`
31+
KubernetesClusterId string `tfschema:"kubernetes_cluster_id"`
32+
TargetResourceId string `tfschema:"target_resource_id"`
33+
ClientType string `tfschema:"client_type"`
34+
AuthInfo []AuthInfoModel `tfschema:"authentication"`
35+
VnetSolution string `tfschema:"vnet_solution"`
36+
SecretStore []SecretStoreModel `tfschema:"secret_store"`
37+
}
38+
39+
func (r KubernetesClusterConnectorResource) Arguments() map[string]*schema.Schema {
40+
return map[string]*schema.Schema{
41+
"name": {
42+
Type: pluginsdk.TypeString,
43+
Required: true,
44+
ForceNew: true,
45+
ValidateFunc: validation.StringIsNotEmpty,
46+
},
47+
48+
"kubernetes_cluster_id": {
49+
Type: pluginsdk.TypeString,
50+
Required: true,
51+
ForceNew: true,
52+
ValidateFunc: validate.ClusterID,
53+
},
54+
55+
"target_resource_id": {
56+
Type: pluginsdk.TypeString,
57+
Required: true,
58+
ForceNew: true,
59+
ValidateFunc: azure.ValidateResourceID,
60+
},
61+
62+
"client_type": {
63+
Type: pluginsdk.TypeString,
64+
Optional: true,
65+
Default: string(servicelinker.ClientTypeNone),
66+
ValidateFunc: validation.StringInSlice([]string{
67+
string(servicelinker.ClientTypeNone),
68+
string(servicelinker.ClientTypeDotnet),
69+
string(servicelinker.ClientTypeJava),
70+
string(servicelinker.ClientTypePython),
71+
string(servicelinker.ClientTypeGo),
72+
string(servicelinker.ClientTypePhp),
73+
string(servicelinker.ClientTypeRuby),
74+
string(servicelinker.ClientTypeDjango),
75+
string(servicelinker.ClientTypeNodejs),
76+
string(servicelinker.ClientTypeSpringBoot),
77+
}, false),
78+
},
79+
80+
"secret_store": secretStoreSchema(),
81+
82+
"vnet_solution": {
83+
Type: pluginsdk.TypeString,
84+
Optional: true,
85+
ValidateFunc: validation.StringInSlice([]string{
86+
string(servicelinker.VNetSolutionTypeServiceEndpoint),
87+
string(servicelinker.VNetSolutionTypePrivateLink),
88+
}, false),
89+
},
90+
91+
"authentication": authInfoSchema(),
92+
}
93+
}
94+
95+
func (r KubernetesClusterConnectorResource) Attributes() map[string]*schema.Schema {
96+
return map[string]*pluginsdk.Schema{}
97+
}
98+
99+
func (r KubernetesClusterConnectorResource) ModelObject() interface{} {
100+
return &KubernetesClusterConnectorResourceModel{}
101+
}
102+
103+
func (r KubernetesClusterConnectorResource) ResourceType() string {
104+
return "azurerm_kubernetes_cluster_connection"
105+
}
106+
107+
func (r KubernetesClusterConnectorResource) Create() sdk.ResourceFunc {
108+
return sdk.ResourceFunc{
109+
Timeout: 30 * time.Minute,
110+
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
111+
var model KubernetesClusterConnectorResourceModel
112+
if err := metadata.Decode(&model); err != nil {
113+
return err
114+
}
115+
116+
client := metadata.Client.ServiceConnector.ServiceLinkerClient
117+
118+
id := servicelinker.NewScopedLinkerID(model.KubernetesClusterId, model.Name)
119+
existing, err := client.LinkerGet(ctx, id)
120+
if err != nil && !response.WasNotFound(existing.HttpResponse) {
121+
return fmt.Errorf("checking for presence of existing %s: %+v", id, err)
122+
}
123+
124+
if !response.WasNotFound(existing.HttpResponse) {
125+
return metadata.ResourceRequiresImport(r.ResourceType(), id)
126+
}
127+
128+
authInfo, err := expandServiceConnectorAuthInfoForCreate(model.AuthInfo)
129+
if err != nil {
130+
return fmt.Errorf("expanding `authentication`: %+v", err)
131+
}
132+
133+
serviceConnectorProperties := servicelinker.LinkerProperties{
134+
AuthInfo: authInfo,
135+
}
136+
137+
if storageAccountId, err := commonids.ParseStorageAccountID(model.TargetResourceId); err == nil {
138+
targetResourceId := fmt.Sprintf("%s/blobServices/default", storageAccountId.ID())
139+
serviceConnectorProperties.TargetService = servicelinker.AzureResource{
140+
Id: &targetResourceId,
141+
}
142+
} else {
143+
serviceConnectorProperties.TargetService = servicelinker.AzureResource{
144+
Id: &model.TargetResourceId,
145+
}
146+
}
147+
148+
if model.SecretStore != nil {
149+
secretStore := expandSecretStore(model.SecretStore)
150+
serviceConnectorProperties.SecretStore = secretStore
151+
}
152+
153+
if model.ClientType != "" {
154+
clientType := servicelinker.ClientType(model.ClientType)
155+
serviceConnectorProperties.ClientType = &clientType
156+
}
157+
158+
if model.VnetSolution != "" {
159+
vNetSolutionType := servicelinker.VNetSolutionType(model.VnetSolution)
160+
vNetSolution := servicelinker.VNetSolution{
161+
Type: &vNetSolutionType,
162+
}
163+
serviceConnectorProperties.VNetSolution = &vNetSolution
164+
}
165+
166+
props := servicelinker.LinkerResource{
167+
Id: utils.String(id.ID()),
168+
Name: utils.String(model.Name),
169+
Properties: serviceConnectorProperties,
170+
}
171+
172+
if err := client.LinkerCreateOrUpdateThenPoll(ctx, id, props); err != nil {
173+
return fmt.Errorf("creating %s: %+v", id, err)
174+
}
175+
176+
metadata.SetID(id)
177+
return nil
178+
},
179+
}
180+
}
181+
182+
func (r KubernetesClusterConnectorResource) Read() sdk.ResourceFunc {
183+
return sdk.ResourceFunc{
184+
Timeout: 5 * time.Minute,
185+
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
186+
client := metadata.Client.ServiceConnector.ServiceLinkerClient
187+
id, err := servicelinker.ParseScopedLinkerID(metadata.ResourceData.Id())
188+
if err != nil {
189+
return err
190+
}
191+
192+
resp, err := client.LinkerGet(ctx, *id)
193+
if err != nil {
194+
if response.WasNotFound(resp.HttpResponse) {
195+
return metadata.MarkAsGone(id)
196+
}
197+
return fmt.Errorf("reading %s: %+v", *id, err)
198+
}
199+
200+
pwd := metadata.ResourceData.Get("authentication.0.secret").(string)
201+
202+
if model := resp.Model; model != nil {
203+
props := model.Properties
204+
if props.AuthInfo == nil || props.TargetService == nil {
205+
return nil
206+
}
207+
208+
state := KubernetesClusterConnectorResourceModel{
209+
Name: id.LinkerName,
210+
KubernetesClusterId: id.ResourceUri,
211+
TargetResourceId: flattenTargetService(props.TargetService),
212+
AuthInfo: flattenServiceConnectorAuthInfo(props.AuthInfo, pwd),
213+
}
214+
215+
if props.ClientType != nil {
216+
state.ClientType = string(*props.ClientType)
217+
}
218+
219+
if props.VNetSolution != nil && props.VNetSolution.Type != nil {
220+
state.VnetSolution = string(*props.VNetSolution.Type)
221+
}
222+
223+
if props.SecretStore != nil {
224+
state.SecretStore = flattenSecretStore(*props.SecretStore)
225+
}
226+
227+
return metadata.Encode(&state)
228+
}
229+
return nil
230+
},
231+
}
232+
}
233+
234+
func (r KubernetesClusterConnectorResource) Delete() sdk.ResourceFunc {
235+
return sdk.ResourceFunc{
236+
Timeout: 30 * time.Minute,
237+
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
238+
client := metadata.Client.ServiceConnector.LinksClient
239+
id, err := links.ParseScopedLinkerID(metadata.ResourceData.Id())
240+
if err != nil {
241+
return err
242+
}
243+
244+
metadata.Logger.Infof("deleting %s", *id)
245+
246+
if err := client.LinkerDeleteThenPoll(ctx, *id); err != nil {
247+
return fmt.Errorf("deleting %s: %+v", *id, err)
248+
}
249+
250+
return nil
251+
},
252+
}
253+
}
254+
255+
func (r KubernetesClusterConnectorResource) Update() sdk.ResourceFunc {
256+
return sdk.ResourceFunc{
257+
Timeout: 30 * time.Minute,
258+
Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
259+
client := metadata.Client.ServiceConnector.LinksClient
260+
id, err := links.ParseScopedLinkerID(metadata.ResourceData.Id())
261+
if err != nil {
262+
return err
263+
}
264+
265+
var state KubernetesClusterConnectorResourceModel
266+
if err := metadata.Decode(&state); err != nil {
267+
return fmt.Errorf("decoding: %+v", err)
268+
}
269+
270+
linkerProps := links.LinkerProperties{}
271+
d := metadata.ResourceData
272+
273+
if d.HasChange("client_type") {
274+
clientType := links.ClientType(state.ClientType)
275+
linkerProps.ClientType = &clientType
276+
}
277+
278+
if d.HasChange("vnet_solution") {
279+
vnetSolutionType := links.VNetSolutionType(state.VnetSolution)
280+
vnetSolution := links.VNetSolution{
281+
Type: &vnetSolutionType,
282+
}
283+
linkerProps.VNetSolution = &vnetSolution
284+
}
285+
286+
if d.HasChange("secret_store") {
287+
linkerProps.SecretStore = pointer.To(links.SecretStore{KeyVaultId: expandSecretStore(state.SecretStore).KeyVaultId})
288+
}
289+
290+
if d.HasChange("authentication") {
291+
authInfo, err := expandServiceConnectorAuthInfoForUpdate(state.AuthInfo)
292+
if err != nil {
293+
return fmt.Errorf("expanding `authentication`: %+v", err)
294+
}
295+
296+
linkerProps.AuthInfo = authInfo
297+
}
298+
299+
props := links.LinkerPatch{
300+
Properties: &linkerProps,
301+
}
302+
303+
if err := client.LinkerUpdateThenPoll(ctx, *id, props); err != nil {
304+
return fmt.Errorf("updating %s: %+v", *id, err)
305+
}
306+
307+
return nil
308+
},
309+
}
310+
}
311+
312+
func (r KubernetesClusterConnectorResource) IDValidationFunc() pluginsdk.SchemaValidateFunc {
313+
return servicelinker.ValidateScopedLinkerID
314+
}

0 commit comments

Comments
 (0)