diff --git a/Parameters.md b/Parameters.md index e87bab3..28e1881 100644 --- a/Parameters.md +++ b/Parameters.md @@ -1,12 +1,5 @@ # Parameters to use in CRD -## replicas (mandatory all configuration) -The number of pods of the JBoss Web Server image you want to run. - -``` - replicas: 2 -``` - ## applicationName (mandatory all configuration) The name of the application, it must be unique in the namespace/project. Note that it is used to create the route to access to that application. @@ -15,80 +8,18 @@ to that application. applicationName: test ``` -## useSessionClustering (off if not filled) -Use the DNSping or KUBEping session clustering if filled, default don't use session clustering (Note that image needs to be based on JWS images as the feature use ENV_FILES environment variable and a shell script to add the clustering in server.xml) - -``` - useSessionClustering: true -``` -## routeHostname -Create a route or not (NONE) and tell if the route uses TLS (tls) and allow to specify a hostname. -``` - routeHostname: NONE -``` -The route will NOT be created by the operator, it needs to be create by hands. -``` - routeHostname: tls -``` -The operator will create a passthrough route to the tomcat. - -## certificateVerification -Use the TLS connector with a client certificates. The value are required, optional or empty see Tomcat connector docs and look for certificateVerification in the connector. -``` - certificateVerification: required -``` - -## TLSSecret -Secret to use for the server certificate (server.cert) and server key (server.key) and optional CA certificat for the client certificates (ca.cert). -``` - tlsSecret: tlssecret -``` - -## TLSPassord -The passpharse used to protect the server key. -``` - tlsPassword: changeit -``` - -## Resources -The configuration of the resources used by the webserver, ie CPU and memory, Use limits and requests. -Those are used for the auto scaling. -``` - resources: - limits: - cpu: 500m - requests: - cpu: 200m -``` -See Horizontal Pod Autoscaling in openshift or kubernetes for more details how to use it. - -## PersistentLogs -If PersistentLogs is true catalina.out of every pod will be saved in a PersistentVolume in order to remain available after a possible pod failure. -``` - persistentLogs: true -``` +## replicas (mandatory all configuration) +The number of pods of the JBoss Web Server image you want to run. -## EnableAccessLogs -If EnableAccessLogs is true but PersistentLogs is false access log will just get produced but not saved in a PV. Access logs of every pod will be saved in a PV in case that EnableAccessLogs and PersistentLogs are true in parallel. ``` - enableAccessLogs: true + replicas: 2 ``` -## IsNotJWS -This parameter is used with PersistentLogs or/and EnableAccessLogs to show the operator how to configure the container for persistent logs because JWS image needs different configuration than the ASF tomcat imag. Setting it to true means that the given image is ASF tomcat image. -``` - isNotJWS: true -``` -## volumeName -If PersistentLogs is true, volumeName is the name of PersistentVolume used to store the access_log and catalina.out -``` - volumeName: pv0000 -``` +## useSessionClustering (off if not filled) +Use the DNSping or KUBEping session clustering if filled, default don't use session clustering (Note that image needs to be based on JWS images as the feature use ENV_FILES environment variable and a shell script to add the clustering in server.xml) -## storageClass -If PersistentLogs is true, storageClass is the name of storageClass of the PersistentVolume used to store the access_log and catalina.out ``` - storageClassvolumeName: nfs-client + useSessionClustering: true ``` ## webImage (to deploy from existing images) @@ -107,13 +38,58 @@ The secret to use to pull images for the repository, the secret must contain the the operator to be used like --authfile /mount_point/.dockerconfigjson to pull the image to deploy the pods. Note that the file might contain several user/password or token to access to the images in the ImageStream, the image builder and the images built by the operator. +### webServerHealthCheck +Describes how the operator will create the health checks for the created pods. The default behavior is to use the health valve which doesn't require any parameters. + +#### serverReadinessScript +String for the pod readiness health check logic. If left empty the default health check is used (it checks http://localhost:8080/health using OpenShift internal) +Example : + +``` +serverReadinessScript: /bin/bash -c " /usr/bin/curl --noproxy '*' -s 'http://localhost:8080/health' | /usr/bin/grep -i 'status.*UP'" +``` + +For the formats see the README.md. + +#### serverLivenessScript +The script that checks if the pod is running. It's use is optional. + ### webApp Describes how the operator will build the webapp to add to application image, if not present the application is just deployed. It has the sourceRepositoryUrl (Mandatory), sourceRepositoryRef, contextDir, webAppWarImage, webAppWarImagePushSecret,Name and builder. -### webServerHealthCheck -Describes how the operator will create the health check for the created pods. +#### sourceRepositoryURL (mandatory) +URL for the repository of the application sources + +#### name +The name of the webapp, default: ROOT.war + +#### webAppWarImage +That is the URL of images where the operator will push what he builds. +#### webAppWarImagePushSecret +The secret to use to push images to the repository, the secret must contain the key .dockerconfigjson and will be mounted by +the operator to be used like --authfile /mount_point/.dockerconfigjson to push the image to repository. Note that if you need a pull secret for the FROM image the webAppImagePushSecret must contain it too. + +#### contextDir +Subdirectory in the source repository + +#### sourceRepositoryRef +Branch in the source repository + +#### builder +It describes how the webapp is build and the docker image is made and push to a docker repository. + +##### image (webapp.builder) +That is the image to use to build +``` +builder: quay.io/jfclere/tomcat10-buildah +``` +##### imagePullSecret (webapp.builder) +If there is an imagePullSecret, that it should also contain the secret to pull the image of the image builder if needed. + +##### applicationBuildScript (webapp.builder) +That is the script to use to build and push the image, if empty a default script using maven and buildah is used. ## webImageStream (to deploy from an ImageStream, openshift only) The webImageStream controls how the operator will use an ImageStream that provides images to run or to build upon. The latest image in the stream is used. @@ -139,6 +115,22 @@ imagestream.image.openshift.io/jboss-webserver56-tomcat9-openshift created Here: imageStreamNamespace: jfc +### webServerHealthCheck +Describes how the operator will create the health checks for the created pods. The default behavior is to use the health valve which doesn't require any parameters. + +#### serverReadinessScript +String for the pod readiness health check logic. If left empty the default health check is used (it checks http://localhost:8080/health using OpenShift internal) +Example : + +``` +serverReadinessScript: /bin/bash -c " /usr/bin/curl --noproxy '*' -s 'http://localhost:8080/health' | /usr/bin/grep -i 'status.*UP'" +``` + +For the formats see the README.md. + +#### serverLivenessScript +The script that checks if the pod is running. It's use is optional. + ### webSources Describes where the sources are located and how build them, if empty the latest image in ImageStream is deployed) It has the sourceRepositoryUrl (Mandatory), sourceRepositoryRef, ContextDir and webSourcesParams @@ -169,7 +161,7 @@ The sub directory where the pom.xml is located and where the `mvn install` shoul #### webhookSecrets Secret names for triggering a build through webhook. -##### Generic (webhookSecrets) +##### generic (webhookSecrets) Secret name for triggering a build. 1 - Create a base64 secret string: @@ -243,10 +235,10 @@ The build is triggered. Go to Setting+Webhooks+Add webhook in your github project and add the URL in the Payload URL, set Content type: application/json, Disable SSL verification if needed and click Add webhook. See https://docs.openshift.com/container-platform/4.6/builds/triggering-builds-build-hooks.html for more details. -##### Github (webhookSecrets) +##### github (webhookSecrets) Secret name for triggering a build from Github. -##### Gitlab (webhookSecrets) +##### gitlab (webhookSecrets) Secret name for triggering a build from Gitlab. #### webSourcesParams @@ -259,51 +251,93 @@ The contents of artifactDir is copied in the webapps directory of the image used ##### mavenMirrorUrl (webSourcesParams) The mavenMirrorUrl is a parameter of the SourceBuildStrategy the operator is using. It is the maven proxy URL that maven will use to build the webapp. It is required if the cluster doesn't have access to the Internet. -##### (Deprecated) genericWebhookSecret (webSourcesParams) +##### (Deprecated - use WebhookSecrets instead) genericWebhookSecret (webSourcesParams) Web hook secret string -##### (Deprecated) githubWebhookSecret (webSourcesParams) +##### (Deprecated - use WebhookSecrets instead) githubWebhookSecret (webSourcesParams) That is a web hook secret string specific to GitHub, it works like `genericWebhookSecret` Note that it is not possible to test the Github webhook by hands: The playload is generated by github and it is NOT empty. +## tlsConfig +TLS configuration for a webserver -## webServerHealthCheck (webImage and webImageStream) -The health check that the operator will use. The default behavior is to use the health valve which doesn't require any parameters. +### routeHostname +Create a route or not (NONE) and tell if the route uses TLS (tls) and allow to specify a hostname. +``` + routeHostname: NONE +``` +The route will NOT be created by the operator, it needs to be create by hands. +``` + routeHostname: tls +``` +The operator will create a passthrough route to the tomcat. -### serverReadinessScript -String for the pod readiness health check logic. If left empty the default health check is used (it checks http://localhost:8080/health using OpenShift internal) -Example : +### certificateVerification +Use the TLS connector with a client certificates. The value are required, optional or empty see Tomcat connector docs and look for certificateVerification in the connector. +``` + certificateVerification: required +``` + +### tlsSecret +Secret to use for the server certificate (server.cert) and server key (server.key) and optional CA certificat for the client certificates (ca.cert). +``` + tlsSecret: tlssecret +``` +### tlsPassord +The passpharse used to protect the server key. ``` -serverReadinessScript: /bin/bash -c " /usr/bin/curl --noproxy '*' -s 'http://localhost:8080/health' | /usr/bin/grep -i 'status.*UP'" + tlsPassword: changeit ``` -For the formats see the README.md. +## environmentVariables +Environment variables for deployment. -### serverLivenessScript -The script that checks if the pod is running. It's use is optional. +## persistentLogs +Persistent volume and logging configuration. -### Name (webapp) -The name of the webapp, default: ROOT.war +### catalinaLogs +Log file catalina.out of every pod will be saved in a PersistentVolume in order to remain available after a possible pod failure. +``` + catalinaLogs: true +``` -### webAppWarImage (webapp) -That is the URL of images where the operator will push what he builds. +### enableAccessLogs +Log file access_log of every pod will be saved in a PersistentVolume in order to remain available after a possible pod failure. +``` + enableAccessLogs: true +``` -### webAppWarImagePushSecret (webapp) -The secret to use to push images to the repository, the secret must contain the key .dockerconfigjson and will be mounted by -the operator to be used like --authfile /mount_point/.dockerconfigjson to push the image to repository. Note that if you need a pull secret for the FROM image the webAppImagePushSecret must contain it too. +### volumeName +Name of PersistentVolume used to store the log files. +``` + volumeName: pv0000 +``` -### builder (webapp) -It describes how the webapp is build and the docker image is made and push to a docker repository. +### storageClass +Name of storageClass of the PersistentVolume used to store the log files. +``` + storageClassvolumeName: nfs-client +``` -#### image (webapp.builder) -That is the image to use to build +## podResources +The configuration of the resources used by the webserver, ie CPU and memory, Use limits and requests. +Those are used for the auto scaling. ``` -builder: quay.io/jfclere/tomcat10-buildah + resources: + limits: + cpu: 500m + requests: + cpu: 200m ``` -#### imagePullSecret (webapp.builder) -If there is an imagePullSecret, that it should also contain the secret to pull the image of the image builder if needed. +See Horizontal Pod Autoscaling in openshift or kubernetes for more details how to use it. -#### applicationBuildScript (webapp.builder) -That is the script to use to build and push the image, if empty a default script using maven and buildah is used. +## securityContext +SecurityContext defines the security capabilities required to run the application. + +## IsNotJWS +This parameter is used with PersistentLogs or/and EnableAccessLogs to show the operator how to configure the container for persistent logs because JWS image needs different configuration than the ASF tomcat imag. Setting it to true means that the given image is ASF tomcat image. +``` + isNotJWS: true +``` diff --git a/api/v1alpha1/webserver_types.go b/api/v1alpha1/webserver_types.go index e43e8e7..e4776cb 100644 --- a/api/v1alpha1/webserver_types.go +++ b/api/v1alpha1/webserver_types.go @@ -24,30 +24,18 @@ type WebServerSpec struct { EnvironmentVariables []corev1.EnvVar `json:"environmentVariables,omitempty"` // Use Session Clustering UseSessionClustering bool `json:"useSessionClustering,omitempty"` - // Route behaviour:[tls]hostname/NONE or empty. - RouteHostname string `json:"routeHostname,omitempty"` - // certificateVerification for tomcat configuration: required/optional or empty. - CertificateVerification string `json:"certificateVerification,omitempty"` - // TLSSecret secret containing server.cert the server certificate, server.key the server key and optional ca.cert the CA cert of the client certificates - TLSSecret string `json:"tlsSecret,omitempty"` - // TLSPassword passphrase for the key in the client.key - TLSPassword string `json:"tlsPassword,omitempty"` + // TLS configuration + TLSConfig TLSConfig `json:"tlsConfig,omitempty"` + // Persistent logs configuration + PersistentLogsConfig PersistentLogs `json:"persistentLogs,omitempty"` // (Deployment method 1) Application image WebImage *WebImageSpec `json:"webImage,omitempty"` // (Deployment method 2) Imagestream WebImageStream *WebImageStreamSpec `json:"webImageStream,omitempty"` // Configuration of the resources used by the WebServer, ie CPU and memory, use limits and requests PodResources corev1.ResourceRequirements `json:"podResources,omitempty"` - //If true operator will create a PVC to save the logs. - PersistentLogs bool `json:"persistentLogs,omitempty"` - //If true operator will log tomcat's access logs - EnableAccessLogs bool `json:"enableAccessLogs,omitempty"` // IsNotJWS boolean that specifies if the image is JWS or not. IsNotJWS bool `json:"isNotJWS,omitempty"` - // VolumeName is the name of pv we eant to bound - VolumeName string `json:"volumeName,omitempty"` - // StorageClass name of the storage class we want to use for the bound - StorageClass string `json:"storageClass,omitempty"` // SecurityContext defines the security capabilities required to run the application. SecurityContext *corev1.SecurityContext `json:"securityContext,omitempty"` } @@ -102,6 +90,29 @@ type WebImageStreamSpec struct { WebServerHealthCheck *WebServerHealthCheckSpec `json:"webServerHealthCheck,omitempty"` } +// TLS settings +type TLSConfig struct { + // TLSSecret secret containing server.cert the server certificate, server.key the server key and optional ca.cert the CA cert of the client certificates + TLSSecret string `json:"tlsSecret,omitempty"` + // TLSPassword passphrase for the key in the client.key + TLSPassword string `json:"tlsPassword,omitempty"` + // certificateVerification for tomcat configuration: required/optional or empty. + CertificateVerification string `json:"certificateVerification,omitempty"` + // Route behaviour:[tls]hostname/NONE or empty. + RouteHostname string `json:"routeHostname,omitempty"` +} + +type PersistentLogs struct { + //If true operator will log tomcat's catalina logs + CatalinaLogs bool `json:"catalinaLogs,omitempty"` + //If true operator will log tomcat's access logs + AccessLogs bool `json:"enableAccessLogs,omitempty"` + // VolumeName is the name of pv we eant to bound + VolumeName string `json:"volumeName,omitempty"` + // StorageClass name of the storage class we want to use for the bound + StorageClass string `json:"storageClass,omitempty"` +} + // (Optional) Source code information type WebSourcesSpec struct { // URL for the repository of the application sources diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 83cc120..854dd95 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -41,6 +41,21 @@ func (in *BuilderSpec) DeepCopy() *BuilderSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PersistentLogs) DeepCopyInto(out *PersistentLogs) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersistentLogs. +func (in *PersistentLogs) DeepCopy() *PersistentLogs { + if in == nil { + return nil + } + out := new(PersistentLogs) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PodStatus) DeepCopyInto(out *PodStatus) { *out = *in @@ -56,6 +71,21 @@ func (in *PodStatus) DeepCopy() *PodStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSConfig) DeepCopyInto(out *TLSConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig. +func (in *TLSConfig) DeepCopy() *TLSConfig { + if in == nil { + return nil + } + out := new(TLSConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WebAppSpec) DeepCopyInto(out *WebAppSpec) { *out = *in @@ -210,6 +240,8 @@ func (in *WebServerSpec) DeepCopyInto(out *WebServerSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + out.TLSConfig = in.TLSConfig + out.PersistentLogsConfig = in.PersistentLogsConfig if in.WebImage != nil { in, out := &in.WebImage, &out.WebImage *out = new(WebImageSpec) diff --git a/bundle/manifests/jws-operator.clusterserviceversion.yaml b/bundle/manifests/jws-operator.clusterserviceversion.yaml index 05b5279..c3769b1 100644 --- a/bundle/manifests/jws-operator.clusterserviceversion.yaml +++ b/bundle/manifests/jws-operator.clusterserviceversion.yaml @@ -16,11 +16,41 @@ spec: name: webservers.web.servers.org version: v1alpha1 specDescriptors: - - description: Pod resources + - description: The base for the names of the deployed application resources + displayName: Application Name + path: applicationName + - description: Desired number of replicas for the application + displayName: Replicas + path: replicas + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:podCount' + - displayName: Enable Session Clustering in Tomcat + path: useSessionClustering + x-descriptors: + - 'urn:alm:descriptor:com.tectonic.ui:booleanSwitch' + - description: (Deployment method 1) Application image + displayName: Web Image + path: webImage + - description: (Deployment method 2) Image stream + displayName: Web Image Stream + path: webImageStream + - description: TLS configuration for the WebServer + displayName: TLS Configuration + path: tlsConfig + - description: Environment variables for the WebServer + displayName: Environment Variables + path: environmentVariables + - description: Persistent logs configuration + displayName: Persistent Logs + path: persistentLogs + - description: Configuration of the resources used by the WebServer e.g. CPU and memory. displayName: Pod Resources path: podResources x-descriptors: - - urn:alm:descriptor:com.tectonic.ui:resourceRequirements + - 'urn:alm:descriptor:com.tectonic.ui:resourceRequirements' + - description: SecurityContext defines the security capabilities required to run the application. + displayName: Security Context + path: securityContext description: jws-mm displayName: jws-mm icon: diff --git a/config/crd/bases/web.servers.org_webservers.yaml b/config/crd/bases/web.servers.org_webservers.yaml index d8e533f..337b715 100644 --- a/config/crd/bases/web.servers.org_webservers.yaml +++ b/config/crd/bases/web.servers.org_webservers.yaml @@ -40,13 +40,6 @@ spec: description: The base for the names of the deployed application resources pattern: ^[a-z]([-a-z0-9]*[a-z0-9])?$ type: string - certificateVerification: - description: 'certificateVerification for tomcat configuration: required/optional - or empty.' - type: string - enableAccessLogs: - description: If true operator will log tomcat's access logs - type: boolean environmentVariables: description: Environment Variables for deployment items: @@ -157,8 +150,22 @@ spec: not. type: boolean persistentLogs: - description: If true operator will create a PVC to save the logs. - type: boolean + description: Persistent logs configuration + properties: + catalinaLogs: + description: If true operator will log tomcat's catalina logs + type: boolean + enableAccessLogs: + description: If true operator will log tomcat's access logs + type: boolean + storageClass: + description: StorageClass name of the storage class we want to + use for the bound + type: string + volumeName: + description: VolumeName is the name of pv we eant to bound + type: string + type: object podResources: description: Configuration of the resources used by the WebServer, ie CPU and memory, use limits and requests @@ -191,9 +198,6 @@ spec: format: int32 minimum: 0 type: integer - routeHostname: - description: Route behaviour:[tls]hostname/NONE or empty. - type: string securityContext: description: SecurityContext defines the security capabilities required to run the application. @@ -354,24 +358,28 @@ spec: type: string type: object type: object - storageClass: - description: StorageClass name of the storage class we want to use - for the bound - type: string - tlsPassword: - description: TLSPassword passphrase for the key in the client.key - type: string - tlsSecret: - description: TLSSecret secret containing server.cert the server certificate, - server.key the server key and optional ca.cert the CA cert of the - client certificates - type: string + tlsConfig: + description: TLS configuration + properties: + certificateVerification: + description: 'certificateVerification for tomcat configuration: + required/optional or empty.' + type: string + routeHostname: + description: Route behaviour:[tls]hostname/NONE or empty. + type: string + tlsPassword: + description: TLSPassword passphrase for the key in the client.key + type: string + tlsSecret: + description: TLSSecret secret containing server.cert the server + certificate, server.key the server key and optional ca.cert + the CA cert of the client certificates + type: string + type: object useSessionClustering: description: Use Session Clustering type: boolean - volumeName: - description: VolumeName is the name of pv we eant to bound - type: string webImage: description: (Deployment method 1) Application image properties: diff --git a/controllers/templates.go b/controllers/templates.go index 2896726..39ce801 100644 --- a/controllers/templates.go +++ b/controllers/templates.go @@ -208,12 +208,12 @@ func (r *WebServerReconciler) generatePersistentVolumeClaimForLogging(webServer }, } - if webServer.Spec.VolumeName != "" { - pvc.Spec.VolumeName = webServer.Spec.VolumeName + if webServer.Spec.PersistentLogsConfig.VolumeName != "" { + pvc.Spec.VolumeName = webServer.Spec.PersistentLogsConfig.VolumeName } - if webServer.Spec.StorageClass != "" { - pvc.Spec.StorageClassName = &webServer.Spec.StorageClass + if webServer.Spec.PersistentLogsConfig.StorageClass != "" { + pvc.Spec.StorageClassName = &webServer.Spec.PersistentLogsConfig.StorageClass } controllerutil.SetControllerReference(webServer, pvc, r.Scheme) @@ -659,7 +659,7 @@ func (r *WebServerReconciler) generateRoute(webServer *webserversv1alpha1.WebSer "description": "Route for application's http service.", } route := &routev1.Route{} - if webServer.Spec.RouteHostname == "" { + if webServer.Spec.TLSConfig.RouteHostname == "" { route = &routev1.Route{ ObjectMeta: objectMeta, Spec: routev1.RouteSpec{ @@ -672,7 +672,7 @@ func (r *WebServerReconciler) generateRoute(webServer *webserversv1alpha1.WebSer route = &routev1.Route{ ObjectMeta: objectMeta, Spec: routev1.RouteSpec{ - Host: webServer.Spec.RouteHostname, + Host: webServer.Spec.TLSConfig.RouteHostname, To: routev1.RouteTargetReference{ Name: webServer.Spec.ApplicationName, }, @@ -690,7 +690,7 @@ func (r *WebServerReconciler) generateSecureRoute(webServer *webserversv1alpha1. "description": "Route for application's https service.", } route := &routev1.Route{} - if len(webServer.Spec.RouteHostname) <= 3 { + if len(webServer.Spec.TLSConfig.RouteHostname) <= 3 { route = &routev1.Route{ ObjectMeta: objectMeta, Spec: routev1.RouteSpec{ @@ -706,7 +706,7 @@ func (r *WebServerReconciler) generateSecureRoute(webServer *webserversv1alpha1. route = &routev1.Route{ ObjectMeta: objectMeta, Spec: routev1.RouteSpec{ - Host: webServer.Spec.RouteHostname[4:], + Host: webServer.Spec.TLSConfig.RouteHostname[4:], To: routev1.RouteTargetReference{ Name: webServer.Spec.ApplicationName, }, @@ -900,20 +900,19 @@ func (r *WebServerReconciler) generateEnvVars(webServer *webserversv1alpha1.WebS Value: value, }, } - if webServer.Spec.EnableAccessLogs { + if webServer.Spec.PersistentLogsConfig.AccessLogs { env = append(env, corev1.EnvVar{ Name: "ENABLE_ACCESS_LOG", Value: "true", }) } - if strings.HasPrefix(webServer.Spec.RouteHostname, "tls") || webServer.Spec.UseSessionClustering || webServer.Spec.EnableAccessLogs { - // Add parameter USE_SESSION_CLUSTERING + if strings.HasPrefix(webServer.Spec.TLSConfig.RouteHostname, "tls") || webServer.Spec.UseSessionClustering || webServer.Spec.PersistentLogsConfig.AccessLogs { env = append(env, corev1.EnvVar{ Name: "ENV_FILES", Value: "/env/my-files/test.sh", }) } - if webServer.Spec.PersistentLogs { + if webServer.Spec.PersistentLogsConfig.CatalinaLogs { //custum logging.properties path env = append(env, corev1.EnvVar{ Name: "CATALINA_LOGGING_CONFIG", @@ -930,7 +929,7 @@ func (r *WebServerReconciler) generateEnvVars(webServer *webserversv1alpha1.WebS func (r *WebServerReconciler) generateVolumeMounts(webServer *webserversv1alpha1.WebServer) []corev1.VolumeMount { var volm []corev1.VolumeMount - if webServer.Spec.PersistentLogs { + if webServer.Spec.PersistentLogsConfig.CatalinaLogs || webServer.Spec.PersistentLogsConfig.AccessLogs { volm = append(volm, corev1.VolumeMount{ Name: "config-volume", MountPath: "/opt/operator_conf/logging.properties", @@ -942,7 +941,7 @@ func (r *WebServerReconciler) generateVolumeMounts(webServer *webserversv1alpha1 }) } - if strings.HasPrefix(webServer.Spec.RouteHostname, "tls") || webServer.Spec.UseSessionClustering || webServer.Spec.EnableAccessLogs { + if strings.HasPrefix(webServer.Spec.TLSConfig.RouteHostname, "tls") || webServer.Spec.UseSessionClustering || webServer.Spec.PersistentLogsConfig.AccessLogs { volm = append(volm, corev1.VolumeMount{ Name: "webserver-" + webServer.Name, MountPath: "/env/my-files", @@ -979,7 +978,7 @@ func (r *WebServerReconciler) generateVolumeMounts(webServer *webserversv1alpha1 } } - if webServer.Spec.TLSSecret != "" { + if webServer.Spec.TLSConfig.TLSSecret != "" { volm = append(volm, corev1.VolumeMount{ Name: "webserver-tls" + webServer.Name, MountPath: "/tls", @@ -993,7 +992,7 @@ func (r *WebServerReconciler) generateVolumeMounts(webServer *webserversv1alpha1 // Create the Volumes func (r *WebServerReconciler) generateVolumes(webServer *webserversv1alpha1.WebServer) []corev1.Volume { var vol []corev1.Volume - if webServer.Spec.PersistentLogs { + if webServer.Spec.PersistentLogsConfig.CatalinaLogs || webServer.Spec.PersistentLogsConfig.AccessLogs { vol = append(vol, corev1.Volume{ Name: "config-volume", VolumeSource: corev1.VolumeSource{ @@ -1015,7 +1014,7 @@ func (r *WebServerReconciler) generateVolumes(webServer *webserversv1alpha1.WebS }) } - if strings.HasPrefix(webServer.Spec.RouteHostname, "tls") || webServer.Spec.UseSessionClustering || webServer.Spec.EnableAccessLogs { + if strings.HasPrefix(webServer.Spec.TLSConfig.RouteHostname, "tls") || webServer.Spec.UseSessionClustering || webServer.Spec.PersistentLogsConfig.AccessLogs { vol = append(vol, corev1.Volume{ Name: "webserver-" + webServer.Name, VolumeSource: corev1.VolumeSource{ @@ -1081,12 +1080,12 @@ func (r *WebServerReconciler) generateVolumes(webServer *webserversv1alpha1.WebS } } - if webServer.Spec.TLSSecret != "" { + if webServer.Spec.TLSConfig.TLSSecret != "" { vol = append(vol, corev1.Volume{ Name: "webserver-tls" + webServer.Name, VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ - SecretName: webServer.Spec.TLSSecret, + SecretName: webServer.Spec.TLSConfig.TLSSecret, }, }, }) @@ -1165,7 +1164,7 @@ func (r *WebServerReconciler) generateCommandForASFStart(webServer *webserversv1 "# Copy the war in webapps (probably we can use a ENV_FILES for that)\n" + "cp /deployments/*.war /deployments/webapps/ || true\n" - if webServer.Spec.PersistentLogs { + if webServer.Spec.PersistentLogsConfig.CatalinaLogs || webServer.Spec.PersistentLogsConfig.AccessLogs { cmd["start.sh"] = cmd["start.sh"] + "#operator's configuration for logging\n" + "export JAVA_OPTS=\"-Dcatalina.base=. -Djava.security.egd=file:/dev/urandom -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.util.logging.config.file=/opt/operator_conf/logging.properties -Dpod_name=\"$HOSTNAME\"\"\n" } @@ -1204,7 +1203,7 @@ func (r *WebServerReconciler) generateLivenessProbeScript(webServer *webserversv func (r *WebServerReconciler) generateCommandForServerXml(webServer *webserversv1alpha1.WebServer) map[string]string { cmd := make(map[string]string) connector := "" - if strings.HasPrefix(webServer.Spec.RouteHostname, "tls") { + if strings.HasPrefix(webServer.Spec.TLSConfig.RouteHostname, "tls") { // "/tls" is the dir in which the secret's contents are mounted to the pod connector += "https=\"\"\n" + @@ -1213,8 +1212,8 @@ func (r *WebServerReconciler) generateCommandForServerXml(webServer *webserversv "https=\"" + " " - if webServer.Spec.CertificateVerification == "required" || webServer.Spec.CertificateVerification == "optional" { - connector += " " + if webServer.Spec.TLSConfig.CertificateVerification == "required" || webServer.Spec.TLSConfig.CertificateVerification == "optional" { + connector += " " } else { connector += " " } @@ -1226,8 +1225,8 @@ func (r *WebServerReconciler) generateCommandForServerXml(webServer *webserversv "https=\"" + " " - if webServer.Spec.CertificateVerification == "required" || webServer.Spec.CertificateVerification == "optional" { - connector += " " + if webServer.Spec.TLSConfig.CertificateVerification == "required" || webServer.Spec.TLSConfig.CertificateVerification == "optional" { + connector += " " } else { connector += " " } @@ -1261,7 +1260,7 @@ func (r *WebServerReconciler) generateCommandForServerXml(webServer *webserversv } else { cmd["test.sh"] = cmd["test.sh"] + connector } - if webServer.Spec.EnableAccessLogs { + if webServer.Spec.PersistentLogsConfig.AccessLogs { cmd["test.sh"] = cmd["test.sh"] + "grep -q directory='\"/proc/self/fd\"' ${FILE}\n" + "if [ $? -eq 0 ]; then\n" + "sed -i 's|directory=\"/proc/self/fd\"|directory=\"/opt/tomcat_logs\"|g' ${FILE}\n" + diff --git a/controllers/webserver_controller.go b/controllers/webserver_controller.go index b23e884..563e1e6 100644 --- a/controllers/webserver_controller.go +++ b/controllers/webserver_controller.go @@ -167,8 +167,8 @@ func (r *WebServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( return reconcile.Result{}, err } else if servicePrometeus == nil { log.Info("Webserver: Create Prometheus Service and requeue reconciliation") - log.Info("Webserver resource (TLSSecret) " + webServer.Spec.TLSSecret) - log.Info("Webserver resource (RouteHostname) " + webServer.Spec.RouteHostname) + log.Info("Webserver resource (TLSSecret) " + webServer.Spec.TLSConfig.TLSSecret) + log.Info("Webserver resource (RouteHostname) " + webServer.Spec.TLSConfig.RouteHostname) return reconcile.Result{Requeue: true}, nil } } @@ -186,15 +186,15 @@ func (r *WebServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( // Check if a Service for routing already exists, and if not create a new one routingService := &corev1.Service{} - if strings.HasPrefix(webServer.Spec.RouteHostname, "tls") { - log.Info("generating routing service with port 8443 " + "cause webServer.Spec.RouteHostname= " + webServer.Spec.RouteHostname) - log.Info("generating routing service with port 8443 " + "with TLSSecret= " + webServer.Spec.TLSSecret) + if strings.HasPrefix(webServer.Spec.TLSConfig.RouteHostname, "tls") { + log.Info("generating routing service with port 8443 " + "cause webServer.Spec.RouteHostname= " + webServer.Spec.TLSConfig.RouteHostname) + log.Info("generating routing service with port 8443 " + "with TLSSecret= " + webServer.Spec.TLSConfig.TLSSecret) routingService = r.generateRoutingService(webServer, 8443) - log.Info("generating routing service with port 8443 " + "cause webServer.Spec.RouteHostname= " + webServer.Spec.RouteHostname) - log.Info("generating routing service with port 8443 " + "with TLSSecret= " + webServer.Spec.TLSSecret) + log.Info("generating routing service with port 8443 " + "cause webServer.Spec.RouteHostname= " + webServer.Spec.TLSConfig.RouteHostname) + log.Info("generating routing service with port 8443 " + "with TLSSecret= " + webServer.Spec.TLSConfig.TLSSecret) } else { - log.Info("generating routing service with port 8080 " + "cause webServer.Spec.RouteHostname= " + webServer.Spec.RouteHostname) - log.Info("generating routing service with port 8080 " + "with TLSSecret= " + webServer.Spec.TLSSecret) + log.Info("generating routing service with port 8080 " + "cause webServer.Spec.RouteHostname= " + webServer.Spec.TLSConfig.RouteHostname) + log.Info("generating routing service with port 8080 " + "with TLSSecret= " + webServer.Spec.TLSConfig.TLSSecret) routingService = r.generateRoutingService(webServer, 8080) } result, err = r.createService(ctx, webServer, routingService, routingService.Name, routingService.Namespace) @@ -250,7 +250,7 @@ func (r *WebServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( } // Check if exists a ConfigMap for the server.xml definition otherwise create it. - if strings.HasPrefix(webServer.Spec.RouteHostname, "tls") || webServer.Spec.UseSessionClustering || webServer.Spec.EnableAccessLogs { + if strings.HasPrefix(webServer.Spec.TLSConfig.RouteHostname, "tls") || webServer.Spec.UseSessionClustering || webServer.Spec.PersistentLogsConfig.AccessLogs { configMap := r.generateConfigMapForDNSTLS(webServer) result, err = r.createConfigMap(ctx, webServer, configMap, configMap.Name, configMap.Namespace) if err != nil || result != (ctrl.Result{}) { @@ -290,7 +290,7 @@ func (r *WebServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( } } - if webServer.Spec.PersistentLogs { + if webServer.Spec.PersistentLogsConfig.CatalinaLogs || webServer.Spec.PersistentLogsConfig.AccessLogs { // Check if exists a ConfigMap for the LoggingProperties otherwise create it. configMap := r.generateConfigMapForLoggingProperties(webServer) result, err = r.createConfigMap(ctx, webServer, configMap, configMap.Name, configMap.Namespace) @@ -565,7 +565,7 @@ func (r *WebServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( if r.isOpenShift { - if webServer.Spec.RouteHostname != "NONE" && !strings.HasPrefix(webServer.Spec.RouteHostname, "tls") { + if webServer.Spec.TLSConfig.RouteHostname != "NONE" && !strings.HasPrefix(webServer.Spec.TLSConfig.RouteHostname, "tls") { // Check if a Route already exists, and if not create a new one route := r.generateRoute(webServer) @@ -585,7 +585,7 @@ func (r *WebServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( webServer.Status.Hosts = hosts log.Info("Status.Hosts update scheduled") } - } else if strings.HasPrefix(webServer.Spec.RouteHostname, "tls") { + } else if strings.HasPrefix(webServer.Spec.TLSConfig.RouteHostname, "tls") { // Check if a Route already exists, and if not create a new one route := r.generateSecureRoute(webServer) result, err = r.createRoute(ctx, webServer, route, route.Name, route.Namespace) diff --git a/test/framework/common.go b/test/framework/common.go index 222ebe3..779cd92 100644 --- a/test/framework/common.go +++ b/test/framework/common.go @@ -167,8 +167,8 @@ func WebServerApplicationImageSourcesBasicTest(clt client.Client, ctx context.Co func WebServerSecureRouteTest(clt client.Client, ctx context.Context, t *testing.T, namespace string, name string, imageStreamName string, testURI string, defaultIngressDomain string, usesessionclustering bool) (err error) { webServer := makeSecureWebserver(namespace, name, imageStreamName, namespace, 1, defaultIngressDomain, usesessionclustering) - t.Logf("WebServerSecureRouteTest for: %s\n", webServer.Spec.RouteHostname) - t.Logf("WebServerSecureRouteTest for: %s\n", webServer.Spec.TLSSecret) + t.Logf("WebServerSecureRouteTest for: %s\n", webServer.Spec.TLSConfig.RouteHostname) + t.Logf("WebServerSecureRouteTest for: %s\n", webServer.Spec.TLSConfig.TLSSecret) deployWebServer(clt, ctx, t, webServer) // cleanup @@ -416,11 +416,13 @@ func PersistentLogsTest(clt client.Client, ctx context.Context, t *testing.T, na ServerReadinessScript: "if [ $(ls /opt/tomcat_logs |grep -c .log) != 4 ];then exit 1;fi", }, }, - PersistentLogs: true, - EnableAccessLogs: true, + PersistentLogsConfig: webserversv1alpha1.PersistentLogs{ + CatalinaLogs: true, + AccessLogs: true, + VolumeName: "pv0000", + StorageClass: "nfs-client", + }, UseSessionClustering: true, - VolumeName: "pv0000", - StorageClass: "nfs-client", }, } @@ -1091,18 +1093,18 @@ func webServerRouteTest(clt client.Client, ctx context.Context, t *testing.T, we return nil, errors.New("Route is empty!") } t.Logf("Route: (%s)\n", webServer.Status.Hosts) - t.Logf("RouteHostName: (%s)\n", webServer.Spec.RouteHostname) - t.Logf("TLSSecret: (%s)\n", webServer.Spec.TLSSecret) + t.Logf("RouteHostName: (%s)\n", webServer.Spec.TLSConfig.RouteHostname) + t.Logf("TLSSecret: (%s)\n", webServer.Spec.TLSConfig.TLSSecret) t.Logf("Route: (%s)\n", curwebServer.Status.Hosts) - t.Logf("RouteHostName: (%s)\n", curwebServer.Spec.RouteHostname) - t.Logf("TLSSecret: (%s)\n", curwebServer.Spec.TLSSecret) + t.Logf("RouteHostName: (%s)\n", curwebServer.Spec.TLSConfig.RouteHostname) + t.Logf("TLSSecret: (%s)\n", curwebServer.Spec.TLSConfig.TLSSecret) if isSecure { - if len(curwebServer.Spec.RouteHostname) <= 4 { + if len(curwebServer.Spec.TLSConfig.RouteHostname) <= 4 { URL = "https://" + curwebServer.Status.Hosts[0] + URI } else { // We have something like tls:hostname - URL = "https://" + curwebServer.Spec.RouteHostname[4:] + URI + URL = "https://" + curwebServer.Spec.TLSConfig.RouteHostname[4:] + URI } } else { URL = "http://" + curwebServer.Status.Hosts[0] + URI diff --git a/test/framework/webserver.go b/test/framework/webserver.go index b2baa9e..b2b92a0 100644 --- a/test/framework/webserver.go +++ b/test/framework/webserver.go @@ -20,8 +20,10 @@ func makeSecureWebserver(namespace string, name string, imageStreamName string, ApplicationName: name, Replicas: replicas, UseSessionClustering: usesessionclustering, - RouteHostname: "tls:" + host + defaultIngressDomain, - TLSSecret: "test-tls-secret", + TLSConfig: webserversv1alpha1.TLSConfig{ + RouteHostname: "tls:" + host + defaultIngressDomain, + TLSSecret: "test-tls-secret", + }, WebImageStream: &webserversv1alpha1.WebImageStreamSpec{ ImageStreamName: imageStreamName, ImageStreamNamespace: imageStreamNamespace,