Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OCM-12837 | feat: support shared vpc attributes in cluster resource #856

Merged
merged 1 commit into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions docs/data-sources/cluster_rosa_hcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ data "rhcs_cluster_rosa_hcp" "cluster" {
- `api_url` (String) URL of the API server.
- `availability_zones` (List of String) Availability zones. This attribute specifically applies to the Worker Machine Pool and becomes irrelevant once the resource is created. Any modifications to the initial Machine Pool should be made through the Terraform imported Machine Pool resource. For more details, refer to [Worker Machine Pool in ROSA Cluster](../guides/worker-machine-pool.md)
- `aws_account_id` (String) Identifier of the AWS account. After the creation of the resource, it is not possible to update the attribute value.
- `aws_additional_allowed_principals` (List of String) AWS additional allowed principals.
- `aws_additional_compute_security_group_ids` (List of String) AWS additional compute security group ids. After the creation of the resource, it is not possible to update the attribute value.
- `aws_billing_account_id` (String) Identifier of the AWS account for billing. After the creation of the resource, it is not possible to update the attribute value.
- `aws_subnet_ids` (List of String) AWS subnet IDs. After the creation of the resource, it is not possible to update the attribute value.
- `base_dns_domain` (String) Base DNS domain name previously reserved, e.g. '1vo8.p3.openshiftapps.com'. After the creation of the resource, it is not possible to update the attribute value.
- `channel_group` (String) This attribute is not supported for cluster data source. Therefore, it will not be displayed as an output of the datasource
- `cloud_region` (String) Cloud region identifier, for example 'us-east-1'.
- `compute_machine_type` (String) This attribute is not supported for cluster data source. Therefore, it will not be displayed as an output of the datasource
Expand All @@ -63,6 +65,7 @@ data "rhcs_cluster_rosa_hcp" "cluster" {
- `proxy` (Attributes) proxy (see [below for nested schema](#nestedatt--proxy))
- `replicas` (Number) This attribute is not supported for cluster data source. Therefore, it will not be displayed as an output of the datasource
- `service_cidr` (String) Block of IP addresses for the cluster service network. After the creation of the resource, it is not possible to update the attribute value.
- `shared_vpc` (Attributes) Shared VPC configuration.After the creation of the resource, it is not possible to update the attribute value. (see [below for nested schema](#nestedatt--shared_vpc))
- `state` (String) State of the cluster.
- `sts` (Attributes) STS configuration. (see [below for nested schema](#nestedatt--sts))
- `tags` (Map of String) Apply user defined tags to all cluster resources created in AWS. After the creation of the resource, it is not possible to update the attribute value.
Expand Down Expand Up @@ -122,6 +125,17 @@ Read-Only:
- `no_proxy` (String) No proxy.


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

Read-Only:

- `ingress_private_hosted_zone_id` (String) ID assigned by AWS to private Route 53 hosted zone associated with intended shared VPC, e.g. 'Z05646003S02O1ENCDCSN'.
- `internal_communication_private_hosted_zone_id` (String) ID assigned by AWS to private Route 53 hosted zone associated with intended shared VPC, e.g. 'Z05646003S02O1ENCDCSN'.
- `route53_role_arn` (String) AWS IAM role ARN with a policy attached, granting permissions necessary to create and manage Route 53 DNS records in private Route 53 hosted zone associated with intended shared VPC.
- `vpce_role_arn` (String) AWS IAM role ARN with a policy attached, granting permissions necessary to create and manage VPC Endpoints associated with intended shared VPC.


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

Expand Down
18 changes: 18 additions & 0 deletions docs/resources/cluster_rosa_hcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ resource "rhcs_cluster_rosa_hcp" "rosa_sts_cluster" {
### Optional

- `admin_credentials` (Attributes) Admin user credentials. After the creation of the resource, it is not possible to update the attribute value. (see [below for nested schema](#nestedatt--admin_credentials))
- `aws_additional_allowed_principals` (List of String) AWS additional allowed principals.
- `aws_additional_compute_security_group_ids` (List of String) AWS additional compute security group ids.
- `base_dns_domain` (String) Base DNS domain name previously reserved, e.g. '1vo8.p3.openshiftapps.com'. After the creation of the resource, it is not possible to update the attribute value.
- `channel_group` (String) Name of the channel group where you select the OpenShift cluster version, for example 'stable'. For ROSA, only 'stable' is supported. After the creation of the resource, it is not possible to update the attribute value.
- `compute_machine_type` (String) Identifies the machine type used by the initial worker nodes, for example `m5.xlarge`. Use the `rhcs_machine_types` data source to find the possible values. This attribute specifically applies to the Worker Machine Pool and becomes irrelevant once the resource is created. Any modifications to the initial Machine Pool should be made through the Terraform imported Machine Pool resource. For more details, refer to [Worker Machine Pool in ROSA Cluster](../guides/worker-machine-pool.md)
- `create_admin_user` (Boolean) Indicates if create cluster admin user. Set it true to create cluster admin user with default username `cluster-admin` and generated password. It will be ignored if `admin_credentials` is set.After the creation of the resource, it is not possible to update the attribute value.
Expand All @@ -80,6 +82,7 @@ resource "rhcs_cluster_rosa_hcp" "rosa_sts_cluster" {
- `registry_config` (Attributes) Registry configuration for this cluster. (see [below for nested schema](#nestedatt--registry_config))
- `replicas` (Number) Number of worker/compute nodes to provision. Requires that the number supplied be a multiple of the number of private subnets. This attribute specifically applies to the Worker Machine Pool and becomes irrelevant once the resource is created. Any modifications to the initial Machine Pool should be made through the Terraform imported Machine Pool resource. For more details, refer to [Worker Machine Pool in ROSA Cluster](../guides/worker-machine-pool.md)
- `service_cidr` (String) Block of IP addresses for the cluster service network. After the creation of the resource, it is not possible to update the attribute value.
- `shared_vpc` (Attributes) Shared VPC configuration.After the creation of the resource, it is not possible to update the attribute value. (see [below for nested schema](#nestedatt--shared_vpc))
- `tags` (Map of String) Apply user defined tags to all cluster resources created in AWS. After the creation of the resource, it is not possible to update the attribute value.
- `upgrade_acknowledgements_for` (String) Indicates acknowledgement of agreements required to upgrade the cluster version between minor versions (e.g. a value of "4.12" indicates acknowledgement of any agreements required to upgrade to OpenShift 4.12.z from 4.11 or before).
- `version` (String) Desired version of OpenShift for the cluster, for example '4.11.0'. If version is greater than the currently running version, an upgrade will be scheduled.
Expand Down Expand Up @@ -173,3 +176,18 @@ Optional:
- `allowed_registries` (List of String) allowed_registries: registries for which image pull and push actions are allowed. To specify all subdomains, add the asterisk (*) wildcard character as a prefix to the domain name. For example, *.example.com. You can specify an individual repository within a registry. For example: reg1.io/myrepo/myapp:latest. All other registries are blocked. Mutually exclusive with `BlockedRegistries`
- `blocked_registries` (List of String) blocked_registries: registries for which image pull and push actions are denied. To specify all subdomains, add the asterisk (*) wildcard character as a prefix to the domain name. For example, *.example.com. You can specify an individual repository within a registry. For example: reg1.io/myrepo/myapp:latest. All other registries are allowed. Mutually exclusive with `AllowedRegistries`
- `insecure_registries` (List of String) insecure_registries are registries which do not have a valid TLS certificate or only support HTTP connections. To specify all subdomains, add the asterisk (*) wildcard character as a prefix to the domain name. For example, *.example.com. You can specify an individual repository within a registry. For example: reg1.io/myrepo/myapp:latest.



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

Required:

- `ingress_private_hosted_zone_id` (String) ID assigned by AWS to private Route 53 hosted zone associated with intended shared VPC, e.g. 'Z05646003S02O1ENCDCSN'.
- `route53_role_arn` (String) AWS IAM role ARN with a policy attached, granting permissions necessary to create and manage Route 53 DNS records in private Route 53 hosted zone associated with intended shared VPC.
- `vpce_role_arn` (String) AWS IAM role ARN with a policy attached, granting permissions necessary to create and manage VPC Endpoints associated with intended shared VPC.

Optional:

- `internal_communication_private_hosted_zone_id` (String) ID assigned by AWS to private Route 53 hosted zone associated with intended shared VPC, e.g. 'Z05646003S02O1ENCDCSN'.
30 changes: 24 additions & 6 deletions internal/ocm/resource/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

var privateHostedZoneRoleArnRE = regexp.MustCompile(
`^arn:aws:iam::\d{12}:role\/[A-Za-z0-9]+(?:-[A-Za-z0-9]+)+$`,
`^arn:aws:iam::\d{12}:role(?:(?:\/?.+\/?)?)(?:\/[0-9A-Za-z\\+\\.@_,-]{1,64})$`,
)

type Cluster struct {
Expand Down Expand Up @@ -142,9 +142,11 @@ func (c *Cluster) CreateAWSBuilder(clusterTopology rosaTypes.ClusterTopology,
isPrivateLink bool, awsAccountID *string, awsBillingAccountId *string,
stsBuilder *cmv1.STSBuilder, awsSubnetIDs []string,
privateHostedZoneID *string, privateHostedZoneRoleARN *string,
hcpInternalCommunicationPrivateHostedZoneId *string, vpceRoleArn *string,
additionalComputeSecurityGroupIds []string,
additionalInfraSecurityGroupIds []string,
additionalControlPlaneSecurityGroupIds []string) error {
additionalControlPlaneSecurityGroupIds []string,
additionalAllowedPrincipals []string) error {

if clusterTopology == rosaTypes.Hcp && awsSubnetIDs == nil {
return errors.New("Hosted Control Plane clusters must have a pre-configure VPC. Make sure to specify the subnet ids.")
Expand Down Expand Up @@ -209,14 +211,30 @@ func (c *Cluster) CreateAWSBuilder(clusterTopology rosaTypes.ClusterTopology,
}

if privateHostedZoneID != nil && privateHostedZoneRoleARN != nil {
if !privateHostedZoneRoleArnRE.MatchString(*privateHostedZoneRoleARN) {
return errors.New(fmt.Sprintf("Expected a valid value for PrivateHostedZoneRoleARN matching %s. Got %s", privateHostedZoneRoleArnRE, *privateHostedZoneRoleARN))
}
if awsSubnetIDs == nil || stsBuilder == nil {
return errors.New("PrivateHostedZone parameters require STS and SubnetIDs configurations.")
return errors.New("Shared VPC parameters require STS and SubnetIDs configurations.")
}
privateRoleArnField := "PrivateHostedZoneRoleARN"
if clusterTopology == rosaTypes.Hcp {
privateRoleArnField = "Route53RoleArn"
}
if !privateHostedZoneRoleArnRE.MatchString(*privateHostedZoneRoleARN) {
return errors.New(fmt.Sprintf("Expected a valid value for %s matching %s. Got %s",
privateRoleArnField, privateHostedZoneRoleArnRE, *privateHostedZoneRoleARN))
}
awsBuilder.PrivateHostedZoneID(*privateHostedZoneID)
awsBuilder.PrivateHostedZoneRoleARN(*privateHostedZoneRoleARN)
if clusterTopology == rosaTypes.Hcp && hcpInternalCommunicationPrivateHostedZoneId != nil && vpceRoleArn != nil {
if !privateHostedZoneRoleArnRE.MatchString(*vpceRoleArn) {
return errors.New(fmt.Sprintf("Expected a valid value for VpcEndpointRoleArn matching %s. Got %s", privateHostedZoneRoleArnRE, *vpceRoleArn))
}
awsBuilder.HcpInternalCommunicationHostedZoneId(*hcpInternalCommunicationPrivateHostedZoneId)
awsBuilder.VpcEndpointRoleArn(*vpceRoleArn)
}
}

if additionalAllowedPrincipals != nil {
awsBuilder.AdditionalAllowedPrincipals(additionalAllowedPrincipals...)
}

c.clusterBuilder.AWS(awsBuilder)
Expand Down
18 changes: 9 additions & 9 deletions internal/ocm/resource/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,17 +203,17 @@ var _ = Describe("Cluster", func() {
})
Context("CreateAWSBuilder validation", func() {
It("PrivateLink true subnets IDs empty - failure", func() {
err := cluster.CreateAWSBuilder(rosaTypes.Classic, nil, nil, nil, nil, true, nil, nil, nil, nil, nil, nil, nil, nil, nil)
err := cluster.CreateAWSBuilder(rosaTypes.Classic, nil, nil, nil, nil, true, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal("Clusters with PrivateLink must have a pre-configured VPC. Make sure to specify the subnet ids."))
})
It("PrivateLink false invalid kmsKeyARN - failure", func() {
err := cluster.CreateAWSBuilder(rosaTypes.Classic, nil, nil, pointer("test"), nil, false, nil, nil, nil, nil, nil, nil, nil, nil, nil)
err := cluster.CreateAWSBuilder(rosaTypes.Classic, nil, nil, pointer("test"), nil, false, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(Equal(fmt.Sprintf("expected the kms-key-arn: %s to match %s", "test", kmsArnRegexpValidator.KmsArnRE)))
})
It("PrivateLink false empty kmsKeyARN - success", func() {
err := cluster.CreateAWSBuilder(rosaTypes.Classic, nil, nil, nil, nil, false, nil, nil, nil, nil, nil, nil, nil, nil, nil)
err := cluster.CreateAWSBuilder(rosaTypes.Classic, nil, nil, nil, nil, false, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
Expect(err).NotTo(HaveOccurred())
ocmCluster, err := cluster.Build()
Expect(err).NotTo(HaveOccurred())
Expand All @@ -228,7 +228,7 @@ var _ = Describe("Cluster", func() {
})
It("PrivateLink false invalid Ec2MetadataHttpTokens - success", func() {
// TODO Need to add validation for Ec2MetadataHttpTokens
err := cluster.CreateAWSBuilder(rosaTypes.Classic, nil, pointer("test"), nil, nil, false, nil, nil, nil, nil, nil, nil, nil, nil, nil)
err := cluster.CreateAWSBuilder(rosaTypes.Classic, nil, pointer("test"), nil, nil, false, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)
Expect(err).NotTo(HaveOccurred())
ocmCluster, err := cluster.Build()
Expect(err).NotTo(HaveOccurred())
Expand Down Expand Up @@ -257,7 +257,7 @@ var _ = Describe("Cluster", func() {
err := cluster.CreateAWSBuilder(rosaTypes.Classic, map[string]string{"key1": "val1"},
pointer(string(cmv1.Ec2MetadataHttpTokensRequired)),
pointer(validKmsKey), nil, true, pointer(accountID), nil,
sts, subnets, nil, nil, nil, nil, nil)
sts, subnets, nil, nil, nil, nil, nil, nil, nil, nil)
Expect(err).NotTo(HaveOccurred())
ocmCluster, err := cluster.Build()
Expect(err).NotTo(HaveOccurred())
Expand Down Expand Up @@ -299,7 +299,7 @@ var _ = Describe("Cluster", func() {
err := cluster.CreateAWSBuilder(rosaTypes.Classic, map[string]string{"key1": "val1"},
pointer(string(cmv1.Ec2MetadataHttpTokensRequired)),
pointer(validKmsKey), nil, true, pointer(accountID), nil,
sts, subnets, &privateHZId, &privateHZRoleArn, nil, nil, nil)
sts, subnets, &privateHZId, &privateHZRoleArn, nil, nil, nil, nil, nil, nil)
Expect(err).NotTo(HaveOccurred())
ocmCluster, err := cluster.Build()
Expect(err).NotTo(HaveOccurred())
Expand All @@ -324,7 +324,7 @@ var _ = Describe("Cluster", func() {
err := cluster.CreateAWSBuilder(rosaTypes.Classic, map[string]string{"key1": "val1"},
pointer(string(cmv1.Ec2MetadataHttpTokensRequired)),
pointer(validKmsKey), nil, true, pointer(accountID), nil,
sts, subnets, &privateHZId, &privateHZRoleArn, nil, nil, nil)
sts, subnets, &privateHZId, &privateHZRoleArn, nil, nil, nil, nil, nil, nil)
Expect(err).To(HaveOccurred())
})
It("PrivateHostedZone set missing STS - fail", func() {
Expand All @@ -336,7 +336,7 @@ var _ = Describe("Cluster", func() {
err := cluster.CreateAWSBuilder(rosaTypes.Classic, map[string]string{"key1": "val1"},
pointer(string(cmv1.Ec2MetadataHttpTokensRequired)),
pointer(validKmsKey), nil, true, pointer(accountID), nil,
nil, subnets, &privateHZId, &privateHZRoleArn, nil, nil, nil)
nil, subnets, &privateHZId, &privateHZRoleArn, nil, nil, nil, nil, nil, nil)
Expect(err).To(HaveOccurred())
})
It("PrivateHostedZone set missing subnet ids - fail", func() {
Expand All @@ -355,7 +355,7 @@ var _ = Describe("Cluster", func() {
err := cluster.CreateAWSBuilder(rosaTypes.Classic, map[string]string{"key1": "val1"},
pointer(string(cmv1.Ec2MetadataHttpTokensRequired)),
pointer(validKmsKey), nil, true, pointer(accountID), nil,
sts, nil, &privateHZId, &privateHZRoleArn, nil, nil, nil)
sts, nil, &privateHZId, &privateHZRoleArn, nil, nil, nil, nil, nil, nil)
Expect(err).To(HaveOccurred())
})
})
Expand Down
8 changes: 5 additions & 3 deletions provider/clusterrosa/classic/cluster_rosa_classic_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -653,9 +653,10 @@ func createClassicClusterObject(ctx context.Context,
}
if err := ocmClusterResource.CreateAWSBuilder(rosaTypes.Classic, awsTags, ec2MetadataHttpTokens,
kmsKeyARN, nil,
isPrivateLink, awsAccountID, nil, stsBuilder, awsSubnetIDs, privateHostedZoneID, privateHostedZoneRoleARN,
isPrivateLink, awsAccountID, nil, stsBuilder, awsSubnetIDs,
privateHostedZoneID, privateHostedZoneRoleARN, nil, nil,
awsAdditionalComputeSecurityGroupIds, awsAdditionalInfraSecurityGroupIds,
awsAdditionalControlPlaneSecurityGroupIds); err != nil {
awsAdditionalControlPlaneSecurityGroupIds, nil); err != nil {
return nil, err
}

Expand Down Expand Up @@ -997,7 +998,8 @@ func validateNoImmutableAttChange(state, plan *ClusterRosaClassicState) diag.Dia
common.ValidateStateAndPlanEquals(state.AWSAdditionalComputeSecurityGroupIds, plan.AWSAdditionalComputeSecurityGroupIds, "aws_additional_compute_security_group_ids", &diags)

if !reflect.DeepEqual(state.PrivateHostedZone, plan.PrivateHostedZone) {
diags.AddError(common.AssertionErrorSummaryMessage, fmt.Sprintf(common.AssertionErrorDetailsMessage, "private_hosted_zone", *state.PrivateHostedZone, *plan.PrivateHostedZone))
diags.AddError(common.AssertionErrorSummaryMessage, fmt.Sprintf(common.AssertionErrorDetailsMessage, "private_hosted_zone",
common.GetJsonStringOrNullString(state.PrivateHostedZone), common.GetJsonStringOrNullString(plan.PrivateHostedZone)))
}

// default machine pool's attributes
Expand Down
2 changes: 1 addition & 1 deletion provider/clusterrosa/common/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ var AvailabilityZoneValidator = attrvalidators.NewStringValidator("AZ should be
}
})

var PrivateHZValidator = attrvalidators.NewObjectValidator("proxy map should not include an hard coded OCM proxy",
var PrivateHZValidator = attrvalidators.NewObjectValidator("Private Hosted Zone attribute must include all attributes",
func(ctx context.Context, req validator.ObjectRequest, resp *validator.ObjectResponse) {
if req.ConfigValue.IsNull() || req.ConfigValue.IsUnknown() {
return
Expand Down
Loading