Skip to content

Commit

Permalink
OCM-2643: Allow default ingress configurations
Browse files Browse the repository at this point in the history
  • Loading branch information
tsorya committed Nov 4, 2023
1 parent da8a10a commit 23bed10
Show file tree
Hide file tree
Showing 11 changed files with 1,004 additions and 70 deletions.
2 changes: 1 addition & 1 deletion examples/create_account_roles/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ variable "ocm_environment" {
}

variable "openshift_version" {
type = string
type = string
default = ""
}

Expand Down
2 changes: 1 addition & 1 deletion examples/create_machine_pool/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,5 @@ variable "max_replicas" {
variable "labels" {
description = "Labels for the machine pool. Format should be a comma-separated list of 'key = value'. This list will overwrite any modifications made to node labels on an ongoing basis."
type = map(string)
default = null
default = null
}
10 changes: 5 additions & 5 deletions examples/list_versions/variables.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
variable token {
type = string
variable "token" {
type = string
sensitive = true
}

variable url {
type = string
default = "https://api.stage.openshift.com"
variable "url" {
type = string
default = "https://api.stage.openshift.com"
}
58 changes: 49 additions & 9 deletions provider/clusterrosaclassic/cluster_rosa_classic_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,15 @@ import (
ocm_errors "github.com/openshift-online/ocm-sdk-go/errors"
"github.com/openshift/rosa/pkg/ocm"
"github.com/openshift/rosa/pkg/properties"
"github.com/terraform-redhat/terraform-provider-rhcs/provider/common/attrvalidators"
"github.com/terraform-redhat/terraform-provider-rhcs/provider/proxy"

"github.com/terraform-redhat/terraform-provider-rhcs/build"
ocmr "github.com/terraform-redhat/terraform-provider-rhcs/internal/ocm/resource"
"github.com/terraform-redhat/terraform-provider-rhcs/provider/clusterrosaclassic/upgrade"
"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"
"github.com/terraform-redhat/terraform-provider-rhcs/provider/identityprovider"
"github.com/terraform-redhat/terraform-provider-rhcs/provider/proxy"
)

const (
Expand Down Expand Up @@ -331,6 +332,11 @@ func (r *ClusterRosaClassicResource) Schema(ctx context.Context, req resource.Sc
Optional: true,
Validators: []validator.Object{proxy.ProxyValidator()},
},
"default_ingress": schema.SingleNestedAttribute{
Description: "Edit a cluster ingress (load balancer)",
Attributes: defaultingress.IngressResource(),
Optional: true,
},
"service_cidr": schema.StringAttribute{
Description: "Block of IP addresses for the cluster service network.",
Optional: true,
Expand Down Expand Up @@ -706,6 +712,8 @@ func createClassicClusterObject(ctx context.Context,
builder.Htpasswd(htPasswdIDP)
}

builder = defaultingress.SetIngress(ctx, state.DefaultIngress, builder)

builder, err = buildProxy(state, builder)
if err != nil {
tflog.Error(ctx, "Failed to build the Proxy's attributes")
Expand Down Expand Up @@ -912,6 +920,18 @@ func (r *ClusterRosaClassicResource) Create(ctx context.Context, request resourc
return
}

err = defaultingress.ValidateDefaultIngress(ctx, state.DefaultIngress, version)
if err != nil {
response.Diagnostics.AddError(
summary,
fmt.Sprintf(
"Can't build cluster with name '%s': %v",
state.Name.ValueString(), err,
),
)
return
}

object, err := createClassicClusterObject(ctx, state, diags)
if err != nil {
response.Diagnostics.AddError(
Expand Down Expand Up @@ -952,7 +972,7 @@ func (r *ClusterRosaClassicResource) Create(ctx context.Context, request resourc
}

// Save the state:
err = populateRosaClassicClusterState(ctx, object, state, common.DefaultHttpClient{})
err = populateRosaClassicClusterState(ctx, object, state, common.DefaultHttpClient{}, r.clusterCollection)
if err != nil {
response.Diagnostics.AddError(
"Can't populate cluster state",
Expand Down Expand Up @@ -1000,7 +1020,7 @@ func (r *ClusterRosaClassicResource) Read(ctx context.Context, request resource.
object := get.Body()

// Save the state:
err = populateRosaClassicClusterState(ctx, object, state, common.DefaultHttpClient{})
err = populateRosaClassicClusterState(ctx, object, state, common.DefaultHttpClient{}, r.clusterCollection)
if err != nil {
response.Diagnostics.AddError(
"Can't populate cluster state",
Expand Down Expand Up @@ -1109,6 +1129,19 @@ func (r *ClusterRosaClassicResource) Update(ctx context.Context, request resourc
return
}

err = defaultingress.UpdateIngress(ctx, state.DefaultIngress, plan.DefaultIngress,
state.ID.ValueString(), state.Version.ValueString(), r.clusterCollection)
if err != nil {
response.Diagnostics.AddError(
"Can't update cluster ingress",
fmt.Sprintf(
"Can't update cluster with identifier '%s': %v",
state.ID.ValueString(), err,
),
)
return
}

update, err := r.clusterCollection.Cluster(state.ID.ValueString()).Update().
Body(clusterSpec).
SendContext(ctx)
Expand All @@ -1126,7 +1159,7 @@ func (r *ClusterRosaClassicResource) Update(ctx context.Context, request resourc
object := update.Body()

// Update the state:
err = populateRosaClassicClusterState(ctx, object, plan, common.DefaultHttpClient{})
err = populateRosaClassicClusterState(ctx, object, plan, common.DefaultHttpClient{}, r.clusterCollection)
if err != nil {
response.Diagnostics.AddError(
"Can't populate cluster state",
Expand Down Expand Up @@ -1396,7 +1429,7 @@ func (r *ClusterRosaClassicResource) ImportState(ctx context.Context, request re
}

// populateRosaClassicClusterState copies the data from the API object to the Terraform state.
func populateRosaClassicClusterState(ctx context.Context, object *cmv1.Cluster, state *ClusterRosaClassicState, httpClient common.HttpClient) error {
func populateRosaClassicClusterState(ctx context.Context, object *cmv1.Cluster, state *ClusterRosaClassicState, httpClient common.HttpClient, clusterCollection *cmv1.ClustersClient) error {
state.ID = types.StringValue(object.ID())
state.ExternalID = types.StringValue(object.ExternalID())
object.API()
Expand Down Expand Up @@ -1599,9 +1632,9 @@ func populateRosaClassicClusterState(ctx context.Context, object *cmv1.Cluster,
} else {
state.HostPrefix = types.Int64Null()
}
channel_group, ok := object.Version().GetChannelGroup()
channelGroup, ok := object.Version().GetChannelGroup()
if ok {
state.ChannelGroup = types.StringValue(channel_group)
state.ChannelGroup = types.StringValue(channelGroup)
}

if awsObj, ok := object.GetAWS(); ok {
Expand All @@ -1619,7 +1652,7 @@ func populateRosaClassicClusterState(ctx context.Context, object *cmv1.Cluster,
version, ok := object.Version().GetID()
// If we're using a non-default channel group, it will have been appended to
// the version ID. Remove it before saving state.
version = strings.TrimSuffix(version, fmt.Sprintf("-%s", channel_group))
version = strings.TrimSuffix(version, fmt.Sprintf("-%s", channelGroup))
version = strings.TrimPrefix(version, "openshift-v")
if ok {
tflog.Debug(ctx, fmt.Sprintf("actual cluster version: %v", version))
Expand All @@ -1633,6 +1666,13 @@ func populateRosaClassicClusterState(ctx context.Context, object *cmv1.Cluster,
state.Name = types.StringValue(object.Name())
state.CloudRegion = types.StringValue(object.Region().ID())

defaultIngress, err := defaultingress.PopulateDefaultIngress(ctx, state.DefaultIngress,
clusterCollection.Cluster(state.ID.ValueString()).Ingresses())
if err != nil {
return err
}
state.DefaultIngress = defaultIngress

return nil
}

Expand Down
87 changes: 81 additions & 6 deletions provider/clusterrosaclassic/cluster_rosa_classic_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ import (
"crypto/x509"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"testing"

"github.com/terraform-redhat/terraform-provider-rhcs/provider/proxy"

"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types"
. "github.com/onsi/ginkgo/v2/dsl/core" // nolint
Expand All @@ -35,6 +35,8 @@ import (

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

type MockHttpClient struct {
Expand All @@ -45,6 +47,12 @@ func (c MockHttpClient) Get(url string) (resp *http.Response, err error) {
return c.response, nil
}

type roundTripFunc func(r *http.Request) (*http.Response, error)

func (s roundTripFunc) RoundTrip(r *http.Request) (*http.Response, error) {
return s(r)
}

const (
clusterId = "1n2j3k4l5m6n7o8p9q0r"
clusterName = "my-cluster"
Expand Down Expand Up @@ -79,6 +87,42 @@ var (
},
},
}
ingressObjectAsString = `{
"kind": "IngressList",
"href": "/api/clusters_mgmt/v1/clusters/25qdoe7kf5fbc1aj3l77ait54obh2g22/ingresses",
"page": 1,
"size": 1,
"total": 1,
"items": [
{
"kind": "Ingress",
"href": "/api/clusters_mgmt/v1/clusters/25qdoe7kf5fbc1aj3l77ait54obh2g22/ingresses/h1w0",
"id": "h1w0",
"listening": "external",
"default": true,
"dns_name": "apps.itsoiref-tf.t9ep.s1.devshift.org",
"route_selectors": {
"foo": "bar",
"ui": "boom",
"yu": "1113"
},
"load_balancer_type": "nlb",
"route_wildcard_policy": "WildcardsAllowed",
"route_namespace_ownership_policy": "Strict"
},
{
"kind": "Ingress",
"id": "not-default",
"listening": "external",
"default": false,
"route_selectors": {
},
"route_wildcard_policy": "not-default",
"route_namespace_ownership_policy": "not-default"
}
]
}
`
)

func generateBasicRosaClassicClusterJson() map[string]interface{} {
Expand Down Expand Up @@ -161,6 +205,14 @@ func TestResource(t *testing.T) {
}

var _ = Describe("Rosa Classic Sts cluster", func() {
dummyTransportMock := roundTripFunc(func(r *http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(strings.NewReader(`{"mock":"mock"}`)),
}, nil
})
clustersClientMock := cmv1.NewClustersClient(dummyTransportMock, "")

Context("createClassicClusterObject", func() {
It("Creates a cluster with correct field values", func() {
clusterState := generateBasicRosaClassicClusterState()
Expand Down Expand Up @@ -231,8 +283,7 @@ var _ = Describe("Rosa Classic Sts cluster", func() {

clusterObject, err := cmv1.UnmarshalCluster(clusterJsonString)
Expect(err).To(BeNil())

Expect(populateRosaClassicClusterState(context.Background(), clusterObject, clusterState, mockHttpClient)).To(Succeed())
Expect(populateRosaClassicClusterState(context.Background(), clusterObject, clusterState, mockHttpClient, clustersClientMock)).To(Succeed())

Expect(clusterState.ID.ValueString()).To(Equal(clusterId))
Expect(clusterState.CloudRegion.ValueString()).To(Equal(regionId))
Expand Down Expand Up @@ -263,6 +314,30 @@ var _ = Describe("Rosa Classic Sts cluster", func() {
Expect(clusterState.Sts.RoleARN.ValueString()).To(Equal(roleArn))
Expect(clusterState.Ec2MetadataHttpTokens.ValueString()).To(Equal(httpTokens))
})
It("Populate default ingress", func() {
clusterState := &ClusterRosaClassicState{}
clusterState.DefaultIngress = &defaultingress.DefaultIngress{}
clusterJson := generateBasicRosaClassicClusterJson()
clusterJsonString, err := json.Marshal(clusterJson)
Expect(err).To(BeNil())

clusterObject, err := cmv1.UnmarshalCluster(clusterJsonString)
Expect(err).To(BeNil())
transportIngress := roundTripFunc(func(r *http.Request) (*http.Response, error) {
return &http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(strings.NewReader(ingressObjectAsString)),
}, nil
})
clustersClientMock = cmv1.NewClustersClient(transportIngress, "")
Expect(populateRosaClassicClusterState(context.Background(), clusterObject, clusterState, mockHttpClient,
clustersClientMock)).To(Succeed())
Expect(clusterState.DefaultIngress.Id.ValueString()).To(Equal("h1w0"))
Expect(clusterState.DefaultIngress.WildcardPolicy.ValueString()).To(Equal("WildcardsAllowed"))
Expect(clusterState.DefaultIngress.NamespaceOwnershipPolicy.ValueString()).To(Equal("Strict"))
Expect(len(clusterState.DefaultIngress.RouteSelectors.Elements())).To(Equal(3))
Expect(clusterState.DefaultIngress.RouteSelectors.Elements()["foo"]).To(Equal(types.StringValue("bar")))
})

It("Check trimming of oidc url with https perfix", func() {
clusterState := &ClusterRosaClassicState{}
Expand All @@ -277,7 +352,7 @@ var _ = Describe("Rosa Classic Sts cluster", func() {
clusterObject, err := cmv1.UnmarshalCluster(clusterJsonString)
Expect(err).To(BeNil())

err = populateRosaClassicClusterState(context.Background(), clusterObject, clusterState, mockHttpClient)
err = populateRosaClassicClusterState(context.Background(), clusterObject, clusterState, mockHttpClient, clustersClientMock)
Expect(err).To(BeNil())
Expect(clusterState.Sts.OIDCEndpointURL.ValueString()).To(Equal("nonce.com"))
})
Expand All @@ -293,7 +368,7 @@ var _ = Describe("Rosa Classic Sts cluster", func() {
clusterObject, err := cmv1.UnmarshalCluster(clusterJsonString)
Expect(err).To(BeNil())

err = populateRosaClassicClusterState(context.Background(), clusterObject, clusterState, mockHttpClient)
err = populateRosaClassicClusterState(context.Background(), clusterObject, clusterState, mockHttpClient, clustersClientMock)
Expect(err).To(BeNil())
Expect(clusterState.Sts.Thumbprint.ValueString()).To(Equal(""))
})
Expand Down
Loading

0 comments on commit 23bed10

Please sign in to comment.