Skip to content
This repository has been archived by the owner on Dec 4, 2023. It is now read-only.

Commit

Permalink
Remove explicit multitenant mode in address controller
Browse files Browse the repository at this point in the history
With this change the address controller no longer requires you to use
it in single or multitenant mode. If you deploy an address space to its
namespace, it will assume single tenant mode and not require cluster
admin privileges.

With this approach, you can choose to not deploy any address spaces by
default, in which case you are free to choose later if you want to run
in multitenant mode or not, and also gives you the ability to configure
properties of the single tenant address space.

This fixes #350
  • Loading branch information
Ulf Lilleengen committed Oct 12, 2017
1 parent d06894a commit 18f1493
Show file tree
Hide file tree
Showing 15 changed files with 81 additions and 89 deletions.
10 changes: 8 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@ OPENSHIFT_PROJECT ?= $(shell oc project -q)
OPENSHIFT_USER ?= $(shell oc whoami)
OPENSHIFT_TOKEN ?= $(shell oc whoami -t)
OPENSHIFT_MASTER ?= $(shell oc whoami --show-server=true)
MULTITENANT ?= false
SYSTEMTEST_ARGS =
MODE ?= singletenant

ifeq ($(MODE),singletenant)
MULTITENANT=false
else
MULTITENANT=true
endif

DOCKER_TARGETS = docker_build docker_tag docker_push
BUILD_TARGETS = init build test package clean $(DOCKER_TARGETS) coverage
Expand All @@ -34,7 +40,7 @@ $(DOCKER_DIRS):
$(MAKE) FULL_BUILD=$(FULL_BUILD) -C $@ $(MAKECMDGOALS)

deploy:
./templates/install/deploy-openshift.sh -n $(OPENSHIFT_PROJECT) -u $(OPENSHIFT_USER) -m $(OPENSHIFT_MASTER) -p MULTITENANT=$(MULTITENANT) -a "standard none"
./templates/install/deploy-openshift.sh -n $(OPENSHIFT_PROJECT) -u $(OPENSHIFT_USER) -m $(OPENSHIFT_MASTER) -o $(MODE) -a "standard none"

