Skip to content

Commit d086f04

Browse files
committed
Add advanced settings support for clickpipes
1 parent c0e3b18 commit d086f04

File tree

4 files changed

+198
-3
lines changed

4 files changed

+198
-3
lines changed

pkg/internal/api/clickpipe_models.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ type ClickPipe struct {
191191
Source ClickPipeSource `json:"source"`
192192
Destination ClickPipeDestination `json:"destination"`
193193
FieldMappings []ClickPipeFieldMapping `json:"fieldMappings"`
194+
Settings map[string]interface{} `json:"settings,omitempty"`
194195
CreatedAt *time.Time `json:"createdAt,omitempty"`
195196
UpdatedAt *time.Time `json:"updatedAt,omitempty"`
196197
}
@@ -200,4 +201,5 @@ type ClickPipeUpdate struct {
200201
Source *ClickPipeSource `json:"source,omitempty"`
201202
Destination *ClickPipeDestinationUpdate `json:"destination,omitempty"`
202203
FieldMappings []ClickPipeFieldMapping `json:"fieldMappings,omitempty"`
204+
Settings map[string]interface{} `json:"settings,omitempty"`
203205
}

pkg/internal/api/interface.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ type Client interface {
3232
ScalingClickPipe(ctx context.Context, serviceId string, clickPipeId string, request ClickPipeScalingRequest) (*ClickPipe, error)
3333
ChangeClickPipeState(ctx context.Context, serviceId string, clickPipeId string, command string) (*ClickPipe, error)
3434
DeleteClickPipe(ctx context.Context, serviceId string, clickPipeId string) error
35+
GetClickPipeSettings(ctx context.Context, serviceId string, clickPipeId string) (map[string]interface{}, error)
36+
UpdateClickPipeSettings(ctx context.Context, serviceId string, clickPipeId string, settings map[string]interface{}) (map[string]interface{}, error)
3537

3638
GetReversePrivateEndpointPath(serviceId, reversePrivateEndpointId string) string
3739
ListReversePrivateEndpoints(ctx context.Context, serviceId string) ([]*ReversePrivateEndpoint, error)

pkg/resource/clickpipe.go

Lines changed: 193 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package resource
55
import (
66
"context"
77
"fmt"
8+
"math/big"
89
"strings"
910

1011
"github.com/ClickHouse/terraform-provider-clickhouse/pkg/internal/api"
@@ -656,6 +657,10 @@ func (c *ClickPipeResource) Schema(_ context.Context, _ resource.SchemaRequest,
656657
},
657658
},
658659
},
660+
"settings": schema.DynamicAttribute{
661+
Description: "Advanced settings for the ClickPipe. These settings are pipe-specific configurations.",
662+
Optional: true,
663+
},
659664
},
660665
}
661666
}
@@ -764,6 +769,59 @@ func (c *ClickPipeResource) Create(ctx context.Context, request resource.CreateR
764769
}
765770
}
766771

