diff --git a/api/v1/webspherelibertyapplication_types.go b/api/v1/webspherelibertyapplication_types.go index b11c3910..d2311e00 100644 --- a/api/v1/webspherelibertyapplication_types.go +++ b/api/v1/webspherelibertyapplication_types.go @@ -520,6 +520,15 @@ type WebSphereLibertyApplicationSemeruCloudCompiler struct { // Resource requests and limits for the Semeru Cloud Compiler. The CPU defaults to 100m with a limit of 2000m. The memory defaults to 800Mi, with a limit of 1200Mi. // +operator-sdk:csv:customresourcedefinitions:order=54,type=spec,displayName="Resource Requirements",xDescriptors="urn:alm:descriptor:com.tectonic.ui:resourceRequirements" Resources *corev1.ResourceRequirements `json:"resources,omitempty"` + // The health settings for the Semeru Cloud Compiler. + // +operator-sdk:csv:customresourcedefinitions:order=55,type=spec,displayName="Health" + Health *WebSphereLibertyApplicationSemeruCloudCompilerHealth `json:"health,omitempty"` +} + +type WebSphereLibertyApplicationSemeruCloudCompilerHealth struct { + // The health port for the Semeru Cloud Compiler. Defaults to 38600. + // +operator-sdk:csv:customresourcedefinitions:order=60,type=spec,displayName="Port",xDescriptors="urn:alm:descriptor:com.tectonic.ui:number" + Port *int32 `json:"port,omitempty"` } // Defines SemeruCompiler status @@ -1287,6 +1296,19 @@ func (scc *WebSphereLibertyApplicationSemeruCloudCompiler) GetReplicas() *int32 return &one } +// GetHealth returns the Semeru Cloud Compiler Health configuration +func (scc *WebSphereLibertyApplicationSemeruCloudCompiler) GetHealth() *WebSphereLibertyApplicationSemeruCloudCompilerHealth { + return scc.Health +} + +func (scch *WebSphereLibertyApplicationSemeruCloudCompilerHealth) GetPort() *int32 { + if scch.Port != nil { + return scch.Port + } + defaultPort := int32(38600) + return &defaultPort +} + // GetTopologySpreadConstraints returns the pod topology spread constraints configuration func (cr *WebSphereLibertyApplication) GetTopologySpreadConstraints() common.BaseComponentTopologySpreadConstraints { if cr.Spec.TopologySpreadConstraints == nil { diff --git a/bundle/manifests/ibm-websphere-liberty.clusterserviceversion.yaml b/bundle/manifests/ibm-websphere-liberty.clusterserviceversion.yaml index c3e4e1fc..9f09630b 100644 --- a/bundle/manifests/ibm-websphere-liberty.clusterserviceversion.yaml +++ b/bundle/manifests/ibm-websphere-liberty.clusterserviceversion.yaml @@ -538,45 +538,53 @@ spec: be removed from service endpoints if the probe fails. displayName: Readiness Probe path: probes.readiness + - description: Enable the Semeru Cloud Compiler. Defaults to false. + displayName: Enable + path: semeruCloudCompiler.enable + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:booleanSwitch - description: Probe to determine successful initialization. If specified, other probes are not executed until this completes successfully. displayName: Startup Probe path: probes.startup + - description: Number of desired pods for the Semeru Cloud Compiler. Defaults + to 1. + displayName: Replicas + path: semeruCloudCompiler.replicas + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:podCount - description: Disable the creation of the network policy. Defaults to false. displayName: Disable path: networkPolicy.disable x-descriptors: - urn:alm:descriptor:com.tectonic.ui:booleanSwitch - - description: Enable the Semeru Cloud Compiler. Defaults to false. - displayName: Enable - path: semeruCloudCompiler.enable + - description: Resource requests and limits for the Semeru Cloud Compiler. The + CPU defaults to 100m with a limit of 2000m. The memory defaults to 800Mi, + with a limit of 1200Mi. + displayName: Resource Requirements + path: semeruCloudCompiler.resources x-descriptors: - - urn:alm:descriptor:com.tectonic.ui:booleanSwitch + - urn:alm:descriptor:com.tectonic.ui:resourceRequirements - description: Specify the labels of namespaces that incoming traffic is allowed from. displayName: Namespace Labels path: networkPolicy.namespaceLabels x-descriptors: - urn:alm:descriptor:com.tectonic.ui:text - - description: Number of desired pods for the Semeru Cloud Compiler. Defaults - to 1. - displayName: Replicas - path: semeruCloudCompiler.replicas - x-descriptors: - - urn:alm:descriptor:com.tectonic.ui:podCount + - description: The health settings for the Semeru Cloud Compiler. + displayName: Health + path: semeruCloudCompiler.health - description: Specify the labels of pod(s) that incoming traffic is allowed from. displayName: From Labels path: networkPolicy.fromLabels x-descriptors: - urn:alm:descriptor:com.tectonic.ui:text - - description: Resource requests and limits for the Semeru Cloud Compiler. The - CPU defaults to 100m with a limit of 2000m. The memory defaults to 800Mi, - with a limit of 1200Mi. - displayName: Resource Requirements - path: semeruCloudCompiler.resources + - description: The health port for the Semeru Cloud Compiler. Defaults to 38600. + displayName: Port + path: semeruCloudCompiler.health.port x-descriptors: - - urn:alm:descriptor:com.tectonic.ui:resourceRequirements + - urn:alm:descriptor:com.tectonic.ui:number - description: 'Product edition. Defaults to IBM WebSphere Application Server. Other options: IBM WebSphere Application Server Liberty Core, IBM WebSphere Application Server Network Deployment' diff --git a/bundle/manifests/liberty.websphere.ibm.com_webspherelibertyapplications.yaml b/bundle/manifests/liberty.websphere.ibm.com_webspherelibertyapplications.yaml index 74c4ea52..7fa87366 100644 --- a/bundle/manifests/liberty.websphere.ibm.com_webspherelibertyapplications.yaml +++ b/bundle/manifests/liberty.websphere.ibm.com_webspherelibertyapplications.yaml @@ -4173,6 +4173,15 @@ spec: enable: description: Enable the Semeru Cloud Compiler. Defaults to false. type: boolean + health: + description: The health settings for the Semeru Cloud Compiler. + properties: + port: + description: The health port for the Semeru Cloud Compiler. + Defaults to 38600. + format: int32 + type: integer + type: object replicas: description: Number of desired pods for the Semeru Cloud Compiler. Defaults to 1. diff --git a/config/crd/bases/liberty.websphere.ibm.com_webspherelibertyapplications.yaml b/config/crd/bases/liberty.websphere.ibm.com_webspherelibertyapplications.yaml index 5a2d7bfb..19186837 100644 --- a/config/crd/bases/liberty.websphere.ibm.com_webspherelibertyapplications.yaml +++ b/config/crd/bases/liberty.websphere.ibm.com_webspherelibertyapplications.yaml @@ -4169,6 +4169,15 @@ spec: enable: description: Enable the Semeru Cloud Compiler. Defaults to false. type: boolean + health: + description: The health settings for the Semeru Cloud Compiler. + properties: + port: + description: The health port for the Semeru Cloud Compiler. + Defaults to 38600. + format: int32 + type: integer + type: object replicas: description: Number of desired pods for the Semeru Cloud Compiler. Defaults to 1. diff --git a/config/manifests/bases/ibm-websphere-liberty.clusterserviceversion.yaml b/config/manifests/bases/ibm-websphere-liberty.clusterserviceversion.yaml index 5ce88edc..94d5f3d8 100644 --- a/config/manifests/bases/ibm-websphere-liberty.clusterserviceversion.yaml +++ b/config/manifests/bases/ibm-websphere-liberty.clusterserviceversion.yaml @@ -480,45 +480,53 @@ spec: be removed from service endpoints if the probe fails. displayName: Readiness Probe path: probes.readiness + - description: Enable the Semeru Cloud Compiler. Defaults to false. + displayName: Enable + path: semeruCloudCompiler.enable + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:booleanSwitch - description: Probe to determine successful initialization. If specified, other probes are not executed until this completes successfully. displayName: Startup Probe path: probes.startup + - description: Number of desired pods for the Semeru Cloud Compiler. Defaults + to 1. + displayName: Replicas + path: semeruCloudCompiler.replicas + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:podCount - description: Disable the creation of the network policy. Defaults to false. displayName: Disable path: networkPolicy.disable x-descriptors: - urn:alm:descriptor:com.tectonic.ui:booleanSwitch - - description: Enable the Semeru Cloud Compiler. Defaults to false. - displayName: Enable - path: semeruCloudCompiler.enable + - description: Resource requests and limits for the Semeru Cloud Compiler. The + CPU defaults to 100m with a limit of 2000m. The memory defaults to 800Mi, + with a limit of 1200Mi. + displayName: Resource Requirements + path: semeruCloudCompiler.resources x-descriptors: - - urn:alm:descriptor:com.tectonic.ui:booleanSwitch + - urn:alm:descriptor:com.tectonic.ui:resourceRequirements - description: Specify the labels of namespaces that incoming traffic is allowed from. displayName: Namespace Labels path: networkPolicy.namespaceLabels x-descriptors: - urn:alm:descriptor:com.tectonic.ui:text - - description: Number of desired pods for the Semeru Cloud Compiler. Defaults - to 1. - displayName: Replicas - path: semeruCloudCompiler.replicas - x-descriptors: - - urn:alm:descriptor:com.tectonic.ui:podCount + - description: The health settings for the Semeru Cloud Compiler. + displayName: Health + path: semeruCloudCompiler.health - description: Specify the labels of pod(s) that incoming traffic is allowed from. displayName: From Labels path: networkPolicy.fromLabels x-descriptors: - urn:alm:descriptor:com.tectonic.ui:text - - description: Resource requests and limits for the Semeru Cloud Compiler. The - CPU defaults to 100m with a limit of 2000m. The memory defaults to 800Mi, - with a limit of 1200Mi. - displayName: Resource Requirements - path: semeruCloudCompiler.resources + - description: The health port for the Semeru Cloud Compiler. Defaults to 38600. + displayName: Port + path: semeruCloudCompiler.health.port x-descriptors: - - urn:alm:descriptor:com.tectonic.ui:resourceRequirements + - urn:alm:descriptor:com.tectonic.ui:number - description: 'Product edition. Defaults to IBM WebSphere Application Server. Other options: IBM WebSphere Application Server Liberty Core, IBM WebSphere Application Server Network Deployment' diff --git a/internal/controller/semeru_compiler.go b/internal/controller/semeru_compiler.go index 795c0590..d8e19cae 100644 --- a/internal/controller/semeru_compiler.go +++ b/internal/controller/semeru_compiler.go @@ -46,14 +46,65 @@ const ( SemeruGenerationLabelNameSuffix = "/semeru-compiler-generation" StatusReferenceSemeruGeneration = "semeruGeneration" StatusReferenceSemeruInstancesCompleted = "semeruInstancesCompleted" + SemeruContainerName = "compiler" ) -// Create the Deployment and Service objects for a Semeru Compiler used by a Websphere Liberty Application -func (r *ReconcileWebSphereLiberty) reconcileSemeruCompiler(wlva *wlv1.WebSphereLibertyApplication) (error, string, bool) { - compilerMeta := metav1.ObjectMeta{ +func getCompilerMeta(wlva *wlv1.WebSphereLibertyApplication) metav1.ObjectMeta { + return metav1.ObjectMeta{ Name: getSemeruCompilerNameWithGeneration(wlva), Namespace: wlva.GetNamespace(), } +} + +func getSemeruDeploymentContainer(deploy *appsv1.Deployment) (corev1.Container, error) { + for _, container := range deploy.Spec.Template.Spec.Containers { + if container.Name == SemeruContainerName { + return container, nil + } + } + return corev1.Container{}, fmt.Errorf("could not find the Semeru Deployment container") +} + +// Returns true if the semeru health port configuration has changed otherwise false +func (r *ReconcileWebSphereLiberty) upgradeSemeruHealthPorts(inputMeta metav1.ObjectMeta, wlva *wlv1.WebSphereLibertyApplication) bool { + var healthPort int32 = 38600 + if wlva.GetSemeruCloudCompiler().GetHealth() != nil { + healthPort = *wlva.GetSemeruCloudCompiler().GetHealth().GetPort() + } + semeruDeployment := &appsv1.Deployment{ObjectMeta: inputMeta} + if r.GetClient().Get(context.TODO(), types.NamespacedName{Name: semeruDeployment.Name, Namespace: semeruDeployment.Namespace}, semeruDeployment) == nil { + container, err := getSemeruDeploymentContainer(semeruDeployment) + if err != nil { + return false + } + if healthPort == 38400 && len(container.Ports) > 1 { + return true + } + containsHealthPort := false + for _, port := range container.Ports { + if port.ContainerPort == healthPort { + containsHealthPort = true + } + } + if !containsHealthPort { + return true + } + } + return false +} + +// Create the Deployment and Service objects for a Semeru Compiler used by a Websphere Liberty Application +func (r *ReconcileWebSphereLiberty) reconcileSemeruCompiler(wlva *wlv1.WebSphereLibertyApplication) (error, string, bool) { + compilerMeta := getCompilerMeta(wlva) + + // check for any diffs that require generation changes + if r.isSemeruEnabled(wlva) { + upgradeRequired := r.upgradeSemeruHealthPorts(compilerMeta, wlva) + if upgradeRequired { + createNewSemeruGeneration(wlva) // update generation + compilerMeta = getCompilerMeta(wlva) // adjust compilerMeta to reference the new generation + } + } currentGeneration := getGeneration(wlva) @@ -255,6 +306,8 @@ func (r *ReconcileWebSphereLiberty) deleteCompletedSemeruInstances(wlva *wlv1.We } func (r *ReconcileWebSphereLiberty) reconcileSemeruDeployment(wlva *wlv1.WebSphereLibertyApplication, deploy *appsv1.Deployment) { + var port int32 = 38400 + var healthPort int32 = 38600 deploy.Labels = getLabels(wlva) deploy.Spec.Strategy.Type = appsv1.RecreateDeploymentStrategyType @@ -276,11 +329,20 @@ func (r *ReconcileWebSphereLiberty) reconcileSemeruDeployment(wlva *wlv1.WebSphe limitsMemory := getQuantityFromLimitsOrDefault(instanceResources, corev1.ResourceMemory, "1200Mi") limitsCPU := getQuantityFromLimitsOrDefault(instanceResources, corev1.ResourceCPU, "2000m") + if semeruCloudCompiler.GetHealth() != nil { + healthPort = *semeruCloudCompiler.GetHealth().GetPort() + } + var portIntOrStr intstr.IntOrString + if healthPort == port { + portIntOrStr = intstr.FromInt32(port) + } else { + portIntOrStr = intstr.FromString(fmt.Sprintf("%d-tcp", healthPort)) + } // Liveness probe livenessProbe := corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ TCPSocket: &corev1.TCPSocketAction{ - Port: intstr.FromInt(38400), + Port: portIntOrStr, }, }, InitialDelaySeconds: 10, @@ -291,7 +353,7 @@ func (r *ReconcileWebSphereLiberty) reconcileSemeruDeployment(wlva *wlv1.WebSphe readinessProbe := corev1.Probe{ ProbeHandler: corev1.ProbeHandler{ TCPSocket: &corev1.TCPSocketAction{ - Port: intstr.FromInt(38400), + Port: portIntOrStr, }, }, InitialDelaySeconds: 5, @@ -301,6 +363,22 @@ func (r *ReconcileWebSphereLiberty) reconcileSemeruDeployment(wlva *wlv1.WebSphe semeruPodMatchLabels := map[string]string{ "app.kubernetes.io/instance": getSemeruCompilerNameWithGeneration(wlva), } + containerPorts := make([]corev1.ContainerPort, 0) + containerPorts = append(containerPorts, corev1.ContainerPort{ + ContainerPort: port, + Protocol: corev1.ProtocolTCP, + }) + + healthProbesFlag := "" + if healthPort != port { + healthProbesFlag = " -XX:+JITServerHealthProbes" + fmt.Sprintf(" -XX:JITServerHealthProbePort=%d", healthPort) + containerPorts[0].Name = fmt.Sprintf("%d-tcp", port) + containerPorts = append(containerPorts, corev1.ContainerPort{ + Name: fmt.Sprintf("%d-tcp", healthPort), + ContainerPort: healthPort, + Protocol: corev1.ProtocolTCP, + }) + } deploy.Spec.Template = corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: getLabels(wlva), @@ -333,16 +411,11 @@ func (r *ReconcileWebSphereLiberty) reconcileSemeruDeployment(wlva *wlv1.WebSphe }, Containers: []corev1.Container{ { - Name: "compiler", + Name: SemeruContainerName, Image: wlva.Status.GetImageReference(), ImagePullPolicy: *wlva.GetPullPolicy(), Command: []string{"jitserver"}, - Ports: []corev1.ContainerPort{ - { - ContainerPort: 38400, - Protocol: corev1.ProtocolTCP, - }, - }, + Ports: containerPorts, Resources: corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceMemory: requestsMemory, @@ -356,6 +429,7 @@ func (r *ReconcileWebSphereLiberty) reconcileSemeruDeployment(wlva *wlv1.WebSphe Env: []corev1.EnvVar{ {Name: "OPENJ9_JAVA_OPTIONS", Value: "-XX:+JITServerLogConnections" + " -XX:+JITServerShareROMClasses" + + healthProbesFlag + " -XX:JITServerSSLKey=/etc/x509/certs/tls.key" + " -XX:JITServerSSLCert=/etc/x509/certs/tls.crt"}, }, @@ -413,16 +487,34 @@ func (r *ReconcileWebSphereLiberty) reconcileSemeruDeployment(wlva *wlv1.WebSphe func reconcileSemeruService(svc *corev1.Service, wlva *wlv1.WebSphereLibertyApplication) { var port int32 = 38400 + var healthPort int32 = 38600 var timeout int32 = 86400 svc.Labels = getLabels(wlva) svc.Spec.Selector = getSelectors(wlva) utils.CustomizeServiceAnnotations(svc) - if len(svc.Spec.Ports) == 0 { + numPorts := len(svc.Spec.Ports) + if numPorts == 0 { svc.Spec.Ports = append(svc.Spec.Ports, corev1.ServicePort{}) } + svc.Spec.Ports[0].Protocol = corev1.ProtocolTCP svc.Spec.Ports[0].Port = port svc.Spec.Ports[0].TargetPort = intstr.FromInt(int(port)) + if wlva.GetSemeruCloudCompiler().GetHealth() != nil { + healthPort = *wlva.GetSemeruCloudCompiler().GetHealth().GetPort() + } + if healthPort != port { + numPorts = len(svc.Spec.Ports) + if numPorts == 1 { + svc.Spec.Ports = append(svc.Spec.Ports, corev1.ServicePort{}) + } + svc.Spec.Ports[0].Name = fmt.Sprintf("%d-tcp", port) + svc.Spec.Ports[0].TargetPort = intstr.FromString(fmt.Sprintf("%d-tcp", port)) + svc.Spec.Ports[1].Name = fmt.Sprintf("%d-tcp", healthPort) + svc.Spec.Ports[1].Protocol = corev1.ProtocolTCP + svc.Spec.Ports[1].Port = healthPort + svc.Spec.Ports[1].TargetPort = intstr.FromString(fmt.Sprintf("%d-tcp", healthPort)) + } svc.Spec.SessionAffinity = corev1.ServiceAffinityClientIP svc.Spec.SessionAffinityConfig = &corev1.SessionAffinityConfig{ ClientIP: &corev1.ClientIPConfig{ @@ -585,14 +677,13 @@ func (r *ReconcileWebSphereLiberty) getSemeruJavaOptions(instance *wlv1.WebSpher certificateLocation = "/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt" } jitServerAddress := instance.Status.SemeruCompiler.ServiceHostname - jitSeverOptions := fmt.Sprintf("-XX:+UseJITServer -XX:+JITServerLogConnections -XX:JITServerAddress=%v -XX:JITServerSSLRootCerts=%v", - jitServerAddress, certificateLocation) + jitServerOptions := fmt.Sprintf("-XX:+UseJITServer -XX:+JITServerLogConnections -XX:JITServerAddress=%v -XX:JITServerSSLRootCerts=%v", jitServerAddress, certificateLocation) args := []string{ "/bin/bash", "-c", - "export OPENJ9_JAVA_OPTIONS=\"$OPENJ9_JAVA_OPTIONS " + jitSeverOptions + - "\" && export OPENJ9_RESTORE_JAVA_OPTIONS=\"$OPENJ9_RESTORE_JAVA_OPTIONS " + jitSeverOptions + + "export OPENJ9_JAVA_OPTIONS=\"$OPENJ9_JAVA_OPTIONS " + jitServerOptions + + "\" && export OPENJ9_RESTORE_JAVA_OPTIONS=\"$OPENJ9_RESTORE_JAVA_OPTIONS " + jitServerOptions + "\" && server run", } return args diff --git a/internal/deploy/kubectl/websphereliberty-app-crd.yaml b/internal/deploy/kubectl/websphereliberty-app-crd.yaml index 5700c256..ec3a6354 100644 --- a/internal/deploy/kubectl/websphereliberty-app-crd.yaml +++ b/internal/deploy/kubectl/websphereliberty-app-crd.yaml @@ -4172,6 +4172,15 @@ spec: enable: description: Enable the Semeru Cloud Compiler. Defaults to false. type: boolean + health: + description: The health settings for the Semeru Cloud Compiler. + properties: + port: + description: The health port for the Semeru Cloud Compiler. + Defaults to 38600. + format: int32 + type: integer + type: object replicas: description: Number of desired pods for the Semeru Cloud Compiler. Defaults to 1. diff --git a/internal/deploy/kustomize/daily/base/websphere-liberty-crd.yaml b/internal/deploy/kustomize/daily/base/websphere-liberty-crd.yaml index 5700c256..ec3a6354 100644 --- a/internal/deploy/kustomize/daily/base/websphere-liberty-crd.yaml +++ b/internal/deploy/kustomize/daily/base/websphere-liberty-crd.yaml @@ -4172,6 +4172,15 @@ spec: enable: description: Enable the Semeru Cloud Compiler. Defaults to false. type: boolean + health: + description: The health settings for the Semeru Cloud Compiler. + properties: + port: + description: The health port for the Semeru Cloud Compiler. + Defaults to 38600. + format: int32 + type: integer + type: object replicas: description: Number of desired pods for the Semeru Cloud Compiler. Defaults to 1.