systemtests:
OPENSHIFT_PROJECT=$(OPENSHIFT_PROJECT) OPENSHIFT_MULTITENANT=$(MULTITENANT) OPENSHIFT_TOKEN=$(OPENSHIFT_TOKEN) OPENSHIFT_USER=$(OPENSHIFT_USER) OPENSHIFT_URL=$(OPENSHIFT_MASTER) OPENSHIFT_USE_TLS=true ./systemtests/scripts/run_tests.sh $(SYSTEMTEST_ARGS)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,9 @@ public Controller(OpenShiftClient client,
AddressSpaceApi addressSpaceApi,
Kubernetes kubernetes,
AuthenticationServiceResolverFactory authResolverFactory,
boolean isMultitenant,
UserDatabase userDatabase,
List<AddressSpaceController> addressSpaceControllers) {
this.helper = new ControllerHelper(kubernetes, isMultitenant, authResolverFactory, userDatabase);
this.helper = new ControllerHelper(kubernetes, authResolverFactory, userDatabase);
this.client = client;
this.addressSpaceApi = addressSpaceApi;
this.addressSpaceControllers = addressSpaceControllers;
Expand Down Expand Up @@ -125,7 +124,7 @@ public void resourcesUpdated(Set<AddressSpace> resources) throws Exception {
}

private void retainAddressSpaces(Set<AddressSpace> desiredAddressSpaces) {
helper.retainAddressSpaces(desiredAddressSpaces.stream().map(AddressSpace::getName).collect(Collectors.toSet()));
helper.retainAddressSpaces(desiredAddressSpaces);
}

private void createAddressSpaces(Set<AddressSpace> instances) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,12 @@
public class ControllerHelper {
private static final Logger log = LoggerFactory.getLogger(ControllerHelper.class.getName());
private final Kubernetes kubernetes;
private final boolean isMultitenant;
private final String namespace;
private final AuthenticationServiceResolverFactory authResolverFactory;
private final UserDatabase userDatabase;

public ControllerHelper(Kubernetes kubernetes, boolean isMultitenant, AuthenticationServiceResolverFactory authResolverFactory, UserDatabase userDatabase) {
public ControllerHelper(Kubernetes kubernetes, AuthenticationServiceResolverFactory authResolverFactory, UserDatabase userDatabase) {
this.kubernetes = kubernetes;
this.isMultitenant = isMultitenant;
this.namespace = kubernetes.getNamespace();
this.authResolverFactory = authResolverFactory;
this.userDatabase = userDatabase;
Expand All @@ -62,7 +60,7 @@ public void create(AddressSpace addressSpace) {
return;
}
log.info("Creating address space {}", addressSpace);
if (isMultitenant) {
if (!addressSpace.getNamespace().equals(namespace)) {
kubernetes.createNamespace(addressSpace.getName(), addressSpace.getNamespace());
kubernetes.addDefaultViewPolicy(addressSpace.getNamespace());
}
Expand Down Expand Up @@ -222,20 +220,23 @@ public boolean isReady(AddressSpace addressSpace) {
return readyDeployments.containsAll(requiredDeployments);
}

public void retainAddressSpaces(Set<String> desiredAddressSpaces) {
if (isMultitenant) {
Map<String, String> labels = new LinkedHashMap<>();
labels.put(LabelKeys.APP, "enmasse");
labels.put(LabelKeys.TYPE, "address-space");
for (Namespace namespace : kubernetes.listNamespaces(labels)) {
String id = namespace.getMetadata().getAnnotations().get(AnnotationKeys.ADDRESS_SPACE);
if (!desiredAddressSpaces.contains(id)) {
try {
log.info("Deleting address space {}", id);
kubernetes.deleteNamespace(namespace.getMetadata().getName());
} catch(KubernetesClientException e){
log.info("Exception when deleting namespace (may already be in progress): " + e.getMessage());
}
public void retainAddressSpaces(Set<AddressSpace> desiredAddressSpaces) {
if (desiredAddressSpaces.size() == 1 && desiredAddressSpaces.iterator().next().getNamespace().equals(namespace)) {
return;
}
Set<String> addressSpaceIds = desiredAddressSpaces.stream().map(AddressSpace::getName).collect(Collectors.toSet());

Map<String, String> labels = new LinkedHashMap<>();
labels.put(LabelKeys.APP, "enmasse");
labels.put(LabelKeys.TYPE, "address-space");
for (Namespace namespace : kubernetes.listNamespaces(labels)) {
String id = namespace.getMetadata().getAnnotations().get(AnnotationKeys.ADDRESS_SPACE);
if (!addressSpaceIds.contains(id)) {
try {
log.info("Deleting address space {}", id);
kubernetes.deleteNamespace(namespace.getMetadata().getName());
} catch(KubernetesClientException e){
log.info("Exception when deleting namespace (may already be in progress): " + e.getMessage());
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ public final class ControllerOptions {
private static final String SERVICEACCOUNT_PATH = "/var/run/secrets/kubernetes.io/serviceaccount";

private final String masterUrl;
private final boolean isMultitenant;
private final String namespace;
private final String token;
private final File caDir;
Expand All @@ -46,13 +45,12 @@ public final class ControllerOptions {
private final String userDbSecretName;
private final boolean enableApiAuth;

private ControllerOptions(String masterUrl, boolean isMultitenant, String namespace, String token,
private ControllerOptions(String masterUrl, String namespace, String token,
File caDir, File templateDir, String messagingHost, String mqttHost,
String consoleHost, String certSecret, String certDir,
PasswordAuthentication osbAuth, AuthServiceInfo noneAuthService, AuthServiceInfo standardAuthService, String userDbSecretName,
boolean enableApiAuth) {
this.masterUrl = masterUrl;
this.isMultitenant = isMultitenant;
this.namespace = namespace;
this.token = token;
this.caDir = caDir;
Expand Down Expand Up @@ -81,10 +79,6 @@ public String token() {
return token;
}

public boolean isMultitenant() {
return isMultitenant;
}

public File caDir() {
return caDir;
}
Expand Down Expand Up @@ -138,7 +132,6 @@ public static ControllerOptions fromEnv(Map<String, String> env) throws IOExcept

String masterHost = getEnvOrThrow(env, "KUBERNETES_SERVICE_HOST");
String masterPort = getEnvOrThrow(env, "KUBERNETES_SERVICE_PORT");
boolean isMultitenant= Boolean.parseBoolean(env.get("MULTITENANT"));

String namespace = getEnv(env, "NAMESPACE")
.orElseGet(() -> readFile(new File(SERVICEACCOUNT_PATH, "namespace")));
Expand Down Expand Up @@ -173,7 +166,6 @@ public static ControllerOptions fromEnv(Map<String, String> env) throws IOExcept
boolean enableApiAuth = Boolean.parseBoolean(getEnv(env, "ADDRESS_CONTROLLER_ENABLE_API_AUTH").orElse("false"));

return new ControllerOptions(String.format("https://%s:%s", masterHost, masterPort),
isMultitenant,
namespace,
token,
caDir,
Expand Down
31 changes: 1 addition & 30 deletions address-controller/src/main/java/io/enmasse/controller/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,10 @@

import java.util.*;

import io.enmasse.address.model.AddressSpace;
import io.enmasse.address.model.AuthenticationService;
import io.enmasse.address.model.AuthenticationServiceResolver;
import io.enmasse.address.model.AuthenticationServiceType;
import io.enmasse.address.model.CertProvider;
import io.enmasse.address.model.Endpoint;
import io.enmasse.address.model.SecretCertProvider;
import io.enmasse.address.model.types.AddressSpaceType;
import io.enmasse.address.model.types.standard.StandardAddressSpaceType;
import io.enmasse.address.model.v1.CodecV1;
import io.enmasse.controller.auth.*;
import io.enmasse.controller.brokered.BrokeredController;
import io.enmasse.controller.common.*;
Expand Down Expand Up @@ -63,29 +57,6 @@ private Main(ControllerOptions options) throws Exception {
public void start(Future<Void> startPromise) {
AddressSpaceApi addressSpaceApi = new ConfigMapAddressSpaceApi(controllerClient);

if (!options.isMultitenant() && !kubernetes.hasService("messaging")) {
AddressSpaceType type = new StandardAddressSpaceType();
AddressSpace.Builder builder = new AddressSpace.Builder()
.setName("default")
.setNamespace(kubernetes.getNamespace())
.setType(type)
.setAuthenticationService(new AuthenticationService.Builder()
.setType(CodecV1.resolveAuthServiceType(System.getenv()))
.build())
.setPlan(type.getDefaultPlan());

CertProvider certProvider = options.certSecret().map(SecretCertProvider::new).orElse(null);

options.messagingHost().ifPresent(host ->
appendEndpoint(certProvider, "messaging", "messaging", host));
options.mqttHost().ifPresent(host ->
appendEndpoint(certProvider, "mqtt", "mqtt", host));
options.consoleHost().ifPresent(host ->
appendEndpoint(certProvider, "console", "console", host));
addressSpaceApi.createAddressSpace(builder.build());
}


UserDatabase userDb = null;
if (options.isEnableApiAuth()) {
userDb = SecretUserDatabase.create(controllerClient, options.namespace(), options.userDbSecretName());
Expand All @@ -98,7 +69,7 @@ public void start(Future<Void> startPromise) {

deployVerticles(startPromise,
new Deployment(new AuthController(certManager, addressSpaceApi)),
new Deployment(new Controller(controllerClient, addressSpaceApi, kubernetes, resolverFactory, options.isMultitenant(), userDb, Arrays.asList(standardController, brokeredController))),
new Deployment(new Controller(controllerClient, addressSpaceApi, kubernetes, resolverFactory, userDb, Arrays.asList(standardController, brokeredController))),
// new Deployment(new AMQPServer(kubernetes.getNamespace(), addressSpaceApi, options.port())),
new Deployment(new HTTPServer(addressSpaceApi, options.certDir(), options.osbAuth().orElse(null), userDb), new DeploymentOptions().setWorker(true)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import io.enmasse.address.model.types.brokered.BrokeredAddressSpaceType;
import io.enmasse.address.model.types.standard.StandardAddressSpaceType;
import io.enmasse.controller.auth.UserDatabase;
import io.enmasse.controller.brokered.BrokeredController;
import io.enmasse.controller.common.AddressSpaceController;
import io.enmasse.controller.common.Kubernetes;
import io.enmasse.controller.common.NoneAuthenticationServiceResolver;
Expand Down Expand Up @@ -70,7 +69,7 @@ public void teardown() {

@Test
public void testController(TestContext context) throws Exception {
Controller controller = new Controller(client, testApi, kubernetes, (a) -> new NoneAuthenticationServiceResolver("localhost", 1234), true, new DummyUserDb(), Arrays.asList(spaceController));
Controller controller = new Controller(client, testApi, kubernetes, (a) -> new NoneAuthenticationServiceResolver("localhost", 1234), new DummyUserDb(), Arrays.asList(spaceController));

vertx.deployVerticle(controller, context.asyncAssertSuccess());

Expand Down
2 changes: 1 addition & 1 deletion systemtests/scripts/run_test_component.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function setup_test() {

DEPLOY_ARGS=( "-y" "-n" "$OPENSHIFT_PROJECT" "-u" "$OPENSHIFT_USER" "-m" "$OPENSHIFT_URL" "-a" "none standard" )
if [ "$OPENSHIFT_MULTITENANT" == true ]; then
DEPLOY_ARGS+=( "-p" "MULTITENANT=true" )
DEPLOY_ARGS+=( "-o" "multi" )
fi

$ENMASSE_DIR/deploy-openshift.sh "${DEPLOY_ARGS[@]}"
Expand Down
6 changes: 1 addition & 5 deletions templates/include/address-controller.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ local common = import "common.jsonnet";
external_service::
self.common_service("address-controller-external", "LoadBalancer", {}),

deployment(image_repo, multitenant, template_config, ca_secret, cert_secret, enable_auth)::
deployment(image_repo, template_config, ca_secret, cert_secret, enable_auth)::
{
"apiVersion": "extensions/v1beta1",
"kind": "Deployment",
Expand Down Expand Up @@ -110,10 +110,6 @@ local common = import "common.jsonnet";
"image": image_repo,
"name": "address-controller",
"env": [{
"name": "MULTITENANT",
"value": multitenant,

}, {
"name": "CA_DIR",
"value": "/ca-cert"
}, {
Expand Down
2 changes: 1 addition & 1 deletion templates/include/enmasse-kubernetes.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ local images = import "images.jsonnet";
"apiVersion": "v1",
"kind": "List",
"items": [ templateConfig.generate(with_kafka),
addressController.deployment(images.address_controller, "false", "enmasse-template-config", "enmasse-ca", "address-controller-cert", "false"),
addressController.deployment(images.address_controller, "enmasse-template-config", "enmasse-ca", "address-controller-cert", "false"),
common.empty_secret("address-controller-userdb"),
restapiRoute.ingress(""),
addressController.internal_service ]
Expand Down
7 changes: 1 addition & 6 deletions templates/include/enmasse-template.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ local images = import "images.jsonnet";
storage.template(true, true),
standardInfra.generate(with_kafka),
brokeredInfra.template,
addressController.deployment("${ADDRESS_CONTROLLER_REPO}", "${MULTITENANT}", "", "${ENMASSE_CA_SECRET}", "${ADDRESS_CONTROLLER_CERT_SECRET}", "${ADDRESS_CONTROLLER_ENABLE_API_AUTH}"),
addressController.deployment("${ADDRESS_CONTROLLER_REPO}", "", "${ENMASSE_CA_SECRET}", "${ADDRESS_CONTROLLER_CERT_SECRET}", "${ADDRESS_CONTROLLER_ENABLE_API_AUTH}"),
common.empty_secret("address-controller-userdb"),
addressController.internal_service,
restapiRoute.route("${RESTAPI_HOSTNAME}") ],
Expand All @@ -31,11 +31,6 @@ local images = import "images.jsonnet";
"name": "RESTAPI_HOSTNAME",
"description": "The hostname to use for the exposed route for the REST API"
},
{
"name": "MULTITENANT",
"description": "If set to true, the address controller will deploy infrastructure to separate namespaces",
"value": "false"
},
{
"name": "ADDRESS_CONTROLLER_REPO",
"description": "The docker image to use for the address controller",
Expand Down
24 changes: 24 additions & 0 deletions templates/install/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,30 @@ function random_string() {
LC_CTYPE=C head /dev/urandom | tr -dc A-Za-z0-9 | head -c 32
}

function create_address_space() {
local CMD=$1
local name=$2
local namespace=$3

payload="{ \\\"kind\\\":\\\"AddressSpace\\\", \\\"apiVersion\\\": \\\"enmasse.io/v1\\\", \\\"metadata\\\": { \\\"name\\\": \\\"$name\\\", \\\"namespace\\\": \\\"$namespace\\\" }, \\\"spec\\\": { \\\"type\\\": \\\"standard\\\" } }"

runcmd "cat <<EOF | $CMD create -n ${NAMESPACE} -f -
{
\"apiVersion\": \"v1\",
\"kind\": \"ConfigMap\",
\"metadata\": {
\"name\": \"address-space-${name}\",
\"labels\": {
\"type\": \"address-space\"
}
},
\"data\": {
\"config.json\": \"$payload\"
}
}
EOF" "Create address space $name"
}

function create_csr() {
local KEYFILE=$1
local CSRFILE=$2
Expand Down
12 changes: 10 additions & 2 deletions templates/install/deploy-kubernetes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ NONE_TEMPLATE=$SCRIPTDIR/kubernetes/addons/none-authservice.yaml
DEFAULT_NAMESPACE=enmasse
AUTH_SERVICES="none"
GUIDE=false
MODE="singletenant"

while getopts a:dglm:n:t:vh opt; do
while getopts a:dglm:n:o:t:vh opt; do
case $opt in
a)
AUTH_SERVICES=$OPTARG
Expand All @@ -50,6 +51,9 @@ while getopts a:dglm:n:t:vh opt; do
n)
NAMESPACE=$OPTARG
;;
o)
MODE=$OPTARG
;;
t)
ALT_TEMPLATE=$OPTARG
;;
Expand All @@ -67,7 +71,7 @@ while getopts a:dglm:n:t:vh opt; do
echo " -d create an all-in-one minikube VM on localhost"
echo " -m MASTER Kubernetes master URI to login against (default: https://localhost:8443)"
echo " -n NAMESPACE Namespace to deploy EnMasse into (default: $DEFAULT_NAMESPACE)"
echo " -o HOSTNAME Custom hostname for messaging endpoint (default: use autogenerated from template)"
echo " -o mode Deploy in given mode, 'singletenant' or 'multitenant'. (default: \"singletenant\")"
echo " -t TEMPLATE An alternative Kubernetes template file to deploy EnMasse"
echo
exit
Expand Down Expand Up @@ -134,6 +138,10 @@ then
ENMASSE_TEMPLATE=$ALT_TEMPLATE
fi

if [ "$MODE" == "singletenant" ]; then
create_address_space "kubectl" "default" $NAMESPACE
fi

runcmd "kubectl apply -f $ENMASSE_TEMPLATE -n $NAMESPACE" "Deploy EnMasse to $NAMESPACE"

if [ "$EXTERNAL_LB" == "true" ]
Expand Down
Loading

0 comments on commit 18f1493

Please sign in to comment.