Skip to content

Commit

Permalink
OCM-6031 | feat: allow to edit component routes of ingress
Browse files Browse the repository at this point in the history
  • Loading branch information
gdbranco committed Apr 9, 2024
1 parent b7ef310 commit 4c462db
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 10 deletions.
9 changes: 9 additions & 0 deletions docs/resources/default_ingress.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,18 @@ Edit a cluster ingress (load balancer)

- `cluster_routes_hostname` (String) Components route hostname for oauth, console, download.
- `cluster_routes_tls_secret_ref` (String) Components route TLS secret reference for oauth, console, download.
- `component_routes` (Map of Object) Component route parameters for oauth, console, downloads. (see [below for nested schema](#nestedatt--component_routes))
- `excluded_namespaces` (List of String) Excluded namespaces for ingress. Format should be a comma-separated list 'value1, value2...'. If no values are specified, all namespaces will be exposed.
- `id` (String) Unique identifier of the ingress.
- `load_balancer_type` (String) Type of Load Balancer. Options are classic,nlb.
- `route_namespace_ownership_policy` (String) Namespace Ownership Policy for ingress. Options are Strict,InterNamespaceAllowed. Default is 'Strict'.
- `route_selectors` (Map of String) Route Selectors for ingress. Format should be a comma-separated list of 'key=value'. If no label is specified, all routes will be exposed on both routers.For legacy ingress support these are inclusion labels, otherwise they are treated as exclusion label.
- `route_wildcard_policy` (String) Wildcard Policy for ingress. Options are WildcardsDisallowed,WildcardsAllowed. Default is 'WildcardsDisallowed'.

<a id="nestedatt--component_routes"></a>
### Nested Schema for `component_routes`

Optional:

- `hostname` (String)
- `tls_secret_ref` (String)
47 changes: 44 additions & 3 deletions provider/defaultingress/classic/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,23 @@ import (

"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-log/tflog"
sdk "github.com/openshift-online/ocm-sdk-go"
cmv1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v1"

"github.com/terraform-redhat/terraform-provider-rhcs/provider/common"
"github.com/terraform-redhat/terraform-provider-rhcs/provider/common/attrvalidators"
"github.com/terraform-redhat/terraform-provider-rhcs/provider/defaultingress"
)

var validWildcardPolicies = []string{string(cmv1.WildcardPolicyWildcardsDisallowed),
Expand Down Expand Up @@ -120,6 +124,13 @@ func (r *DefaultIngressResource) Schema(ctx context.Context, req resource.Schema
Optional: true,
Validators: []validator.String{stringvalidator.LengthAtLeast(1)},
},
"component_routes": schema.MapAttribute{
Description: "Component route parameters for oauth, console, downloads.",
ElementType: basetypes.ObjectType{
AttrTypes: defaultingress.ComponentRouteAttributeTypes,
},
Optional: true,
},
},
}
return
Expand Down Expand Up @@ -163,7 +174,7 @@ func (r *DefaultIngressResource) Create(ctx context.Context, req resource.Create
)
return
}
err = r.updateIngress(ctx, nil, plan, plan.Cluster.ValueString(), r.collection)
err = r.updateIngress(ctx, nil, plan, plan.Cluster.ValueString(), r.collection, resp.Diagnostics)
if err != nil {
resp.Diagnostics.AddError(
"Failed building cluster default ingress",
Expand Down Expand Up @@ -230,7 +241,7 @@ func (r *DefaultIngressResource) Update(ctx context.Context, req resource.Update
return
}

err := r.updateIngress(ctx, state, plan, plan.Cluster.ValueString(), r.collection)
err := r.updateIngress(ctx, state, plan, plan.Cluster.ValueString(), r.collection, resp.Diagnostics)
if err != nil {
diags.AddError(
"Failed to update default ingress",
Expand Down Expand Up @@ -365,13 +376,31 @@ func (r *DefaultIngressResource) populateState(ingress *cmv1.Ingress, state *Def
} else {
state.ClusterRoutesTlsSecretRef = types.StringNull()
}
componentRoutes, ok := ingress.GetComponentRoutes()
if ok {
elements := map[string]attr.Value{}
for k, v := range componentRoutes {
elements[k] = defaultingress.FlattenComponentRoute(v.Hostname(), v.TlsSecretRef())
}
mapValue, diags := types.MapValue(types.ObjectType{
AttrTypes: defaultingress.ComponentRouteAttributeTypes,
}, elements)
if diags != nil && diags.HasError() {
return fmt.Errorf("failed to convert to MapType %v", diags.Errors()[0].Detail())
}
state.ComponentRoutes = mapValue
} else {
state.ComponentRoutes = types.MapNull(types.ObjectType{
AttrTypes: defaultingress.ComponentRouteAttributeTypes,
})
}
state.LoadBalancerType = types.StringValue(string(ingress.LoadBalancerType()))

return nil
}

func (r *DefaultIngressResource) updateIngress(ctx context.Context, state, plan *DefaultIngress,
clusterId string, clusterCollection *cmv1.ClustersClient) error {
clusterId string, clusterCollection *cmv1.ClustersClient, diags diag.Diagnostics) error {

if state == nil {
state = &DefaultIngress{Cluster: plan.Cluster}
Expand Down Expand Up @@ -411,6 +440,18 @@ func (r *DefaultIngressResource) updateIngress(ctx context.Context, state, plan
ingressBuilder.ClusterRoutesTlsSecretRef(value)
}

if !reflect.DeepEqual(state.ComponentRoutes, plan.ComponentRoutes) {
componentRoutes := map[string]*cmv1.ComponentRouteBuilder{}
for k, v := range plan.ComponentRoutes.Elements() {
componentRouteBuilder := cmv1.NewComponentRoute()
hostname, tlsSecretRef := defaultingress.ExpandComponentRoute(ctx, v.(types.Object), diags)
componentRouteBuilder.Hostname(hostname)
componentRouteBuilder.TlsSecretRef(tlsSecretRef)
componentRoutes[k] = componentRouteBuilder
}
ingressBuilder.ComponentRoutes(componentRoutes)
}

ingress, err := ingressBuilder.Build()
if err != nil {
return err
Expand Down
17 changes: 10 additions & 7 deletions provider/defaultingress/classic/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package classic
import "github.com/hashicorp/terraform-plugin-framework/types"

type DefaultIngress struct {
Cluster types.String `tfsdk:"cluster"`
RouteSelectors types.Map `tfsdk:"route_selectors"`
ExcludedNamespaces types.List `tfsdk:"excluded_namespaces"`
WildcardPolicy types.String `tfsdk:"route_wildcard_policy"`
NamespaceOwnershipPolicy types.String `tfsdk:"route_namespace_ownership_policy"`
Id types.String `tfsdk:"id"`
Cluster types.String `tfsdk:"cluster"`
RouteSelectors types.Map `tfsdk:"route_selectors"`
ExcludedNamespaces types.List `tfsdk:"excluded_namespaces"`
WildcardPolicy types.String `tfsdk:"route_wildcard_policy"`
NamespaceOwnershipPolicy types.String `tfsdk:"route_namespace_ownership_policy"`
Id types.String `tfsdk:"id"`
LoadBalancerType types.String `tfsdk:"load_balancer_type"`
ComponentRoutes types.Map `tfsdk:"component_routes"`

// Soon to be deprecated
ClusterRoutesHostname types.String `tfsdk:"cluster_routes_hostname"`
ClusterRoutesTlsSecretRef types.String `tfsdk:"cluster_routes_tls_secret_ref"`
LoadBalancerType types.String `tfsdk:"load_balancer_type"`
}
48 changes: 48 additions & 0 deletions provider/defaultingress/component_routes.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package defaultingress

import (
"context"

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
)

type ComponentRoute struct {
Hostname types.String `tfsdk:"hostname"`
TlsSecretRef types.String `tfsdk:"tls_secret_ref"`
}

var ComponentRouteAttributeTypes = map[string]attr.Type{
"hostname": types.StringType,
"tls_secret_ref": types.StringType,
}

func FlattenComponentRoute(hostname, tlsSecretRef string) types.Object {
if hostname == "" && tlsSecretRef == "" {
return types.ObjectNull(ComponentRouteAttributeTypes)
}

attrs := map[string]attr.Value{
"hostname": types.StringValue(hostname),
"tls_secret_ref": types.StringValue(tlsSecretRef),
}

return types.ObjectValueMust(ComponentRouteAttributeTypes, attrs)
}

func ExpandComponentRoute(ctx context.Context,
object types.Object, diags diag.Diagnostics) (string, string) {
if object.IsNull() {
return "", ""
}

var componentRoute ComponentRoute
diags.Append(object.As(ctx, &componentRoute, basetypes.ObjectAsOptions{})...)
if diags.HasError() {
return "", ""
}

return componentRoute.Hostname.ValueString(), componentRoute.TlsSecretRef.ValueString()
}
65 changes: 65 additions & 0 deletions subsystem/default_ingress_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,71 @@ var _ = Describe("default ingress", func() {
Expect(terraform.Apply()).To(Equal(1))
})

It("Create cluster with default ingress - component_routes set to actual value", func() {
// Prepare the server:
server.AppendHandlers(
CombineHandlers(
VerifyRequest(http.MethodGet, "/api/clusters_mgmt/v1/clusters/123"),
RespondWithJSON(http.StatusOK, clusterReady),
),
CombineHandlers(
VerifyRequest(http.MethodGet, "/api/clusters_mgmt/v1/clusters/123/ingresses"),
RespondWithJSON(http.StatusOK, defaultDay1Template),
),

CombineHandlers(
VerifyRequest(http.MethodPatch, "/api/clusters_mgmt/v1/clusters/123/ingresses/d6z2"),
RespondWithJSON(http.StatusOK, `
{
"kind": "Ingress",
"href": "/api/clusters_mgmt/v1/clusters/123/ingresses/d6z2",
"id": "d6z2",
"listening": "external",
"default": true,
"dns_name": "redhat.com",
"load_balancer_type": "classic",
"route_wildcard_policy": "WildcardsDisallowed",
"route_namespace_ownership_policy": "Strict",
"component_routes": {
"console": {
"hostname": "console-host",
"tls_secret_ref": "console-secret"
},
"downloads": {
"hostname": "downloads-host",
"tls_secret_ref": "downloads-secret"
},
"oauth": {
"hostname": "oauth-host-new",
"tls_secret_ref": "oauth-secret"
}
}
}
`),
),
)
// Run the apply command:
terraform.Source(`
resource "rhcs_default_ingress" "default_ingress" {
cluster = "123"
component_routes = {
"oauth" = {
"hostname" = "oauth-host-new"
"tls_secret_ref" = "oauth-secret"
}
"console" = {
"hostname" = "console-host"
"tls_secret_ref" = "console-secret"
}
"downloads" = {
"hostname" = "downloads-host"
"tls_secret_ref" = "downloads-secret"
}
}
}`)
Expect(terraform.Apply()).To(BeZero())
})

It("Create default ingress and delete it", func() {
// Prepare the server:
server.AppendHandlers(
Expand Down

0 comments on commit 4c462db

Please sign in to comment.