772+
// Handle settings
773+
if !plan.Settings.IsNull() && !plan.Settings.IsUnknown() {
774+
settingsMap := make(map[string]interface{})
775+
underlyingValue := plan.Settings.UnderlyingValue()
776+
777+
// Settings should be an object/map at the top level
778+
if objValue, ok := underlyingValue.(types.Object); ok {
779+
for key, value := range objValue.Attributes() {
780+
if dynamicValue, ok := value.(types.Dynamic); ok {
781+
innerValue := dynamicValue.UnderlyingValue()
782+
switch v := innerValue.(type) {
783+
case types.String:
784+
settingsMap[key] = v.ValueString()
785+
case types.Bool:
786+
settingsMap[key] = v.ValueBool()
787+
case types.Number:
788+
if intVal, accuracy := v.ValueBigFloat().Int64(); accuracy == big.Exact {
789+
settingsMap[key] = intVal
790+
} else if floatVal, accuracy := v.ValueBigFloat().Float64(); accuracy == big.Exact {
791+
settingsMap[key] = floatVal
792+
} else {
793+
settingsMap[key] = v.ValueBigFloat().String()
794+
}
795+
default:
796+
settingsMap[key] = fmt.Sprintf("%v", v)
797+
}
798+
} else {
799+
// Handle direct values
800+
switch v := value.(type) {
801+
case types.String:
802+
settingsMap[key] = v.ValueString()
803+
case types.Bool:
804+
settingsMap[key] = v.ValueBool()
805+
case types.Number:
806+
if intVal, accuracy := v.ValueBigFloat().Int64(); accuracy == big.Exact {
807+
settingsMap[key] = intVal
808+
} else if floatVal, accuracy := v.ValueBigFloat().Float64(); accuracy == big.Exact {
809+
settingsMap[key] = floatVal
810+
} else {
811+
settingsMap[key] = v.ValueBigFloat().String()
812+
}
813+
default:
814+
settingsMap[key] = fmt.Sprintf("%v", v)
815+
}
816+
}
817+
}
818+
}
819+
820+
if len(settingsMap) > 0 {
821+
clickPipe.Settings = settingsMap
822+
}
823+
}
824+
767825
createdClickPipe, err := c.client.CreateClickPipe(ctx, serviceID, clickPipe)
768826
if err != nil {
769827
response.Diagnostics.AddError(
@@ -1115,10 +1173,36 @@ func (c *ClickPipeResource) syncClickPipeState(ctx context.Context, state *model
11151173
state.State = types.StringValue(clickPipe.State)
11161174

11171175
if clickPipe.Scaling != nil {
1176+
cpuMillicores := clickPipe.Scaling.GetCpuMillicores()
1177+
memoryGb := clickPipe.Scaling.GetMemoryGb()
1178+
1179+
// Create scaling model with proper null handling
1180+
var replicasValue types.Int64
1181+
var cpuValue types.Int64
1182+
var memoryValue types.Float64
1183+
1184+
if clickPipe.Scaling.Replicas != nil {
1185+
replicasValue = types.Int64Value(*clickPipe.Scaling.Replicas)
1186+
} else {
1187+
replicasValue = types.Int64Null()
1188+
}
1189+
1190+
if cpuMillicores != nil {
1191+
cpuValue = types.Int64Value(*cpuMillicores)
1192+
} else {
1193+
cpuValue = types.Int64Null()
1194+
}
1195+
1196+
if memoryGb != nil {
1197+
memoryValue = types.Float64Value(*memoryGb)
1198+
} else {
1199+
memoryValue = types.Float64Null()
1200+
}
1201+
11181202
scalingModel := models.ClickPipeScalingModel{
1119-
Replicas: types.Int64PointerValue(clickPipe.Scaling.Replicas),
1120-
ReplicaCpuMillicores: types.Int64PointerValue(clickPipe.Scaling.GetCpuMillicores()),
1121-
ReplicaMemoryGb: types.Float64PointerValue(clickPipe.Scaling.GetMemoryGb()),
1203+
Replicas: replicasValue,
1204+
ReplicaCpuMillicores: cpuValue,
1205+
ReplicaMemoryGb: memoryValue,
11221206
}
11231207

11241208
state.Scaling = scalingModel.ObjectValue()
@@ -1373,6 +1457,45 @@ func (c *ClickPipeResource) syncClickPipeState(ctx context.Context, state *model
13731457
state.FieldMappings, _ = types.ListValue(models.ClickPipeFieldMappingModel{}.ObjectType(), fieldMappingList)
13741458
}
13751459

1460+
// Handle settings
1461+
if clickPipe.Settings != nil && len(clickPipe.Settings) > 0 {
1462+
settingsElements := make(map[string]attr.Value)
1463+
for key, value := range clickPipe.Settings {
1464+
switch v := value.(type) {
1465+
case string:
1466+
settingsElements[key] = types.StringValue(v)
1467+
case bool:
1468+
settingsElements[key] = types.BoolValue(v)
1469+
case int64:
1470+
settingsElements[key] = types.NumberValue(big.NewFloat(float64(v)))
1471+
case float64:
1472+
settingsElements[key] = types.NumberValue(big.NewFloat(v))
1473+
case int:
1474+
settingsElements[key] = types.NumberValue(big.NewFloat(float64(v)))
1475+
case float32:
1476+
settingsElements[key] = types.NumberValue(big.NewFloat(float64(v)))
1477+
default:
1478+
// Fallback to string representation
1479+
settingsElements[key] = types.StringValue(fmt.Sprintf("%v", v))
1480+
}
1481+
}
1482+
settingsObj, _ := types.ObjectValue(
1483+
map[string]attr.Type{},
1484+
make(map[string]attr.Value),
1485+
)
1486+
1487+
// Create object type dynamically based on actual values
1488+
attrTypes := make(map[string]attr.Type)
1489+
for key := range settingsElements {
1490+
attrTypes[key] = settingsElements[key].Type(ctx)
1491+
}
1492+
1493+
settingsObj, _ = types.ObjectValue(attrTypes, settingsElements)
1494+
state.Settings = types.DynamicValue(settingsObj)
1495+
} else {
1496+
state.Settings = types.DynamicNull()
1497+
}
1498+
13761499
return nil
13771500
}
13781501

@@ -1477,6 +1600,62 @@ func (c *ClickPipeResource) Update(ctx context.Context, req resource.UpdateReque
14771600
}
14781601
}
14791602

1603+
// Handle settings separately using dedicated endpoint
1604+
var settingsChanged bool
1605+
var newSettingsMap map[string]interface{}
1606+
1607+
if !plan.Settings.Equal(state.Settings) {
1608+
settingsChanged = true
1609+
newSettingsMap = make(map[string]interface{})
1610+
if !plan.Settings.IsNull() && !plan.Settings.IsUnknown() {
1611+
underlyingValue := plan.Settings.UnderlyingValue()
1612+
1613+
// Settings should be an object/map at the top level
1614+
if objValue, ok := underlyingValue.(types.Object); ok {
1615+
for key, value := range objValue.Attributes() {
1616+
if dynamicValue, ok := value.(types.Dynamic); ok {
1617+
innerValue := dynamicValue.UnderlyingValue()
1618+
switch v := innerValue.(type) {
1619+
case types.String:
1620+
newSettingsMap[key] = v.ValueString()
1621+
case types.Bool:
1622+
newSettingsMap[key] = v.ValueBool()
1623+
case types.Number:
1624+
if intVal, accuracy := v.ValueBigFloat().Int64(); accuracy == big.Exact {
1625+
newSettingsMap[key] = intVal
1626+
} else if floatVal, accuracy := v.ValueBigFloat().Float64(); accuracy == big.Exact {
1627+
newSettingsMap[key] = floatVal
1628+
} else {
1629+
newSettingsMap[key] = v.ValueBigFloat().String()
1630+
}
1631+
default:
1632+
newSettingsMap[key] = fmt.Sprintf("%v", v)
1633+
}
1634+
} else {
1635+
// Handle direct values
1636+
switch v := value.(type) {
1637+
case types.String:
1638+
newSettingsMap[key] = v.ValueString()
1639+
case types.Bool:
1640+
newSettingsMap[key] = v.ValueBool()
1641+
case types.Number:
1642+
if intVal, accuracy := v.ValueBigFloat().Int64(); accuracy == big.Exact {
1643+
newSettingsMap[key] = intVal
1644+
} else if floatVal, accuracy := v.ValueBigFloat().Float64(); accuracy == big.Exact {
1645+
newSettingsMap[key] = floatVal
1646+
} else {
1647+
newSettingsMap[key] = v.ValueBigFloat().String()
1648+
}
1649+
default:
1650+
newSettingsMap[key] = fmt.Sprintf("%v", v)
1651+
}
1652+
}
1653+
}
1654+
}
1655+
}
1656+
}
1657+
1658+
// Update the main ClickPipe if non-settings fields changed
14801659
if pipeChanged {
14811660
if _, err := c.client.UpdateClickPipe(ctx, state.ServiceID.ValueString(), state.ID.ValueString(), clickPipeUpdate); err != nil {
14821661
response.Diagnostics.AddError(
@@ -1487,6 +1666,17 @@ func (c *ClickPipeResource) Update(ctx context.Context, req resource.UpdateReque
14871666
}
14881667
}
14891668

1669+
// Update settings separately if they changed
1670+
if settingsChanged {
1671+
if _, err := c.client.UpdateClickPipeSettings(ctx, state.ServiceID.ValueString(), state.ID.ValueString(), newSettingsMap); err != nil {
1672+
response.Diagnostics.AddError(
1673+
"Error Updating ClickPipe Settings",
1674+
"Could not update ClickPipe settings, unexpected error: "+err.Error(),
1675+
)
1676+
return
1677+
}
1678+
}
1679+
14901680
if !plan.State.Equal(state.State) {
14911681
var command string
14921682

pkg/resource/models/clickpipe_resource.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,4 +455,5 @@ type ClickPipeResourceModel struct {
455455
Source types.Object `tfsdk:"source"`
456456
Destination types.Object `tfsdk:"destination"`
457457
FieldMappings types.List `tfsdk:"field_mappings"`
458+
Settings types.Dynamic `tfsdk:"settings"`
458459
}

0 commit comments

Comments
 (0)