From cb977b3c73a723c1abb602a4fe43af63f15a697c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wilson=20J=C3=BAnior?= Date: Thu, 13 Feb 2025 10:52:22 -0300 Subject: [PATCH 1/3] Update dependencies for rpaas-operator and Kubernetes libraries to latest versions --- go.mod | 17 +++++++++-------- go.sum | 32 ++++++++++++++++---------------- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index 00b442c..2a72a91 100644 --- a/go.mod +++ b/go.mod @@ -11,8 +11,8 @@ require ( github.com/hashicorp/terraform-plugin-sdk/v2 v2.27.0 github.com/stretchr/testify v1.8.4 github.com/tsuru/go-tsuruclient v0.0.0-20240403182619-fe8da980483b - github.com/tsuru/rpaas-operator v0.43.0 - k8s.io/apimachinery v0.26.2 + github.com/tsuru/rpaas-operator v0.45.0 + k8s.io/apimachinery v0.26.7 ) require ( @@ -144,6 +144,7 @@ require ( go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect go.uber.org/atomic v1.10.0 // indirect golang.org/x/crypto v0.11.0 // indirect + golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect golang.org/x/mod v0.10.0 // indirect golang.org/x/net v0.12.0 // indirect golang.org/x/oauth2 v0.10.0 // indirect @@ -161,16 +162,16 @@ require ( gopkg.in/ini.v1 v1.66.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/api v0.26.2 // indirect + k8s.io/api v0.26.7 // indirect k8s.io/apiextensions-apiserver v0.26.2 // indirect - k8s.io/cli-runtime v0.26.2 // indirect - k8s.io/client-go v0.26.2 // indirect - k8s.io/component-base v0.26.2 // indirect + k8s.io/cli-runtime v0.26.7 // indirect + k8s.io/client-go v0.26.7 // indirect + k8s.io/component-base v0.26.7 // indirect k8s.io/klog/v2 v2.90.1 // indirect k8s.io/kube-aggregator v0.24.2 // indirect k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d // indirect - k8s.io/kubectl v0.26.2 // indirect - k8s.io/metrics v0.26.2 // indirect + k8s.io/kubectl v0.26.7 // indirect + k8s.io/metrics v0.26.7 // indirect k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 // indirect knative.dev/pkg v0.0.0-20230306194819-b77a78c6c0ad // indirect sigs.k8s.io/controller-runtime v0.14.5 // indirect diff --git a/go.sum b/go.sum index ed687f4..00080e0 100644 --- a/go.sum +++ b/go.sum @@ -759,8 +759,8 @@ github.com/tsuru/go-tsuruclient v0.0.0-20240403182619-fe8da980483b h1:CWioMVdmtk github.com/tsuru/go-tsuruclient v0.0.0-20240403182619-fe8da980483b/go.mod h1:qwh/KJ6ypa2GISRI79XFOHhnSjGOe1cZVPHF3nfrf18= github.com/tsuru/nginx-operator v0.15.2-0.20240515194244-a38b4b58e866 h1:aCoSpcfQuMztS/7xFrQ2ml02NxqipXYLMgJonyux6fk= github.com/tsuru/nginx-operator v0.15.2-0.20240515194244-a38b4b58e866/go.mod h1:qdJQVY4buUQymyhcpYO99ZCfLMPRvcB/1ywK3PAh/+Q= -github.com/tsuru/rpaas-operator v0.43.0 h1:QLeNUiDFIrHeVwVlzmVieWoBJfAGgC/9DT1rDuafRl8= -github.com/tsuru/rpaas-operator v0.43.0/go.mod h1:dxlwKGKICcstTwH0sbrrsb9Shsl2/BdDVo7uh1FWWRQ= +github.com/tsuru/rpaas-operator v0.45.0 h1:c0pf6nxSGzriuBx61k1V5dFGHtaPWqnZQEghfqTRizM= +github.com/tsuru/rpaas-operator v0.45.0/go.mod h1:aUYNaPrPgNn/5k+VdA+6JgcPwYkhUvh790r8Q0vZ+O4= github.com/tsuru/stern v1.20.2-0.20210928180051-1157b938dc3f h1:9dTZI6bQUVkKAsCnqaDl4V7fKAc5ErVpmX+bzevz3Cg= github.com/tsuru/stern v1.20.2-0.20210928180051-1157b938dc3f/go.mod h1:SUQKJ3CLsVARBwkz5z9IIL8Pj008JNj4U8eF50kkm2c= github.com/tsuru/tablecli v0.0.0-20190131152944-7ded8a3383c6 h1:1XDdWFAjIbCSG1OjN9v9KdWhuM8UtYlFcfHe/Ldkchk= @@ -1349,32 +1349,32 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 k8s.io/api v0.21.3/go.mod h1:hUgeYHUbBp23Ue4qdX9tR8/ANi/g3ehylAqDn9NWVOg= k8s.io/api v0.22.1/go.mod h1:bh13rkTp3F1XEaLGykbyRD2QaTTzPm0e/BMd8ptFONY= k8s.io/api v0.24.2/go.mod h1:AHqbSkTm6YrQ0ObxjO3Pmp/ubFF/KuM7jU+3khoBsOg= -k8s.io/api v0.26.2 h1:dM3cinp3PGB6asOySalOZxEG4CZ0IAdJsrYZXE/ovGQ= -k8s.io/api v0.26.2/go.mod h1:1kjMQsFE+QHPfskEcVNgL3+Hp88B80uj0QtSOlj8itU= +k8s.io/api v0.26.7 h1:Lf4iEBEJb5OFNmawtBfSZV/UNi9riSJ0t1qdhyZqI40= +k8s.io/api v0.26.7/go.mod h1:Vk9bMadzA49UHPmHB//lX7VRCQSXGoVwfLd3Sc1SSXI= k8s.io/apiextensions-apiserver v0.21.3/go.mod h1:kl6dap3Gd45+21Jnh6utCx8Z2xxLm8LGDkprcd+KbsE= k8s.io/apiextensions-apiserver v0.26.2 h1:/yTG2B9jGY2Q70iGskMf41qTLhL9XeNN2KhI0uDgwko= k8s.io/apiextensions-apiserver v0.26.2/go.mod h1:Y7UPgch8nph8mGCuVk0SK83LnS8Esf3n6fUBgew8SH8= k8s.io/apimachinery v0.21.3/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI= k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0= k8s.io/apimachinery v0.24.2/go.mod h1:82Bi4sCzVBdpYjyI4jY6aHX+YCUchUIrZrXKedjd2UM= -k8s.io/apimachinery v0.26.2 h1:da1u3D5wfR5u2RpLhE/ZtZS2P7QvDgLZTi9wrNZl/tQ= -k8s.io/apimachinery v0.26.2/go.mod h1:ats7nN1LExKHvJ9TmwootT00Yz05MuYqPXEXaVeOy5I= +k8s.io/apimachinery v0.26.7 h1:590jSBwaSHCAFCqltaEogY/zybFlhGsnLteLpuF2wig= +k8s.io/apimachinery v0.26.7/go.mod h1:qYzLkrQ9lhrZRh0jNKo2cfvf/R1/kQONnSiyB7NUJU0= k8s.io/apiserver v0.21.3/go.mod h1:eDPWlZG6/cCCMj/JBcEpDoK+I+6i3r9GsChYBHSbAzU= k8s.io/apiserver v0.24.2/go.mod h1:pSuKzr3zV+L+MWqsEo0kHHYwCo77AT5qXbFXP2jbvFI= -k8s.io/cli-runtime v0.26.2 h1:6XcIQOYW1RGNwFgRwejvyUyAojhToPmJLGr0JBMC5jw= -k8s.io/cli-runtime v0.26.2/go.mod h1:U7sIXX7n6ZB+MmYQsyJratzPeJwgITqrSlpr1a5wM5I= +k8s.io/cli-runtime v0.26.7 h1:ZhAV9RK9wzXUeMKVvtVVX8jnsJcxw6hcSAu4K3eQbEo= +k8s.io/cli-runtime v0.26.7/go.mod h1:THp0KBlPxRk4SdpeoBmsuxJwNrwfpTT4+oDaNqhpv0c= k8s.io/client-go v0.21.3/go.mod h1:+VPhCgTsaFmGILxR/7E1N0S+ryO010QBeNCv5JwRGYU= k8s.io/client-go v0.22.1/go.mod h1:BquC5A4UOo4qVDUtoc04/+Nxp1MeHcVc1HJm1KmG8kk= k8s.io/client-go v0.24.2/go.mod h1:zg4Xaoo+umDsfCWr4fCnmLEtQXyCNXCvJuSsglNcV30= -k8s.io/client-go v0.26.2 h1:s1WkVujHX3kTp4Zn4yGNFK+dlDXy1bAAkIl+cFAiuYI= -k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU= +k8s.io/client-go v0.26.7 h1:hyU9aKHlwVOykgyxzGYkrDSLCc4+mimZVyUJjPyUn1E= +k8s.io/client-go v0.26.7/go.mod h1:okYjy0jtq6sdeztALDvCh24tg4opOQS1XNvsJlERDAo= k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo= k8s.io/code-generator v0.22.0/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o= k8s.io/code-generator v0.24.2/go.mod h1:dpVhs00hTuTdTY6jvVxvTFCk6gSMrtfRydbhZwHI15w= k8s.io/component-base v0.21.3/go.mod h1:kkuhtfEHeZM6LkX0saqSK8PbdO7A0HigUngmhhrwfGQ= k8s.io/component-base v0.24.2/go.mod h1:ucHwW76dajvQ9B7+zecZAP3BVqvrHoOxm8olHEg0nmM= -k8s.io/component-base v0.26.2 h1:IfWgCGUDzrD6wLLgXEstJKYZKAFS2kO+rBRi0p3LqcI= -k8s.io/component-base v0.26.2/go.mod h1:DxbuIe9M3IZPRxPIzhch2m1eT7uFrSBJUBuVCQEBivs= +k8s.io/component-base v0.26.7 h1:uqsOyZh0Zqoaup8tmHa491D/CvgFdGUs+X2H/inNUKM= +k8s.io/component-base v0.26.7/go.mod h1:CZe1HTmX/DQdeBrb9XYOXzs96jXth8ZbFvhLMsoJLUg= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20201203183100-97869a43a9d9/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= @@ -1396,10 +1396,10 @@ k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2R k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d h1:VcFq5n7wCJB2FQMCIHfC+f+jNcGgNMar1uKd6rVlifU= k8s.io/kube-openapi v0.0.0-20230303024457-afdc3dddf62d/go.mod h1:y5VtZWM9sHHc2ZodIH/6SHzXj+TPU5USoA8lcIeKEKY= -k8s.io/kubectl v0.26.2 h1:SMPB4j48eVFxsYluBq3VLyqXtE6b72YnszkbTAtFye4= -k8s.io/kubectl v0.26.2/go.mod h1:KYWOXSwp2BrDn3kPeoU/uKzKtdqvhK1dgZGd0+no4cM= -k8s.io/metrics v0.26.2 h1:2gUvUWWnHPdE2tyA5DvyHC8HGryr+izhY9i5dzLP06s= -k8s.io/metrics v0.26.2/go.mod h1:PX1wm9REV9hSGuw9GcXTFNDgab1KRXck3mNeiLYbRho= +k8s.io/kubectl v0.26.7 h1:s24r6MjKDMW4sMOsuBLaNYQHlweTZeDC0BPkMiom8s0= +k8s.io/kubectl v0.26.7/go.mod h1:4PGqS2bPQ5yGE0ZSQajzYdWKFUAi8HiuWBZQ2/iEFHg= +k8s.io/metrics v0.26.7 h1:GziC+HlH1Gpbh4xrI5Vfz8QxBmy5nXzzRiul2HS5Ioc= +k8s.io/metrics v0.26.7/go.mod h1:k1LCQu9vAS1HRZ2BGAosFHy2qSGZEUYn6bqHVMiFNK0= k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= From 8ae712ce4dfe63f2bd14b32f11a80630937f7612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wilson=20J=C3=BAnior?= Date: Thu, 13 Feb 2025 11:55:09 -0300 Subject: [PATCH 2/3] Add support for server_name parameter in rpaas_route resource --- internal/provider/resource_rpaas_route.go | 101 ++++++++++------- .../provider/resource_rpaas_route_test.go | 104 ++++++++++++++++++ 2 files changed, 168 insertions(+), 37 deletions(-) diff --git a/internal/provider/resource_rpaas_route.go b/internal/provider/resource_rpaas_route.go index d4a01b3..9c6f965 100644 --- a/internal/provider/resource_rpaas_route.go +++ b/internal/provider/resource_rpaas_route.go @@ -39,6 +39,12 @@ func resourceRpaasRoute() *schema.Resource { ForceNew: true, Description: "RPaaS Service Name", }, + "server_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Optional parameter used to match the server name in the location block. If not provided, it will apply to all servers.", + }, "path": { Type: schema.TypeString, Required: true, @@ -72,6 +78,7 @@ func resourceRpaasRouteCreate(ctx context.Context, d *schema.ResourceData, meta instance := d.Get("instance").(string) serviceName := d.Get("service_name").(string) + serverName := d.Get("server_name").(string) path := d.Get("path").(string) rpaasClient, err := provider.RpaasClient.SetService(serviceName) @@ -80,27 +87,33 @@ func resourceRpaasRouteCreate(ctx context.Context, d *schema.ResourceData, meta } tflog.Info(ctx, "Create route", map[string]interface{}{ - "service": serviceName, - "instance": instance, - "path": path, + "service": serviceName, + "instance": instance, + "serverName": serverName, + "path": path, }) err = rpaasRetry(ctx, d.Timeout(schema.TimeoutCreate), func() (*http.Response, error) { - return nil, updateRpaasRoute(ctx, d, instance, path, rpaasClient) + return nil, updateRpaasRoute(ctx, d, instance, serverName, path, rpaasClient) }) if err != nil { return diag.Errorf("Unable to create route %s for instance %s: %v", path, instance, err) } - d.SetId(fmt.Sprintf("%s::%s::%s", serviceName, instance, path)) + if serverName == "" { + d.SetId(fmt.Sprintf("%s::%s::%s", serviceName, instance, path)) + } else { + d.SetId(fmt.Sprintf("%s::%s::%s::%s", serviceName, instance, serverName, path)) + } + return resourceRpaasRouteRead(ctx, d, meta) } func resourceRpaasRouteUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { provider := meta.(*rpaasProvider) - serviceName, instance, path, err := parseRpaasRouteID(d.Id()) + serviceName, instance, serverName, path, err := parseRpaasRouteID(d.Id()) if err != nil { return diag.Errorf("Unable to parse Route ID: %v", err) } @@ -111,13 +124,14 @@ func resourceRpaasRouteUpdate(ctx context.Context, d *schema.ResourceData, meta } tflog.Info(ctx, "Update route", map[string]interface{}{ - "service": serviceName, - "instance": instance, - "path": path, + "service": serviceName, + "instance": instance, + "serverName": serverName, + "path": path, }) err = rpaasRetry(ctx, d.Timeout(schema.TimeoutUpdate), func() (*http.Response, error) { - return nil, updateRpaasRoute(ctx, d, instance, path, rpaasClient) + return nil, updateRpaasRoute(ctx, d, instance, serverName, path, rpaasClient) }) if err != nil { @@ -130,13 +144,14 @@ func resourceRpaasRouteUpdate(ctx context.Context, d *schema.ResourceData, meta func resourceRpaasRouteRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { provider := meta.(*rpaasProvider) - serviceName, instance, path, err := parseRpaasRouteID(d.Id()) + serviceName, instance, serverName, path, err := parseRpaasRouteID(d.Id()) if err != nil { return diag.Errorf("Unable to parse Route ID: %v", err) } d.Set("instance", instance) d.Set("service_name", serviceName) + d.Set("server_name", serverName) rpaasClient, err := provider.RpaasClient.SetService(serviceName) if err != nil { @@ -171,12 +186,17 @@ func resourceRpaasRouteRead(ctx context.Context, d *schema.ResourceData, meta in } for _, b := range routes { - if b.Path == path { + if b.ServerName == serverName && b.Path == path { d.Set("path", b.Path) d.Set("https_only", b.HTTPSOnly) d.Set("destination", b.Destination) d.Set("content", b.Content) - d.SetId(fmt.Sprintf("%s::%s::%s", serviceName, instance, path)) + + if serverName == "" { + d.SetId(fmt.Sprintf("%s::%s::%s", serviceName, instance, path)) + } else { + d.SetId(fmt.Sprintf("%s::%s::%s::%s", serviceName, instance, serverName, path)) + } return nil } } @@ -189,24 +209,28 @@ func resourceRpaasRouteRead(ctx context.Context, d *schema.ResourceData, meta in func resourceRpaasRouteDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { provider := meta.(*rpaasProvider) - instance := d.Get("instance").(string) - serviceName := d.Get("service_name").(string) - path := d.Get("path").(string) + serviceName, instance, serverName, path, err := parseRpaasRouteID(d.Id()) + if err != nil { + return diag.Errorf("Unable to parse Route ID: %v", err) + } + rpaasClient, err := provider.RpaasClient.SetService(serviceName) if err != nil { return diag.Errorf("Unable to create client for service %s: %v", serviceName, err) } tflog.Info(ctx, "Delete route", map[string]interface{}{ - "service": serviceName, - "instance": instance, - "path": path, + "service": serviceName, + "instance": instance, + "serverName": serverName, + "path": path, }) err = rpaasRetry(ctx, d.Timeout(schema.TimeoutDelete), func() (*http.Response, error) { return nil, rpaasClient.DeleteRoute(ctx, rpaas_client.DeleteRouteArgs{ - Instance: instance, - Path: path, + Instance: instance, + ServerName: serverName, + Path: path, }) }) @@ -217,28 +241,31 @@ func resourceRpaasRouteDelete(ctx context.Context, d *schema.ResourceData, meta return nil } -func parseRpaasRouteID(id string) (serviceName, instance, path string, err error) { +func parseRpaasRouteID(id string) (serviceName, instance, serverName, path string, err error) { splitID := strings.Split(id, "::") - if len(splitID) != 3 { - serviceName, instance, path, err = parseRpaasRouteID_legacyV0(id) - if err != nil { - err = fmt.Errorf("Could not parse id %q. Format should be \"service::instance::path\"", id) - } - return + if len(splitID) == 4 { + serviceName = splitID[0] + instance = splitID[1] + serverName = splitID[2] + path = splitID[3] + } else if len(splitID) == 3 { + serviceName = splitID[0] + instance = splitID[1] + path = splitID[2] + } else { + serviceName, instance, err = parseRpaasRouteID_legacyV0(id) } - serviceName = splitID[0] - instance = splitID[1] - path = splitID[2] return } -func updateRpaasRoute(ctx context.Context, d *schema.ResourceData, instance, path string, rpaasClient rpaas_client.Client) error { +func updateRpaasRoute(ctx context.Context, d *schema.ResourceData, instance, serverName, path string, rpaasClient rpaas_client.Client) error { args := rpaas_client.UpdateRouteArgs{ - Instance: instance, - Path: path, - HTTPSOnly: d.Get("https_only").(bool), + Instance: instance, + ServerName: serverName, + Path: path, + HTTPSOnly: d.Get("https_only").(bool), } if content, ok := d.GetOk("content"); ok { @@ -251,10 +278,10 @@ func updateRpaasRoute(ctx context.Context, d *schema.ResourceData, instance, pat return rpaasClient.UpdateRoute(ctx, args) } -func parseRpaasRouteID_legacyV0(id string) (serviceName, instance, path string, err error) { +func parseRpaasRouteID_legacyV0(id string) (serviceName, instance string, err error) { splitID := strings.Split(id, "/") if len(splitID) != 2 { - err = fmt.Errorf("Resource ID could not be parsed. Legacy WRONG format: \"service/instance\"") + err = fmt.Errorf("Could not parse id %q. Format should be \"service::instance::path\" or \"service::instance::serverName::path\"", id) return } diff --git a/internal/provider/resource_rpaas_route_test.go b/internal/provider/resource_rpaas_route_test.go index 5295c81..ca09ac2 100644 --- a/internal/provider/resource_rpaas_route_test.go +++ b/internal/provider/resource_rpaas_route_test.go @@ -99,6 +99,94 @@ func TestAccRpaasRoute_basic(t *testing.T) { }) } +func TestAccRpaasRoute_multiserver(t *testing.T) { + testAPIClient, testAPIServer := setupTestAPIServer(t) + defer testAPIServer.Stop() + + resourceName := "rpaas_route.custom_route" + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: resourceName, + ProviderFactories: testAccProviderFactories, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testAccRpaasRouteConfigWithServername("example.org", "/", "original content"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccResourceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "id", "rpaasv2-be::my-rpaas::example.org::/"), + resource.TestCheckResourceAttr(resourceName, "instance", "my-rpaas"), + resource.TestCheckResourceAttr(resourceName, "service_name", "rpaasv2-be"), + resource.TestCheckResourceAttr(resourceName, "server_name", "example.org"), + resource.TestCheckResourceAttr(resourceName, "path", "/"), + resource.TestCheckResourceAttr(resourceName, "https_only", "false"), + resource.TestCheckResourceAttr(resourceName, "content", "original content\n"), + resource.TestCheckResourceAttr(resourceName, "destination", ""), + func(s *terraform.State) error { + routes, err := testAPIClient.ListRoutes(context.Background(), client.ListRoutesArgs{Instance: "my-rpaas"}) + assert.NoError(t, err) + assert.Len(t, routes, 1) + assert.Equal(t, "/", routes[0].Path) + assert.Equal(t, false, routes[0].HTTPSOnly) + assert.Equal(t, "original content\n", routes[0].Content) + assert.Equal(t, "", routes[0].Destination) + return nil + }, + ), + }, + { + Config: testAccRpaasRouteConfigWithServername("example.org", "/", "change content"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccResourceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "id", "rpaasv2-be::my-rpaas::example.org::/"), + resource.TestCheckResourceAttr(resourceName, "instance", "my-rpaas"), + resource.TestCheckResourceAttr(resourceName, "service_name", "rpaasv2-be"), + resource.TestCheckResourceAttr(resourceName, "server_name", "example.org"), + + resource.TestCheckResourceAttr(resourceName, "path", "/"), + resource.TestCheckResourceAttr(resourceName, "https_only", "false"), + resource.TestCheckResourceAttr(resourceName, "content", "change content\n"), + resource.TestCheckResourceAttr(resourceName, "destination", ""), + func(s *terraform.State) error { + routes, err := testAPIClient.ListRoutes(context.Background(), client.ListRoutesArgs{Instance: "my-rpaas"}) + assert.NoError(t, err) + assert.Len(t, routes, 1) + assert.Equal(t, "/", routes[0].Path) + assert.Equal(t, false, routes[0].HTTPSOnly) + assert.Equal(t, "change content\n", routes[0].Content) + assert.Equal(t, "", routes[0].Destination) + return nil + }, + ), + }, + { + Config: testAccRpaasRouteConfigWithServername("example.org", "/another/path", "change content"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccResourceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "id", "rpaasv2-be::my-rpaas::example.org::/another/path"), + resource.TestCheckResourceAttr(resourceName, "instance", "my-rpaas"), + resource.TestCheckResourceAttr(resourceName, "service_name", "rpaasv2-be"), + resource.TestCheckResourceAttr(resourceName, "server_name", "example.org"), + resource.TestCheckResourceAttr(resourceName, "path", "/another/path"), + resource.TestCheckResourceAttr(resourceName, "https_only", "false"), + resource.TestCheckResourceAttr(resourceName, "content", "change content\n"), + resource.TestCheckResourceAttr(resourceName, "destination", ""), + func(s *terraform.State) error { + routes, err := testAPIClient.ListRoutes(context.Background(), client.ListRoutesArgs{Instance: "my-rpaas"}) + assert.NoError(t, err) + assert.Len(t, routes, 1) + assert.Equal(t, "/another/path", routes[0].Path) + assert.Equal(t, false, routes[0].HTTPSOnly) + assert.Equal(t, "change content\n", routes[0].Content) + assert.Equal(t, "", routes[0].Destination) + return nil + }, + ), + }, + }, + }) +} + func TestAccRpaasRoute_import(t *testing.T) { testAPIClient, testAPIServer := setupTestAPIServer(t) defer testAPIServer.Stop() @@ -161,3 +249,19 @@ resource "rpaas_route" "custom_route" { } `, path, content) } + +func testAccRpaasRouteConfigWithServername(serverName, path, content string) string { + return fmt.Sprintf(` +resource "rpaas_route" "custom_route" { + instance = "my-rpaas" + service_name = "rpaasv2-be" + server_name = "%s" + + path = "%s" + + content = <<-EOF + %s + EOF +} +`, serverName, path, content) +} From dfcc562e90f4b3966f652932887c4faa5ff1026a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wilson=20J=C3=BAnior?= Date: Thu, 13 Feb 2025 17:16:38 -0300 Subject: [PATCH 3/3] Add support for server_name parameter in rpaas_block resource --- go.mod | 2 +- go.sum | 4 +- internal/provider/resource_rpaas_block.go | 119 ++++++++++++------ .../provider/resource_rpaas_block_test.go | 74 +++++++++++ 4 files changed, 157 insertions(+), 42 deletions(-) diff --git a/go.mod b/go.mod index 2a72a91..f3d545b 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/hashicorp/terraform-plugin-sdk/v2 v2.27.0 github.com/stretchr/testify v1.8.4 github.com/tsuru/go-tsuruclient v0.0.0-20240403182619-fe8da980483b - github.com/tsuru/rpaas-operator v0.45.0 + github.com/tsuru/rpaas-operator v0.45.1 k8s.io/apimachinery v0.26.7 ) diff --git a/go.sum b/go.sum index 00080e0..e3c43d5 100644 --- a/go.sum +++ b/go.sum @@ -759,8 +759,8 @@ github.com/tsuru/go-tsuruclient v0.0.0-20240403182619-fe8da980483b h1:CWioMVdmtk github.com/tsuru/go-tsuruclient v0.0.0-20240403182619-fe8da980483b/go.mod h1:qwh/KJ6ypa2GISRI79XFOHhnSjGOe1cZVPHF3nfrf18= github.com/tsuru/nginx-operator v0.15.2-0.20240515194244-a38b4b58e866 h1:aCoSpcfQuMztS/7xFrQ2ml02NxqipXYLMgJonyux6fk= github.com/tsuru/nginx-operator v0.15.2-0.20240515194244-a38b4b58e866/go.mod h1:qdJQVY4buUQymyhcpYO99ZCfLMPRvcB/1ywK3PAh/+Q= -github.com/tsuru/rpaas-operator v0.45.0 h1:c0pf6nxSGzriuBx61k1V5dFGHtaPWqnZQEghfqTRizM= -github.com/tsuru/rpaas-operator v0.45.0/go.mod h1:aUYNaPrPgNn/5k+VdA+6JgcPwYkhUvh790r8Q0vZ+O4= +github.com/tsuru/rpaas-operator v0.45.1 h1:TTfS95vPOO7mpfpMTtqrLDA/ctA9wGl4A2p75cXm0K0= +github.com/tsuru/rpaas-operator v0.45.1/go.mod h1:aUYNaPrPgNn/5k+VdA+6JgcPwYkhUvh790r8Q0vZ+O4= github.com/tsuru/stern v1.20.2-0.20210928180051-1157b938dc3f h1:9dTZI6bQUVkKAsCnqaDl4V7fKAc5ErVpmX+bzevz3Cg= github.com/tsuru/stern v1.20.2-0.20210928180051-1157b938dc3f/go.mod h1:SUQKJ3CLsVARBwkz5z9IIL8Pj008JNj4U8eF50kkm2c= github.com/tsuru/tablecli v0.0.0-20190131152944-7ded8a3383c6 h1:1XDdWFAjIbCSG1OjN9v9KdWhuM8UtYlFcfHe/Ldkchk= diff --git a/internal/provider/resource_rpaas_block.go b/internal/provider/resource_rpaas_block.go index c400a25..57be0fc 100644 --- a/internal/provider/resource_rpaas_block.go +++ b/internal/provider/resource_rpaas_block.go @@ -42,6 +42,18 @@ func resourceRpaasBlock() *schema.Resource { ForceNew: true, Description: "RPaaS Service Name", }, + "server_name": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Description: "Optional parameter used to match the server name in the block. If not provided, it will apply to all servers.", + }, + "extend": { + Type: schema.TypeBool, + Optional: true, + Default: false, + Description: "Extend is a flag to indicate if the block should be appended to the default configuration, only valid when specify a server_name.", + }, "name": { Type: schema.TypeString, Required: true, @@ -72,8 +84,10 @@ func resourceRpaasBlockCreate(ctx context.Context, d *schema.ResourceData, meta instance := d.Get("instance").(string) serviceName := d.Get("service_name").(string) + serverName := d.Get("server_name").(string) blockName := d.Get("name").(string) content := d.Get("content").(string) + extend := d.Get("extend").(bool) rpaasClient, err := provider.RpaasClient.SetService(serviceName) if err != nil { @@ -81,16 +95,20 @@ func resourceRpaasBlockCreate(ctx context.Context, d *schema.ResourceData, meta } tflog.Info(ctx, "Create block", map[string]interface{}{ - "service": serviceName, - "instance": instance, - "name": blockName, + "service": serviceName, + "instance": instance, + "serverName": serverName, + "name": blockName, + "extend": extend, }) err = rpaasRetry(ctx, d.Timeout(schema.TimeoutCreate), func() (*http.Response, error) { return nil, rpaasClient.UpdateBlock(ctx, rpaas_client.UpdateBlockArgs{ - Instance: instance, - Name: blockName, - Content: content, + Instance: instance, + Name: blockName, + ServerName: serverName, + Content: content, + Extend: extend, }) }) @@ -98,14 +116,18 @@ func resourceRpaasBlockCreate(ctx context.Context, d *schema.ResourceData, meta return diag.Errorf("Unable to create/update block %s for instance %s: %v", blockName, instance, err) } - d.SetId(fmt.Sprintf("%s::%s::%s", serviceName, instance, blockName)) + if serverName == "" { + d.SetId(fmt.Sprintf("%s::%s::%s", serviceName, instance, blockName)) + } else { + d.SetId(fmt.Sprintf("%s::%s::%s::%s", serviceName, instance, serverName, blockName)) + } return resourceRpaasBlockRead(ctx, d, meta) } func resourceRpaasBlockUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { provider := meta.(*rpaasProvider) - serviceName, instance, blockName, err := parseRpaasBlockID(d.Id()) + serviceName, instance, serverName, blockName, err := parseRpaasBlockID(d.Id()) if err != nil { return diag.Errorf("Unable to parse Block ID: %v", err) } @@ -116,18 +138,22 @@ func resourceRpaasBlockUpdate(ctx context.Context, d *schema.ResourceData, meta } content := d.Get("content").(string) + extend := d.Get("extend").(bool) tflog.Info(ctx, "Update block", map[string]interface{}{ - "id": d.Id(), - "service": serviceName, - "instance": instance, - "name": blockName, + "id": d.Id(), + "service": serviceName, + "instance": instance, + "serverName": serverName, + "name": blockName, }) err = rpaasRetry(ctx, d.Timeout(schema.TimeoutUpdate), func() (*http.Response, error) { return nil, rpaasClient.UpdateBlock(ctx, rpaas_client.UpdateBlockArgs{ - Instance: instance, - Name: blockName, - Content: content, + Instance: instance, + Name: blockName, + ServerName: serverName, + Content: content, + Extend: extend, }) }) @@ -141,7 +167,7 @@ func resourceRpaasBlockUpdate(ctx context.Context, d *schema.ResourceData, meta func resourceRpaasBlockRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { provider := meta.(*rpaasProvider) - serviceName, instance, blockName, err := parseRpaasBlockID(d.Id()) + serviceName, instance, serverName, blockName, err := parseRpaasBlockID(d.Id()) if err != nil { return diag.Errorf("Unable to parse Block ID: %v", err) } @@ -149,6 +175,7 @@ func resourceRpaasBlockRead(ctx context.Context, d *schema.ResourceData, meta in d.SetId(fmt.Sprintf("%s::%s::%s", serviceName, instance, blockName)) d.Set("instance", instance) d.Set("service_name", serviceName) + d.Set("server_name", serverName) rpaasClient, err := provider.RpaasClient.SetService(serviceName) if err != nil { @@ -182,12 +209,20 @@ func resourceRpaasBlockRead(ctx context.Context, d *schema.ResourceData, meta in } for _, b := range blocks { - if b.Name == blockName { - d.Set("name", b.Name) - d.Set("content", b.Content) + if b.ServerName != serverName || b.Name != blockName { + continue + } + + d.Set("name", b.Name) + d.Set("content", b.Content) + d.Set("extend", b.Extend) + + if serverName == "" { d.SetId(fmt.Sprintf("%s::%s::%s", serviceName, instance, blockName)) - return nil + } else { + d.SetId(fmt.Sprintf("%s::%s::%s::%s", serviceName, instance, serverName, blockName)) } + return nil } // no match @@ -198,25 +233,29 @@ func resourceRpaasBlockRead(ctx context.Context, d *schema.ResourceData, meta in func resourceRpaasBlockDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { provider := meta.(*rpaasProvider) - instance := d.Get("instance").(string) - serviceName := d.Get("service_name").(string) - blockName := d.Get("name").(string) + serviceName, instance, serverName, blockName, err := parseRpaasBlockID(d.Id()) + if err != nil { + return diag.Errorf("Unable to parse Block ID: %v", err) + } + rpaasClient, err := provider.RpaasClient.SetService(serviceName) if err != nil { return diag.Errorf("Unable to create client for service %s: %v", serviceName, err) } tflog.Info(ctx, "Delete block", map[string]interface{}{ - "id": d.Id(), - "service": serviceName, - "instance": instance, - "name": blockName, + "id": d.Id(), + "service": serviceName, + "instance": instance, + "serverName": serverName, + "name": blockName, }) err = rpaasRetry(ctx, d.Timeout(schema.TimeoutDelete), func() (*http.Response, error) { return nil, rpaasClient.DeleteBlock(ctx, rpaas_client.DeleteBlockArgs{ - Instance: instance, - Name: blockName, + Instance: instance, + Name: blockName, + ServerName: serverName, }) }) @@ -227,20 +266,22 @@ func resourceRpaasBlockDelete(ctx context.Context, d *schema.ResourceData, meta return nil } -func parseRpaasBlockID(id string) (serviceName, instance, blockName string, err error) { +func parseRpaasBlockID(id string) (serviceName, instance, serverName, blockName string, err error) { splitID := strings.Split(id, "::") - if len(splitID) != 3 { + if len(splitID) == 3 { + serviceName = splitID[0] + instance = splitID[1] + blockName = splitID[2] + } else if len(splitID) == 4 { + serviceName = splitID[0] + instance = splitID[1] + serverName = splitID[2] + blockName = splitID[3] + } else { serviceName, instance, blockName, err = parseRpaasBlockID_legacyV0(id) - if err != nil { - err = fmt.Errorf("Could not parse id %q. Format should be \"service::instance::blockName\"", id) - } - return } - serviceName = splitID[0] - instance = splitID[1] - blockName = splitID[2] return } @@ -248,7 +289,7 @@ func parseRpaasBlockID_legacyV0(id string) (serviceName, instance, blockName str splitID := strings.Split(id, "/") if len(splitID) != 2 { - err = fmt.Errorf("Resource ID could not be parsed. Legacy WRONG format: \"service/instance\"") + err = fmt.Errorf("Could not parse id %q. Format should be \"service::instance::blockName\" or \"service::instance::serverName::blockName\"", id) return } diff --git a/internal/provider/resource_rpaas_block_test.go b/internal/provider/resource_rpaas_block_test.go index dffaeef..bd95573 100644 --- a/internal/provider/resource_rpaas_block_test.go +++ b/internal/provider/resource_rpaas_block_test.go @@ -88,6 +88,64 @@ func TestAccRpaasBlock_basic(t *testing.T) { }) } +func TestAccRpaasBlock_multiserver(t *testing.T) { + testAPIClient, testAPIServer := setupTestAPIServer(t) + defer testAPIServer.Stop() + + resourceName := "rpaas_block.custom_block_server" + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: resourceName, + ProviderFactories: testAccProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccRpaasBlockConfigWithServerName("example.org", "server", "# nginx config"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccResourceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "id", "rpaasv2-be::my-rpaas::example.org::server"), + resource.TestCheckResourceAttr(resourceName, "instance", "my-rpaas"), + resource.TestCheckResourceAttr(resourceName, "service_name", "rpaasv2-be"), + resource.TestCheckResourceAttr(resourceName, "server_name", "example.org"), + resource.TestCheckResourceAttr(resourceName, "name", "server"), + resource.TestCheckResourceAttr(resourceName, "content", "# nginx config\n"), + func(s *terraform.State) error { + blocks, err := testAPIClient.ListBlocks(context.Background(), client.ListBlocksArgs{Instance: "my-rpaas"}) + assert.NoError(t, err) + assert.Len(t, blocks, 1) + assert.Equal(t, "server", blocks[0].Name) + assert.Equal(t, "# nginx config\n", blocks[0].Content) + assert.Equal(t, "example.org", blocks[0].ServerName) + return nil + }, + ), + }, + { + // Testing Update - block content + Config: testAccRpaasBlockConfigWithServerName("example.net", "server", "# a different content"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccResourceExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "id", "rpaasv2-be::my-rpaas::example.net::server"), + resource.TestCheckResourceAttr(resourceName, "instance", "my-rpaas"), + resource.TestCheckResourceAttr(resourceName, "service_name", "rpaasv2-be"), + resource.TestCheckResourceAttr(resourceName, "server_name", "example.net"), + resource.TestCheckResourceAttr(resourceName, "name", "server"), + resource.TestCheckResourceAttr(resourceName, "content", "# a different content\n"), + func(s *terraform.State) error { + blocks, err := testAPIClient.ListBlocks(context.Background(), client.ListBlocksArgs{Instance: "my-rpaas"}) + assert.NoError(t, err) + assert.Len(t, blocks, 1) + assert.Equal(t, "server", blocks[0].Name) + assert.Equal(t, "# a different content\n", blocks[0].Content) + assert.Equal(t, "example.net", blocks[0].ServerName) + + return nil + }, + ), + }, + }, + }) +} + func TestAccRpaasBlock_import(t *testing.T) { testAPIClient, testAPIServer := setupTestAPIServer(t) defer testAPIServer.Stop() @@ -149,3 +207,19 @@ resource "rpaas_block" "custom_block_server" { } `, block, content) } + +func testAccRpaasBlockConfigWithServerName(serverName, block, content string) string { + return fmt.Sprintf(` +resource "rpaas_block" "custom_block_server" { + instance = "my-rpaas" + service_name = "rpaasv2-be" + server_name = %q + + name = %q + + content = <<-EOF + %s + EOF +} +`, serverName, block, content) +}