Skip to content

Commit

Permalink
Add additional ingress builder onlylang
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefan Bethke committed Mar 23, 2022
1 parent 8311b62 commit 23a4ea6
Show file tree
Hide file tree
Showing 10 changed files with 198 additions and 9 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,15 @@ If installing the custom resource definition is not an option for you, you can i

When installing the Operator, you need to set the Spring Boot property `cmcc.useConfigMap` to `true`, and `cmcc.useCrd` to `false`. You can accomplish this by setting the environment variables `CMCC_USECONFIGMAP` and `CMCC_USECRD` on the deployment for the operator.

## Configuring the Operator

The operator has a number of configuration parameters that can be set using the [usual Spring Boot ways](https://docs.spring.io/spring-boot/docs/1.5.22.RELEASE/reference/html/boot-features-external-config.html): as an application.properties or application.yaml file, or using environment variables. The following properties can be configured:

| Property | Environment | Default | Description |
|-----------------------|-----------------------|-------------|---------------------------------------------------------------------------------------------------------------------------------------|
| `cmcc.ingressbuilder` | `CMCC_INGRESSBUILDER` | `blueprint` | The ingress builder to use. See [site mappings](docs/custom-resource#automatic-eneration-of-ingresses-and-site-mappings-sitemappings) |
| `cmcc.useConfigMap` | `CMCC_USECONFIGMAP` | `false` | Use the ConfigMap reconciler (see [Installing the Operator Using a Config Map](#installing-the-operator-using-a-config-map)) |
| `cmcc.useCrd` | `CMCC_USECRD` | `true` | Use the Custom Resource reconciler |
## Using the Operator

### Pull Secret
Expand Down
26 changes: 26 additions & 0 deletions docs/custom-resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,32 @@ This makes the Chef Corp. example site available under these URLs:
* `https://corporate.example.com/corporate-en-ca`
* `https://corporate.example.com/corporate-en-gb`


### Configuring the Ingress Builder

The operator supports two different schemes for mapping live URLs to CAE URIs: the default `blueprint` scheme (the default Link Building Scheme in the CAE, see above), and `onlylang`. You configure the ingress builder by setting the application property `cmcc.ingressbuilder`, for example by adding the `CMCC_INGRESSBUILDER` environment variable to the deployment resource of the operator.

The `onlylang` ingress builder maps hostnames of the form *countrysite*/*lang* to URIs of the form *sitesegment*-*lang*-*locale*. Consider these `siteMappings`:

```yaml
siteMappings:
- hostname: corporate.example.de
primarySegment: corporate-de-de
- hostname: corporate.example.ca
primarySegment: corporate-en-ca
additionalSegments:
- corporate-fr-ca
```

This will create ingresses for:
* `https://corporate.example.de/` redirects to `/de/`
* `https://corporate.example.de/de` maps to `corporate-de-de`
* `https://corporate.example.ca/` redirects to `/en`
* `https://corporate.example.ca/en` maps to `corporate-en-ca`
* `https://corporate.example.ca/fr` maps to `corporate-en-fr`

**Note** You will need to your own code to the CAE to have it generate links in this form.

## Components

`components` specifies a list of CoreMedia components and their parameters. The only required parameter is `type`, which specifies the type of component, and for some component types, `kind` as a sub-type.
Expand Down
2 changes: 2 additions & 0 deletions k8s/cmcc-operator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ spec:
image: ghcr.io/t-systems-mms/cmcc-operator/cmcc-operator:latest
imagePullPolicy: Always
env:
- name: CMCC_INGRESSBUILDER
value: "blueprint"
- name: CMCC_USECONFIGMAP
value: "false"
- name: CMCC_USECRD
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@

package com.tsystemsmms.cmcc.cmccoperator;

import com.tsystemsmms.cmcc.cmccoperator.ingress.BlueprintCmccIngressGeneratorFactory;
import com.tsystemsmms.cmcc.cmccoperator.ingress.CmccIngressGeneratorFactory;
import com.tsystemsmms.cmcc.cmccoperator.ingress.IngressBuilderFactory;
import com.tsystemsmms.cmcc.cmccoperator.ingress.NginxIngressBuilderFactory;
import com.tsystemsmms.cmcc.cmccoperator.ingress.*;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.*;
import com.tsystemsmms.cmcc.cmccoperator.resource.ResourceReconcilerManager;
import io.fabric8.kubernetes.client.KubernetesClient;
Expand Down Expand Up @@ -57,10 +54,17 @@ public ResourceReconcilerManager resourceReconciler(KubernetesClient kubernetesC
}

@Bean
public CmccIngressGeneratorFactory caeIngressGeneratorFactory(IngressBuilderFactory ingressBuilderFactory) {
@ConditionalOnProperty(value = "cmcc.ingressbuilder", havingValue = "blueprint")
public CmccIngressGeneratorFactory blueprintIngressGeneratorFactory(IngressBuilderFactory ingressBuilderFactory) {
return new BlueprintCmccIngressGeneratorFactory(ingressBuilderFactory);
}

@Bean
@ConditionalOnProperty(value = "cmcc.ingressbuilder", havingValue = "onlylang")
public CmccIngressGeneratorFactory onlylangIngressGeneratorFactory(IngressBuilderFactory ingressBuilderFactory) {
return new OnlyLangCmccIngressGeneratorFactory(ingressBuilderFactory);
}

@Bean
public IngressBuilderFactory ingressBuilderFactory() {
return new NginxIngressBuilderFactory();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public EnvVarSet getEnvVars() {
case KIND_MLS:
break;
case KIND_RLS:
env.addAll(getUapiClientEnvVars("REPLICATOR"));
env.addAll(getUapiClientEnvVars("REPLICATOR_PUBLICATION"));
break;
}

Expand Down Expand Up @@ -141,12 +141,16 @@ public Map<String, String> getSpringBootProperties() {
"cap.server.cache.resource-cache-size", "5000"
));
if (getComponentSpec().getKind().equals(KIND_CMS)) {
properties.put("publisher.target[0].iorUrl", getTargetState().getServiceUrlFor("content-server", "mls"));
properties.put("publisher.target[0].iorUrl", "x" + getTargetState().getServiceUrlFor("content-server", "mls"));
properties.put("publisher.target[0].name", "mls");
properties.put("publisher.target[0].ior-url", "y" + getTargetState().getServiceUrlFor("content-server", "mls"));
}
if (getComponentSpec().getKind().equals(KIND_RLS)) {
properties.put("replicator.publication-ior-url", getTargetState().getServiceUrlFor("content-server", "mls"));
}

properties.put("debug", "true");

return properties;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public Collection<? extends HasMetadata> buildPreviewResources() {
ingresses.addAll(ingressBuilderFactory.builder(targetState, previewName("blueprint"), fqdn)
.pathPrefix("/blueprint", serviceName).build());
ingresses.addAll(ingressBuilderFactory.builder(targetState, previewName("all"), fqdn)
.pathPattern("/(.*)$", serviceName).rewrite("/blueprint/servlet/$1").build());
.pathPattern("/(.*)", serviceName).rewrite("/blueprint/servlet/$1").build());
return ingresses;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,19 @@

import static com.tsystemsmms.cmcc.cmccoperator.utils.Utils.concatOptional;

/**
* Implements the URL rewriting for the standard Blueprint link scheme, where the site segment is always the first part
* of the URL. For example, consider this site mapping:
*
* - hostname: corporate
* primarySegment: corporate
* additionalSegments:
* - corporate-de-de
* - corporate-en-ca
* - corporate-en-gb
*
* The resulting rewrite rules for the Ingress serving the host corporate simply prepend /blueprint/servlet to the URL.
*/
@Slf4j
public class BlueprintCmccIngressGenerator extends AbstractCmccIngressGenerator {

Expand All @@ -43,7 +56,7 @@ public Collection<? extends HasMetadata> buildLiveResources() {
ingresses.addAll(ingressBuilderFactory.builder(targetState, liveName(site, "blueprint"), fqdn)
.pathPrefix("/blueprint", serviceName).build());
ingresses.addAll(ingressBuilderFactory.builder(targetState, liveName(site, "all"), fqdn)
.pathPattern("/(.*)$", serviceName).rewrite("/blueprint/servlet/$1").build());
.pathPattern("/(.*)", serviceName).rewrite("/blueprint/servlet/$1").build());
}

return ingresses;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2022. T-Systems Multimedia Solutions GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/

package com.tsystemsmms.cmcc.cmccoperator.ingress;

import com.tsystemsmms.cmcc.cmccoperator.crds.SiteMapping;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.CustomResourceConfigError;
import com.tsystemsmms.cmcc.cmccoperator.targetstate.TargetState;
import io.fabric8.kubernetes.api.model.HasMetadata;
import lombok.extern.slf4j.Slf4j;

import java.util.Collection;
import java.util.LinkedList;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;

import static com.tsystemsmms.cmcc.cmccoperator.utils.Utils.concatOptional;

/**
* Implements the URL rewriting for a customized link scheme, where the URL starts with the language, and the site
* segment is determined by the hostname and the language identifier. For example, consider this site mapping:
*
* <pre>
* - hostname: corporate.example.de
* primarySegment: corporate-de-de
* - hostname: corporate.example.ca
* primarySegment: corporate-en-ca
* additionalSegments:
* - corporate-fr-ca
* </pre>
* <p>
* The resulting rewrite rules build these mappings:
* <ul>
* <li>https://corporate.example.de/ redirects to /de/</li>
* <li>https://corporate.example.de/de maps to corporate-de-de</li>
* <li>https://corporate.example.ca/ redirects to /en</li>
* <li>https://corporate.example.ca/en maps to corporate-en-ca</li>
* <li>https://corporate.example.ca/fr maps corporate-en-fr</li>
* </ul>
* <p>
* Note that the CAE needs to be modified to generate links like these.
* <p>
* The site segment has to follow a specific format for this to work correctly: the last two parts (separated by dash)
* need to be the language and the locale, respectively. For example, fr-ca for French in Canada.
*/
@Slf4j
public class OnlyLangCmccIngressGenerator extends AbstractCmccIngressGenerator {

public OnlyLangCmccIngressGenerator(IngressBuilderFactory ingressBuilderFactory, TargetState targetState, String serviceName) {
super(ingressBuilderFactory, targetState, serviceName);
}

@Override
public Collection<? extends HasMetadata> buildLiveResources() {
LinkedList<HasMetadata> ingresses = new LinkedList<>();

for (SiteMapping siteMapping : targetState.getCmcc().getSpec().getSiteMappings()) {
String site = siteMapping.getHostname();
String fqdn = concatOptional(getDefaults().getNamePrefix(), site) + "." + getDefaults().getIngressDomain();
Set<String> segments = new TreeSet<>(siteMapping.getAdditionalSegments());
segments.add(siteMapping.getPrimarySegment());
String languagePattern = segments.stream().map(this::getLanguage).collect(Collectors.joining("|"));

if (!siteMapping.getFqdn().isBlank())
fqdn = siteMapping.getFqdn();


ingresses.addAll(ingressBuilderFactory.builder(targetState, liveName(site, "home"), fqdn)
.pathExact("/", serviceName).redirect("/" + getLanguage(siteMapping.getPrimarySegment())).build());
ingresses.addAll(ingressBuilderFactory.builder(targetState, liveName(site, "blueprint"), fqdn)
.pathPrefix("/blueprint", serviceName).build());
ingresses.addAll(ingressBuilderFactory.builder(targetState, liveName(site, "all"), fqdn)
.pathPattern("/(.*)", serviceName).rewrite("/blueprint/servlet/$1").build());
ingresses.addAll(ingressBuilderFactory.builder(targetState, liveName(site, "language"), fqdn)
.pathPattern("/(" + languagePattern + ")(.*)", serviceName).rewrite("/blueprint/servlet/" + getReplacement(siteMapping.getPrimarySegment()) + "$2").build());
}

return ingresses;
}

private String getLanguage(String segment) {
String[] parts = segment.split("-");
if (parts.length < 3)
throw new CustomResourceConfigError("Segment \"" + segment + "\" in site mapping is too short, needs to have at least three parts separated by -");
return parts[parts.length - 2];
}

private String getReplacement(String segment) {
String[] parts = segment.split("-");
if (parts.length < 3)
throw new CustomResourceConfigError("Segment \"" + segment + "\" in site mapping is too short, needs to have at least three parts separated by -");
parts[parts.length - 2] = "$1";
return String.join("-", parts);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2022. T-Systems Multimedia Solutions GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/

package com.tsystemsmms.cmcc.cmccoperator.ingress;

import com.tsystemsmms.cmcc.cmccoperator.targetstate.TargetState;

public class OnlyLangCmccIngressGeneratorFactory implements CmccIngressGeneratorFactory {
private final IngressBuilderFactory ingressBuilderFactory;

public OnlyLangCmccIngressGeneratorFactory(IngressBuilderFactory ingressBuilderFactory) {
this.ingressBuilderFactory = ingressBuilderFactory;
}

@Override
public CmccIngressGenerator instance(TargetState targetState, String serviceName) {
return new OnlyLangCmccIngressGenerator(ingressBuilderFactory, targetState, serviceName);
}
}
2 changes: 2 additions & 0 deletions src/main/resources/application.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
cmcc:
ingressbuilder: blueprint
logging:
pattern:
console: "%d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n"
Expand Down

0 comments on commit 23a4ea6

Please sign in to comment.