Repository: EnMasseProject/enmasse
Pull request #2381 (2019-02-28 11:25:53)

add patch for DISPATCH-1273

lulf: @enmasse-ci run tests

Patch:
diff --git a/.jenkins/jenkins-functions.groovy b/.jenkins/jenkins-functions.groovy
index 0df1b42be..d021908fc 100644
--- a/.jenkins/jenkins-functions.groovy
+++ b/.jenkins/jenkins-functions.groovy
@@ -1,6 +1,6 @@
 def storeArtifacts(String artifactDir) {
-    sh "./systemtests/scripts/store_kubernetes_info.sh '${artifactDir}/openshift-info/'"
-    sh "./systemtests/scripts/collect_logs.sh '/tmp/testlogs' '${artifactDir}/openshift-logs'"
+    sh "./systemtests/scripts/store_kubernetes_info.sh '${artifactDir}/openshift-info/' || true"
+    sh "./systemtests/scripts/collect_logs.sh '/tmp/testlogs' '${artifactDir}/openshift-logs' || true"
     sh "cp -rf ${HOME}/.npm/_logs ${artifactDir}/npm-logs || true"
     sh 'rm -rf /tmp/testlogs'
 }
@@ -98,7 +98,6 @@ def postAction(String coresDir, String artifactDir) {
     if (status == null) {
         currentBuild.result = 'SUCCESS'
     }
-    tearDownOpenshift()
     sh "./systemtests/scripts/check_and_clear_cores.sh ${coresDir}"
 }
 
diff --git a/.travis.yml b/.travis.yml
index a307c541b..8b194fada 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,7 +18,7 @@ cache:
   directories:
     - "$HOME/.m2"
 jdk:
-- openjdk8
+- openjdk11
 python:
   - "2.7.14"
 go:
@@ -68,7 +68,7 @@ jobs:
         - tar xzf s2i.tar.gz
       install: true
       script:
-        - ./s2i build . fabric8/s2i-java:3.0-java8 tenant-service -e MAVEN_ARGS_APPEND="-pl io.enmasse:tenant-service --also-make" -e ARTIFACT_DIR="iot/tenant-service/target"
+        - ./s2i build . fabric8/s2i-java:3.0-java8 iot-tenant-service -e MAVEN_ARGS_APPEND="-pl io.enmasse:iot-tenant-service --also-make" -e ARTIFACT_DIR="iot/iot-tenant-service/target"
 env:
   global:
     - BRANCH=${TRAVIS_BRANCH}
diff --git a/.travis/build.sh b/.travis/build.sh
index 271165b53..99ad3fdfc 100755
--- a/.travis/build.sh
+++ b/.travis/build.sh
@@ -21,7 +21,7 @@ fi
 echo "Building EnMasse with tag $TAG, version $VERSION from $BRANCH. PR: $PULL_REQUEST"
 make clean
 
-make
+time make
 
 make docu_html
 
@@ -47,4 +47,4 @@ else
 fi
 
 echo "Running systemtests"
-./systemtests/scripts/run_test_kubernetes.sh templates/build/enmasse-${TAG} ${SYSTEMTEST_PROFILE} ${SYSTEMTEST_ARGS}
+time ./systemtests/scripts/run_test_kubernetes.sh templates/build/enmasse-${TAG} ${SYSTEMTEST_PROFILE} ${SYSTEMTEST_ARGS}
diff --git a/Makefile b/Makefile
index 8ff66cfce..bbe75abe4 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@ TOPDIR          := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
 include $(TOPDIR)/Makefile.env.mk
 
 BUILD_DIRS       = none-authservice
-DOCKER_DIRS      = agent topic-forwarder artemis broker-plugin api-server address-space-controller standard-controller keycloak-plugin keycloak-controller router router-metrics mqtt-gateway mqtt-lwt service-broker
+DOCKER_DIRS      = agent topic-forwarder artemis broker-plugin api-server address-space-controller standard-controller keycloak-plugin keycloak-controller router router-metrics mqtt-gateway mqtt-lwt service-broker iot/iot-tenant-service
 FULL_BUILD       = true
 
 GO_DIRS          = iot/qdr-proxy-configurator iot/iot-operator iot/iot-gc
diff --git a/Makefile.env.mk b/Makefile.env.mk
index 500f165c4..69fec5034 100644
--- a/Makefile.env.mk
+++ b/Makefile.env.mk
@@ -68,5 +68,5 @@ IMAGE_ENV=ADDRESS_SPACE_CONTROLLER_IMAGE=$(ADDRESS_SPACE_CONTROLLER_IMAGE) \
 			OAUTH_PROXY_IMAGE=$(OAUTH_PROXY_IMAGE) \
 			IMAGE_PULL_POLICY=$(IMAGE_PULL_POLICY) \
 			HONO_VERSION=${HONO_VERSION} \
-			ENMASSE_VERSION=$(VERSION)
-
+			ENMASSE_VERSION=$(VERSION) \
+			MAVEN_VERSION=$(MAVEN_VERSION)
diff --git a/address-space-controller/src/main/java/io/enmasse/controller/CreateController.java b/address-space-controller/src/main/java/io/enmasse/controller/CreateController.java
index 4acf5e5e5..ef6993fdd 100644
--- a/address-space-controller/src/main/java/io/enmasse/controller/CreateController.java
+++ b/address-space-controller/src/main/java/io/enmasse/controller/CreateController.java
@@ -7,7 +7,9 @@ package io.enmasse.controller;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import io.enmasse.address.model.*;
-import io.enmasse.admin.model.v1.*;
+import io.enmasse.admin.model.AddressPlan;
+import io.enmasse.admin.model.AddressSpacePlan;
+import io.enmasse.admin.model.v1.InfraConfig;
 import io.enmasse.config.AnnotationKeys;
 import io.enmasse.controller.common.ControllerKind;
 import io.enmasse.controller.common.Kubernetes;
@@ -174,26 +176,26 @@ public class CreateController implements Controller {
 
         Map<String, Double> quota = new HashMap<>();
         Map<String, Double> usage = new HashMap<>();
-        for (ResourceAllowance allowance : plan.getResources()) {
-            quota.put(allowance.getName(), allowance.getMax());
+        for (Map.Entry<String, Double> allowance : plan.getResourceLimits().entrySet()) {
+            quota.put(allowance.getKey(), allowance.getValue());
         }
 
         AddressResolver addressResolver = new AddressResolver(addressSpaceType);
         for (Address address : addresses) {
             AddressPlan addressPlan = addressResolver.getPlan(address);
-            for (ResourceRequest resourceRequest : addressPlan.getRequiredResources()) {
-                usage.compute(resourceRequest.getName(), (s, old) -> {
+            for (Map.Entry<String, Double> resourceRequest : addressPlan.getResources().entrySet()) {
+                usage.compute(resourceRequest.getKey(), (s, old) -> {
                     if (old == null) {
-                        return resourceRequest.getCredit();
+                        return resourceRequest.getValue();
                     } else {
-                        return old + resourceRequest.getCredit();
+                        return old + resourceRequest.getValue();
                     }
                 });
                 usage.compute("aggregate", (s, old) -> {
                     if (old == null) {
-                        return resourceRequest.getCredit();
+                        return resourceRequest.getValue();
                     } else {
-                        return old + resourceRequest.getCredit();
+                        return old + resourceRequest.getValue();
                     }
                 });
             }
diff --git a/agent/lib/internal_address_source.js b/agent/lib/internal_address_source.js
index 8d33e9f6a..3e28d8d2b 100644
--- a/agent/lib/internal_address_source.js
+++ b/agent/lib/internal_address_source.js
@@ -309,17 +309,32 @@ AddressSource.prototype.delete_address = function (definition) {
 function display_order (plan_a, plan_b) {
     // explicitly ordered plans always come before those with undefined order
     var a = plan_a.displayOrder === undefined ? Number.MAX_VALUE : plan_a.displayOrder;
+    if (plan_a.spec !== undefined) {
+        a = plan_a.spec.displayOrder === undefined ? Number.MAX_VALUE : plan_a.spec.displayOrder;
+    }
     var b = plan_b.displayOrder === undefined ? Number.MAX_VALUE : plan_b.displayOrder;
+    if (plan_b.spec !== undefined) {
+        b = plan_b.spec.displayOrder === undefined ? Number.MAX_VALUE : plan_b.spec.displayOrder;
+    }
     return a - b;
 }
 
 function extract_plan_details (plan) {
-    return {
-        name: plan.metadata.name,
-        displayName: plan.displayName || plan.metadata.name,
-        shortDescription: plan.shortDescription,
-        longDescription: plan.longDescription,
-    };
+    if (plan.spec !== undefined) {
+        return {
+            name: plan.metadata.name,
+            displayName: plan.spec.displayName || plan.metadata.name,
+            shortDescription: plan.spec.shortDescription,
+            longDescription: plan.spec.longDescription,
+        };
+    } else {
+        return {
+            name: plan.metadata.name,
+            displayName: plan.displayName || plan.metadata.name,
+            shortDescription: plan.shortDescription,
+            longDescription: plan.longDescription,
+        };
+    }
 }
 
 AddressSource.prototype.get_address_types = function () {
@@ -338,11 +353,12 @@ AddressSource.prototype.get_address_types = function () {
                 //group by addressType
                 var types = [];
                 var by_type = plans.reduce(function (map, plan) {
-                    var list = map[plan.addressType];
+                    var addressType = plan.spec !== undefined ? plan.spec.addressType : plan.addressType;
+                    var list = map[addressType];
                     if (list === undefined) {
                         list = [];
-                        map[plan.addressType] = list;
-                        types.push(plan.addressType);
+                        map[addressType] = list;
+                        types.push(addressType);
                     }
                     list.push(plan);
                     return map;
diff --git a/api-model/src/main/java/io/enmasse/address/model/AddressResolver.java b/api-model/src/main/java/io/enmasse/address/model/AddressResolver.java
index d23f256d8..d6332c920 100644
--- a/api-model/src/main/java/io/enmasse/address/model/AddressResolver.java
+++ b/api-model/src/main/java/io/enmasse/address/model/AddressResolver.java
@@ -4,7 +4,7 @@
  */
 package io.enmasse.address.model;
 
-import io.enmasse.admin.model.v1.AddressPlan;
+import io.enmasse.admin.model.AddressPlan;
 import io.enmasse.config.AnnotationKeys;
 
 import java.util.Optional;
diff --git a/api-model/src/main/java/io/enmasse/address/model/AddressSpaceResolver.java b/api-model/src/main/java/io/enmasse/address/model/AddressSpaceResolver.java
index 93eafa884..d47c62616 100644
--- a/api-model/src/main/java/io/enmasse/address/model/AddressSpaceResolver.java
+++ b/api-model/src/main/java/io/enmasse/address/model/AddressSpaceResolver.java
@@ -4,7 +4,7 @@
  */
 package io.enmasse.address.model;
 
-import io.enmasse.admin.model.v1.AddressSpacePlan;
+import io.enmasse.admin.model.AddressSpacePlan;
 import io.enmasse.admin.model.v1.InfraConfig;
 import io.enmasse.config.AnnotationKeys;
 
diff --git a/api-model/src/main/java/io/enmasse/address/model/AddressSpaceType.java b/api-model/src/main/java/io/enmasse/address/model/AddressSpaceType.java
index 600a000c6..fdfda17ae 100644
--- a/api-model/src/main/java/io/enmasse/address/model/AddressSpaceType.java
+++ b/api-model/src/main/java/io/enmasse/address/model/AddressSpaceType.java
@@ -4,7 +4,7 @@
  */
 package io.enmasse.address.model;
 
-import io.enmasse.admin.model.v1.AddressSpacePlan;
+import io.enmasse.admin.model.AddressSpacePlan;
 import io.enmasse.admin.model.v1.InfraConfig;
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.sundr.builder.annotations.Buildable;
diff --git a/api-model/src/main/java/io/enmasse/address/model/AddressType.java b/api-model/src/main/java/io/enmasse/address/model/AddressType.java
index 5543621fe..341e0a07e 100644
--- a/api-model/src/main/java/io/enmasse/address/model/AddressType.java
+++ b/api-model/src/main/java/io/enmasse/address/model/AddressType.java
@@ -4,7 +4,7 @@
  */
 package io.enmasse.address.model;
 
-import io.enmasse.admin.model.v1.AddressPlan;
+import io.enmasse.admin.model.AddressPlan;
 import io.enmasse.common.model.AbstractHasMetadata;
 import io.fabric8.kubernetes.api.model.Doneable;
 import io.sundr.builder.annotations.Buildable;
diff --git a/api-model/src/main/java/io/enmasse/admin/model/AddressPlan.java b/api-model/src/main/java/io/enmasse/admin/model/AddressPlan.java
new file mode 100644
index 000000000..f639ca554
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/admin/model/AddressPlan.java
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2019, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+
+package io.enmasse.admin.model;
+
+import io.fabric8.kubernetes.api.model.HasMetadata;
+
+import java.util.Map;
+
+public interface AddressPlan extends HasMetadata {
+    String getShortDescription();
+    String getAddressType();
+    Map<String, Double> getResources();
+}
diff --git a/api-model/src/main/java/io/enmasse/admin/model/AddressSpacePlan.java b/api-model/src/main/java/io/enmasse/admin/model/AddressSpacePlan.java
new file mode 100644
index 000000000..178dbb249
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/admin/model/AddressSpacePlan.java
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2019, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+package io.enmasse.admin.model;
+
+import io.fabric8.kubernetes.api.model.HasMetadata;
+
+import java.util.List;
+import java.util.Map;
+
+public interface AddressSpacePlan extends HasMetadata {
+    Map<String, Double> getResourceLimits();
+    List<String> getAddressPlans();
+    String getShortDescription();
+    String getAddressSpaceType();
+}
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlan.java b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlan.java
index d63d249c2..4e57918d5 100644
--- a/api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlan.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlan.java
@@ -5,15 +5,8 @@
 
 package io.enmasse.admin.model.v1;
 
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
 import com.fasterxml.jackson.annotation.JsonAnyGetter;
 import com.fasterxml.jackson.annotation.JsonAnySetter;
-
 import io.enmasse.common.model.AbstractHasMetadata;
 import io.enmasse.common.model.DefaultCustomResource;
 import io.fabric8.kubernetes.api.model.Doneable;
@@ -21,6 +14,11 @@ import io.sundr.builder.annotations.Buildable;
 import io.sundr.builder.annotations.BuildableReference;
 import io.sundr.builder.annotations.Inline;
 
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
 @Buildable(
         editableEnabled = false,
         generateBuilderPackage = false,
@@ -30,49 +28,21 @@ import io.sundr.builder.annotations.Inline;
 )
 @DefaultCustomResource
 @SuppressWarnings("serial")
-public class AddressPlan extends AbstractHasMetadata<AddressPlan> {
+public class AddressPlan extends AbstractHasMetadata<AddressPlan> implements io.enmasse.admin.model.AddressPlan {
 
     public static final String KIND = "AddressPlan";
 
+    private AddressPlanSpec spec;
+
+    // Deprecated format
     private String shortDescription;
-    private String uuid;
     private String addressType;
-
-    private List<ResourceRequest> requiredResources = new LinkedList<>();
+    private List<ResourceRequest> requiredResources;
 
     private Map<String, Object> additionalProperties = new HashMap<>(0);
 
     public AddressPlan() {
-        super(KIND, AdminCrd.API_VERSION);
-    }
-
-    public void setRequiredResources(List<ResourceRequest> requiredResources) {
-        this.requiredResources = requiredResources;
-    }
-    
-    public List<ResourceRequest> getRequiredResources() {
-        return requiredResources;
-    }
-
-    public void setAddressType(String addressType) {
-        this.addressType = addressType;
-    }
-
-    public String getAddressType() {
-        return addressType;
-    }
-
-    public void setShortDescription(String shortDescription) {
-        this.shortDescription = shortDescription;
-    }
-
-    public String getShortDescription() {
-        return shortDescription;
-    }
-
-    public void validate() {
-        Objects.requireNonNull(shortDescription);
-        Objects.requireNonNull(uuid);
+        super(KIND, AdminCrd.API_VERSION_V1BETA2);
     }
 
     @Override
@@ -81,31 +51,22 @@ public class AddressPlan extends AbstractHasMetadata<AddressPlan> {
         if (o == null || getClass() != o.getClass()) return false;
         AddressPlan that = (AddressPlan) o;
         return Objects.equals(getMetadata(), that.getMetadata()) &&
-                Objects.equals(uuid, that.uuid);
+                Objects.equals(spec, that.spec);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(getMetadata(), uuid);
+        return Objects.hash(getMetadata(), spec);
     }
 
     @Override
     public String toString() {
         return "AddressPlan{" +
                 "metadata='" + getMetadata() + '\'' +
-                ", uuid='" + uuid + '\'' +
-                ", requiredResources=" + requiredResources +
+                ", spec ='" + spec + '\'' +
                 '}';
     }
 
-    public void setUuid(String uuid) {
-        this.uuid = uuid;
-    }
-    
-    public String getUuid() {
-        return uuid;
-    }
-
     @JsonAnyGetter
     public Map<String, Object> getAdditionalProperties() {
         return this.additionalProperties;
@@ -119,4 +80,59 @@ public class AddressPlan extends AbstractHasMetadata<AddressPlan> {
     public void setAdditionalProperty(String name, Object value) {
         this.additionalProperties.put(name, value);
     }
+
+    public void setSpec(AddressPlanSpec spec) {
+        this.spec = spec;
+    }
+
+    public AddressPlanSpec getSpec() {
+        return spec;
+    }
+
+    @Override
+    public String getShortDescription() {
+        if (spec != null) {
+            return spec.getShortDescription();
+        } else {
+            return shortDescription;
+        }
+    }
+
+    @Override
+    public String getAddressType() {
+        if (spec != null) {
+            return spec.getAddressType();
+        } else {
+            return addressType;
+        }
+    }
+
+    @Override
+    public Map<String, Double> getResources() {
+        if (spec != null) {
+            return spec.getResources();
+        } else {
+            Map<String, Double> returnedResources = new HashMap<>();
+            for (ResourceRequest resourceRequest : getRequiredResources()) {
+                returnedResources.put(resourceRequest.getName(), resourceRequest.getCredit());
+            }
+            return returnedResources;
+        }
+    }
+
+    public void setShortDescription(String shortDescription) {
+        this.shortDescription = shortDescription;
+    }
+
+    public void setAddressType(String addressType) {
+        this.addressType = addressType;
+    }
+
+    List<ResourceRequest> getRequiredResources() {
+        return requiredResources;
+    }
+
+    public void setRequiredResources(List<ResourceRequest> requiredResources) {
+        this.requiredResources = requiredResources;
+    }
 }
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlanList.java b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlanList.java
index f188884bb..a6aac61b2 100644
--- a/api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlanList.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlanList.java
@@ -14,7 +14,7 @@ public class AddressPlanList extends AbstractList<AddressPlan> {
     public static final String KIND = "AddressPlanList";
 
     public AddressPlanList() {
-        super(KIND, AdminCrd.API_VERSION);
+        super(KIND, AdminCrd.API_VERSION_V1BETA2);
     }
 
 }
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlanSpec.java b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlanSpec.java
new file mode 100644
index 000000000..4a26ced83
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressPlanSpec.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2019, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+package io.enmasse.admin.model.v1;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import io.fabric8.kubernetes.api.model.Doneable;
+import io.sundr.builder.annotations.Buildable;
+import io.sundr.builder.annotations.Inline;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+@Buildable(
+        editableEnabled = false,
+        generateBuilderPackage = false,
+        builderPackage = "io.fabric8.kubernetes.api.builder",
+        inline = @Inline(type = Doneable.class, prefix = "Doneable", value = "done")
+)
+@JsonPropertyOrder({"displayName", "shortDescription", "addressType", "resources"})
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class AddressPlanSpec extends AbstractWithAdditionalProperties {
+    private String shortDescription;
+    private String addressType;
+    private Map<String, Double> resources = new HashMap<>();
+
+    public String getShortDescription() {
+        return shortDescription;
+    }
+
+    public void setShortDescription(String shortDescription) {
+        this.shortDescription = shortDescription;
+    }
+
+    public String getAddressType() {
+        return addressType;
+    }
+
+    public void setAddressType(String addressType) {
+        this.addressType = addressType;
+    }
+
+    public Map<String, Double> getResources() {
+        return Collections.unmodifiableMap(resources);
+    }
+
+    public void setResources(Map<String, Double> resources) {
+        this.resources = new HashMap<>(resources);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        AddressPlanSpec that = (AddressPlanSpec) o;
+        return Objects.equals(shortDescription, that.shortDescription) &&
+                Objects.equals(addressType, that.addressType) &&
+                Objects.equals(resources, that.resources);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(shortDescription, addressType, resources);
+    }
+
+    @Override
+    public String toString() {
+        return "AddressPlanSpec{" +
+                "shortDescription='" + shortDescription + '\'' +
+                ", addressType='" + addressType + '\'' +
+                ", resources=" + resources +
+                '}';
+    }
+}
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlan.java b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlan.java
index 5943d8c1d..d26ce7f07 100644
--- a/api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlan.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlan.java
@@ -29,12 +29,13 @@ import io.sundr.builder.annotations.Inline;
 )
 @DefaultCustomResource
 @SuppressWarnings("serial")
-public class AddressSpacePlan extends AbstractHasMetadata<AddressSpacePlan> {
+public class AddressSpacePlan extends AbstractHasMetadata<AddressSpacePlan> implements io.enmasse.admin.model.AddressSpacePlan {
 
     public static final String KIND = "AddressSpacePlan";
 
+    private AddressSpacePlanSpec spec;
+
     private String shortDescription;
-    private String uuid;
     private String addressSpaceType;
     private List<ResourceAllowance> resources = new LinkedList<>();
     private List<String> addressPlans = new LinkedList<>();
@@ -42,7 +43,7 @@ public class AddressSpacePlan extends AbstractHasMetadata<AddressSpacePlan> {
     private Map<String, Object> additionalProperties = new HashMap<>(0);
 
     public AddressSpacePlan() {
-        super(KIND, AdminCrd.API_VERSION);
+        super(KIND, AdminCrd.API_VERSION_V1BETA1);
     }
 
     public void setResources(List<ResourceAllowance> resources) {
@@ -57,8 +58,25 @@ public class AddressSpacePlan extends AbstractHasMetadata<AddressSpacePlan> {
         this.addressPlans = addressPlans;
     }
 
+    @Override
+    public Map<String, Double> getResourceLimits() {
+        if (spec != null) {
+            return spec.getResourceLimits();
+        } else {
+            Map<String, Double> resourceLimits = new HashMap<>();
+            for (ResourceAllowance allowance : resources) {
+                resourceLimits.put(allowance.getName(), allowance.getMax());
+            }
+            return resourceLimits;
+        }
+    }
+
     public List<String> getAddressPlans() {
-        return addressPlans;
+        if (spec != null) {
+            return spec.getAddressPlans();
+        } else {
+            return addressPlans;
+        }
     }
 
     public void setShortDescription(String shortDescription) {
@@ -66,7 +84,11 @@ public class AddressSpacePlan extends AbstractHasMetadata<AddressSpacePlan> {
     }
     
     public String getShortDescription() {
-        return shortDescription;
+        if (spec != null) {
+            return spec.getShortDescription();
+        } else {
+            return shortDescription;
+        }
     }
 
     public void setAddressSpaceType(String addressSpaceType) {
@@ -74,15 +96,11 @@ public class AddressSpacePlan extends AbstractHasMetadata<AddressSpacePlan> {
     }
     
     public String getAddressSpaceType() {
-        return addressSpaceType;
-    }
-
-    public void setUuid(String uuid) {
-        this.uuid = uuid;
-    }
-    
-    public String getUuid() {
-        return uuid;
+        if (spec != null) {
+            return spec.getAddressSpaceType();
+        } else {
+            return addressSpaceType;
+        }
     }
 
     @Override
@@ -91,21 +109,19 @@ public class AddressSpacePlan extends AbstractHasMetadata<AddressSpacePlan> {
         if (o == null || getClass() != o.getClass()) return false;
         AddressSpacePlan that = (AddressSpacePlan) o;
         return Objects.equals(getMetadata(), that.getMetadata()) &&
-                Objects.equals(uuid, that.uuid);
+                Objects.equals(spec, that.getSpec());
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(getMetadata(), uuid);
+        return Objects.hash(getMetadata(), spec);
     }
 
     @Override
     public String toString() {
         return "AddressSpacePlan{" +
                 "metadata='" + getMetadata()+ '\'' +
-                ", uuid='" + uuid + '\'' +
-                ", resources=" + resources +
-                ", addressPlans=" + addressPlans +
+                ", spec='" + spec + '\'' +
                 '}';
     }
 
@@ -122,4 +138,12 @@ public class AddressSpacePlan extends AbstractHasMetadata<AddressSpacePlan> {
     public void setAdditionalProperty(String name, Object value) {
         this.additionalProperties.put(name, value);
     }
+
+    public void setSpec(AddressSpacePlanSpec spec) {
+        this.spec = spec;
+    }
+
+    public AddressSpacePlanSpec getSpec() {
+        return spec;
+    }
 }
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlanList.java b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlanList.java
index 3fc0aaba5..5b94b0f94 100644
--- a/api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlanList.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlanList.java
@@ -17,6 +17,6 @@ public class AddressSpacePlanList extends AbstractList<AddressSpacePlan> {
 
     @JsonCreator
     public AddressSpacePlanList() {
-        super(KIND, AdminCrd.API_VERSION);
+        super(KIND, AdminCrd.API_VERSION_V1BETA1);
     }
 }
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlanSpec.java b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlanSpec.java
new file mode 100644
index 000000000..4efce16d8
--- /dev/null
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/AddressSpacePlanSpec.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2019, EnMasse authors.
+ * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html).
+ */
+package io.enmasse.admin.model.v1;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import io.fabric8.kubernetes.api.model.Doneable;
+import io.sundr.builder.annotations.Buildable;
+import io.sundr.builder.annotations.Inline;
+
+import java.util.*;
+
+@Buildable(
+        editableEnabled = false,
+        generateBuilderPackage = false,
+        builderPackage = "io.fabric8.kubernetes.api.builder",
+        inline = @Inline(type = Doneable.class, prefix = "Doneable", value = "done")
+)
+@JsonPropertyOrder({"displayName", "shortDescription", "addressSpaceType", "addressPlans", "resourceLimits"})
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class AddressSpacePlanSpec extends AbstractWithAdditionalProperties {
+    private String shortDescription;
+    private String addressSpaceType;
+    private Map<String, Double> resourceLimits = new HashMap<>();
+    private List<String> addressPlans;
+
+    public String getShortDescription() {
+        return shortDescription;
+    }
+
+    public void setShortDescription(String shortDescription) {
+        this.shortDescription = shortDescription;
+    }
+
+    public String getAddressSpaceType() {
+        return addressSpaceType;
+    }
+
+    public void setAddressSpaceType(String addressSpaceType) {
+        this.addressSpaceType = addressSpaceType;
+    }
+
+    public Map<String, Double> getResourceLimits() {
+        return Collections.unmodifiableMap(resourceLimits);
+    }
+
+    public void setResourceLimits(Map<String, Double> resources) {
+        this.resourceLimits = new HashMap<>(resources);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        AddressSpacePlanSpec that = (AddressSpacePlanSpec) o;
+        return Objects.equals(shortDescription, that.shortDescription) &&
+                Objects.equals(addressSpaceType, that.addressSpaceType) &&
+                Objects.equals(addressPlans, that.addressPlans) &&
+                Objects.equals(resourceLimits, that.resourceLimits);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(shortDescription, addressSpaceType, resourceLimits, addressPlans);
+    }
+
+    @Override
+    public String toString() {
+        return "AddressPlanSpec{" +
+                "shortDescription='" + shortDescription + '\'' +
+                ", addressSpaceType='" + addressSpaceType + '\'' +
+                ", resourceLimits=" + resourceLimits +
+                ", addressPlans=" + addressPlans +
+                '}';
+    }
+
+    public void setAddressPlans(List<String> addressPlans) {
+        this.addressPlans = new ArrayList<>(addressPlans);
+    }
+
+    public List<String> getAddressPlans() {
+        return Collections.unmodifiableList(addressPlans);
+    }
+}
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/AdminCrd.java b/api-model/src/main/java/io/enmasse/admin/model/v1/AdminCrd.java
index ec24e9509..15728b719 100644
--- a/api-model/src/main/java/io/enmasse/admin/model/v1/AdminCrd.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/AdminCrd.java
@@ -10,9 +10,11 @@ import io.fabric8.kubernetes.internal.KubernetesDeserializer;
 
 public class AdminCrd {
 
-    public static final String VERSION = "v1beta1";
+    public static final String VERSION_V1BETA1 = "v1beta1";
+    public static final String VERSION_V1BETA2 = "v1beta2";
     public static final String GROUP = "admin.enmasse.io";
-    public static final String API_VERSION = GROUP + "/" + VERSION;
+    public static final String API_VERSION_V1BETA1 = GROUP + "/" + VERSION_V1BETA1;
+    public static final String API_VERSION_V1BETA2 = GROUP + "/" + VERSION_V1BETA2;
 
     private static final CustomResourceDefinition ADDRESS_PLAN_CRD;
     private static final CustomResourceDefinition ADDRESS_SPACE_PLAN_CRD;
@@ -20,25 +22,25 @@ public class AdminCrd {
     private static final CustomResourceDefinition STANDARD_INFRA_CONFIG_CRD;
 
     static {
-        ADDRESS_PLAN_CRD = CustomResources.createCustomResource(GROUP, VERSION, AddressPlan.KIND);
-        ADDRESS_SPACE_PLAN_CRD = CustomResources.createCustomResource(GROUP, VERSION, AddressSpacePlan.KIND);
-        BROKERED_INFRA_CONFIG_CRD = CustomResources.createCustomResource(GROUP, VERSION, BrokeredInfraConfig.KIND);
-        STANDARD_INFRA_CONFIG_CRD = CustomResources.createCustomResource(GROUP, VERSION, StandardInfraConfig.KIND);
+        ADDRESS_PLAN_CRD = CustomResources.createCustomResource(GROUP, VERSION_V1BETA2, AddressPlan.KIND);
+        ADDRESS_SPACE_PLAN_CRD = CustomResources.createCustomResource(GROUP, VERSION_V1BETA2, AddressSpacePlan.KIND);
+        BROKERED_INFRA_CONFIG_CRD = CustomResources.createCustomResource(GROUP, VERSION_V1BETA1, BrokeredInfraConfig.KIND);
+        STANDARD_INFRA_CONFIG_CRD = CustomResources.createCustomResource(GROUP, VERSION_V1BETA1, StandardInfraConfig.KIND);
     }
 
     public static void registerCustomCrds() {
 
-        KubernetesDeserializer.registerCustomKind(API_VERSION, AddressPlan.KIND, AddressPlan.class);
-        KubernetesDeserializer.registerCustomKind(API_VERSION, AddressPlanList.KIND, AddressPlanList.class);
+        KubernetesDeserializer.registerCustomKind(API_VERSION_V1BETA2, AddressPlan.KIND, AddressPlan.class);
+        KubernetesDeserializer.registerCustomKind(API_VERSION_V1BETA2, AddressPlanList.KIND, AddressPlanList.class);
 
-        KubernetesDeserializer.registerCustomKind(API_VERSION, AddressSpacePlan.KIND, AddressSpacePlan.class);
-        KubernetesDeserializer.registerCustomKind(API_VERSION, AddressSpacePlanList.KIND, AddressSpacePlanList.class);
+        KubernetesDeserializer.registerCustomKind(API_VERSION_V1BETA2, AddressSpacePlan.KIND, AddressSpacePlan.class);
+        KubernetesDeserializer.registerCustomKind(API_VERSION_V1BETA2, AddressSpacePlanList.KIND, AddressSpacePlanList.class);
 
-        KubernetesDeserializer.registerCustomKind(API_VERSION, BrokeredInfraConfig.KIND, BrokeredInfraConfig.class);
-        KubernetesDeserializer.registerCustomKind(API_VERSION, BrokeredInfraConfigList.KIND, BrokeredInfraConfigList.class);
+        KubernetesDeserializer.registerCustomKind(API_VERSION_V1BETA1, BrokeredInfraConfig.KIND, BrokeredInfraConfig.class);
+        KubernetesDeserializer.registerCustomKind(API_VERSION_V1BETA1, BrokeredInfraConfigList.KIND, BrokeredInfraConfigList.class);
 
-        KubernetesDeserializer.registerCustomKind(API_VERSION, StandardInfraConfig.KIND, StandardInfraConfig.class);
-        KubernetesDeserializer.registerCustomKind(API_VERSION, StandardInfraConfigList.KIND, StandardInfraConfigList.class);
+        KubernetesDeserializer.registerCustomKind(API_VERSION_V1BETA1, StandardInfraConfig.KIND, StandardInfraConfig.class);
+        KubernetesDeserializer.registerCustomKind(API_VERSION_V1BETA1, StandardInfraConfigList.KIND, StandardInfraConfigList.class);
 
     }
 
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfig.java b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfig.java
index 802940395..9c160af77 100644
--- a/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfig.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfig.java
@@ -34,7 +34,7 @@ public class BrokeredInfraConfig extends AbstractInfraConfig<BrokeredInfraConfig
     private BrokeredInfraConfigSpec spec;
 
     public BrokeredInfraConfig() {
-        super(KIND, AdminCrd.API_VERSION);
+        super(KIND, AdminCrd.API_VERSION_V1BETA1);
     }
 
     @Override
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigList.java b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigList.java
index 05bc42fa0..870f86b0f 100644
--- a/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigList.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/BrokeredInfraConfigList.java
@@ -14,6 +14,6 @@ public class BrokeredInfraConfigList extends AbstractList<BrokeredInfraConfig> {
     public static final String KIND = "BrokeredInfraConfigList";
 
     public BrokeredInfraConfigList() {
-        super(KIND, AdminCrd.API_VERSION);
+        super(KIND, AdminCrd.API_VERSION_V1BETA1);
     }
 }
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfig.java b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfig.java
index 3ec3e5128..a3b5ed111 100644
--- a/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfig.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfig.java
@@ -34,7 +34,7 @@ public class StandardInfraConfig extends AbstractInfraConfig<StandardInfraConfig
     private StandardInfraConfigSpec spec;
 
     public StandardInfraConfig() {
-        super(KIND, AdminCrd.API_VERSION);
+        super(KIND, AdminCrd.API_VERSION_V1BETA1);
     }
 
     public void setSpec(StandardInfraConfigSpec spec) {
diff --git a/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigList.java b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigList.java
index 1123f4a4a..9a1e1f91b 100644
--- a/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigList.java
+++ b/api-model/src/main/java/io/enmasse/admin/model/v1/StandardInfraConfigList.java
@@ -14,7 +14,7 @@ public class StandardInfraConfigList extends AbstractList<StandardInfraConfig>{
     public static final String KIND = "StandardInfraConfigList";
 
     public StandardInfraConfigList() {
-        super(KIND, AdminCrd.API_VERSION);
+        super(KIND, AdminCrd.API_VERSION_V1BETA1);
     }
 
 }
diff --git a/api-server/Dockerfile b/api-server/Dockerfile
index 3eec36df1..fbe19e629 100644
--- a/api-server/Dockerfile
+++ b/api-server/Dockerfile
@@ -1,5 +1,7 @@
 FROM enmasseproject/java-base:8-11
 
+RUN yum -y install openssl && yum -y clean all
+
 ARG version
 ARG maven_version
 ARG commit
diff --git a/api-server/pom.xml b/api-server/pom.xml
index 355fee307..53469f16c 100644
--- a/api-server/pom.xml
+++ b/api-server/pom.xml
@@ -23,6 +23,11 @@
       <artifactId>keycloak-user-api</artifactId>
       <scope>compile</scope>
     </dependency>
+    <dependency>
+      <groupId>org.bouncycastle</groupId>
+      <artifactId>bcprov-jdk15on</artifactId>
+      <version>1.60</version>
+    </dependency>
     <dependency>
       <groupId>io.enmasse</groupId>
       <artifactId>api-common</artifactId>
diff --git a/api-server/src/main/java/io/enmasse/api/server/ApiServer.java b/api-server/src/main/java/io/enmasse/api/server/ApiServer.java
index fd25e62dc..8d92db0a3 100644
--- a/api-server/src/main/java/io/enmasse/api/server/ApiServer.java
+++ b/api-server/src/main/java/io/enmasse/api/server/ApiServer.java
@@ -28,6 +28,7 @@ import okhttp3.HttpUrl;
 import okhttp3.OkHttpClient;
 import okhttp3.Request;
 import okhttp3.Response;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -37,6 +38,7 @@ import java.io.UncheckedIOException;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.nio.charset.StandardCharsets;
+import java.security.Security;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.time.Clock;
@@ -152,6 +154,7 @@ public class ApiServer extends AbstractVerticle {
 
     public static void main(String args[]) {
         try {
+            Security.addProvider(new BouncyCastleProvider());
             Vertx vertx = Vertx.vertx();
             vertx.deployVerticle(new ApiServer(ApiServerOptions.fromEnv(System.getenv())));
         } catch (IllegalArgumentException e) {
diff --git a/api-server/src/main/java/io/enmasse/api/server/HTTPServer.java b/api-server/src/main/java/io/enmasse/api/server/HTTPServer.java
index d5844ab8a..affe7ebed 100644
--- a/api-server/src/main/java/io/enmasse/api/server/HTTPServer.java
+++ b/api-server/src/main/java/io/enmasse/api/server/HTTPServer.java
@@ -23,6 +23,7 @@ import io.vertx.core.http.ClientAuth;
 import io.vertx.core.http.HttpServer;
 import io.vertx.core.http.HttpServerOptions;
 import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.net.JksOptions;
 import io.vertx.core.net.PemKeyCertOptions;
 import io.vertx.core.net.PemTrustOptions;
 import org.jboss.resteasy.plugins.server.vertx.VertxRequestHandler;
@@ -30,8 +31,11 @@ import org.jboss.resteasy.plugins.server.vertx.VertxResteasyDeployment;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.File;
+import java.io.*;
 import java.time.Clock;
+import java.util.Deque;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.TimeUnit;
 
 /**
  * HTTP server for deploying address config
@@ -39,6 +43,7 @@ import java.time.Clock;
 public class HTTPServer extends AbstractVerticle {
     public static final int PORT = 8080;
     public static final int SECURE_PORT = 8443;
+    private static final int PROCESS_LINE_BUFFER_SIZE = 10;
     private static final Logger log = LoggerFactory.getLogger(HTTPServer.class.getName());
     private final AddressSpaceApi addressSpaceApi;
     private final SchemaProvider schemaProvider;
@@ -178,11 +183,20 @@ public class HTTPServer extends AbstractVerticle {
         if (new File(certDir).exists()) {
             HttpServerOptions options = new HttpServerOptions();
             File keyFile = new File(certDir, "tls.key");
+            if (!keyFile.exists()) {
+                keyFile = new File(certDir, "apiserver.key");
+            }
             File certFile = new File(certDir, "tls.crt");
+            if (!certFile.exists()) {
+                certFile = new File(certDir, "apiserver.crt");
+            }
+
             log.info("Loading key from " + keyFile.getAbsolutePath() + ", cert from " + certFile.getAbsolutePath());
-            options.setKeyCertOptions(new PemKeyCertOptions()
-                    .setKeyPath(keyFile.getAbsolutePath())
-                    .setCertPath(certFile.getAbsolutePath()));
+            runCommand("openssl", "pkcs12", "-export", "-passout", "pass:enmasse", "-in", certFile.getAbsolutePath(), "-inkey", keyFile.getAbsolutePath(), "-name", "server", "-out", "/tmp/cert.p12");
+            runCommand("keytool", "-importkeystore", "-srcstorepass", "enmasse", "-deststorepass", "enmasse", "-destkeystore", "/tmp/keystore.jks", "-srckeystore", "/tmp/cert.p12", "-srcstoretype", "PKCS12");
+            options.setKeyCertOptions(new JksOptions()
+                    .setPassword("enmasse")
+                    .setPath("/tmp/keystore.jks"));
             options.setSsl(true);
 
             if (clientCa != null || requestHeaderClientCa != null) {
@@ -241,4 +255,50 @@ public class HTTPServer extends AbstractVerticle {
     public int getActualPort() {
         return httpServer.actualPort();
     }
+
+    private static void runCommand(String... cmd) {
+        ProcessBuilder keyGenBuilder = new ProcessBuilder(cmd).redirectErrorStream(true);
+
+        log.info("Running command '{}'", keyGenBuilder.command());
+        Deque<String> outBuf = new LinkedBlockingDeque<>(PROCESS_LINE_BUFFER_SIZE);
+        boolean success = false;
+        try {
+            Process process = keyGenBuilder.start();
+            try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    boolean added = outBuf.offerLast(line);
+                    if (log.isDebugEnabled()) {
+                        log.debug("Command output: {}", line);
+                    }
+                    if (!added) {
+                        outBuf.removeFirst();
+                        outBuf.addLast(line);
+                    }
+                }
+            }
+            if (!process.waitFor(1, TimeUnit.MINUTES)) {
+                throw new RuntimeException(String.format("Command '%s' timed out", keyGenBuilder.command()));
+            }
+
+            final int exitValue = process.waitFor();
+            success = exitValue == 0;
+            String msg = String.format("Command '%s' completed with exit value %d", keyGenBuilder.command(), exitValue);
+            if (success) {
+                log.info(msg);
+            } else {
+                log.error(msg);
+                throw new RuntimeException(String.format("Command '%s' failed with exit value %d", keyGenBuilder.command(), exitValue));
+            }
+        } catch (InterruptedException ignored) {
+            Thread.currentThread().interrupt();
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        } finally {
+            if (!success && !outBuf.isEmpty()) {
+                log.error("Last {} line(s) written by command to stdout/stderr follow", outBuf.size());
+                outBuf.forEach(line -> log.error("Command output: {}", line));
+            }
+        }
+    }
 }
diff --git a/api-server/src/main/resources/swagger.json b/api-server/src/main/resources/swagger.json
index 2ffdbe1be..d6b261d84 100644
--- a/api-server/src/main/resources/swagger.json
+++ b/api-server/src/main/resources/swagger.json
@@ -953,15 +953,15 @@
                 }
             ]
         },
-        "/apis/admin.enmasse.io/v1beta1/namespaces/{namespace}/addressspaceplans": {
+        "/apis/admin.enmasse.io/v1beta2/namespaces/{namespace}/addressspaceplans": {
           "get": {
             "tags": [
-                    "enmasse_v1beta1",
+                    "enmasse_v1beta2",
                     "admin",
                     "addressspaceplan"
                 ],
                 "description": "list objects of kind AddressSpacePlan",
-                "operationId": "listAdminEnmasseV1alpha1NamespacedAddresSpacePlan",
+                "operationId": "listAdminEnmasseV1beta2NamespacedAddresSpacePlan",
                 "produces": [
                     "application/json"
                 ],
@@ -978,7 +978,7 @@
                     "200": {
                         "description": "OK",
                         "schema": {
-                            "$ref": "#/definitions/io.enmasse.admin.v1beta1.AddressSpacePlanList"
+                            "$ref": "#/definitions/io.enmasse.admin.v1beta2.AddressSpacePlanList"
                         }
                     },
                     "401": {
@@ -988,12 +988,12 @@
             },
             "post": {
                 "tags": [
-                    "enmasse_v1beta1",
+                    "enmasse_v1beta2",
                     "admin",
                     "addressspaceplan"
                 ],
                 "description": "create an AddressSpacePlan",
-                "operationId": "createAdminEnmasseV1alpha1NamespacedAddressSpacePlan",
+                "operationId": "createAdminEnmasseV1beta2NamespacedAddressSpacePlan",
                 "consumes": [
                     "application/json"
                 ],
@@ -1006,7 +1006,7 @@
                         "name": "body",
                         "required": true,
                         "schema": {
-                            "$ref": "#/definitions/io.enmasse.admin.v1beta1.AddressSpacePlan"
+                            "$ref": "#/definitions/io.enmasse.admin.v1beta2.AddressSpacePlan"
                         }
                     }
                 ],
@@ -1014,13 +1014,13 @@
                     "200": {
                         "description": "OK",
                         "schema": {
-                            "$ref": "#/definitions/io.enmasse.admin.v1beta1.AddressSpacePlan"
+                            "$ref": "#/definitions/io.enmasse.admin.v1beta2.AddressSpacePlan"
                         }
                     },
                     "201": {
                         "description": "Created",
                         "schema": {
-                            "$ref": "#/definitions/io.enmasse.admin.v1beta1.AddressSpacePlan"
+                            "$ref": "#/definitions/io.enmasse.admin.v1beta2.AddressSpacePlan"
                         }
                     },
                     "401": {
@@ -1039,15 +1039,15 @@
                 }
             ]
         },
-        "/apis/admin.enmasse.io/v1beta1/namespaces/{namespace}/addressspaceplans/{name}": {
+        "/apis/admin.enmasse.io/v1beta2/namespaces/{namespace}/addressspaceplans/{name}": {
             "get": {
                 "tags": [
-                    "enmasse_v1beta1",
+                    "enmasse_v1beta2",
                     "admin",
                     "addressspaceplan"
                 ],
                 "description": "read the specified AddressSpacePlan",
-                "operationId": "readAdminEnmasseV1alpha1NamespacedAddressSpacePlan",
+                "operationId": "readAdminEnmasseV1beta2NamespacedAddressSpacePlan",
                 "consumes": [
                     "application/json"
                 ],
@@ -1067,7 +1067,7 @@
                     "200": {
                         "description": "OK",
                         "schema": {
-                            "$ref": "#/definitions/io.enmasse.admin.v1beta1.AddressSpacePlan"
+                            "$ref": "#/definitions/io.enmasse.admin.v1beta2.AddressSpacePlan"
                         }
                     },
                     "401": {
@@ -1080,12 +1080,12 @@
             },
             "put": {
                 "tags": [
-                    "enmasse_v1beta1",
+                    "enmasse_v1beta2",
                     "admin",
                     "addressspaceplan"
                 ],
                 "description": "replace the specified AddressSpacePlan",
-                "operationId": "replaceAdminEnmasseV1alpha1NamespacedAddressSpacePlan",
+                "operationId": "replaceAdminEnmasseV1beta2NamespacedAddressSpacePlan",
                 "produces": [
                     "application/json"
                 ],
@@ -1102,7 +1102,7 @@
                         "name": "body",
                         "required": true,
                         "schema": {
-                            "$ref": "#/definitions/io.enmasse.admin.v1beta1.AddressSpacePlan"
+                            "$ref": "#/definitions/io.enmasse.admin.v1beta2.AddressSpacePlan"
                         }
                     }
                 ],
@@ -1110,13 +1110,13 @@
                     "200": {
                         "description": "OK",
                         "schema": {
-                            "$ref": "#/definitions/io.enmasse.admin.v1beta1.AddressSpacePlan"
+                            "$ref": "#/definitions/io.enmasse.admin.v1beta2.AddressSpacePlan"
                         }
                     },
                     "201": {
                         "description": "Created",
                         "schema": {
-                            "$ref": "#/definitions/io.enmasse.admin.v1beta1.AddressSpacePlan"
+                            "$ref": "#/definitions/io.enmasse.admin.v1beta2.AddressSpacePlan"
                         }
                     },
                     "401": {
@@ -1126,12 +1126,12 @@
             },
             "delete": {
                 "tags": [
-                    "enmasse_v1beta1",
+                    "enmasse_v1beta2",
                     "admin",
                     "addressspaceplan"
                 ],
                 "description": "delete an AddressSpacePlan",
-                "operationId": "deleteAdminEnmasseV1alpha1NamespacedAddressSpacePlan",
+                "operationId": "deleteAdminEnmasseV1beta2NamespacedAddressSpacePlan",
                 "produces": [
                     "application/json"
                 ],
@@ -1971,24 +1971,19 @@
                 }
             }
         },
-        "io.enmasse.admin.v1beta1.AddressSpacePlan": {
+        "io.enmasse.admin.v1beta2.AddressSpacePlan": {
             "type": "object",
             "required": [
                 "apiVersion",
                 "kind",
                 "metadata",
-                "displayName",
-                "displayOrder",
-                "shortDescription",
-                "uuid",
-                "addressSpaceType",
-                "resources"
+                "spec"
             ],
             "properties": {
                 "apiVersion": {
                     "type": "string",
                     "enum": [
-                        "admin.enmasse.io/v1beta1"
+                        "admin.enmasse.io/v1beta2"
                     ]
                 },
                 "kind": {
@@ -2000,6 +1995,20 @@
                 "metadata": {
                     "$ref": "#/definitions/ObjectMeta"
                 },
+                "spec": {
+                    "$ref": "#/definitions/io.enmasse.admin.v1beta2.AddressSpacePlanSpec"
+                }
+            }
+        },
+        "io.enmasse.admin.v1beta2.AddressSpacePlanSpec": {
+            "type": "object",
+            "required": [
+                "displayName",
+                "resourceLimits",
+                "addressSpaceType",
+                "addressPlans"
+            ],
+            "properties": {
                 "displayName": {
                     "type": "string"
                 },
@@ -2012,27 +2021,20 @@
                 "longDescription": {
                     "type": "string"
                 },
-                "uuid": {
-                    "type": "string"
-                },
                 "addressSpaceType": {
                     "type": "string"
                 },
-                "resources": {
-                    "type": "array",
-                    "items": {
-                        "type": "object",
-                        "required": [
-                            "name",
-                            "max"
-                        ],
-                        "properties": {
-                            "name": {
-                                "type": "string"
-                            },
-                            "max": {
-                                "type": "number"
-                            }
+                "resourceLimits": {
+                    "type": "object",
+                    "properties": {
+                        "router": {
+                            "type": "number"
+                        },
+                        "broker": {
+                            "type": "number"
+                        },
+                        "aggregate": {
+                            "type": "number"
                         }
                     }
                 },
@@ -2044,7 +2046,7 @@
                 }
             }
         },
-        "io.enmasse.admin.v1beta1.AddressSpacePlanList": {
+        "io.enmasse.admin.v1beta2.AddressSpacePlanList": {
             "type": "object",
             "required": [
                 "apiVersion",
@@ -2055,7 +2057,7 @@
                 "apiVersion": {
                     "type": "string",
                     "enum": [
-                        "admin.enmasse.io/v1beta1"
+                        "admin.enmasse.io/v1beta2"
                     ]
                 },
                 "kind": {
@@ -2067,29 +2069,24 @@
                 "items": {
                     "type": "array",
                     "items": {
-                        "$ref": "#/definitions/io.enmasse.admin.v1beta1.AddressSpacePlan"
+                        "$ref": "#/definitions/io.enmasse.admin.v1beta2.AddressSpacePlan"
                     }
                 }
             }
         },
-        "io.enmasse.admin.v1beta1.AddressPlan": {
+        "io.enmasse.admin.v1beta2.AddressPlan": {
             "type": "object",
             "required": [
                 "apiVersion",
                 "kind",
                 "metadata",
-                "displayName",
-                "displayOrder",
-                "shortDescription",
-                "uuid",
-                "addressType",
-                "requiredResources"
+                "spec"
             ],
             "properties": {
                 "apiVersion": {
                     "type": "string",
                     "enum": [
-                        "admin.enmasse.io/v1beta1"
+                        "admin.enmasse.io/v1beta2"
                     ]
                 },
                 "kind": {
@@ -2101,6 +2098,19 @@
                 "metadata": {
                     "$ref": "#/definitions/ObjectMeta"
                 },
+                "spec": {
+                    "$ref": "#/definitions/io.enmasse.admin.v1beta2.AddressPlanSpec"
+                }
+            }
+        },
+        "io.enmasse.admin.v1beta2.AddressPlanSpec": {
+            "type": "object",
+            "required": [
+                "displayName",
+                "addressType",
+                "resources"
+            ],
+            "properties": {
                 "displayName": {
                     "type": "string"
                 },
@@ -2113,33 +2123,23 @@
                 "longDescription": {
                     "type": "string"
                 },
-                "uuid": {
-                    "type": "string"
-                },
                 "addressType": {
                     "type": "string"
                 },
-                "requiredResources": {
-                    "type": "array",
-                    "items": {
-                        "type": "object",
-                        "required": [
-                            "name",
-                            "credit"
-                        ],
-                        "properties": {
-                            "name": {
-                                "type": "string"
-                            },
-                            "credit": {
-                                "type": "number"
-                            }
+                "resources": {
+                    "type": "object",
+                    "properties": {
+                        "router": {
+                            "type": "number"
+                        },
+                        "broker": {
+                            "type": "number"
                         }
                     }
                 }
             }
         },
-        "io.enmasse.admin.v1beta1.AddressPlanList": {
+        "io.enmasse.admin.v1beta2.AddressPlanList": {
             "type": "object",
             "required": [
                 "apiVersion",
@@ -2150,7 +2150,7 @@
                 "apiVersion": {
                     "type": "string",
                     "enum": [
-                        "admin.enmasse.io/v1beta1"
+                        "admin.enmasse.io/v1beta2"
                     ]
                 },
                 "kind": {
@@ -2162,7 +2162,7 @@
                 "items": {
                     "type": "array",
                     "items": {
-                        "$ref": "#/definitions/io.enmasse.admin.v1beta1.AddressPlan"
+                        "$ref": "#/definitions/io.enmasse.admin.v1beta2.AddressPlan"
                     }
                 }
             }
diff --git a/broker-plugin/sasl-delegation/src/main/java/io/enmasse/artemis/sasl_delegation/SaslDelegatingLogin.java b/broker-plugin/sasl-delegation/src/main/java/io/enmasse/artemis/sasl_delegation/SaslDelegatingLogin.java
index b7f6a8b25..e3b7aa40d 100644
--- a/broker-plugin/sasl-delegation/src/main/java/io/enmasse/artemis/sasl_delegation/SaslDelegatingLogin.java
+++ b/broker-plugin/sasl-delegation/src/main/java/io/enmasse/artemis/sasl_delegation/SaslDelegatingLogin.java
@@ -32,6 +32,7 @@ import java.security.NoSuchAlgorithmException;
 import java.security.Principal;
 import java.util.*;
 import java.util.function.BooleanSupplier;
+import java.util.stream.Collectors;
 import javax.naming.InvalidNameException;
 import javax.naming.ldap.LdapName;
 import javax.net.ssl.SSLContext;
@@ -352,9 +353,12 @@ public class SaslDelegatingLogin implements LoginModule {
             roles.addAll(defaultRolesAuthenticated);
 
             if (remoteProperties.get(Symbol.valueOf(GROUPS)) instanceof List) {
-                List<String> groups = (List<String>) remoteProperties.get(Symbol.valueOf(GROUPS));
+                List<String> groups = new ArrayList<>(((List<String>) ((List) remoteProperties.get(Symbol.valueOf(GROUPS)))));
                 groups.retainAll(SPECIAL_AUTHZ_GROUPS);
                 roles.addAll(groups);
+                for (String group : groups) {
+                    roles.add(group + "_#");
+                }
             }
         }
 
@@ -364,7 +368,7 @@ public class SaslDelegatingLogin implements LoginModule {
                 List<String> groups = new ArrayList<>();
                 for(Map.Entry<String, String[]> entry : authz.entrySet()) {
                     for(String permission : entry.getValue()) {
-                        groups.add(permission + "_" + entry.getKey());
+                        groups.add(permission + "_" + entry.getKey().replace('*', '#'));
                     }
                 }
                 roles.addAll(groups);
diff --git a/documentation/common/restapi-reference.adoc b/documentation/common/restapi-reference.adoc
index 2d2ba0ef8..ef5decff3 100644
--- a/documentation/common/restapi-reference.adoc
+++ b/documentation/common/restapi-reference.adoc
@@ -38,8 +38,8 @@ __URL__ : http://enmasse.io
 [[_paths]]
 == Paths
 
-[[_createadminenmassev1alpha1namespacedaddressspaceplan]]
-=== POST /apis/admin.enmasse.io/v1beta1/namespaces/{namespace}/addressspaceplans
+[[_createadminenmassev1beta2namespacedaddressspaceplan]]
+=== POST /apis/admin.enmasse.io/v1beta2/namespaces/{namespace}/addressspaceplans
 
 ==== Description
 create an AddressSpacePlan
@@ -53,7 +53,7 @@ create an AddressSpacePlan
 |**Path**|**namespace** +
 __required__|object name and auth scope, such as for teams and projects|string
 |**Body**|**body** +
-__required__||<<_io_enmasse_admin_v1beta1_addressspaceplan,io.enmasse.admin.v1beta1.AddressSpacePlan>>
+__required__||<<_io_enmasse_admin_v1beta2_addressspaceplan,io.enmasse.admin.v1beta2.AddressSpacePlan>>
 |===
 
 
@@ -62,8 +62,8 @@ __required__||<<_io_enmasse_admin_v1beta1_addressspaceplan,io.enmasse.admin.v1be
 [options="header", cols=".^2a,.^14a,.^4a"]
 |===
 |HTTP Code|Description|Schema
-|**200**|OK|<<_io_enmasse_admin_v1beta1_addressspaceplan,io.enmasse.admin.v1beta1.AddressSpacePlan>>
-|**201**|Created|<<_io_enmasse_admin_v1beta1_addressspaceplan,io.enmasse.admin.v1beta1.AddressSpacePlan>>
+|**200**|OK|<<_io_enmasse_admin_v1beta2_addressspaceplan,io.enmasse.admin.v1beta2.AddressSpacePlan>>
+|**201**|Created|<<_io_enmasse_admin_v1beta2_addressspaceplan,io.enmasse.admin.v1beta2.AddressSpacePlan>>
 |**401**|Unauthorized|No Content
 |===
 
@@ -82,11 +82,11 @@ __required__||<<_io_enmasse_admin_v1beta1_addressspaceplan,io.enmasse.admin.v1be
 
 * addressspaceplan
 * admin
-* enmasse_v1beta1
+* enmasse_v1beta2
 
 
-[[_listadminenmassev1alpha1namespacedaddresspaceplan]]
-=== GET /apis/admin.enmasse.io/v1beta1/namespaces/{namespace}/addressspaceplans
+[[_listadminenmassev1beta2namespacedaddresspaceplan]]
+=== GET /apis/admin.enmasse.io/v1beta2/namespaces/{namespace}/addressspaceplans
 
 ==== Description
 list objects of kind AddressSpacePlan
@@ -109,7 +109,7 @@ __optional__|A selector to restrict the list of returned objects by their labels
 [options="header", cols=".^2a,.^14a,.^4a"]
 |===
 |HTTP Code|Description|Schema
-|**200**|OK|<<_io_enmasse_admin_v1beta1_addressspaceplanlist,io.enmasse.admin.v1beta1.AddressSpacePlanList>>
+|**200**|OK|<<_io_enmasse_admin_v1beta2_addressspaceplanlist,io.enmasse.admin.v1beta2.AddressSpacePlanList>>
 |**401**|Unauthorized|No Content
 |===
 
@@ -123,11 +123,11 @@ __optional__|A selector to restrict the list of returned objects by their labels
 
 * addressspaceplan
 * admin
-* enmasse_v1beta1
+* enmasse_v1beta2
 
 
-[[_readadminenmassev1alpha1namespacedaddressspaceplan]]
-=== GET /apis/admin.enmasse.io/v1beta1/namespaces/{namespace}/addressspaceplans/{name}
+[[_readadminenmassev1beta2namespacedaddressspaceplan]]
+=== GET /apis/admin.enmasse.io/v1beta2/namespaces/{namespace}/addressspaceplans/{name}
 
 ==== Description
 read the specified AddressSpacePlan
@@ -150,7 +150,7 @@ __required__|object name and auth scope, such as for teams and projects|string
 [options="header", cols=".^2a,.^14a,.^4a"]
 |===
 |HTTP Code|Description|Schema
-|**200**|OK|<<_io_enmasse_admin_v1beta1_addressspaceplan,io.enmasse.admin.v1beta1.AddressSpacePlan>>
+|**200**|OK|<<_io_enmasse_admin_v1beta2_addressspaceplan,io.enmasse.admin.v1beta2.AddressSpacePlan>>
 |**401**|Unauthorized|No Content
 |**404**|Not found|No Content
 |===
@@ -170,11 +170,11 @@ __required__|object name and auth scope, such as for teams and projects|string
 
 * addressspaceplan
 * admin
-* enmasse_v1beta1
+* enmasse_v1beta2
 
 
-[[_replaceadminenmassev1alpha1namespacedaddressspaceplan]]
-=== PUT /apis/admin.enmasse.io/v1beta1/namespaces/{namespace}/addressspaceplans/{name}
+[[_replaceadminenmassev1beta2namespacedaddressspaceplan]]
+=== PUT /apis/admin.enmasse.io/v1beta2/namespaces/{namespace}/addressspaceplans/{name}
 
 ==== Description
 replace the specified AddressSpacePlan
@@ -190,7 +190,7 @@ __required__|Name of AddressSpacePlan to replace.|string
 |**Path**|**namespace** +
 __required__|object name and auth scope, such as for teams and projects|string
 |**Body**|**body** +
-__required__||<<_io_enmasse_admin_v1beta1_addressspaceplan,io.enmasse.admin.v1beta1.AddressSpacePlan>>
+__required__||<<_io_enmasse_admin_v1beta2_addressspaceplan,io.enmasse.admin.v1beta2.AddressSpacePlan>>
 |===
 
 
@@ -199,8 +199,8 @@ __required__||<<_io_enmasse_admin_v1beta1_addressspaceplan,io.enmasse.admin.v1be
 [options="header", cols=".^2a,.^14a,.^4a"]
 |===
 |HTTP Code|Description|Schema
-|**200**|OK|<<_io_enmasse_admin_v1beta1_addressspaceplan,io.enmasse.admin.v1beta1.AddressSpacePlan>>
-|**201**|Created|<<_io_enmasse_admin_v1beta1_addressspaceplan,io.enmasse.admin.v1beta1.AddressSpacePlan>>
+|**200**|OK|<<_io_enmasse_admin_v1beta2_addressspaceplan,io.enmasse.admin.v1beta2.AddressSpacePlan>>
+|**201**|Created|<<_io_enmasse_admin_v1beta2_addressspaceplan,io.enmasse.admin.v1beta2.AddressSpacePlan>>
 |**401**|Unauthorized|No Content
 |===
 
@@ -214,11 +214,11 @@ __required__||<<_io_enmasse_admin_v1beta1_addressspaceplan,io.enmasse.admin.v1be
 
 * addressspaceplan
 * admin
-* enmasse_v1beta1
+* enmasse_v1beta2
 
 
-[[_deleteadminenmassev1alpha1namespacedaddressspaceplan]]
-=== DELETE /apis/admin.enmasse.io/v1beta1/namespaces/{namespace}/addressspaceplans/{name}
+[[_deleteadminenmassev1beta2namespacedaddressspaceplan]]
+=== DELETE /apis/admin.enmasse.io/v1beta2/namespaces/{namespace}/addressspaceplans/{name}
 
 ==== Description
 delete an AddressSpacePlan
@@ -256,7 +256,7 @@ __required__|object name and auth scope, such as for teams and projects|string
 
 * addressspaceplan
 * admin
-* enmasse_v1beta1
+* enmasse_v1beta2
 
 
 [[_createenmassev1alpha1namespacedaddress]]
@@ -1171,120 +1171,6 @@ __optional__|Suggested HTTP return code for this status, 0 if not set.|integer (
 |===
 
 
-[[_io_enmasse_admin_v1beta1_addressplan]]
-=== io.enmasse.admin.v1beta1.AddressPlan
-
-[options="header", cols=".^3a,.^4a"]
-|===
-|Name|Schema
-|**addressType** +
-__required__|string
-|**apiVersion** +
-__required__|enum (admin.enmasse.io/v1beta1)
-|**displayName** +
-__required__|string
-|**displayOrder** +
-__required__|integer
-|**kind** +
-__required__|enum (AddressPlan)
-|**longDescription** +
-__optional__|string
-|**metadata** +
-__required__|<<_objectmeta,ObjectMeta>>
-|**requiredResources** +
-__required__|< <<_io_enmasse_admin_v1beta1_addressplan_requiredresources,requiredResources>> > array
-|**shortDescription** +
-__required__|string
-|**uuid** +
-__required__|string
-|===
-
-[[_io_enmasse_admin_v1beta1_addressplan_requiredresources]]
-**requiredResources**
-
-[options="header", cols=".^3a,.^4a"]
-|===
-|Name|Schema
-|**credit** +
-__required__|number
-|**name** +
-__required__|string
-|===
-
-
-[[_io_enmasse_admin_v1beta1_addressplanlist]]
-=== io.enmasse.admin.v1beta1.AddressPlanList
-
-[options="header", cols=".^3a,.^4a"]
-|===
-|Name|Schema
-|**apiVersion** +
-__required__|enum (admin.enmasse.io/v1beta1)
-|**items** +
-__required__|< <<_io_enmasse_admin_v1beta1_addressplan,io.enmasse.admin.v1beta1.AddressPlan>> > array
-|**kind** +
-__required__|enum (AddressPlanList)
-|===
-
-
-[[_io_enmasse_admin_v1beta1_addressspaceplan]]
-=== io.enmasse.admin.v1beta1.AddressSpacePlan
-
-[options="header", cols=".^3a,.^4a"]
-|===
-|Name|Schema
-|**addressPlans** +
-__optional__|< string > array
-|**addressSpaceType** +
-__required__|string
-|**apiVersion** +
-__required__|enum (admin.enmasse.io/v1beta1)
-|**displayName** +
-__required__|string
-|**displayOrder** +
-__required__|integer
-|**kind** +
-__required__|enum (AddressSpacePlan)
-|**longDescription** +
-__optional__|string
-|**metadata** +
-__required__|<<_objectmeta,ObjectMeta>>
-|**resources** +
-__required__|< <<_io_enmasse_admin_v1beta1_addressspaceplan_resources,resources>> > array
-|**shortDescription** +
-__required__|string
-|**uuid** +
-__required__|string
-|===
-
-[[_io_enmasse_admin_v1beta1_addressspaceplan_resources]]
-**resources**
-
-[options="header", cols=".^3a,.^4a"]
-|===
-|Name|Schema
-|**max** +
-__required__|number
-|**name** +
-__required__|string
-|===
-
-
-[[_io_enmasse_admin_v1beta1_addressspaceplanlist]]
-=== io.enmasse.admin.v1beta1.AddressSpacePlanList
-
-[options="header", cols=".^3a,.^4a"]
-|===
-|Name|Schema
-|**apiVersion** +
-__required__|enum (admin.enmasse.io/v1beta1)
-|**items** +
-__required__|< <<_io_enmasse_admin_v1beta1_addressspaceplan,io.enmasse.admin.v1beta1.AddressSpacePlan>> > array
-|**kind** +
-__required__|enum (AddressSpacePlanList)
-|===
-
-
 [[_io_enmasse_admin_v1beta1_brokeredinfraconfig]]
 === io.enmasse.admin.v1beta1.BrokeredInfraConfig
 
@@ -1534,6 +1420,140 @@ __optional__|string
 |===
 
 
+[[_io_enmasse_admin_v1beta2_addressplan]]
+=== io.enmasse.admin.v1beta2.AddressPlan
+
+[options="header", cols=".^3a,.^4a"]
+|===
+|Name|Schema
+|**apiVersion** +
+__required__|enum (admin.enmasse.io/v1beta2)
+|**kind** +
+__required__|enum (AddressPlan)
+|**metadata** +
+__required__|<<_objectmeta,ObjectMeta>>
+|**spec** +
+__required__|<<_io_enmasse_admin_v1beta2_addressplanspec,io.enmasse.admin.v1beta2.AddressPlanSpec>>
+|===
+
+
+[[_io_enmasse_admin_v1beta2_addressplanlist]]
+=== io.enmasse.admin.v1beta2.AddressPlanList
+
+[options="header", cols=".^3a,.^4a"]
+|===
+|Name|Schema
+|**apiVersion** +
+__required__|enum (admin.enmasse.io/v1beta2)
+|**items** +
+__required__|< <<_io_enmasse_admin_v1beta2_addressplan,io.enmasse.admin.v1beta2.AddressPlan>> > array
+|**kind** +
+__required__|enum (AddressPlanList)
+|===
+
+
+[[_io_enmasse_admin_v1beta2_addressplanspec]]
+=== io.enmasse.admin.v1beta2.AddressPlanSpec
+
+[options="header", cols=".^3a,.^4a"]
+|===
+|Name|Schema
+|**addressType** +
+__required__|string
+|**displayName** +
+__required__|string
+|**displayOrder** +
+__optional__|integer
+|**longDescription** +
+__optional__|string
+|**resources** +
+__required__|<<_io_enmasse_admin_v1beta2_addressplanspec_resources,resources>>
+|**shortDescription** +
+__optional__|string
+|===
+
+[[_io_enmasse_admin_v1beta2_addressplanspec_resources]]
+**resources**
+
+[options="header", cols=".^3a,.^4a"]
+|===
+|Name|Schema
+|**broker** +
+__optional__|number
+|**router** +
+__optional__|number
+|===
+
+
+[[_io_enmasse_admin_v1beta2_addressspaceplan]]
+=== io.enmasse.admin.v1beta2.AddressSpacePlan
+
+[options="header", cols=".^3a,.^4a"]
+|===
+|Name|Schema
+|**apiVersion** +
+__required__|enum (admin.enmasse.io/v1beta2)
+|**kind** +
+__required__|enum (AddressSpacePlan)
+|**metadata** +
+__required__|<<_objectmeta,ObjectMeta>>
+|**spec** +
+__required__|<<_io_enmasse_admin_v1beta2_addressspaceplanspec,io.enmasse.admin.v1beta2.AddressSpacePlanSpec>>
+|===
+
+
+[[_io_enmasse_admin_v1beta2_addressspaceplanlist]]
+=== io.enmasse.admin.v1beta2.AddressSpacePlanList
+
+[options="header", cols=".^3a,.^4a"]
+|===
+|Name|Schema
+|**apiVersion** +
+__required__|enum (admin.enmasse.io/v1beta2)
+|**items** +
+__required__|< <<_io_enmasse_admin_v1beta2_addressspaceplan,io.enmasse.admin.v1beta2.AddressSpacePlan>> > array
+|**kind** +
+__required__|enum (AddressSpacePlanList)
+|===
+
+
+[[_io_enmasse_admin_v1beta2_addressspaceplanspec]]
+=== io.enmasse.admin.v1beta2.AddressSpacePlanSpec
+
+[options="header", cols=".^3a,.^4a"]
+|===
+|Name|Schema
+|**addressPlans** +
+__required__|< string > array
+|**addressSpaceType** +
+__required__|string
+|**displayName** +
+__required__|string
+|**displayOrder** +
+__optional__|integer
+|**longDescription** +
+__optional__|string
+|**resourceLimits** +
+__required__|<<_io_enmasse_admin_v1beta2_addressspaceplanspec_resourcelimits,resourceLimits>>
+|**shortDescription** +
+__optional__|string
+|===
+
+[[_io_enmasse_admin_v1beta2_addressspaceplanspec_resourcelimits]]
+**resourceLimits**
+
+[options="header", cols=".^3a,.^4a"]
+|===
+|Name|Schema
+|**aggregate** +
+__optional__|number
+|**broker** +
+__optional__|number
+|**router** +
+__optional__|number
+|===
+
+
 [[_io_enmasse_user_v1beta1_messaginguser]]
 === io.enmasse.user.v1beta1.MessagingUser
 
diff --git a/documentation/common/restrictive-plan.yaml b/documentation/common/restrictive-plan.yaml
index 9b66ae816..f4c9d251b 100644
--- a/documentation/common/restrictive-plan.yaml
+++ b/documentation/common/restrictive-plan.yaml
@@ -1,4 +1,4 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressSpacePlan
 metadata:
   name: restrictive-plan
@@ -6,19 +6,16 @@ metadata:
     app: enmasse
   annotations:
     enmasse.io/defined-by: default
-displayName: Restrictive Plan
-displayOrder: 0
-shortDescription: A plan with restrictive quotas
-longDescription: A plan with restrictive quotas for the standard address space
-uuid: 74b9a40e-117e-11e8-b4e1-507b9def37d9
-addressSpaceType: standard
-addressPlans:
-- small-queue
-- small-anycast
-resources:
-- name: router
-  max: 2.0
-- name: broker
-  max: 2.0
-- name: aggregate
-  max: 2.0
+spec:
+  displayName: Restrictive Plan
+  displayOrder: 0
+  shortDescription: A plan with restrictive quotas
+  longDescription: A plan with restrictive quotas for the standard address space
+  addressSpaceType: standard
+  addressPlans:
+  - small-queue
+  - small-anycast
+  resourceLimits:
+    router: 2.0
+    broker: 2.0
+    aggregate: 2.0
diff --git a/documentation/common/small-anycast-plan.yaml b/documentation/common/small-anycast-plan.yaml
index 4387ec713..ec9bcd3a1 100644
--- a/documentation/common/small-anycast-plan.yaml
+++ b/documentation/common/small-anycast-plan.yaml
@@ -1,15 +1,14 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: small-anycast
   labels:
     app: enmasse
-displayName: Small anycast plan
-displayOrder: 0
-shortDescription: A plan for small anycast addresses
-longDescription: A plan for small anycast addresses that consume little resources
-uuid: cb61f440-1184-11e8-adda-507b9def37d9
-addressType: anycast
-requiredResources:
-- name: router
-  credit: 0.2
+spec:
+  displayName: Small anycast plan
+  displayOrder: 0
+  shortDescription: A plan for small anycast addresses
+  longDescription: A plan for small anycast addresses that consume little resources
+  addressType: anycast
+  resources:
+    router: 0.2
diff --git a/documentation/common/small-queue-plan.yaml b/documentation/common/small-queue-plan.yaml
index 39cec5e7f..9f3ae2580 100644
--- a/documentation/common/small-queue-plan.yaml
+++ b/documentation/common/small-queue-plan.yaml
@@ -1,17 +1,15 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: small-queue
   labels:
     app: enmasse
-displayName: Small queue plan
-displayOrder: 0
-shortDescription: A plan for small queues
-longDescription: A plan for small queues that consume little resources
-uuid: 98feabb6-1183-11e8-a769-507b9def37d9
-addressType: queue
-requiredResources:
-- name: router
-  credit: 0.2
-- name: broker
-  credit: 0.3
+spec:
+  displayName: Small queue plan
+  displayOrder: 0
+  shortDescription: A plan for small queues
+  longDescription: A plan for small queues that consume little resources
+  addressType: queue
+  resources:
+    router: 0.2
+    broker: 0.3
diff --git a/iot/examples/readme.md b/iot/examples/README.md
similarity index 54%
rename from iot/examples/readme.md
rename to iot/examples/README.md
index 318d89faa..a7b25bab5 100644
--- a/iot/examples/readme.md
+++ b/iot/examples/README.md
@@ -1,5 +1,6 @@
 # Start and test managed IoT Project
 
+* Log in to user with cluster admin privileges
 * Create project
 
   ```
@@ -9,7 +10,11 @@
 * Install EnMasse with IoT services
 
   ```
-  oc apply -f templates/build/enmasse-latest/install/bundles/enmasse-iot-with-standard-authservice/
+  oc apply -f templates/build/enmasse-latest/install/components/standard-authservice
+  oc apply -f templates/build/enmasse-latest/install/components/example-roles
+  oc apply -f templates/build/enmasse-latest/install/components/example-plans
+  oc apply -f templates/build/enmasse-latest/install/bundles/enmasse
+  oc apply -f templates/build/enmasse-latest/install/bundles/iot
   ```
 
 * Wait for the EnMasse installation to succeed. The following command should show all pods to be ready:
@@ -18,9 +23,18 @@
   oc get pods
   ```
 
+* Switch back to a non-admin user
+
+* Create a new project
+
+  ```
+  oc new-project my-iot-1
+  ```
+
 * Create Managed IoT Project
 
   ```
+  oc new-project myapp || oc project myapp
   oc create -f iot/examples/iot-project-managed.yaml
   ```
 
@@ -33,7 +47,8 @@
 * Register a device
 
   ```
-  curl --insecure -X POST -i -H 'Content-Type: application/json' --data-binary '{"device-id": "4711"}' https://$(oc get routes device-registry --template='{{ .spec.host }}')/registration/enmasse-infra.managed
+  oc project enmasse-infra
+  curl --insecure -X POST -i -H 'Content-Type: application/json' --data-binary '{"device-id": "4711"}' https://$(oc get routes device-registry --template='{{ .spec.host }}')/registration/myapp.iot
   ```
 
 * Add credentials for a device
@@ -41,22 +56,26 @@
   ```
   PWD_HASH=$(echo -n "hono-secret" | openssl dgst -binary -sha512 | base64 | tr -d '\n')
   
-  curl --insecure -X POST -i -H 'Content-Type: application/json' --data-binary '{"device-id": "4711","type": "hashed-password","auth-id": "sensor1","secrets": [{"hash-function" : "sha-512","pwd-hash":"'$PWD_HASH'"}]}' https://$(oc get routes device-registry --template='{{ .spec.host }}')/credentials/enmasse-infra.managed
+  curl --insecure -X POST -i -H 'Content-Type: application/json' --data-binary '{"device-id": "4711","type": "hashed-password","auth-id": "sensor1","secrets": [{"hash-function" : "sha-512","pwd-hash":"'$PWD_HASH'"}]}' https://$(oc get routes device-registry --template='{{ .spec.host }}')/credentials/myapp.iot
   ```
 
 * Start a telemetry consumer
 
+In Hono project run
+
   ```
-  oc get addressspace managed -o jsonpath={.status.endpointStatuses[?\(@.name==\'messaging\'\)].cert} | base64 --decode > target/config/hono-demo-certs-jar/tls.crt
-  
   cd cli
-  mvn spring-boot:run -Drun.arguments=--hono.client.host=$(oc get addressspace managed -o jsonpath={.status.endpointStatuses[?\(@.name==\'messaging\'\)].externalHost}),--hono.client.port=443,--hono.client.username=consumer,--hono.client.password=foobar,--tenant.id=enmasse-infra.managed,--hono.client.trustStorePath=target/config/hono-demo-certs-jar/tls.crt
+
+  oc project myapp
+  oc get addressspace iot -o jsonpath={.status.endpointStatuses[?\(@.name==\'messaging\'\)].cert} | base64 --decode > target/config/hono-demo-certs-jar/tls.crt
+
+  mvn spring-boot:run -Drun.arguments=--hono.client.host=$(oc get addressspace iot -o jsonpath={.status.endpointStatuses[?\(@.name==\'messaging\'\)].externalHost}),--hono.client.port=443,--hono.client.username=consumer,--hono.client.password=foobar,--tenant.id=myapp.iot,--hono.client.trustStorePath=target/config/hono-demo-certs-jar/tls.crt
   ```
 
 * Send telemetry message using HTTP
 
   ```
-  curl --insecure -X POST -i -u sensor1@enmasse-infra.managed:hono-secret -H 'Content-Type: application/json' --data-binary '{"temp": 5}' https://$(oc get route iot-http-adapter --template='{{.spec.host}}')/telemetry
+  curl --insecure -X POST -i -u sensor1@myapp.iot:hono-secret -H 'Content-Type: application/json' --data-binary '{"temp": 5}' https://$(oc get route iot-http-adapter --template='{{.spec.host}}')/telemetry
   ```
 
 * Send telemetry message using MQTT
@@ -64,7 +83,7 @@
   This is an example using NodePort, so you need to know your cluster IP and use in the command
 
   ```
-  mosquitto_pub -h ${cluster.ip} -p 31883 -u 'sensor1@enmasse-infra.managed' -P hono-secret -t telemetry -m '{"temp": 5}'
+  mosquitto_pub -h ${cluster.ip} -p 31883 -u 'sensor1@myapp.iot' -P hono-secret -t telemetry -m '{"temp": 5}'
   ```
 
   In the future, we'll provide a proper examples based on the Openshift route with TLS and remove NodePort.
@@ -75,7 +94,7 @@
 * Create a new context:
 
   ```
-  hat context create my-iot-1 --default-tenant enmasse-infra.managed https://$(oc get routes device-registry --template='{{ .spec.host }}')
+  hat context create myapp1 --default-tenant myapp.iot https://$(oc get routes device-registry --template='{{ .spec.host }}')
   ```
 
 * Register a new device
diff --git a/iot/examples/iot-project-managed.yaml b/iot/examples/iot-project-managed.yaml
index dc43628a1..2abdb9df2 100644
--- a/iot/examples/iot-project-managed.yaml
+++ b/iot/examples/iot-project-managed.yaml
@@ -1,24 +1,8 @@
----
 kind: IoTProject
 apiVersion: iot.enmasse.io/v1alpha1
 metadata:
-  name: managed
+  name: iot
 spec:
   downstreamStrategy:
     managedStrategy:
-      addressSpaceName: managed
----
-kind: MessagingUser
-apiVersion: user.enmasse.io/v1beta1
-metadata:
-  name: managed.consumer
-spec:
-  username: consumer
-  authentication:
-    type: password
-    password: Zm9vYmFy # <- foobar
-  authorization:
-  - addresses:  [ "telemetry/my-iot-1.managed", "telemetry/my-iot-1.managed/*", "event/my-iot-1.managed", "event/my-iot-1.managed/*" ]
-    operations: [ "recv" ]
-  - addresses:  [ "command/my-iot-1.managed", "command/my-iot-1.managed/*" ]
-    operations: [ "send", "recv" ]
+      addressSpaceName: iot
diff --git a/iot/examples/iot-project-provided.yaml b/iot/examples/iot-project-provided.yaml
deleted file mode 100644
index 30d76e7dd..000000000
--- a/iot/examples/iot-project-provided.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
----
-kind: IoTProject
-apiVersion: iot.enmasse.io/v1alpha1
-metadata:
-  name: default
-spec:
-  downstreamStrategy:
-    providedStrategy:
-      namespace: hono
-      addressSpaceName: default
-      username: http
-      password: http-secret
-  
\ No newline at end of file
diff --git a/iot/examples/iot-user.yaml b/iot/examples/iot-user.yaml
index 9c4f83270..580e262ef 100644
--- a/iot/examples/iot-user.yaml
+++ b/iot/examples/iot-user.yaml
@@ -1,14 +1,14 @@
 kind: MessagingUser
 apiVersion: user.enmasse.io/v1beta1
 metadata:
-  name: managed.consumer
+  name: iot.consumer
 spec:
   username: consumer
   authentication:
     type: password
     password: Zm9vYmFy # <- foobar
   authorization:
-  - addresses:  [ "telemetry/enmasse-infra.managed", "telemetry/enmasse-infra.managed/*", "event/enmasse-infra.managed", "event/enmasse-infra.managed/*" ]
+  - addresses:  [ "telemetry/myapp.iot", "telemetry/myapp.iot/*", "event/myapp.iot", "event/myapp.iot/*" ]
     operations: [ "recv" ]
-  - addresses:  [ "command/enmasse-infra.managed", "command/enmasse-infra.managed/*" ]
-    operations: [ "send", "recv" ]
\ No newline at end of file
+  - addresses:  [ "command/myapp.iot", "command/myapp.iot/*" ]
+    operations: [ "send", "recv" ]
diff --git a/iot/iot-tenant-service/Dockerfile b/iot/iot-tenant-service/Dockerfile
new file mode 100644
index 000000000..55827e4ef
--- /dev/null
+++ b/iot/iot-tenant-service/Dockerfile
@@ -0,0 +1,10 @@
+FROM enmasseproject/java-base:8-11
+
+ARG version
+ARG maven_version
+ARG commit
+ENV VERSION=${version} COMMIT=${commit} MAVEN_VERSION=${maven_version}
+
+ADD target/iot-tenant-service-${MAVEN_VERSION}.jar /iot-tenant-service.jar
+
+CMD ["/opt/run-java/launch_java.sh", "/iot-tenant-service.jar"]
diff --git a/iot/tenant-service/Makefile b/iot/iot-tenant-service/Makefile
similarity index 100%
rename from iot/tenant-service/Makefile
rename to iot/iot-tenant-service/Makefile
diff --git a/iot/tenant-service/pom.xml b/iot/iot-tenant-service/pom.xml
similarity index 98%
rename from iot/tenant-service/pom.xml
rename to iot/iot-tenant-service/pom.xml
index 59445abc5..df8ecf70a 100644
--- a/iot/tenant-service/pom.xml
+++ b/iot/iot-tenant-service/pom.xml
@@ -11,7 +11,7 @@
     <version>0.27-SNAPSHOT</version>
   </parent>
 
-  <artifactId>tenant-service</artifactId>
+  <artifactId>iot-tenant-service</artifactId>
 
   <properties>
     <!--  Hono requires 3.5.4 -->
diff --git a/iot/tenant-service/src/main/java/io/enmasse/iot/model/IoTProjects.java b/iot/iot-tenant-service/src/main/java/io/enmasse/iot/model/IoTProjects.java
similarity index 100%
rename from iot/tenant-service/src/main/java/io/enmasse/iot/model/IoTProjects.java
rename to iot/iot-tenant-service/src/main/java/io/enmasse/iot/model/IoTProjects.java
diff --git a/iot/tenant-service/src/main/java/io/enmasse/iot/tenant/Application.java b/iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/Application.java
similarity index 100%
rename from iot/tenant-service/src/main/java/io/enmasse/iot/tenant/Application.java
rename to iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/Application.java
diff --git a/iot/tenant-service/src/main/java/io/enmasse/iot/tenant/config/AmqpEndpointConfiguration.java b/iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/config/AmqpEndpointConfiguration.java
similarity index 100%
rename from iot/tenant-service/src/main/java/io/enmasse/iot/tenant/config/AmqpEndpointConfiguration.java
rename to iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/config/AmqpEndpointConfiguration.java
diff --git a/iot/tenant-service/src/main/java/io/enmasse/iot/tenant/config/ApplicationConfiguration.java b/iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/config/ApplicationConfiguration.java
similarity index 100%
rename from iot/tenant-service/src/main/java/io/enmasse/iot/tenant/config/ApplicationConfiguration.java
rename to iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/config/ApplicationConfiguration.java
diff --git a/iot/tenant-service/src/main/java/io/enmasse/iot/tenant/config/AuthenticationConfiguration.java b/iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/config/AuthenticationConfiguration.java
similarity index 100%
rename from iot/tenant-service/src/main/java/io/enmasse/iot/tenant/config/AuthenticationConfiguration.java
rename to iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/config/AuthenticationConfiguration.java
diff --git a/iot/tenant-service/src/main/java/io/enmasse/iot/tenant/config/HttpEndpointConfiguration.java b/iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/config/HttpEndpointConfiguration.java
similarity index 100%
rename from iot/tenant-service/src/main/java/io/enmasse/iot/tenant/config/HttpEndpointConfiguration.java
rename to iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/config/HttpEndpointConfiguration.java
diff --git a/iot/tenant-service/src/main/java/io/enmasse/iot/tenant/config/MetricsConfiguration.java b/iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/config/MetricsConfiguration.java
similarity index 100%
rename from iot/tenant-service/src/main/java/io/enmasse/iot/tenant/config/MetricsConfiguration.java
rename to iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/config/MetricsConfiguration.java
diff --git a/iot/tenant-service/src/main/java/io/enmasse/iot/tenant/config/ServiceConfiguration.java b/iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/config/ServiceConfiguration.java
similarity index 100%
rename from iot/tenant-service/src/main/java/io/enmasse/iot/tenant/config/ServiceConfiguration.java
rename to iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/config/ServiceConfiguration.java
diff --git a/iot/tenant-service/src/main/java/io/enmasse/iot/tenant/config/VertxConfiguration.java b/iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/config/VertxConfiguration.java
similarity index 100%
rename from iot/tenant-service/src/main/java/io/enmasse/iot/tenant/config/VertxConfiguration.java
rename to iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/config/VertxConfiguration.java
diff --git a/iot/tenant-service/src/main/java/io/enmasse/iot/tenant/impl/AbstractKubernetesTenantService.java b/iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/impl/AbstractKubernetesTenantService.java
similarity index 100%
rename from iot/tenant-service/src/main/java/io/enmasse/iot/tenant/impl/AbstractKubernetesTenantService.java
rename to iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/impl/AbstractKubernetesTenantService.java
diff --git a/iot/tenant-service/src/main/java/io/enmasse/iot/tenant/impl/TenantAmqpService.java b/iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/impl/TenantAmqpService.java
similarity index 100%
rename from iot/tenant-service/src/main/java/io/enmasse/iot/tenant/impl/TenantAmqpService.java
rename to iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/impl/TenantAmqpService.java
diff --git a/iot/tenant-service/src/main/java/io/enmasse/iot/tenant/impl/TenantRestService.java b/iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/impl/TenantRestService.java
similarity index 100%
rename from iot/tenant-service/src/main/java/io/enmasse/iot/tenant/impl/TenantRestService.java
rename to iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/impl/TenantRestService.java
diff --git a/iot/tenant-service/src/main/java/io/enmasse/iot/tenant/impl/TenantServiceConfigProperties.java b/iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/impl/TenantServiceConfigProperties.java
similarity index 100%
rename from iot/tenant-service/src/main/java/io/enmasse/iot/tenant/impl/TenantServiceConfigProperties.java
rename to iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/impl/TenantServiceConfigProperties.java
diff --git a/iot/tenant-service/src/main/java/io/enmasse/iot/tenant/impl/TenantServiceImpl.java b/iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/impl/TenantServiceImpl.java
similarity index 100%
rename from iot/tenant-service/src/main/java/io/enmasse/iot/tenant/impl/TenantServiceImpl.java
rename to iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/impl/TenantServiceImpl.java
diff --git a/iot/tenant-service/src/main/java/io/enmasse/iot/tenant/utils/HonoUtils.java b/iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/utils/HonoUtils.java
similarity index 100%
rename from iot/tenant-service/src/main/java/io/enmasse/iot/tenant/utils/HonoUtils.java
rename to iot/iot-tenant-service/src/main/java/io/enmasse/iot/tenant/utils/HonoUtils.java
diff --git a/iot/tenant-service/src/main/resources/banner.txt b/iot/iot-tenant-service/src/main/resources/banner.txt
similarity index 100%
rename from iot/tenant-service/src/main/resources/banner.txt
rename to iot/iot-tenant-service/src/main/resources/banner.txt
diff --git a/iot/tenant-service/src/main/resources/config/application-dev.yml b/iot/iot-tenant-service/src/main/resources/config/application-dev.yml
similarity index 100%
rename from iot/tenant-service/src/main/resources/config/application-dev.yml
rename to iot/iot-tenant-service/src/main/resources/config/application-dev.yml
diff --git a/iot/tenant-service/src/main/resources/config/application-prod.yml b/iot/iot-tenant-service/src/main/resources/config/application-prod.yml
similarity index 100%
rename from iot/tenant-service/src/main/resources/config/application-prod.yml
rename to iot/iot-tenant-service/src/main/resources/config/application-prod.yml
diff --git a/iot/tenant-service/src/main/resources/config/application.yml b/iot/iot-tenant-service/src/main/resources/config/application.yml
similarity index 100%
rename from iot/tenant-service/src/main/resources/config/application.yml
rename to iot/iot-tenant-service/src/main/resources/config/application.yml
diff --git a/iot/tenant-service/src/main/resources/logback-spring.xml b/iot/iot-tenant-service/src/main/resources/logback-spring.xml
similarity index 100%
rename from iot/tenant-service/src/main/resources/logback-spring.xml
rename to iot/iot-tenant-service/src/main/resources/logback-spring.xml
diff --git a/iot/tenant-service/src/test/java/io/enmasse/iot/tenant/TestApplication.java b/iot/iot-tenant-service/src/test/java/io/enmasse/iot/tenant/TestApplication.java
similarity index 100%
rename from iot/tenant-service/src/test/java/io/enmasse/iot/tenant/TestApplication.java
rename to iot/iot-tenant-service/src/test/java/io/enmasse/iot/tenant/TestApplication.java
diff --git a/iot/pom.xml b/iot/pom.xml
index c0d25398b..75b1e6a44 100644
--- a/iot/pom.xml
+++ b/iot/pom.xml
@@ -21,7 +21,7 @@
   </properties>
 
   <modules>
-    <module>tenant-service</module>
+    <module>iot-tenant-service</module>
   </modules>
 
   <dependencyManagement>
diff --git a/iot/tenant-service/Dockerfile b/iot/tenant-service/Dockerfile
deleted file mode 100644
index 5fb221c87..000000000
--- a/iot/tenant-service/Dockerfile
+++ /dev/null
@@ -1,9 +0,0 @@
-FROM enmasseproject/java-base:8-11
-
-ARG version
-ARG commit
-ENV VERSION=${version} COMMIT=${commit}
-
-ADD target/tenant-service-${VERSION}.jar /tenant-service.jar
-
-CMD ["/opt/run-java/launch_java.sh", "/tenant-service.jar"]
diff --git a/k8s-api/src/main/java/io/enmasse/k8s/api/KubeSchemaApi.java b/k8s-api/src/main/java/io/enmasse/k8s/api/KubeSchemaApi.java
index 73e18f337..1fea4b3da 100644
--- a/k8s-api/src/main/java/io/enmasse/k8s/api/KubeSchemaApi.java
+++ b/k8s-api/src/main/java/io/enmasse/k8s/api/KubeSchemaApi.java
@@ -5,7 +5,12 @@
 package io.enmasse.k8s.api;
 
 import io.enmasse.address.model.*;
-import io.enmasse.admin.model.v1.*;
+import io.enmasse.admin.model.AddressPlan;
+import io.enmasse.admin.model.AddressSpacePlan;
+import io.enmasse.admin.model.v1.AdminCrd;
+import io.enmasse.admin.model.v1.BrokeredInfraConfig;
+import io.enmasse.admin.model.v1.InfraConfig;
+import io.enmasse.admin.model.v1.StandardInfraConfig;
 import io.enmasse.config.AnnotationKeys;
 import io.fabric8.openshift.client.NamespacedOpenShiftClient;
 import org.slf4j.Logger;
@@ -31,8 +36,8 @@ public class KubeSchemaApi implements SchemaApi {
             .withZone(ZoneId.of("UTC"));
     private final boolean isOpenShift;
 
-    private volatile List<AddressSpacePlan> currentAddressSpacePlans;
-    private volatile List<AddressPlan> currentAddressPlans;
+    private volatile List<io.enmasse.admin.model.v1.AddressSpacePlan> currentAddressSpacePlans;
+    private volatile List<io.enmasse.admin.model.v1.AddressPlan> currentAddressPlans;
     private volatile List<StandardInfraConfig> currentStandardInfraConfigs;
     private volatile List<BrokeredInfraConfig> currentBrokeredInfraConfigs;
 
@@ -60,7 +65,7 @@ public class KubeSchemaApi implements SchemaApi {
     }
 
     private void validateAddressSpacePlan(AddressSpacePlan addressSpacePlan, List<AddressPlan> addressPlans, List<String> infraTemplateNames) {
-        String definedBy = addressSpacePlan.getAnnotation(AnnotationKeys.DEFINED_BY);
+        String definedBy = addressSpacePlan.getMetadata().getAnnotations().get(AnnotationKeys.DEFINED_BY);
         if (!infraTemplateNames.contains(definedBy)) {
             String error = "Error validating address space plan " + addressSpacePlan.getMetadata().getName() + ": missing infra config definition " + definedBy + ", found: " + infraTemplateNames;
             log.warn(error);
@@ -76,10 +81,7 @@ public class KubeSchemaApi implements SchemaApi {
             throw new SchemaValidationException(error);
         }
 
-        Set<String> resources = addressSpacePlan.getResources().stream()
-                .map(ResourceAllowance::getName)
-                .collect(Collectors.toSet());
-
+        Set<String> resources = addressSpacePlan.getResourceLimits().keySet();
         List<String> required = "brokered".equals(addressSpacePlan.getAddressSpaceType()) ? Arrays.asList("broker") : Arrays.asList("broker", "router", "aggregate");
         if (!resources.containsAll(required)) {
             Set<String> missing = new HashSet<>(required);
@@ -101,7 +103,7 @@ public class KubeSchemaApi implements SchemaApi {
                 requiredResources.add("broker");
             }
         }
-        Set<String> resourcesUsed = addressPlan.getRequiredResources().stream().map(ResourceRequest::getName).collect(Collectors.toSet());
+        Set<String> resourcesUsed = addressPlan.getResources().keySet();
 
         if (!resourcesUsed.containsAll(requiredResources)) {
             Set<String> missing = new HashSet<>(requiredResources);
@@ -283,7 +285,7 @@ public class KubeSchemaApi implements SchemaApi {
         }
     }
 
-    Schema assembleSchema(List<AddressSpacePlan> addressSpacePlans, List<AddressPlan> addressPlans, List<StandardInfraConfig> standardInfraConfigs, List<BrokeredInfraConfig> brokeredInfraConfigs) {
+    Schema assembleSchema(List<io.enmasse.admin.model.v1.AddressSpacePlan> addressSpacePlans, List<io.enmasse.admin.model.v1.AddressPlan> addressPlans, List<StandardInfraConfig> standardInfraConfigs, List<BrokeredInfraConfig> brokeredInfraConfigs) {
         if (addressSpacePlans == null || addressPlans == null || brokeredInfraConfigs == null || standardInfraConfigs == null) {
             return null;
         }
@@ -295,7 +297,7 @@ public class KubeSchemaApi implements SchemaApi {
         }
 
         List<AddressSpacePlan> validAddressSpacePlans = new ArrayList<>();
-        for (AddressSpacePlan addressSpacePlan : addressSpacePlans) {
+        for (io.enmasse.admin.model.v1.AddressSpacePlan addressSpacePlan : addressSpacePlans) {
             List<AddressPlan> plansForAddressSpacePlan = new ArrayList<>();
             for (String addressPlanName : addressSpacePlan.getAddressPlans()) {
                 try {
diff --git a/keycloak-user-api/src/main/java/io/enmasse/user/keycloak/KeycloakUserApi.java b/keycloak-user-api/src/main/java/io/enmasse/user/keycloak/KeycloakUserApi.java
index 648df5b05..832342013 100644
--- a/keycloak-user-api/src/main/java/io/enmasse/user/keycloak/KeycloakUserApi.java
+++ b/keycloak-user-api/src/main/java/io/enmasse/user/keycloak/KeycloakUserApi.java
@@ -16,15 +16,7 @@ import java.nio.charset.StandardCharsets;
 import java.time.Clock;
 import java.time.Duration;
 import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.Set;
+import java.util.*;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
@@ -325,7 +317,7 @@ public class KeycloakUserApi implements UserApi {
     /**
      * Create the set of desired groups.
      *
-     * @param user The user to create the groups for.
+     * @param authorization The authorization rule list to create the groups for.
      * @return A set of groups.
      */
     static Set<String> createDesiredGroupsSet(final List<UserAuthorization> authorization) {
@@ -338,11 +330,9 @@ public class KeycloakUserApi implements UserApi {
 
                 switch (operation) {
                     case manage:
-                        desiredGroups.add("manage_#");
                         desiredGroups.add("manage");
                         break;
                     case view:
-                        desiredGroups.add("monitor_#");
                         desiredGroups.add("monitor");
                         break;
                     default:
@@ -351,8 +341,6 @@ public class KeycloakUserApi implements UserApi {
                                 String groupName = operation.name() + "_" + encodePart(address);
                                 // normal name
                                 desiredGroups.add(groupName);
-                                // brokered name ( the set will remove duplicates for us)
-                                desiredGroups.add(groupName.replace("*", "#"));
                             }
                         }
                         break;
@@ -582,8 +570,8 @@ public class KeycloakUserApi implements UserApi {
 
     static User buildUser(UserRepresentation userRep, List<GroupRepresentation> groupReps) {
         log.debug("Creating user from user representation id {}, name {} part of groups {}", userRep.getId(), userRep.getUsername(), userRep.getGroups());
-        Map<String, Set<Operation>> operationsByAddress = new HashMap<>();
-        Set<Operation> globalOperations = new HashSet<>();
+        Map<String, Set<Operation>> operationsByAddress = new LinkedHashMap<>();
+        Set<Operation> globalOperations = new LinkedHashSet<>();
         for (GroupRepresentation groupRep : groupReps) {
             log.debug("Checking group id {} name {}", groupRep.getId(), groupRep.getName());
             if (groupRep.getName().startsWith("manage")) {
@@ -594,15 +582,15 @@ public class KeycloakUserApi implements UserApi {
                 String[] parts = groupRep.getName().split("_");
                 Operation operation = Operation.valueOf(parts[0]);
                 String address = decodePart(parts[1]);
-                operationsByAddress.computeIfAbsent(address, k -> new HashSet<>())
+                operationsByAddress.computeIfAbsent(address, k -> new LinkedHashSet<>())
                         .add(operation);
             }
         }
 
-        Map<Set<Operation>, Set<String>> operations = new HashMap<>();
+        Map<Set<Operation>, Set<String>> operations = new LinkedHashMap<>();
         for (Map.Entry<String, Set<Operation>> byAddressEntry : operationsByAddress.entrySet()) {
             if (!operations.containsKey(byAddressEntry.getValue())) {
-                operations.put(byAddressEntry.getValue(), new HashSet<>());
+                operations.put(byAddressEntry.getValue(), new LinkedHashSet<>());
             }
             operations.get(byAddressEntry.getValue()).add(byAddressEntry.getKey());
         }
diff --git a/pom.xml b/pom.xml
index 085eb756f..1dbb3b504 100644
--- a/pom.xml
+++ b/pom.xml
@@ -59,9 +59,10 @@
         <commons-collections.version>3.2.2</commons-collections.version>
         <guava.version>25.0-jre</guava.version>
         <hamcrest.version>1.3</hamcrest.version>
-        <junit.jupiter.version>5.3.1</junit.jupiter.version>
-        <junit.platform.runner.version>1.1.0</junit.platform.runner.version>
-        <junit.platform.launcher.version>1.3.0</junit.platform.launcher.version>
+        <junit.jupiter.version>5.4.0</junit.jupiter.version>
+        <junit.platform.runner.version>1.4.0</junit.platform.runner.version>
+        <junit.platform.launcher.version>1.4.0</junit.platform.launcher.version>
+        <junit.platform.surefire.provider.version>1.3.2</junit.platform.surefire.provider.version>
         <artemis.version>2.6.4</artemis.version>
         <ngwebdriver.version>1.1.4</ngwebdriver.version>
         <paho.version>1.2.0</paho.version>
@@ -89,7 +90,7 @@
         <maven-checkstyle-plugin.version>3.0.0</maven-checkstyle-plugin.version>
         <maven-compiler-plugin.version>3.8.0</maven-compiler-plugin.version>
         <maven-shade-plugin.version>3.1.0</maven-shade-plugin.version>
-        <maven-surefire-plugin.version>2.19.1</maven-surefire-plugin.version>
+        <maven-surefire-plugin.version>2.22.1</maven-surefire-plugin.version>
         <maven-site-plugin.version>3.5.1</maven-site-plugin.version>
         <maven-project-info-reports-plugin.version>2.9</maven-project-info-reports-plugin.version>
         <maven-enforcer-plugin.version>3.0.0-M2</maven-enforcer-plugin.version>
@@ -840,7 +841,7 @@
                     <dependency>
                         <groupId>org.junit.platform</groupId>
                         <artifactId>junit-platform-surefire-provider</artifactId>
-                        <version>${junit.platform.runner.version}</version>
+                        <version>${junit.platform.surefire.provider.version}</version>
                     </dependency>
                 </dependencies>
             </plugin>
diff --git a/router/Dockerfile b/router/Dockerfile
index dca656f9d..e3931db22 100644
--- a/router/Dockerfile
+++ b/router/Dockerfile
@@ -1,4 +1,4 @@
-FROM enmasseproject/qdrouterd-base:1.5-rc2
+FROM enmasseproject/qdrouterd-base:1.5-DISPATCH-1273
 ARG version
 ARG maven_version
 ARG commit
diff --git a/service-broker/src/main/java/io/enmasse/osb/api/ServiceMapping.java b/service-broker/src/main/java/io/enmasse/osb/api/ServiceMapping.java
index de872ea63..d72f659c6 100644
--- a/service-broker/src/main/java/io/enmasse/osb/api/ServiceMapping.java
+++ b/service-broker/src/main/java/io/enmasse/osb/api/ServiceMapping.java
@@ -8,7 +8,7 @@ import com.fasterxml.jackson.module.jsonSchema.types.ObjectSchema;
 import com.fasterxml.jackson.module.jsonSchema.types.StringSchema;
 import io.enmasse.address.model.AddressSpaceType;
 import io.enmasse.address.model.Schema;
-import io.enmasse.admin.model.v1.AddressSpacePlan;
+import io.enmasse.admin.model.AddressSpacePlan;
 import io.enmasse.osb.api.catalog.InputParameters;
 import io.enmasse.osb.api.catalog.Plan;
 import io.enmasse.osb.api.catalog.Schemas;
diff --git a/standard-controller/src/main/java/io/enmasse/controller/standard/AddressController.java b/standard-controller/src/main/java/io/enmasse/controller/standard/AddressController.java
index d3b4b290a..8b24f4655 100644
--- a/standard-controller/src/main/java/io/enmasse/controller/standard/AddressController.java
+++ b/standard-controller/src/main/java/io/enmasse/controller/standard/AddressController.java
@@ -5,7 +5,10 @@
 package io.enmasse.controller.standard;
 
 import io.enmasse.address.model.*;
-import io.enmasse.admin.model.v1.*;
+import io.enmasse.admin.model.AddressPlan;
+import io.enmasse.admin.model.AddressSpacePlan;
+import io.enmasse.admin.model.v1.StandardInfraConfig;
+import io.enmasse.admin.model.v1.StandardInfraConfigBuilder;
 import io.enmasse.config.AnnotationKeys;
 import io.enmasse.k8s.api.*;
 import io.enmasse.metrics.api.*;
@@ -239,9 +242,9 @@ public class AddressController implements Watcher<Address> {
                         if (address != null) {
                             AddressPlan plan = addressResolver.getPlan(address);
                             int brokerNeeded = 0;
-                            for (ResourceRequest resourceRequest : plan.getRequiredResources()) {
-                                if (resourceRequest.getName().equals("broker")) {
-                                    brokerNeeded = (int) resourceRequest.getCredit();
+                            for (Map.Entry<String, Double> resourceRequest : plan.getResources().entrySet()) {
+                                if (resourceRequest.getKey().equals("broker")) {
+                                    brokerNeeded = resourceRequest.getValue().intValue();
                                     break;
                                 }
                             }
@@ -448,8 +451,8 @@ public class AddressController implements Watcher<Address> {
     }
 
     private boolean isPooled(AddressPlan plan) {
-        for (ResourceRequest request : plan.getRequiredResources()) {
-            if ("broker".equals(request.getName()) && request.getCredit() < 1.0) {
+        for (Map.Entry<String, Double> request : plan.getResources().entrySet()) {
+            if ("broker".equals(request.getKey()) && request.getValue() < 1.0) {
                 return true;
             }
         }
diff --git a/standard-controller/src/main/java/io/enmasse/controller/standard/AddressProvisioner.java b/standard-controller/src/main/java/io/enmasse/controller/standard/AddressProvisioner.java
index 4d652384b..3ea9ac7c1 100644
--- a/standard-controller/src/main/java/io/enmasse/controller/standard/AddressProvisioner.java
+++ b/standard-controller/src/main/java/io/enmasse/controller/standard/AddressProvisioner.java
@@ -16,7 +16,9 @@ import java.util.stream.Collectors;
 import java.util.zip.CRC32;
 
 import io.enmasse.address.model.*;
-import io.enmasse.admin.model.v1.*;
+import io.enmasse.admin.model.AddressPlan;
+import io.enmasse.admin.model.AddressSpacePlan;
+import io.enmasse.admin.model.v1.StandardInfraConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -64,7 +66,7 @@ public class AddressProvisioner {
         AddressType addressType = addressResolver.getType(address);
         AddressPlan addressPlan = addressResolver.getPlan(addressType, address);
 
-        for (ResourceRequest resourceRequest : addressPlan.getRequiredResources()) {
+        for (Map.Entry<String, Double> resourceRequest : addressPlan.getResources().entrySet()) {
             if ("subscription".equals(address.getSpec().getType())) {
                 if (address.getStatus().getBrokerStatuses().isEmpty() && address.getAnnotation(AnnotationKeys.BROKER_ID) == null) {
                     log.warn("Unexpected pooled address without cluster id: " + address.getSpec().getAddress());
@@ -74,16 +76,16 @@ public class AddressProvisioner {
                 if (!address.getStatus().getBrokerStatuses().isEmpty()) {
                     for (BrokerStatus status : address.getStatus().getBrokerStatuses()) {
                         if (BrokerState.Active.equals(status.getState())) {
-                            addToUsage(usageMap, status.getContainerId(), "subscription", resourceRequest.getCredit());
+                            addToUsage(usageMap, status.getContainerId(), "subscription", resourceRequest.getValue());
                         }
                     }
                 } else {
-                    addToUsage(usageMap, instanceId, "subscription", resourceRequest.getCredit());
+                    addToUsage(usageMap, instanceId, "subscription", resourceRequest.getValue());
                 }
-            } else if (resourceRequest.getName().equals("router")) {
-                addToUsage(usageMap, "all", "router", resourceRequest.getCredit());
+            } else if (resourceRequest.getKey().equals("router")) {
+                addToUsage(usageMap, "all", "router", resourceRequest.getValue());
 
-            } else if (resourceRequest.getName().equals("broker") && resourceRequest.getCredit() < 1) {
+            } else if (resourceRequest.getKey().equals("broker") && resourceRequest.getValue() < 1) {
                 if (address.getStatus().getBrokerStatuses().isEmpty() && address.getAnnotation(AnnotationKeys.CLUSTER_ID) == null) {
                     log.warn("Unexpected pooled address without cluster id: " + address.getSpec().getAddress());
                     return;
@@ -91,20 +93,20 @@ public class AddressProvisioner {
                 if (!address.getStatus().getBrokerStatuses().isEmpty()) {
                     for (BrokerStatus status : address.getStatus().getBrokerStatuses()) {
                         if (BrokerState.Active.equals(status.getState())) {
-                            addToUsage(usageMap, status.getClusterId(), "broker", resourceRequest.getCredit());
+                            addToUsage(usageMap, status.getClusterId(), "broker", resourceRequest.getValue());
                         }
                     }
                 } else {
-                    addToUsage(usageMap, address.getAnnotation(AnnotationKeys.CLUSTER_ID), "broker", resourceRequest.getCredit());
+                    addToUsage(usageMap, address.getAnnotation(AnnotationKeys.CLUSTER_ID), "broker", resourceRequest.getValue());
                 }
 
-            } else if (resourceRequest.getName().equals("broker")) {
+            } else if (resourceRequest.getKey().equals("broker")) {
                 if (address.getStatus().getBrokerStatuses().isEmpty()) {
-                    addToUsage(usageMap, getShardedClusterId(address), "broker", resourceRequest.getCredit());
+                    addToUsage(usageMap, getShardedClusterId(address), "broker", resourceRequest.getValue());
                 } else {
                     for (BrokerStatus status : address.getStatus().getBrokerStatuses()) {
                         if (BrokerState.Active.equals(status.getState())) {
-                            addToUsage(usageMap, status.getClusterId(), "broker", resourceRequest.getCredit());
+                            addToUsage(usageMap, status.getClusterId(), "broker", resourceRequest.getValue());
                         }
                     }
                 }
@@ -121,7 +123,7 @@ public class AddressProvisioner {
 
     public Map<String, Map<String, UsageInfo>> checkQuota(Map<String, Map<String, UsageInfo>> usageMap, Set<Address> pending, Set<Address> all) {
         Map<String, Map<String, UsageInfo>> newUsageMap = usageMap;
-        Map<String, Double> limits = computeLimits();
+        Map<String, Double> limits = addressSpacePlan.getResourceLimits();
 
         Set<Address> pendingSubscriptionsWithConfiguredTopics = filterSubscriptionsWithConfiguredTopics(pending, all);
         Set<Address> pendingSubscriptionsWithPendingTopics = filterSubscriptionsWithPendingTopics(pending, all);
@@ -207,15 +209,15 @@ public class AddressProvisioner {
         return null;
     }
 
-    private boolean scheduleSubscription(Address subscription, Address topic, Map<String, UsageInfo> brokerUsage, Map<String, UsageInfo> subscriptionUsage, ResourceRequest requested) {
+    private boolean scheduleSubscription(Address subscription, Address topic, Map<String, UsageInfo> brokerUsage, Map<String, UsageInfo> subscriptionUsage, double requestedValue) {
         String cluster = topic.getAnnotation(AnnotationKeys.CLUSTER_ID);
         String broker = topic.getAnnotation(AnnotationKeys.BROKER_ID);
 
         AddressPlan topicPlan = addressResolver.getPlan(topic);
         boolean isPooled = false;
 
-        for (ResourceRequest resourceRequest : topicPlan.getRequiredResources()) {
-            if ("broker".equals(resourceRequest.getName()) && resourceRequest.getCredit() < 1) {
+        for (Map.Entry<String, Double> resourceRequest : topicPlan.getResources().entrySet()) {
+            if ("broker".equals(resourceRequest.getKey()) && resourceRequest.getValue() < 1) {
                 isPooled = true;
                 break;
             }
@@ -229,8 +231,8 @@ public class AddressProvisioner {
 
         if (isPooled) {
             UsageInfo usageInfo = subscriptionUsage.computeIfAbsent(broker, k -> new UsageInfo());
-            if (usageInfo.getUsed()+requested.getCredit() <= 1) {
-                usageInfo.addUsed(requested.getCredit());
+            if (usageInfo.getUsed() + requestedValue <= 1) {
+                usageInfo.addUsed(requestedValue);
 
                 // TODO: Remove after releasing 0.26.0
                 subscription.putAnnotation(AnnotationKeys.BROKER_ID, broker);
@@ -258,13 +260,13 @@ public class AddressProvisioner {
             }
             for (BrokerInfo brokerInfo : shardedBrokers) {
                 UsageInfo usageInfo = subscriptionUsage.computeIfAbsent(brokerInfo.getBrokerId(), k -> new UsageInfo());
-                if (brokerInfo.getCredit() + requested.getCredit() <= 1) {
+                if (brokerInfo.getCredit() + requestedValue <= 1) {
                     // TODO: Remove after releasing 0.26.0
                     subscription.putAnnotation(AnnotationKeys.BROKER_ID, brokerInfo.getBrokerId());
                     BrokerStatus brokerStatus = new BrokerStatus(cluster, brokerInfo.getBrokerId());
                     brokerStatus.setState(BrokerState.Active);
                     subscription.getStatus().setBrokerStatuses(Collections.singletonList(brokerStatus));
-                    usageInfo.addUsed(requested.getCredit());
+                    usageInfo.addUsed(requestedValue);
                     break;
                 }
             }
@@ -278,29 +280,29 @@ public class AddressProvisioner {
 
         Map<String, Map<String, UsageInfo>> needed = copyUsageMap(usage);
 
-        for (ResourceRequest resourceRequest : addressPlan.getRequiredResources()) {
-            String resourceName = resourceRequest.getName();
+        for (Map.Entry<String, Double> resourceRequest : addressPlan.getResources().entrySet()) {
+            String resourceName = resourceRequest.getKey();
             Map<String, UsageInfo> resourceUsage = needed.computeIfAbsent(resourceName, k -> new HashMap<>());
             if ("router".equals(resourceName)) {
                 UsageInfo info = resourceUsage.computeIfAbsent("all", k -> new UsageInfo());
-                info.addUsed(resourceRequest.getCredit());
+                info.addUsed(resourceRequest.getValue());
             } else if ("broker".equals(resourceName)) {
                 if ("subscription".equals(address.getSpec().getType())) {
                     Map<String, UsageInfo> subscriptionUsage = needed.computeIfAbsent("subscription", k -> new HashMap<>());
                     if (address.getSpec().getTopic() != null ) {
                         Address topic = findAddress(address.getSpec().getTopic(), addressSet);
-                        if (!scheduleSubscription(address, topic, resourceUsage, subscriptionUsage, resourceRequest)) {
+                        if (!scheduleSubscription(address, topic, resourceUsage, subscriptionUsage, resourceRequest.getValue())) {
                             log.warn("Unable to find broker for scheduling subscription: {}", address);
                             return null;
                         }
                     } else {
                         log.warn("No topic specified for subscription {}", address.getSpec().getAddress());
                     }
-                } else if (resourceRequest.getCredit() < 1) {
-                    boolean scheduled = scheduleAddress(resourceUsage, address, resourceRequest.getCredit());
+                } else if (resourceRequest.getValue() < 1) {
+                    boolean scheduled = scheduleAddress(resourceUsage, address, resourceRequest.getValue());
                     if (!scheduled) {
                         allocateBroker(resourceUsage, pooledClusterIdPrefix);
-                        if (!scheduleAddress(resourceUsage, address, resourceRequest.getCredit())) {
+                        if (!scheduleAddress(resourceUsage, address, resourceRequest.getValue())) {
                             log.warn("Unable to find broker for scheduling {}", address);
                             return null;
                         }
@@ -312,7 +314,7 @@ public class AddressProvisioner {
                     }
                     String clusterId = getShardedClusterId(address);
                     UsageInfo info = new UsageInfo();
-                    info.addUsed(resourceRequest.getCredit());
+                    info.addUsed(resourceRequest.getValue());
                     resourceUsage.put(clusterId, info);
 
                     address.putAnnotation(AnnotationKeys.CLUSTER_ID, clusterId);
@@ -331,9 +333,9 @@ public class AddressProvisioner {
                     brokers.sort(Comparator.comparingDouble(BrokerInfo::getCredit));
 
                     for (BrokerInfo brokerInfo : brokers) {
-                        if (brokerInfo.getCredit() + resourceRequest.getCredit() < 1) {
+                        if (brokerInfo.getCredit() + resourceRequest.getValue() < 1) {
                             UsageInfo used = resourceUsage.get(brokerInfo.getBrokerId());
-                            used.addUsed(resourceRequest.getCredit());
+                            used.addUsed(resourceRequest.getValue());
                             break;
                         } else {
                             log.warn("not enough credit on {} for {} ",brokerInfo.getBrokerId(), address.getSpec().getAddress() );
@@ -346,7 +348,7 @@ public class AddressProvisioner {
 
             double resourceNeeded = sumNeeded(resourceUsage);
             if (resourceNeeded > limits.get(resourceName)) {
-                log.info("address {} for {} needed {} > limit {}", address.getSpec().getAddress(), resourceName, resourceNeeded, limits.get(resourceRequest.getName()));
+                log.info("address {} for {} needed {} > limit {}", address.getSpec().getAddress(), resourceName, resourceNeeded, limits.get(resourceRequest.getKey()));
                 address.getStatus().appendMessage("Quota exceeded");
                 return null;
             }
@@ -432,14 +434,6 @@ public class AddressProvisioner {
         return "broker-sharded-" + Long.toHexString(crc32.getValue()) + "-" + infraUuid;
     }
 
-    private Map<String, Double> computeLimits() {
-        Map<String, Double> limits = new HashMap<>();
-        for (ResourceAllowance allowance : addressSpacePlan.getResources()) {
-            limits.put(allowance.getName(), allowance.getMax());
-        }
-        return limits;
-    }
-
     public void provisionResources(RouterCluster router, List<BrokerCluster> existingClusters, Map<String, Map<String, UsageInfo>> neededMap, Set<Address> addressSet) {
 
         Map<String, Address> addressByClusterId = new HashMap<>();
diff --git a/standard-controller/src/main/java/io/enmasse/controller/standard/BrokerSetGenerator.java b/standard-controller/src/main/java/io/enmasse/controller/standard/BrokerSetGenerator.java
index 38db796c9..1d8fa2cb5 100644
--- a/standard-controller/src/main/java/io/enmasse/controller/standard/BrokerSetGenerator.java
+++ b/standard-controller/src/main/java/io/enmasse/controller/standard/BrokerSetGenerator.java
@@ -5,7 +5,7 @@
 package io.enmasse.controller.standard;
 
 import io.enmasse.address.model.Address;
-import io.enmasse.admin.model.v1.AddressPlan;
+import io.enmasse.admin.model.AddressPlan;
 import io.enmasse.admin.model.v1.StandardInfraConfig;
 
 /**
diff --git a/standard-controller/src/main/java/io/enmasse/controller/standard/TemplateBrokerSetGenerator.java b/standard-controller/src/main/java/io/enmasse/controller/standard/TemplateBrokerSetGenerator.java
index 21f45b76a..32984e412 100644
--- a/standard-controller/src/main/java/io/enmasse/controller/standard/TemplateBrokerSetGenerator.java
+++ b/standard-controller/src/main/java/io/enmasse/controller/standard/TemplateBrokerSetGenerator.java
@@ -7,8 +7,7 @@ package io.enmasse.controller.standard;
 
 import com.fasterxml.jackson.databind.ObjectMapper;
 import io.enmasse.address.model.*;
-import io.enmasse.admin.model.v1.AddressPlan;
-import io.enmasse.admin.model.v1.ResourceRequest;
+import io.enmasse.admin.model.AddressPlan;
 import io.enmasse.admin.model.v1.StandardInfraConfig;
 import io.enmasse.config.AnnotationKeys;
 import io.fabric8.kubernetes.api.model.HasMetadata;
@@ -35,8 +34,8 @@ public class TemplateBrokerSetGenerator implements BrokerSetGenerator {
     private boolean isShardedTopic(AddressPlan addressPlan) {
         if (addressPlan.getAddressType().equals("topic")) {
             boolean isSharded = true;
-            for (ResourceRequest resourceRequest : addressPlan.getRequiredResources()) {
-                if (resourceRequest.getName().equals("broker") && resourceRequest.getCredit() < 1) {
+            for (Map.Entry<String, Double> resourceRequest : addressPlan.getResources().entrySet()) {
+                if (resourceRequest.getKey().equals("broker") && resourceRequest.getValue() < 1) {
                     isSharded = false;
                     break;
                 }
diff --git a/templates/Makefile b/templates/Makefile
index 33bf5ab91..3c3f58ad8 100644
--- a/templates/Makefile
+++ b/templates/Makefile
@@ -18,7 +18,7 @@ IOT_MODULES=\
 	iot/tenant \
 	iot/tenant-service-s2i \
 
-MODULES=crds address-space-controller example-roles example-plans api-server api-service grafana none-authservice prometheus service-broker cluster-service-broker standard-authservice alertmanager kube-state-metrics service-monitors prometheus-rules $(IOT_MODULES)
+MODULES=crds address-space-controller example-roles example-plans api-server api-service grafana none-authservice prometheus service-broker cluster-service-broker standard-authservice alertmanager kube-state-metrics service-monitors prometheus-rules $(IOT_MODULES) csv
 
 prepare:
 	mkdir -p $(PACKAGE_INSTALL_DIR)
@@ -33,7 +33,7 @@ replace_images: prepare
 		cp -r $$i $(BUILDDIR)/replaced/$$D/ ; \
 	done
 	for i in `find $(BUILDDIR)/replaced -name "*.yaml"`; do \
-		cat $$i | $(IMAGE_ENV) envsubst '$${ENMASSE_VERSION},$${IMAGE_PULL_POLICY},$${ADDRESS_SPACE_CONTROLLER_IMAGE},$${STANDARD_CONTROLLER_IMAGE},$${ROUTER_IMAGE},$${NONE_AUTHSERVICE_IMAGE},$${KEYCLOAK_IMAGE},$${KEYCLOAK_CONTROLLER_IMAGE},$${KEYCLOAK_PLUGIN_IMAGE},$${TOPIC_FORWARDER_IMAGE},$${ARTEMIS_IMAGE},$${ARTEMIS_PLUGIN_IMAGE},$${ROUTER_METRICS_IMAGE},$${SUBSERV_IMAGE},$${API_SERVER_IMAGE},$${SERVICE_BROKER_IMAGE},$${AGENT_IMAGE},$${MQTT_GATEWAY_IMAGE},$${MQTT_LWT_IMAGE},$${PROMETHEUS_IMAGE},$${ALERTMANAGER_IMAGE},$${GRAFANA_IMAGE},$${KUBE_STATE_METRICS_IMAGE},$${OAUTH_PROXY_IMAGE},$${HONO_IMAGE}' > $$i.tmp; \
+		cat $$i | $(IMAGE_ENV) envsubst '$${MAVEN_VERSION},$${ENMASSE_VERSION},$${IMAGE_PULL_POLICY},$${ADDRESS_SPACE_CONTROLLER_IMAGE},$${STANDARD_CONTROLLER_IMAGE},$${ROUTER_IMAGE},$${NONE_AUTHSERVICE_IMAGE},$${KEYCLOAK_IMAGE},$${KEYCLOAK_CONTROLLER_IMAGE},$${KEYCLOAK_PLUGIN_IMAGE},$${TOPIC_FORWARDER_IMAGE},$${ARTEMIS_IMAGE},$${ARTEMIS_PLUGIN_IMAGE},$${ROUTER_METRICS_IMAGE},$${SUBSERV_IMAGE},$${API_SERVER_IMAGE},$${SERVICE_BROKER_IMAGE},$${AGENT_IMAGE},$${MQTT_GATEWAY_IMAGE},$${MQTT_LWT_IMAGE},$${PROMETHEUS_IMAGE},$${ALERTMANAGER_IMAGE},$${GRAFANA_IMAGE},$${KUBE_STATE_METRICS_IMAGE},$${OAUTH_PROXY_IMAGE},$${HONO_IMAGE}' > $$i.tmp; \
 		mv $$i.tmp $$i; \
 	done
 
@@ -81,7 +81,14 @@ $(IOT_BUNDLE): replace_images
 		mv $$i.tmp $$i; \
 	done
 
-install: ansible_install component_install $(ENMASSE_BUNDLE) $(MONITORING_BUNDLE) $(IOT_BUNDLE)
+OLM=$(PACKAGE_INSTALL_DIR)/olm/enmasse
+$(OLM): replace_images
+	mkdir -p $(OLM)
+	for i in crds csv; do \
+		cp $(BUILDDIR)/replaced/$$i/*.yaml $(OLM)/; \
+	done
+
+install: ansible_install component_install $(ENMASSE_BUNDLE) $(MONITORING_BUNDLE) $(IOT_BUNDLE) $(OLM)
 	cp -r $(PACKAGE_DOCS_DIR) $(INSTALLDIR)/docs
 
 package: prepare install
@@ -89,4 +96,4 @@ package: prepare install
 
 coverage:
 
-.PHONY: prepare package clean $(ENMASSE_BUNDLE) $(MONITORING_BUNDLE) $(IOT_BUNDLE)
+.PHONY: prepare package clean $(ENMASSE_BUNDLE) $(MONITORING_BUNDLE) $(IOT_BUNDLE) $(OLM)
diff --git a/templates/crds/010-CustomResourceDefinition-address-plan.yaml b/templates/crds/addressplans.crd.yaml
similarity index 61%
rename from templates/crds/010-CustomResourceDefinition-address-plan.yaml
rename to templates/crds/addressplans.crd.yaml
index 4bacfe315..223e01291 100644
--- a/templates/crds/010-CustomResourceDefinition-address-plan.yaml
+++ b/templates/crds/addressplans.crd.yaml
@@ -6,7 +6,7 @@ metadata:
     app: enmasse
 spec:
   group: admin.enmasse.io
-  version: v1beta1
+  version: v1beta2
   scope: Namespaced
   names:
     kind: AddressPlan
@@ -14,15 +14,41 @@ spec:
     singular: addressplan
     plural: addressplans
   versions:
-    - name: v1beta1
+    - name: v1beta2
       served: true
       storage: true
+    - name: v1beta1
+      served: true
+      storage: false
     - name: v1alpha1
       served: true
       storage: false
   validation:
     openAPIV3Schema:
       properties:
+        spec:
+          type: object
+          required:
+            - addressType
+            - resources
+          properties:
+            displayName:
+              type: string
+            displayOrder:
+              type: integer
+            shortDescription:
+              type: string
+            longDescription:
+              type: string
+            addressType:
+              type: string
+            resources:
+              type: object
+              properties:
+                router:
+                  type: number
+                broker:
+                  type: number
         displayName:
           type: string
         displayOrder:
diff --git a/templates/crds/010-CustomResourceDefinition-address-space-plan.yaml b/templates/crds/addressspaceplans.crd.yaml
similarity index 56%
rename from templates/crds/010-CustomResourceDefinition-address-space-plan.yaml
rename to templates/crds/addressspaceplans.crd.yaml
index 41065fff4..8fd568fd5 100644
--- a/templates/crds/010-CustomResourceDefinition-address-space-plan.yaml
+++ b/templates/crds/addressspaceplans.crd.yaml
@@ -6,7 +6,7 @@ metadata:
     app: enmasse
 spec:
   group: admin.enmasse.io
-  version: v1beta1
+  version: v1beta2
   scope: Namespaced
   names:
     kind: AddressSpacePlan
@@ -14,15 +14,48 @@ spec:
     singular: addressspaceplan
     plural: addressspaceplans
   versions:
-    - name: v1beta1
+    - name: v1beta2
       served: true
       storage: true
+    - name: v1beta1
+      served: true
+      storage: false
     - name: v1alpha1
       served: true
       storage: false
   validation:
     openAPIV3Schema:
       properties:
+        spec:
+          type: object
+          required:
+            - addressSpaceType
+            - resourceLimits 
+            - addressPlans
+          properties:
+            displayName:
+              type: string
+            displayOrder:
+              type: integer
+            shortDescription:
+              type: string
+            longDescription:
+              type: string
+            addressSpaceType:
+              type: string
+            resourceLimits:
+              type: object
+              properties:
+                aggregate:
+                  type: number
+                router:
+                  type: number
+                broker:
+                  type: number
+            addressPlans:
+              type: array
+              items:
+                type: string
         displayName:
           type: string
         displayOrder:
diff --git a/templates/crds/010-CustomResourceDefinition-brokered-infra-config.yaml b/templates/crds/brokeredinfraconfigs.crd.yaml
similarity index 100%
rename from templates/crds/010-CustomResourceDefinition-brokered-infra-config.yaml
rename to templates/crds/brokeredinfraconfigs.crd.yaml
diff --git a/templates/crds/010-CustomResourceDefinition-standard-infra-config.yaml b/templates/crds/standardinfraconfigs.crd.yaml
similarity index 100%
rename from templates/crds/010-CustomResourceDefinition-standard-infra-config.yaml
rename to templates/crds/standardinfraconfigs.crd.yaml
diff --git a/templates/csv/enmasse.clusterserviceversion.yaml b/templates/csv/enmasse.clusterserviceversion.yaml
new file mode 100644
index 000000000..40bd2744f
--- /dev/null
+++ b/templates/csv/enmasse.clusterserviceversion.yaml
@@ -0,0 +1,614 @@
+#! validate-crd: deploy/chart/templates/0000_30_02-clusterserviceversion.crd.yaml
+#! parse-kind: ClusterServiceVersion
+apiVersion: operators.coreos.com/v1alpha1
+kind: ClusterServiceVersion
+metadata:
+  name: enmasse.${MAVEN_VERSION}
+  namespace: placeholder
+  annotations:
+    categories: "Streaming & Messaging"
+    certified: "false"
+    description: EnMasse provides a self-service messaging platform with a uniform interface to manage different messaging infrastructure.
+    containerImage: ${ADDRESS_SPACE_CONTROLLER_IMAGE}
+    createdAt: 2019-02-19T00:00:00Z
+    support: EnMasse
+    alm-examples: '[{"apiVersion":"admin.enmasse.io/v1beta1","kind":"StandardInfraConfig","metadata":{"name":"my-standard-infra"},"spec":{"version":"${ENMASSE_VERSION}","broker":{"resources":{"storage":"5Gi"},"addressFullPolicy":"DROP"},"router":{"linkCapacity":50}}},{"apiVersion":"admin.enmasse.io/v1beta1","kind":"BrokeredInfraConfig","metadata":{"name":"my-brokered-infra"},"spec":{"version":"${ENMASSE_VERSION}","broker":{"resources":{"memory":"4Gi"}}}},{"apiVersion":"admin.enmasse.io/v1beta2","kind":"AddressPlan","metadata":{"name":"small-standard-queue"},"spec":{"addressType":"queue","shortDescription":"Small Queue","resources":{"router":0.01,"broker":0.1}}},{"apiVersion":"admin.enmasse.io/v1beta2","kind":"AddressSpacePlan","metadata":{"name":"standard-small","annotations":{"enmasse.io/defined-by":"my-standard-infra"}},"addressSpaceType":"standard","shortDescription":"Small Address Space Plan","resourceLimits":{"router":1,"broker":2,"aggregate":2},"addressPlans":["small-standard-queue"]}]'
+spec:
+  maturity: beta
+  displayName: EnMasse
+  description: >
+    EnMasse provides a self-service messaging platform on Kubernetes and OpenShift with a uniform interface to manage different messaging infrastructure.
+    See our [website](http://enmasse.io) for more details about the project.
+
+    ### Supported features
+
+    * ** Built-in authentication and authorization ** - Use the built-in or plug in your own authentication service for authentication and authorization of messaging clients.
+
+    * ** Self-service messaging for applications ** - The service admin deploys and manages the messaging infrastructure, while applications can request messaging resources without caring about the messaging infrastructure.
+
+    * ** Supports a wide variety of messaging patterns ** - Choose between JMS-style messaging with strict guarantees, or messaging that supports a larger number of connections and higher throughput.
+
+    ### Documentation
+    
+    Documentation for the latest releases can be found on our [website](http://enmasse.io)
+
+    ### Getting help
+
+    * [EnMasse mailing list](https://www.redhat.com/mailman/listinfo/enmasse)
+    * [#enmasse IRC channel on Freenode](https://webchat.freenode.net/?randomnick=1&channels=enmasse&uio=d4)
+
+    ### Contributing
+
+    If you've got some great ideas and use cases for EnMasse, we would love to hear them!
+
+    * Raise issues on [GitHub](https://github.com/EnMasseProject/enmasse/issues).
+    * Read the [Hacking guide](https://github.com/EnMasseProject/enmasse/blob/master/HACKING.md) for details on how to build EnMasse.
+    * Fix issues by opening Pull Requests
+
+    ### License
+
+    EnMasse is licensed under the [Apache License, Version 2.0](https://github.com/EnMasseProject/enmasse/blob/master/LICENSE) license.
+  version: ${MAVEN_VERSION}
+  keywords: ['messaging', 'amqp', 'iot', 'mqtt']
+  icon:
+    - base64data: PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNzlweCIgaGVpZ2h0PSI3OXB4IiB2aWV3Qm94PSIwIDAgNzkgNzkiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDQyICgzNjc4MSkgLSBodHRwOi8vd3d3LmJvaGVtaWFuY29kaW5nLmNvbS9za2V0Y2ggLS0+CiAgICA8dGl0bGU+dmVyc2lvbnM8L3RpdGxlPgogICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+CiAgICA8ZGVmcz48L2RlZnM+CiAgICA8ZyBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgICAgICA8ZyBpZD0idmVyc2lvbnMiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0zMDguMDAwMDAwLCAtNzIuMDAwMDAwKSI+CiAgICAgICAgICAgIDxlbGxpcHNlIGlkPSJDb21iaW5lZC1TaGFwZS1Db3B5LTIiIGZpbGw9IiMwMDQ5OUUiIGN4PSIzNDcuNSIgY3k9IjExMS41IiByeD0iMjQuNSIgcnk9IjI0LjUiPjwvZWxsaXBzZT4KICAgICAgICAgICAgPHBhdGggZD0iTTMzOSwxMDIuNjkxMDE0IEMzMzksMTAyLjY5MTAxNCAzNDIuNjkwMjE1LDk0LjQxMDUzMjMgMzUwLjIwNTY1MSwxMDAuOTM1OTEyIEwzNTEuMDE1Njk5LDEwMS43NDU5NTkgQzM1MS4wMTU2OTksMTAxLjc0NTk1OSAzNTIuNzI1Nzk4LDEwMy41MDEwNjEgMzUzLjQ0NTg0LDEwMy41MDEwNjEgQzM1NC4xNjU4ODIsMTAzLjUwMTA2MSAzNTQuMjU1ODg3LDEwMy40MTEwNTYgMzU1Ljk2NTk4NiwxMDEuNzAwOTU2IEMzNTcuNjc2MDg2LDk5Ljk5MDg1NjggMzU3LjQwNjA3LDEwMC4wMzU4NTkgMzU5Ljg4MTIxNCw5Ny43ODU3Mjg2IEMzNjIuMzU2MzU4LDk1LjUzNTU5NzcgMzY1LjY3MTUyMSw5My45MzA1MzQ0IDM2NS42NzE1MjEsOTMuOTMwNTM0NCBDMzY1LjY3MTUyMSw5My45MzA1MzQ0IDM2Ny4yOTE2MTUsOTIuOTEwNDE1MSAzNzAuMjYxNzg4LDkyLjE2MDQwMTUgQzM3My4yMzE5Niw5MS40MTAzODc5IDM3Ny40MDk3MzMsOTAuNjUyODEzOSAzODIsOTEuMTcwMzQ0IEMzODIsOTEuMTcwMzQ0IDM4MC4xMzIzOTEsOTIuMjUwNDA2NyAzNzcuOTI3MjYzLDk4Ljk1NTc5NjYgQzM3NS43MjIxMzUsMTA1LjY2MTE4NiAzNzQuNTA3MDY0LDEwNy43MzEzMDcgMzc0LjUwNzA2NCwxMDcuNzMxMzA3IEMzNzQuNTA3MDY0LDEwNy43MzEzMDcgMzcxLjg1MTkxLDExMy4zNTY2MzQgMzY1LjQ2MTUzOCwxMTQuNTcxNzA0IEMzNjUuNDYxNTM4LDExNC41NzE3MDQgMzY4LjY1NjcyNCwxMTguMzk2OTI3IDM3OS45OTczODQsMTE3LjEzNjg1NCBDMzc5Ljk5NzM4NCwxMTcuMTM2ODU0IDM1OC4wODExMDksMTMxLjE3NzY3IDM0OC4yNzA1MzksMTE0Ljg0MTcyIEMzNDguMDQ4OTQ2LDExNC4zNDQyNjEgMzQ1Ljg0OTM5OCwxMTAuMDI1NDUgMzQ1LjMwMDM2NiwxMDguMjExMzA1IEMzNDQuNjEwMjk2LDEwNS45MzEyMDIgMzQ0LjMwOTEzOSwxMDUuMTI1Mzg1IDM0My4yOTAyNzksMTA0LjE2MTA2OSBDMzQwLjc3MDEzMywxMDEuNzc1OTMxIDMzOSwxMDIuNjkxMDE0IDMzOSwxMDIuNjkxMDE0IiBpZD0iRmlsbC0xLUNvcHktNyIgZmlsbD0iIzc1QTBEMyI+PC9wYXRoPgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+
+      mediatype: image/svg+xml
+  maintainers:
+  - name: EnMasse
+    email: enmasse@redhat.com
+  provider:
+    name: EnMasse
+  labels:
+    app: enmasse
+  selector:
+    matchLabels:
+      app: enmasse
+  links:
+  - name: Documentation
+    url: http://enmasse.io/documentation
+  - name: GitHub
+    url: https://github.com/EnMasseProject/enmasse
+
+  installModes:
+  - type: OwnNamespace
+    supported: true
+  - type: SingleNamespace
+    supported: true
+  - type: MultiNamespace
+    supported: false
+  - type: AllNamespaces
+    supported: true
+
+  install:
+    strategy: deployment
+    spec:
+      permissions:
+      - serviceAccountName: address-space-controller
+        rules:
+        - apiGroups: [ "admin.enmasse.io" ]
+          resources: [ "addressplans", "addressspaceplans", "brokeredinfraconfigs", "standardinfraconfigs" ]
+          verbs: [ "get", "list", "watch" ]
+        - apiGroups: [ "" ]
+          resources: [ "pods" ]
+          verbs: [ "get", "list" ]
+        - apiGroups: [ "" ]
+          resources: [ "configmaps" ]
+          verbs: [ "create", "update", "patch", "get", "list", "watch", "delete" ]
+        - apiGroups: [ "" ]
+          resources: [ "events" ]
+          verbs: [ "create", "update", "patch", "get", "list" ]
+        - apiGroups: [ "" ]
+          resources: [ "services", "secrets", "persistentvolumeclaims" ]
+          verbs: [ "create", "update", "patch", "get", "list", "delete" ]
+        - apiGroups: [ "networking.k8s.io", "extensions" ]
+          resources: [ "networkpolicies" ]
+          verbs: [ "create", "update", "patch", "get", "list", "delete" ]
+        - apiGroups: [ "route.openshift.io", "" ]
+          resources: [ "routes", "routes/custom-host", "routes/status" ]
+          verbs: [ "create", "update", "patch", "get", "list", "delete" ]
+        - apiGroups: [ "apps" ]
+          resources: [ "statefulsets", "deployments", "replicasets" ]
+          verbs: [ "create", "update", "patch", "get", "list", "delete" ]
+      - serviceAccountName: address-space-admin
+        rules:
+        - apiGroups: [ "admin.enmasse.io" ]
+          resources: [ "addressplans", "addressspaceplans", "brokeredinfraconfigs", "standardinfraconfigs" ]
+          verbs: [ "get", "list", "watch" ]
+        - apiGroups: [ "" ]
+          resources: [ "pods", "secrets" ]
+          verbs: [ "get", "list", "watch" ]
+        - apiGroups: [ "" ]
+          resources: [ "configmaps" ]
+          verbs: [ "create", "update", "patch", "get", "list", "watch", "delete" ]
+        - apiGroups: [ "" ]
+          resources: [ "events" ]
+          verbs: [ "create", "update", "patch", "get", "list" ]
+        - apiGroups: [ "" ]
+          resources: [ "persistentvolumeclaims", "services" ]
+          verbs: [ "create", "update", "patch", "get", "list", "delete" ]
+        - apiGroups: [ "apps" ]
+          resources: [ "statefulsets", "deployments" ]
+          verbs: [ "create", "update", "patch", "get", "list", "delete" ]
+      - serviceAccountName: api-server
+        rules:
+        - apiGroups: [ "" ]
+          resources: [ "services", "secrets" ]
+          verbs: [ "get", "list", "watch" ]
+        - apiGroups: [ "" ]
+          resources: [ "configmaps" ]
+          verbs: [ "create", "update", "patch", "get", "list", "watch", "delete" ]
+        - apiGroups: [ "admin.enmasse.io" ]
+          resources: [ "addressspaceplans", "addressplans", "standardinfraconfigs", "brokeredinfraconfigs" ]
+          verbs: [ "get", "list", "watch" ]
+      clusterPermissions:
+      - serviceAccountName: api-server
+        rules:
+        - apiGroups: [ "authentication.k8s.io" ]
+          resources: [ "tokenreviews" ]
+          verbs: [ "create" ]
+        - apiGroups: [ "authorization.k8s.io" ]
+          resources: [ "subjectaccessreviews" ]
+          verbs: [ "create" ]
+        - apiGroups: [ "" ]
+          resources: [ "configmaps" ]
+          resourceNames: [ "extension-apiserver-authentication" ]
+          verbs: [ "get" ]
+      deployments:
+      - name: user-api-server
+        spec:
+          replicas: 1
+          selector:
+            matchLabels:
+              app: enmasse
+              component: user-api-server
+          template:
+            metadata:
+              labels:
+                app: enmasse
+                component: user-api-server
+            spec:
+              affinity:
+                nodeAffinity:
+                  preferredDuringSchedulingIgnoredDuringExecution:
+                    - weight: 1
+                      preference:
+                        matchExpressions:
+                          - key: node-role.enmasse.io/operator-infra
+                            operator: In
+                            values:
+                              - "true"
+              containers:
+              - env:
+                - name: JAVA_OPTS
+                  value: -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps
+                - name: CERT_DIR
+                  value: /api-server-cert
+                - name: ENABLE_RBAC
+                  value: "true"
+                - name: APISERVER_CLIENT_CA_CONFIG_NAME
+                  value: extension-apiserver-authentication
+                - name: APISERVER_CLIENT_CA_CONFIG_NAMESPACE
+                  value: kube-system
+                - name: APISERVER_ROUTE_NAME
+                  value: restapi
+                - name: STANDARD_AUTHSERVICE_CONFIG_NAME
+                  value: keycloak-config
+                - name: STANDARD_AUTHSERVICE_CREDENTIALS_SECRET_NAME
+                  value: keycloak-credentials
+                - name: STANDARD_AUTHSERVICE_CERT_SECRET_NAME
+                  value: standard-authservice-cert
+                image: ${API_SERVER_IMAGE}
+                imagePullPolicy: ${IMAGE_PULL_POLICY}
+                livenessProbe:
+                  httpGet:
+                    path: /healthz
+                    port: http
+                    scheme: HTTP
+                  initialDelaySeconds: 30
+                name: api-server
+                ports:
+                - containerPort: 8080
+                  name: http
+                - containerPort: 8443
+                  name: https
+                readinessProbe:
+                  httpGet:
+                    path: /healthz
+                    port: http
+                    scheme: HTTP
+                resources:
+                  limits:
+                    memory: 512Mi
+                  requests:
+                    memory: 512Mi
+                volumeMounts:
+                - mountPath: /api-server-cert
+                  name: apiservice-cert
+                  readOnly: true
+              serviceAccountName: api-server
+      - name: api-server
+        spec:
+          replicas: 1
+          selector:
+            matchLabels:
+              app: enmasse
+              component: api-server
+          template:
+            metadata:
+              labels:
+                app: enmasse
+                component: api-server
+            spec:
+              affinity:
+                nodeAffinity:
+                  preferredDuringSchedulingIgnoredDuringExecution:
+                    - weight: 1
+                      preference:
+                        matchExpressions:
+                          - key: node-role.enmasse.io/operator-infra
+                            operator: In
+                            values:
+                              - "true"
+              containers:
+              - env:
+                - name: JAVA_OPTS
+                  value: -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps
+                - name: CERT_DIR
+                  value: /api-server-cert
+                - name: ENABLE_RBAC
+                  value: "true"
+                - name: APISERVER_CLIENT_CA_CONFIG_NAME
+                  value: extension-apiserver-authentication
+                - name: APISERVER_CLIENT_CA_CONFIG_NAMESPACE
+                  value: kube-system
+                - name: APISERVER_ROUTE_NAME
+                  value: restapi
+                - name: STANDARD_AUTHSERVICE_CONFIG_NAME
+                  value: keycloak-config
+                - name: STANDARD_AUTHSERVICE_CREDENTIALS_SECRET_NAME
+                  value: keycloak-credentials
+                - name: STANDARD_AUTHSERVICE_CERT_SECRET_NAME
+                  value: standard-authservice-cert
+                image: ${API_SERVER_IMAGE}
+                imagePullPolicy: ${IMAGE_PULL_POLICY}
+                livenessProbe:
+                  httpGet:
+                    path: /healthz
+                    port: http
+                    scheme: HTTP
+                  initialDelaySeconds: 30
+                name: api-server
+                ports:
+                - containerPort: 8080
+                  name: http
+                - containerPort: 8443
+                  name: https
+                readinessProbe:
+                  httpGet:
+                    path: /healthz
+                    port: http
+                    scheme: HTTP
+                resources:
+                  limits:
+                    memory: 512Mi
+                  requests:
+                    memory: 512Mi
+                volumeMounts:
+                - mountPath: /api-server-cert
+                  name: apiservice-cert
+                  readOnly: true
+              serviceAccountName: api-server
+      - name: address-space-controller
+        spec:
+          replicas: 1
+          strategy:
+            type: Recreate
+          selector:
+            matchLabels:
+              app: enmasse
+              name: address-space-controller
+          template:
+            metadata:
+              labels:
+                app: enmasse
+                name: address-space-controller
+            spec:
+              affinity:
+                nodeAffinity:
+                  preferredDuringSchedulingIgnoredDuringExecution:
+                    - weight: 1
+                      preference:
+                        matchExpressions:
+                          - key: node-role.enmasse.io/operator-infra
+                            operator: In
+                            values:
+                              - "true"
+              containers:
+              - env:
+                - name: JAVA_OPTS
+                  value: -verbose:gc
+                - name: ENABLE_EVENT_LOGGER
+                  value: "true"
+                - name: EXPOSE_ENDPOINTS_BY_DEFAULT
+                  valueFrom:
+                    configMapKeyRef:
+                      key: exposeEndpointsByDefault
+                      name: address-space-controller-config
+                      optional: true
+                - name: ENVIRONMENT
+                  valueFrom:
+                    configMapKeyRef:
+                      key: environment
+                      name: address-space-controller-config
+                      optional: true
+                - name: TEMPLATE_DIR
+                  value: /templates
+                - name: RESOURCES_DIR
+                  value: /
+                - name: STANDARD_AUTHSERVICE_CONFIG_NAME
+                  value: keycloak-config
+                - name: STANDARD_AUTHSERVICE_CREDENTIALS_SECRET_NAME
+                  value: keycloak-credentials
+                - name: STANDARD_AUTHSERVICE_CERT_SECRET_NAME
+                  value: standard-authservice-cert
+                - name: WILDCARD_ENDPOINT_CERT_SECRET
+                  valueFrom:
+                    configMapKeyRef:
+                      key: wildcardEndpointCertSecret
+                      name: address-space-controller-config
+                      optional: true
+                - name: RESYNC_INTERVAL
+                  valueFrom:
+                    configMapKeyRef:
+                      key: resyncInterval
+                      name: address-space-controller-config
+                      optional: true
+                - name: RECHECK_INTERVAL
+                  valueFrom:
+                    configMapKeyRef:
+                      key: recheckInterval
+                      name: address-space-controller-config
+                      optional: true
+                image: ${ADDRESS_SPACE_CONTROLLER_IMAGE}
+                imagePullPolicy: ${IMAGE_PULL_POLICY}
+                livenessProbe:
+                  httpGet:
+                    path: /healthz
+                    port: http
+                    scheme: HTTP
+                name: address-space-controller
+                ports:
+                - containerPort: 8080
+                  name: http
+                readinessProbe:
+                  httpGet:
+                    path: /healthz
+                    port: http
+                    scheme: HTTP
+                resources:
+                  limits:
+                    memory: 512Mi
+                  requests:
+                    memory: 256Mi
+              serviceAccountName: address-space-controller
+  apiservicedefinitions:
+    owned:
+    - group: enmasse.io
+      version: v1beta1
+      kind: AddressSpace 
+      name: addressspaces
+      displayName: Address Space
+      description: A group of messaging addresses that can be accessed via the same endpoint
+      deploymentName: api-server
+      containerPort: 8443
+      specDescriptors:
+        - description: The address space type.
+          displayName: Type
+          path: type
+          x-descriptors:
+            - 'urn:alm:descriptor:com.tectonic.ui:label'
+        - description: The address space plan.
+          displayName: Plan
+          path: plan
+          x-descriptors:
+            - 'urn:alm:descriptor:com.tectonic.ui:label'
+      statusDescriptors:
+        - description: Address space ready.
+          displayName: Ready
+          path: isReady
+          x-descriptors:
+            - 'urn:alm:descriptor:text'
+    - group: enmasse.io
+      version: v1beta1
+      kind: Address
+      name: addresses
+      displayName: Address
+      description: A messaging address that can be used to send/receive messages to/from
+      deploymentName: api-server
+      containerPort: 8443
+      specDescriptors:
+        - description: The address type.
+          displayName: Type
+          path: type
+          x-descriptors:
+            - 'urn:alm:descriptor:com.tectonic.ui:label'
+        - description: The address plan.
+          displayName: Plan
+          path: plan
+          x-descriptors:
+            - 'urn:alm:descriptor:com.tectonic.ui:label'
+      statusDescriptors:
+        - description: Address ready.
+          displayName: Ready
+          path: isReady
+          x-descriptors:
+            - 'urn:alm:descriptor:text'
+        - description: Address phase
+          displayName: Phase
+          path: phase
+          x-descriptors:
+            - 'urn:alm:descriptor:text'
+    - group: user.enmasse.io
+      version: v1beta1
+      kind: MessagingUser
+      name: messagingusers
+      displayName: Messaging User
+      description: A messaging user that can connect to an Address Space
+      deploymentName: user-api-server
+      containerPort: 8443
+      specDescriptors:
+        - description: The user name.
+          displayName: Username
+          path: username
+          x-descriptors:
+            - 'urn:alm:descriptor:com.tectonic.ui:label'
+        - description: The authentication type
+          displayName: Authentication type
+          path: authentication.type
+          x-descriptors:
+            - 'urn:alm:descriptor:com.tectonic.ui:label'
+        - description: The password
+          displayName: Password
+          path: authentication.password
+          x-descriptors:
+            - 'urn:alm:descriptor:com.tectonic.ui:label'
+  customresourcedefinitions:
+    owned:
+      - group: admin.enmasse.io
+        version: v1beta1
+        kind: StandardInfraConfig
+        name: standardinfraconfigs.admin.enmasse.io
+        displayName: Standard Infra Config
+        description: Infrastructure configuration template for the standard address space type
+        specDescriptors:
+          - description: The minimal number of AMQP router replicas to create.
+            displayName: Minimum Router Replicas
+            path: router.minReplicas
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:podCount'
+          - description: The link capacity of AMQP producer links attached to the routers.
+            displayName: Link capacity
+            path: router.linkCapacity
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The amount of memory to configure for AMQP router pods.
+            displayName: Router Memory
+            path: router.resources.memory
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The amount of memory to configure for message brokers.
+            displayName: Broker Memory
+            path: broker.resources.memory
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The amount of storage to configure for message brokers.
+            displayName: Broker Storage
+            path: broker.resources.storage
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The storage class name to use for message broker persistent volumes.
+            displayName: Broker Storage Class
+            path: broker.storageClassName
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The policy to apply when message queues are full.
+            displayName: Broker Address Full Policy
+            path: broker.addressFullPolicy
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The amount of memory to configure for the admin operator.
+            displayName: Admin Memory
+            path: admin.resources.memory
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+      - group: admin.enmasse.io
+        version: v1beta1
+        kind: BrokeredInfraConfig
+        name: brokeredinfraconfigs.admin.enmasse.io
+        displayName: Brokered Infra Config
+        description: Infrastructure configuration template for the brokered address space type
+        specDescriptors:
+          - description: The amount of memory to configure for message brokers.
+            displayName: Broker Memory
+            path: broker.resources.memory
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The amount of storage to configure for message brokers.
+            displayName: Broker Storage
+            path: broker.resources.storage
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The storage class name to use for message broker persistent volumes.
+            displayName: Broker Storage Class
+            path: broker.storageClassName
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The policy to apply when message queues are full.
+            displayName: Broker Address Full Policy
+            path: broker.addressFullPolicy
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The amount of memory to configure for the admin operator.
+            displayName: Admin Memory
+            path: admin.resources.memory
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+      - group: admin.enmasse.io
+        version: v1beta2
+        kind: AddressSpacePlan
+        name: addressspaceplans.admin.enmasse.io
+        displayName: Address Space Plan
+        description: Plan describing the capabilities and resource limits of a given address space type
+        specDescriptors:
+          - description: The name to be displayed in the console UI.
+            displayName: Display Name
+            path: displayName
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The description to be shown in the console UI.
+            displayName: Short Description
+            path: shortDescription
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The quota for broker resources
+            displayName: Broker Quota
+            path: resourceLimits.broker
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The quota for router resources
+            displayName: Router Quota
+            path: resourceLimits.router
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The aggregate quota for all resources
+            displayName: Aggregate Quota
+            path: resourceLimits.aggregate
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+      - group: admin.enmasse.io
+        version: v1beta2
+        kind: AddressPlan
+        name: addressplans.admin.enmasse.io
+        displayName: Address Plan
+        description: Plan describing the resource usage of a given address type
+        specDescriptors:
+          - description: The name to be displayed in the console UI.
+            displayName: Display Name
+            path: displayName
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The description to be shown in the console UI.
+            displayName: Short Description
+            path: shortDescription
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The broker resource usage.
+            displayName: Broker Usage
+            path: resources.broker
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
+          - description: The router resource usage.
+            displayName: Router Usage
+            path: resources.router
+            x-descriptors:
+              - 'urn:alm:descriptor:com.tectonic.ui:label'
diff --git a/templates/csv/enmasse.package.yaml b/templates/csv/enmasse.package.yaml
new file mode 100644
index 000000000..ed0bc6915
--- /dev/null
+++ b/templates/csv/enmasse.package.yaml
@@ -0,0 +1,4 @@
+packageName: enmasse
+channels:
+- name: alpha
+  currentCSV: enmasse.${MAVEN_VERSION}
diff --git a/templates/example-plans/020-AddressPlan-brokered-queue.yaml b/templates/example-plans/020-AddressPlan-brokered-queue.yaml
index 32237d674..019eb00f2 100644
--- a/templates/example-plans/020-AddressPlan-brokered-queue.yaml
+++ b/templates/example-plans/020-AddressPlan-brokered-queue.yaml
@@ -1,15 +1,14 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: brokered-queue
   labels:
     app: enmasse
-displayName: Brokered Queue
-displayOrder: 0
-shortDescription: Creates a queue on a broker.
-longDescription: Creates a queue on a broker.
-uuid: 69f82df8-0501-11e8-a0a8-507b9def37d9
-addressType: queue
-requiredResources:
-- name: broker
-  credit: 0.0
+spec:
+  displayName: Brokered Queue
+  displayOrder: 0
+  shortDescription: Creates a queue on a broker.
+  longDescription: Creates a queue on a broker.
+  addressType: queue
+  resources:
+    broker: 0.0
diff --git a/templates/example-plans/020-AddressPlan-brokered-topic.yaml b/templates/example-plans/020-AddressPlan-brokered-topic.yaml
index 7e84a6ecf..9bf98ac0a 100644
--- a/templates/example-plans/020-AddressPlan-brokered-topic.yaml
+++ b/templates/example-plans/020-AddressPlan-brokered-topic.yaml
@@ -1,16 +1,14 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: brokered-topic
   labels:
     app: enmasse
-displayName: Brokered Topic
-displayOrder: 0
-shortDescription: Creates a topic on a broker.
-longDescription: Creates a topic on a broker.
-uuid: a991e6fc-0501-11e8-8230-507b9def37d9
-addressType: topic
-requiredResources:
-- name: broker
-  credit: 0.0
-
+spec:
+  displayName: Brokered Topic
+  displayOrder: 0
+  shortDescription: Creates a topic on a broker.
+  longDescription: Creates a topic on a broker.
+  addressType: topic
+  resources:
+    broker: 0.0
diff --git a/templates/example-plans/020-AddressPlan-standard-large-anycast.yaml b/templates/example-plans/020-AddressPlan-standard-large-anycast.yaml
index 0d63c73eb..c28dc3fb0 100644
--- a/templates/example-plans/020-AddressPlan-standard-large-anycast.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-large-anycast.yaml
@@ -1,15 +1,14 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-large-anycast
   labels:
     app: enmasse
-displayName: Large Anycast
-displayOrder: 2
-shortDescription: Creates a large anycast address.
-longDescription: Creates a large anycast address where messages go via a router that does not take ownership of the messages.
-uuid: 1643dbcc-db74-11e8-bbe9-d45ddf138840
-addressType: anycast
-requiredResources:
-- name: router
-  credit: 0.1
+spec:
+  displayName: Large Anycast
+  displayOrder: 2
+  shortDescription: Creates a large anycast address.
+  longDescription: Creates a large anycast address where messages go via a router that does not take ownership of the messages.
+  addressType: anycast
+  resources:
+    router: 0.1
diff --git a/templates/example-plans/020-AddressPlan-standard-large-multicast.yaml b/templates/example-plans/020-AddressPlan-standard-large-multicast.yaml
index 4af5e4b28..19adcae6a 100644
--- a/templates/example-plans/020-AddressPlan-standard-large-multicast.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-large-multicast.yaml
@@ -1,15 +1,14 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-large-multicast
   labels:
     app: enmasse
-displayName: Large Multicast
-displayOrder: 2
-shortDescription: Creates a large multicast address.
-longDescription: Creates a large multicast address where messages go via a router that does not take ownership of the messages.
-uuid: 370d20e8-db74-11e8-8fbb-d45ddf138840
-addressType: multicast
-requiredResources:
-- name: router
-  credit: 0.1
+spec:
+  displayName: Large Multicast
+  displayOrder: 2
+  shortDescription: Creates a large multicast address.
+  longDescription: Creates a large multicast address where messages go via a router that does not take ownership of the messages.
+  addressType: multicast
+  resources:
+    router: 0.1
diff --git a/templates/example-plans/020-AddressPlan-standard-large-queue.yaml b/templates/example-plans/020-AddressPlan-standard-large-queue.yaml
index 3bd62a543..63c94cb12 100644
--- a/templates/example-plans/020-AddressPlan-standard-large-queue.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-large-queue.yaml
@@ -1,18 +1,15 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-large-queue
   labels:
     app: enmasse
-displayName: Large Queue
-displayOrder: 2
-shortDescription: Creates a large queue backed by a dedicated broker.
-longDescription: Creates a large queue backed by a dedicated broker.
-uuid: ae13292a-db70-11e8-8013-d45ddf138840
-addressType: queue
-requiredResources:
-- name: router
-  credit: 0.1
-- name: broker
-  credit: 1.0
-
+spec:
+  displayName: Large Queue
+  displayOrder: 2
+  shortDescription: Creates a large queue backed by a dedicated broker.
+  longDescription: Creates a large queue backed by a dedicated broker.
+  addressType: queue
+  resources:
+    router: 0.1
+    broker: 1.0
diff --git a/templates/example-plans/020-AddressPlan-standard-large-subscription.yaml b/templates/example-plans/020-AddressPlan-standard-large-subscription.yaml
index 7987c3b11..af140de0e 100644
--- a/templates/example-plans/020-AddressPlan-standard-large-subscription.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-large-subscription.yaml
@@ -1,18 +1,15 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-large-subscription
   labels:
     app: enmasse
-displayName: Large Subscription
-displayOrder: 2
-shortDescription: Creates a large durable subscription on a topic.
-longDescription: Creates a large durable subscription on a topic, which is then accessed as a distinct address.
-uuid: a7c5caf2-db73-11e8-a0fe-d45ddf138840
-addressType: subscription
-requiredResources:
-- name: router
-  credit: 0.1
-- name: broker
-  credit: 1.0
-
+spec:
+  displayName: Large Subscription
+  displayOrder: 2
+  shortDescription: Creates a large durable subscription on a topic.
+  longDescription: Creates a large durable subscription on a topic, which is then accessed as a distinct address.
+  addressType: subscription
+  resources:
+    router: 0.1
+    broker: 1.0
diff --git a/templates/example-plans/020-AddressPlan-standard-large-topic.yaml b/templates/example-plans/020-AddressPlan-standard-large-topic.yaml
index da77a77bc..6c50ebebb 100644
--- a/templates/example-plans/020-AddressPlan-standard-large-topic.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-large-topic.yaml
@@ -1,18 +1,15 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-large-topic
   labels:
     app: enmasse
-displayName: Large Topic
-displayOrder: 2
-shortDescription: Creates a large topic backed by a dedicated broker.
-longDescription: Creates a large topic backed by a dedicated broker.
-uuid: 2971f018-db73-11e8-ab81-d45ddf138840
-addressType: topic
-requiredResources:
-- name: router
-  credit: 0.1
-- name: broker
-  credit: 1.0
-
+spec:
+  displayName: Large Topic
+  displayOrder: 2
+  shortDescription: Creates a large topic backed by a dedicated broker.
+  longDescription: Creates a large topic backed by a dedicated broker.
+  addressType: topic
+  resources:
+    router: 0.1
+    broker: 1.0
diff --git a/templates/example-plans/020-AddressPlan-standard-medium-anycast.yaml b/templates/example-plans/020-AddressPlan-standard-medium-anycast.yaml
index 79fe66274..eaf6f07ac 100644
--- a/templates/example-plans/020-AddressPlan-standard-medium-anycast.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-medium-anycast.yaml
@@ -1,15 +1,14 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-medium-anycast
   labels:
     app: enmasse
-displayName: Medium Anycast
-displayOrder: 1
-shortDescription: Creates a medium anycast address.
-longDescription: Creates a medium anycast address where messages go via a router that does not take ownership of the messages.
-uuid: eb62f1d6-db73-11e8-9570-d45ddf138840
-addressType: anycast
-requiredResources:
-- name: router
-  credit: 0.01
+spec:
+  displayName: Medium Anycast
+  displayOrder: 1
+  shortDescription: Creates a medium anycast address.
+  longDescription: Creates a medium anycast address where messages go via a router that does not take ownership of the messages.
+  addressType: anycast
+  resources:
+    router: 0.01
diff --git a/templates/example-plans/020-AddressPlan-standard-medium-multicast.yaml b/templates/example-plans/020-AddressPlan-standard-medium-multicast.yaml
index cf3949715..60e9b862c 100644
--- a/templates/example-plans/020-AddressPlan-standard-medium-multicast.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-medium-multicast.yaml
@@ -1,15 +1,14 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-medium-multicast
   labels:
     app: enmasse
-displayName: Medium Multicast
-displayOrder: 1
-shortDescription: Creates a medium multicast address.
-longDescription: Creates a medium multicast address where messages go via a router that does not take ownership of the messages.
-uuid: 36a53db6-db74-11e8-b24f-d45ddf138840
-addressType: multicast
-requiredResources:
-- name: router
-  credit: 0.01
+spec:
+  displayName: Medium Multicast
+  displayOrder: 1
+  shortDescription: Creates a medium multicast address.
+  longDescription: Creates a medium multicast address where messages go via a router that does not take ownership of the messages.
+  addressType: multicast
+  resources:
+    router: 0.01
diff --git a/templates/example-plans/020-AddressPlan-standard-medium-queue.yaml b/templates/example-plans/020-AddressPlan-standard-medium-queue.yaml
index 9e22097d3..2e14982a6 100644
--- a/templates/example-plans/020-AddressPlan-standard-medium-queue.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-medium-queue.yaml
@@ -1,18 +1,15 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-medium-queue
   labels:
     app: enmasse
-displayName: Medium Queue
-displayOrder: 1
-shortDescription: Creates a medium sized queue sharing underlying broker with other queues.
-longDescription: Creates a medium sized queue sharing underlying broker with other queues.
-uuid: fbc9178e-db6f-11e8-b9eb-d45ddf138840
-addressType: queue
-requiredResources:
-- name: router
-  credit: 0.01
-- name: broker
-  credit: 0.1
-
+spec:
+  displayName: Medium Queue
+  displayOrder: 1
+  shortDescription: Creates a medium sized queue sharing underlying broker with other queues.
+  longDescription: Creates a medium sized queue sharing underlying broker with other queues.
+  addressType: queue
+  resources:
+    router: 0.01
+    broker: 0.1
diff --git a/templates/example-plans/020-AddressPlan-standard-medium-subscription.yaml b/templates/example-plans/020-AddressPlan-standard-medium-subscription.yaml
index 8b81ee7b2..9b6654fc3 100644
--- a/templates/example-plans/020-AddressPlan-standard-medium-subscription.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-medium-subscription.yaml
@@ -1,18 +1,15 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-medium-subscription
   labels:
     app: enmasse
-displayName: Medium Subscription
-displayOrder: 1
-shortDescription: Creates a medium durable subscription on a topic.
-longDescription: Creates a medium durable subscription on a topic, which is then accessed as a distinct address.
-uuid: 8dd4a758-db73-11e8-9971-d45ddf138840
-addressType: subscription
-requiredResources:
-- name: router
-  credit: 0.01
-- name: broker
-  credit: 0.1
-
+spec:
+  displayName: Medium Subscription
+  displayOrder: 1
+  shortDescription: Creates a medium durable subscription on a topic.
+  longDescription: Creates a medium durable subscription on a topic, which is then accessed as a distinct address.
+  addressType: subscription
+  resources:
+    router: 0.01
+    broker: 0.1
diff --git a/templates/example-plans/020-AddressPlan-standard-medium-topic.yaml b/templates/example-plans/020-AddressPlan-standard-medium-topic.yaml
index 7cd9ffc1d..08720ee47 100644
--- a/templates/example-plans/020-AddressPlan-standard-medium-topic.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-medium-topic.yaml
@@ -1,18 +1,15 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-medium-topic
   labels:
     app: enmasse
-displayName: Medium Topic
-displayOrder: 1
-shortDescription: Creates a medium sized topic sharing underlying broker with other topics.
-longDescription: Creates a medium sized topic sharing underlying broker with other topics.
-uuid: 16db0426-db73-11e8-9a10-d45ddf138840
-addressType: topic
-requiredResources:
-- name: router
-  credit: 0.01
-- name: broker
-  credit: 0.1
-
+spec:
+  displayName: Medium Topic
+  displayOrder: 1
+  shortDescription: Creates a medium sized topic sharing underlying broker with other topics.
+  longDescription: Creates a medium sized topic sharing underlying broker with other topics.
+  addressType: topic
+  resources:
+    router: 0.01
+    broker: 0.1
diff --git a/templates/example-plans/020-AddressPlan-standard-small-anycast.yaml b/templates/example-plans/020-AddressPlan-standard-small-anycast.yaml
index b4abd97c1..670a68a8c 100644
--- a/templates/example-plans/020-AddressPlan-standard-small-anycast.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-small-anycast.yaml
@@ -1,15 +1,14 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-small-anycast
   labels:
     app: enmasse
-displayName: Small Anycast
-displayOrder: 0
-shortDescription: Creates a small anycast address.
-longDescription: Creates a small anycast address where messages go via a router that does not take ownership of the messages.
-uuid: eb62f1d6-db73-11e8-9570-d45ddf138840
-addressType: anycast
-requiredResources:
-- name: router
-  credit: 0.001
+spec:
+  displayName: Small Anycast
+  displayOrder: 0
+  shortDescription: Creates a small anycast address.
+  longDescription: Creates a small anycast address where messages go via a router that does not take ownership of the messages.
+  addressType: anycast
+  resources:
+    router: 0.001
diff --git a/templates/example-plans/020-AddressPlan-standard-small-multicast.yaml b/templates/example-plans/020-AddressPlan-standard-small-multicast.yaml
index 72e3ce70f..67ca6c356 100644
--- a/templates/example-plans/020-AddressPlan-standard-small-multicast.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-small-multicast.yaml
@@ -1,15 +1,14 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-small-multicast
   labels:
     app: enmasse
-displayName: Small Multicast
-displayOrder: 0
-shortDescription: Creates a small multicast address.
-longDescription: Creates a small multicast address where messages go via a router that does not take ownership of the messages.
-uuid: 363b10bc-db74-11e8-a528-d45ddf138840
-addressType: multicast
-requiredResources:
-- name: router
-  credit: 0.001
+spec:
+  displayName: Small Multicast
+  displayOrder: 0
+  shortDescription: Creates a small multicast address.
+  longDescription: Creates a small multicast address where messages go via a router that does not take ownership of the messages.
+  addressType: multicast
+  resources:
+    router: 0.001
diff --git a/templates/example-plans/020-AddressPlan-standard-small-queue.yaml b/templates/example-plans/020-AddressPlan-standard-small-queue.yaml
index 3b1ddfcaa..c71423f03 100644
--- a/templates/example-plans/020-AddressPlan-standard-small-queue.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-small-queue.yaml
@@ -1,18 +1,15 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-small-queue
   labels:
     app: enmasse
-displayName: Small Queue
-displayOrder: 0
-shortDescription: Creates a small queue sharing underlying broker with other queues.
-longDescription: Creates a small queue sharing underlying broker with other queues.
-uuid: 0843743a-0503-11e8-91df-507b9def37d9
-addressType: queue
-requiredResources:
-- name: router
-  credit: 0.001
-- name: broker
-  credit: 0.01
-
+spec:
+  displayName: Small Queue
+  displayOrder: 0
+  shortDescription: Creates a small queue sharing underlying broker with other queues.
+  longDescription: Creates a small queue sharing underlying broker with other queues.
+  addressType: queue
+  resources:
+    router: 0.001
+    broker: 0.01
diff --git a/templates/example-plans/020-AddressPlan-standard-small-subscription.yaml b/templates/example-plans/020-AddressPlan-standard-small-subscription.yaml
index 537e12867..23458d75c 100644
--- a/templates/example-plans/020-AddressPlan-standard-small-subscription.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-small-subscription.yaml
@@ -1,18 +1,15 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-small-subscription
   labels:
     app: enmasse
-displayName: Small Subscription
-displayOrder: 0
-shortDescription: Creates a small durable subscription on a topic.
-longDescription: Creates a small durable subscription on a topic, which is then accessed as a distinct address.
-uuid: 6a567f0e-db73-11e8-9e09-d45ddf138840
-addressType: subscription
-requiredResources:
-- name: router
-  credit: 0.001
-- name: broker
-  credit: 0.01
-
+spec:
+  displayName: Small Subscription
+  displayOrder: 0
+  shortDescription: Creates a small durable subscription on a topic.
+  longDescription: Creates a small durable subscription on a topic, which is then accessed as a distinct address.
+  addressType: subscription
+  resources:
+    router: 0.001
+    broker: 0.01
diff --git a/templates/example-plans/020-AddressPlan-standard-small-topic.yaml b/templates/example-plans/020-AddressPlan-standard-small-topic.yaml
index 9b60eff3d..d4593e210 100644
--- a/templates/example-plans/020-AddressPlan-standard-small-topic.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-small-topic.yaml
@@ -1,18 +1,15 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-small-topic
   labels:
     app: enmasse
-displayName: Small Topic
-displayOrder: 0
-shortDescription: Creates a small topic sharing underlying broker with other topics.
-longDescription: Creates a small topic sharing underlying broker with other topics.
-uuid: c10377e0-db72-11e8-91a3-d45ddf138840
-addressType: topic
-requiredResources:
-- name: router
-  credit: 0.001
-- name: broker
-  credit: 0.01
-
+spec:
+  displayName: Small Topic
+  displayOrder: 0
+  shortDescription: Creates a small topic sharing underlying broker with other topics.
+  longDescription: Creates a small topic sharing underlying broker with other topics.
+  addressType: topic
+  resources:
+    router: 0.001
+    broker: 0.01
diff --git a/templates/example-plans/020-AddressPlan-standard-xlarge-queue.yaml b/templates/example-plans/020-AddressPlan-standard-xlarge-queue.yaml
index d5f017006..cbb6814fa 100644
--- a/templates/example-plans/020-AddressPlan-standard-xlarge-queue.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-xlarge-queue.yaml
@@ -1,18 +1,15 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-xlarge-queue
   labels:
     app: enmasse
-displayName: Extra Large Queue
-displayOrder: 3
-shortDescription: Creates an extra large queue backed by 2 brokers.
-longDescription: Creates an extra large queue backed by 2 brokers.
-uuid: 5539846e-db72-11e8-93bc-d45ddf138840
-addressType: queue
-requiredResources:
-- name: router
-  credit: 0.2
-- name: broker
-  credit: 2.0
-
+spec:
+  displayName: Extra Large Queue
+  displayOrder: 3
+  shortDescription: Creates an extra large queue backed by 2 brokers.
+  longDescription: Creates an extra large queue backed by 2 brokers.
+  addressType: queue
+  resources:
+    router: 0.2
+    broker: 2.0
diff --git a/templates/example-plans/020-AddressPlan-standard-xlarge-topic.yaml b/templates/example-plans/020-AddressPlan-standard-xlarge-topic.yaml
index 30ecaa8f9..0544b9f73 100644
--- a/templates/example-plans/020-AddressPlan-standard-xlarge-topic.yaml
+++ b/templates/example-plans/020-AddressPlan-standard-xlarge-topic.yaml
@@ -1,18 +1,15 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressPlan
 metadata:
   name: standard-xlarge-topic
   labels:
     app: enmasse
-displayName: Extra Large Topic
-displayOrder: 3
-shortDescription: Creates an extra large topic backed by 2 brokers.
-longDescription: Creates an extra large topic backed by 2 brokers.
-uuid: 3f9b2990-db73-11e8-9d79-d45ddf138840
-addressType: topic
-requiredResources:
-- name: router
-  credit: 0.2
-- name: broker
-  credit: 2.0
-
+spec:
+  displayName: Extra Large Topic
+  displayOrder: 3
+  shortDescription: Creates an extra large topic backed by 2 brokers.
+  longDescription: Creates an extra large topic backed by 2 brokers.
+  addressType: topic
+  resources:
+    router: 0.2
+    broker: 2.0
diff --git a/templates/example-plans/020-AddressSpacePlan-brokered-single-broker.yaml b/templates/example-plans/020-AddressSpacePlan-brokered-single-broker.yaml
index 1a6d4c068..6077a4f1e 100644
--- a/templates/example-plans/020-AddressSpacePlan-brokered-single-broker.yaml
+++ b/templates/example-plans/020-AddressSpacePlan-brokered-single-broker.yaml
@@ -1,4 +1,4 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressSpacePlan
 metadata:
   name: brokered-single-broker
@@ -6,15 +6,14 @@ metadata:
     app: enmasse
   annotations:
     enmasse.io/defined-by: default
-displayName: Single Broker
-displayOrder: 0
-shortDescription: Single Broker instance
-longDescription: Single Broker plan where you can create an infinite number of queues until the system falls over.
-uuid: 5d5acf5c-0500-11e8-ab55-507b9def37d9
-addressSpaceType: brokered
-resources:
-- name: broker
-  max: 1.9 
-addressPlans:
-- brokered-queue
-- brokered-topic
+spec:
+  displayName: Single Broker
+  displayOrder: 0
+  shortDescription: Single Broker instance
+  longDescription: Single Broker plan where you can create an infinite number of queues until the system falls over.
+  addressSpaceType: brokered
+  resourceLimits:
+    broker: 1.9
+  addressPlans:
+  - brokered-queue
+  - brokered-topic
diff --git a/templates/example-plans/020-AddressSpacePlan-standard-medium.yaml b/templates/example-plans/020-AddressSpacePlan-standard-medium.yaml
index 4c7698308..2a8d75a87 100644
--- a/templates/example-plans/020-AddressSpacePlan-standard-medium.yaml
+++ b/templates/example-plans/020-AddressSpacePlan-standard-medium.yaml
@@ -1,4 +1,4 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressSpacePlan
 metadata:
   name: standard-medium
@@ -6,34 +6,31 @@ metadata:
     app: enmasse
   annotations:
     enmasse.io/defined-by: default
-displayName: Medium
-displayOrder: 0
-shortDescription: Messaging infrastructure based on Apache Qpid Dispatch Router and Apache ActiveMQ Artemis.
-longDescription: Messaging infrastructure based on Apache Qpid Dispatch Router and Apache ActiveMQ Artemis. This plan allows up to 3 routers and 3 broker in total, and is suitable for applications using small address plans and few addresses.
-uuid: 3610533c-db6e-11e8-a390-d45ddf138840
-addressSpaceType: standard
-resources:
-- name: router
-  max: 3.0
-- name: broker
-  max: 3.0
-- name: aggregate
-  max: 6.0
-addressPlans:
-- standard-small-anycast
-- standard-medium-anycast
-- standard-large-anycast
-- standard-small-multicast
-- standard-medium-multicast
-- standard-large-multicast
-- standard-small-queue
-- standard-medium-queue
-- standard-large-queue
-- standard-xlarge-queue
-- standard-small-topic
-- standard-medium-topic
-- standard-large-topic
-- standard-xlarge-topic
-- standard-small-subscription
-- standard-medium-subscription
-- standard-large-subscription
+spec:
+  displayName: Medium
+  displayOrder: 0
+  shortDescription: Messaging infrastructure based on Apache Qpid Dispatch Router and Apache ActiveMQ Artemis.
+  longDescription: Messaging infrastructure based on Apache Qpid Dispatch Router and Apache ActiveMQ Artemis. This plan allows up to 3 routers and 3 broker in total, and is suitable for applications using small address plans and few addresses.
+  addressSpaceType: standard
+  resourceLimits:
+    router: 3.0
+    broker: 3.0
+    aggregate: 6.0
+  addressPlans:
+  - standard-small-anycast
+  - standard-medium-anycast
+  - standard-large-anycast
+  - standard-small-multicast
+  - standard-medium-multicast
+  - standard-large-multicast
+  - standard-small-queue
+  - standard-medium-queue
+  - standard-large-queue
+  - standard-xlarge-queue
+  - standard-small-topic
+  - standard-medium-topic
+  - standard-large-topic
+  - standard-xlarge-topic
+  - standard-small-subscription
+  - standard-medium-subscription
+  - standard-large-subscription
diff --git a/templates/example-plans/020-AddressSpacePlan-standard-small.yaml b/templates/example-plans/020-AddressSpacePlan-standard-small.yaml
index 23c75524a..d6b21aea5 100644
--- a/templates/example-plans/020-AddressSpacePlan-standard-small.yaml
+++ b/templates/example-plans/020-AddressSpacePlan-standard-small.yaml
@@ -1,4 +1,4 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressSpacePlan
 metadata:
   name: standard-small
@@ -6,32 +6,29 @@ metadata:
     app: enmasse
   annotations:
     enmasse.io/defined-by: default-minimal
-displayName: Small
-displayOrder: 0
-shortDescription: Messaging infrastructure based on Apache Qpid Dispatch Router and Apache ActiveMQ Artemis
-longDescription: Messaging infrastructure based on Apache Qpid Dispatch Router and Apache ActiveMQ Artemis. This plan allows up to 1 router and 1 broker in total, and is suitable for small applications using small address plans and few addresses.
-uuid: f084d7f4-0501-11e8-a572-507b9def37d9
-addressSpaceType: standard
-resources:
-- name: router
-  max: 1.0
-- name: broker
-  max: 1.0
-- name: aggregate
-  max: 2.0
-addressPlans:
-- standard-small-anycast
-- standard-medium-anycast
-- standard-large-anycast
-- standard-small-multicast
-- standard-medium-multicast
-- standard-large-multicast
-- standard-small-queue
-- standard-medium-queue
-- standard-large-queue
-- standard-small-topic
-- standard-medium-topic
-- standard-large-topic
-- standard-small-subscription
-- standard-medium-subscription
-- standard-large-subscription
+spec:
+  displayName: Small
+  displayOrder: 0
+  shortDescription: Messaging infrastructure based on Apache Qpid Dispatch Router and Apache ActiveMQ Artemis
+  longDescription: Messaging infrastructure based on Apache Qpid Dispatch Router and Apache ActiveMQ Artemis. This plan allows up to 1 router and 1 broker in total, and is suitable for small applications using small address plans and few addresses.
+  addressSpaceType: standard
+  resourceLimits:
+    router: 1.0
+    broker: 1.0
+    aggregate: 2.0
+  addressPlans:
+  - standard-small-anycast
+  - standard-medium-anycast
+  - standard-large-anycast
+  - standard-small-multicast
+  - standard-medium-multicast
+  - standard-large-multicast
+  - standard-small-queue
+  - standard-medium-queue
+  - standard-large-queue
+  - standard-small-topic
+  - standard-medium-topic
+  - standard-large-topic
+  - standard-small-subscription
+  - standard-medium-subscription
+  - standard-large-subscription
diff --git a/templates/example-plans/020-AddressSpacePlan-standard-unlimited-with-mqtt.yaml b/templates/example-plans/020-AddressSpacePlan-standard-unlimited-with-mqtt.yaml
index 138b19e9c..39ed3c62c 100644
--- a/templates/example-plans/020-AddressSpacePlan-standard-unlimited-with-mqtt.yaml
+++ b/templates/example-plans/020-AddressSpacePlan-standard-unlimited-with-mqtt.yaml
@@ -1,4 +1,4 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressSpacePlan
 metadata:
   name: standard-unlimited-with-mqtt
@@ -6,34 +6,31 @@ metadata:
     app: enmasse
   annotations:
     enmasse.io/defined-by: default-with-mqtt
-displayName: Unlimited With MQTT
-displayOrder: 0
-shortDescription: Messaging infrastructure based on Apache Qpid Dispatch Router and Apache ActiveMQ Artemis and MQTT support.
-longDescription: Messaging infrastructure based on Apache Qpid Dispatch Router and Apache ActiveMQ Artemis and MQTT support. This plan allows an unlimited number of routers (minimum 2) and brokers, and is suitable for applications where you do not want to impose any restrictions.
-uuid: b10bce7c-db6e-11e8-a6b8-d45ddf138840
-addressSpaceType: standard
-resources:
-- name: router
-  max: 10000.0
-- name: broker
-  max: 10000.0
-- name: aggregate
-  max: 10000.0
-addressPlans:
-- standard-small-anycast
-- standard-medium-anycast
-- standard-large-anycast
-- standard-small-multicast
-- standard-medium-multicast
-- standard-large-multicast
-- standard-small-queue
-- standard-medium-queue
-- standard-large-queue
-- standard-xlarge-queue
-- standard-small-topic
-- standard-medium-topic
-- standard-large-topic
-- standard-xlarge-topic
-- standard-small-subscription
-- standard-medium-subscription
-- standard-large-subscription
+spec:
+  displayName: Unlimited With MQTT
+  displayOrder: 0
+  shortDescription: Messaging infrastructure based on Apache Qpid Dispatch Router and Apache ActiveMQ Artemis and MQTT support.
+  longDescription: Messaging infrastructure based on Apache Qpid Dispatch Router and Apache ActiveMQ Artemis and MQTT support. This plan allows an unlimited number of routers (minimum 2) and brokers, and is suitable for applications where you do not want to impose any restrictions.
+  addressSpaceType: standard
+  resourceLimits:
+    router: 10000.0
+    broker: 10000.0
+    aggregate: 10000.0
+  addressPlans:
+  - standard-small-anycast
+  - standard-medium-anycast
+  - standard-large-anycast
+  - standard-small-multicast
+  - standard-medium-multicast
+  - standard-large-multicast
+  - standard-small-queue
+  - standard-medium-queue
+  - standard-large-queue
+  - standard-xlarge-queue
+  - standard-small-topic
+  - standard-medium-topic
+  - standard-large-topic
+  - standard-xlarge-topic
+  - standard-small-subscription
+  - standard-medium-subscription
+  - standard-large-subscription
diff --git a/templates/example-plans/020-AddressSpacePlan-standard-unlimited.yaml b/templates/example-plans/020-AddressSpacePlan-standard-unlimited.yaml
index abb60c6c1..bc142fa31 100644
--- a/templates/example-plans/020-AddressSpacePlan-standard-unlimited.yaml
+++ b/templates/example-plans/020-AddressSpacePlan-standard-unlimited.yaml
@@ -1,4 +1,4 @@
-apiVersion: admin.enmasse.io/v1beta1
+apiVersion: admin.enmasse.io/v1beta2
 kind: AddressSpacePlan
 metadata:
   name: standard-unlimited
@@ -6,34 +6,31 @@ metadata:
     app: enmasse
   annotations:
     enmasse.io/defined-by: default
-displayName: Unlimited
-displayOrder: 0
-shortDescription: Messaging infrastructure based on Apache Qpid Dispatch Router and Apache ActiveMQ Artemis.
-longDescription: Messaging infrastructure based on Apache Qpid Dispatch Router and Apache ActiveMQ Artemis. This plan allows an unlimited number of routers and brokers, and is suitable for applications where you do not want to impose any restrictions.
-uuid: 7669c18e-db6e-11e8-8b65-d45ddf138840
-addressSpaceType: standard
-resources:
-- name: router
-  max: 10000.0
-- name: broker
-  max: 10000.0
-- name: aggregate
-  max: 10000.0
-addressPlans:
-- standard-small-anycast
-- standard-medium-anycast
-- standard-large-anycast
-- standard-small-multicast
-- standard-medium-multicast
-- standard-large-multicast
-- standard-small-queue
-- standard-medium-queue
-- standard-large-queue
-- standard-xlarge-queue
-- standard-small-topic
-- standard-medium-topic
-- standard-large-topic
-- standard-xlarge-topic
-- standard-small-subscription
-- standard-medium-subscription
-- standard-large-subscription
+spec:
+  displayName: Unlimited
+  displayOrder: 0
+  shortDescription: Messaging infrastructure based on Apache Qpid Dispatch Router and Apache ActiveMQ Artemis.
+  longDescription: Messaging infrastructure based on Apache Qpid Dispatch Router and Apache ActiveMQ Artemis. This plan allows an unlimited number of routers and brokers, and is suitable for applications where you do not want to impose any restrictions.
+  addressSpaceType: standard
+  resourceLimits:
+    router: 10000.0
+    broker: 10000.0
+    aggregate: 10000.0
+  addressPlans:
+  - standard-small-anycast
+  - standard-medium-anycast
+  - standard-large-anycast
+  - standard-small-multicast
+  - standard-medium-multicast
+  - standard-large-multicast
+  - standard-small-queue
+  - standard-medium-queue
+  - standard-large-queue
+  - standard-xlarge-queue
+  - standard-small-topic
+  - standard-medium-topic
+  - standard-large-topic
+  - standard-xlarge-topic
+  - standard-small-subscription
+  - standard-medium-subscription
+  - standard-large-subscription
diff --git a/templates/iot/tenant-service-s2i/020-BuildConfig-tenant-service.yaml b/templates/iot/tenant-service-s2i/020-BuildConfig-tenant-service.yaml
index 71d412b79..beca8fd6c 100644
--- a/templates/iot/tenant-service-s2i/020-BuildConfig-tenant-service.yaml
+++ b/templates/iot/tenant-service-s2i/020-BuildConfig-tenant-service.yaml
@@ -22,9 +22,9 @@ spec:
         name: fabric8-s2i-java-custom:java8
       env:
       - name: MAVEN_ARGS_APPEND
-        value: -pl io.enmasse:tenant-service --also-make
+        value: -pl io.enmasse:iot-tenant-service --also-make
       - name: ARTIFACT_DIR
-        value: iot/tenant-service/target
+        value: iot/iot-tenant-service/target
   output:
     to:
       kind: ImageStreamTag


Test patch:
diff --git a/agent/testlib/mock_resource_server.js b/agent/testlib/mock_resource_server.js
index 6f30db2a9..1e487cfba 100644
--- a/agent/testlib/mock_resource_server.js
+++ b/agent/testlib/mock_resource_server.js
@@ -413,14 +413,16 @@ ConfigMapServer.prototype.add_address_plan = function (params) {
     var plan = {
         kind: 'AddressPlan',
         metadata: {name: params.plan_name},
-        displayName: params.display_name,
-        shortDescription: params.shortDescription,
-        longDescription: params.longDescription,
-        displayOrder: params.displayOrder,
-        addressType: params.address_type,
+        spec: {
+            displayName: params.display_name,
+            shortDescription: params.shortDescription,
+            longDescription: params.longDescription,
+            displayOrder: params.displayOrder,
+            addressType: params.address_type,
+        }
     };
-    if (params.required_resources) {
-        plan.requiredResources = params.required_resources;
+    if (params.resources) {
+        plan.resources = params.resources;
     }
     this.add_resource('addressplans', plan);
 };
diff --git a/api-model/src/test/java/io/enmasse/address/model/v1/address/SerializationTest.java b/api-model/src/test/java/io/enmasse/address/model/v1/address/SerializationTest.java
index c882a6aaf..d129266c4 100644
--- a/api-model/src/test/java/io/enmasse/address/model/v1/address/SerializationTest.java
+++ b/api-model/src/test/java/io/enmasse/address/model/v1/address/SerializationTest.java
@@ -304,7 +304,7 @@ public class SerializationTest {
     }
 
     @Test
-    public void testDeserializeAddressSpacePlan() throws IOException {
+    public void testDeserializeDeprecatedAddressSpacePlan() throws IOException {
         String json = "{" +
                 "\"apiVersion\":\"enmasse.io/v1beta1\"," +
                 "\"kind\":\"AddressSpacePlan\"," +
@@ -330,7 +330,6 @@ public class SerializationTest {
         AddressSpacePlan addressSpacePlan = mapper.readValue(json, AddressSpacePlan.class);
         assertThat(addressSpacePlan.getMetadata().getName(), is("myspace"));
         assertThat(addressSpacePlan.getAdditionalProperties().get("displayName"), is("MySpace"));
-        assertFalse(addressSpacePlan.getUuid().isEmpty());
         assertThat(addressSpacePlan.getAddressPlans().size(), is(1));
         assertThat(addressSpacePlan.getAddressPlans().get(0), is("plan1"));
         assertThat(addressSpacePlan.getResources().size(), is(2));
@@ -341,7 +340,43 @@ public class SerializationTest {
     }
 
     @Test
-    public void testDeserializeAddressSpacePlanWithDefaults() throws IOException {
+    public void testDeserializeAddressSpacePlan() throws IOException {
+        String json = "{" +
+                "\"apiVersion\":\"enmasse.io/v1beta2\"," +
+                "\"kind\":\"AddressSpacePlan\"," +
+                "\"metadata\":{" +
+                "  \"name\":\"myspace\"," +
+                "  \"annotations\": {" +
+                "    \"mykey\": \"myvalue\"" +
+                "  }" +
+                "}," +
+                "\"spec\": {" +
+                "  \"displayName\": \"MySpace\"," +
+                "  \"shortDescription\": \"MySpace is cool\"," +
+                "  \"longDescription\": \"MySpace is cool, but not much used anymore\"," +
+                "  \"addressPlans\":[\"plan1\"]," +
+                "  \"addressSpaceType\": \"standard\"," +
+                "  \"resourceLimits\": {" +
+                "    \"router\": 1.0," +
+                "    \"broker\": 0.5" +
+                "  }" +
+                "}}";
+
+        ObjectMapper mapper = new ObjectMapper();
+        AddressSpacePlan addressSpacePlan = mapper.readValue(json, AddressSpacePlan.class);
+        assertThat(addressSpacePlan.getMetadata().getName(), is("myspace"));
+        assertThat(addressSpacePlan.getSpec().getAdditionalProperties().get("displayName"), is("MySpace"));
+        assertThat(addressSpacePlan.getAddressPlans().size(), is(1));
+        assertThat(addressSpacePlan.getAddressPlans().get(0), is("plan1"));
+        assertThat(addressSpacePlan.getResourceLimits().size(), is(2));
+        assertThat(addressSpacePlan.getResourceLimits().get("router"), is(1.0));
+        assertThat(addressSpacePlan.getResourceLimits().get("broker"), is(0.5));
+        assertThat(addressSpacePlan.getMetadata().getAnnotations().size(), is(1));
+        assertThat(addressSpacePlan.getAnnotation("mykey"), is("myvalue"));
+    }
+
+    @Test
+    public void testDeserializeDeprecatedAddressSpacePlanWithDefaults() throws IOException {
         String json = "{" +
                 "\"apiVersion\":\"enmasse.io/v1beta1\"," +
                 "\"kind\":\"AddressSpacePlan\"," +
@@ -359,7 +394,6 @@ public class SerializationTest {
         ObjectMapper mapper = new ObjectMapper();
         AddressSpacePlan addressSpacePlan = mapper.readValue(json, AddressSpacePlan.class);
         assertThat(addressSpacePlan.getMetadata().getName(), is("myspace"));
-        assertNull(addressSpacePlan.getUuid());
         assertThat(addressSpacePlan.getAddressPlans().size(), is(1));
         assertThat(addressSpacePlan.getAddressPlans().get(0), is("plan1"));
         assertThat(addressSpacePlan.getResources().size(), is(2));
@@ -367,6 +401,33 @@ public class SerializationTest {
         assertThat(addressSpacePlan.getResources().get(1).getName(), is("broker"));
     }
 
+    @Test
+    public void testDeserializeAddressSpacePlanWithDefaults() throws IOException {
+        String json = "{" +
+                "\"apiVersion\":\"enmasse.io/v1beta2\"," +
+                "\"kind\":\"AddressSpacePlan\"," +
+                "\"metadata\":{" +
+                "  \"name\":\"myspace\"" +
+                "}," +
+                "\"spec\": {" +
+                "  \"addressPlans\":[\"plan1\"]," +
+                "  \"addressSpaceType\": \"standard\"," +
+                "  \"resourceLimits\": {" +
+                "    \"router\": 1.0," +
+                "    \"broker\": 0.5" +
+                "  }" +
+                "}}";
+
+        ObjectMapper mapper = new ObjectMapper();
+        AddressSpacePlan addressSpacePlan = mapper.readValue(json, AddressSpacePlan.class);
+        assertThat(addressSpacePlan.getMetadata().getName(), is("myspace"));
+        assertThat(addressSpacePlan.getAddressPlans().size(), is(1));
+        assertThat(addressSpacePlan.getAddressPlans().get(0), is("plan1"));
+        assertThat(addressSpacePlan.getResourceLimits().size(), is(2));
+        assertThat(addressSpacePlan.getResourceLimits().get("router"), is(1.0));
+        assertThat(addressSpacePlan.getResourceLimits().get("broker"), is(0.5));
+    }
+
     @Test
     public void testBuilder() {
         AddressSpacePlan plan = new AddressSpacePlanBuilder()
@@ -376,7 +437,6 @@ public class SerializationTest {
                 .endMetadata()
 
                 .withShortDescription("desc")
-                .withUuid("uuid")
                 .withAddressPlans(Arrays.asList("a", "b"))
                 .build();
         assertEquals(2, plan.getAddressPlans().size());
@@ -425,7 +485,7 @@ public class SerializationTest {
     }*/
 
     @Test
-    public void testDeserializeAddressPlan() throws IOException {
+    public void testDeserializeDeprecatedAddressPlan() throws IOException {
         String json = "{" +
                 "\"apiVersion\":\"enmasse.io/v1beta1\"," +
                 "\"kind\":\"AddressPlan\"," +
@@ -447,14 +507,42 @@ public class SerializationTest {
         assertThat(addressPlan.getMetadata().getName(), is("plan1"));
         assertThat(addressPlan.getAdditionalProperties().get("displayName"), is("MyPlan"));
         assertThat(addressPlan.getAddressType(), is("queue"));
-        assertNull(addressPlan.getUuid());
-        assertThat(addressPlan.getRequiredResources().size(), is(2));
-        assertThat(addressPlan.getRequiredResources().get(0).getName(), is("router"));
-        assertThat(addressPlan.getRequiredResources().get(1).getName(), is("broker"));
+        assertThat(addressPlan.getResources().size(), is(2));
+        assertThat(addressPlan.getResources().get("router"), is(0.2));
+        assertThat(addressPlan.getResources().get("broker"), is(0.5));
     }
 
     @Test
-    public void testDeserializeAddressPlanWithDefaults() throws IOException {
+    public void testDeserializeAddressPlan() throws IOException {
+        String json = "{" +
+                "\"apiVersion\":\"enmasse.io/v1beta2\"," +
+                "\"kind\":\"AddressPlan\"," +
+                "\"metadata\":{" +
+                "  \"name\":\"plan1\"" +
+                "}," +
+                "\"spec\": {" +
+                "  \"displayName\": \"MyPlan\"," +
+                "  \"shortDescription\": \"MyPlan is cool\"," +
+                "  \"longDescription\": \"MyPlan is cool, but not much used anymore\"," +
+                "  \"addressType\": \"queue\"," +
+                "  \"resources\": {" +
+                "    \"router\": 0.2," +
+                "    \"broker\": 0.5" +
+                "  }" +
+                "}}";
+
+        ObjectMapper mapper = new ObjectMapper();
+        AddressPlan addressPlan = mapper.readValue(json, AddressPlan.class);
+        assertThat(addressPlan.getMetadata().getName(), is("plan1"));
+        assertThat(addressPlan.getSpec().getAdditionalProperties().get("displayName"), is("MyPlan"));
+        assertThat(addressPlan.getAddressType(), is("queue"));
+        assertThat(addressPlan.getResources().size(), is(2));
+        assertThat(addressPlan.getResources().get("router"), is(0.2));
+        assertThat(addressPlan.getResources().get("broker"), is(0.5));
+    }
+
+    @Test
+    public void testDeserializeDeprecatedAddressPlanWithDefaults() throws IOException {
         String json = "{" +
                 "\"apiVersion\":\"enmasse.io/v1beta1\"," +
                 "\"kind\":\"AddressPlan\"," +
@@ -472,10 +560,34 @@ public class SerializationTest {
         AddressPlan addressPlan = mapper.readValue(json, AddressPlan.class);
         assertThat(addressPlan.getMetadata().getName(), is("plan1"));
         assertThat(addressPlan.getAddressType(), is("queue"));
-        assertNull(addressPlan.getUuid());
-        assertThat(addressPlan.getRequiredResources().size(), is(2));
-        assertThat(addressPlan.getRequiredResources().get(0).getName(), is("router"));
-        assertThat(addressPlan.getRequiredResources().get(1).getName(), is("broker"));
+        assertThat(addressPlan.getResources().size(), is(2));
+        assertThat(addressPlan.getResources().get("router"), is(0.2));
+        assertThat(addressPlan.getResources().get("broker"), is(0.5));
+    }
+
+    @Test
+    public void testDeserializeAddressPlanWithDefaults() throws IOException {
+        String json = "{" +
+                "\"apiVersion\":\"enmasse.io/v1beta2\"," +
+                "\"kind\":\"AddressPlan\"," +
+                "\"metadata\":{" +
+                "  \"name\":\"plan1\"" +
+                "}," +
+                "\"spec\": {" +
+                "  \"addressType\": \"queue\"," +
+                "  \"resources\": {" +
+                "    \"router\": 0.2," +
+                "    \"broker\": 0.5" +
+                "  }" +
+                "}}";
+
+        ObjectMapper mapper = new ObjectMapper();
+        AddressPlan addressPlan = mapper.readValue(json, AddressPlan.class);
+        assertThat(addressPlan.getMetadata().getName(), is("plan1"));
+        assertThat(addressPlan.getAddressType(), is("queue"));
+        assertThat(addressPlan.getResources().size(), is(2));
+        assertThat(addressPlan.getResources().get("router"), is(0.2));
+        assertThat(addressPlan.getResources().get("broker"), is(0.5));
     }
 
     @Test
diff --git a/keycloak-user-api/src/test/java/io/enmasse/user/keycloak/KeycloakUserApiTest.java b/keycloak-user-api/src/test/java/io/enmasse/user/keycloak/KeycloakUserApiTest.java
index c32ee035d..9f6970462 100644
--- a/keycloak-user-api/src/test/java/io/enmasse/user/keycloak/KeycloakUserApiTest.java
+++ b/keycloak-user-api/src/test/java/io/enmasse/user/keycloak/KeycloakUserApiTest.java
@@ -264,7 +264,7 @@ public class KeycloakUserApiTest {
 
         final Set<String> result = KeycloakUserApi.createDesiredGroupsSet(auth);
 
-        assertGroups(result, "manage", "manage_#");
+        assertGroups(result, "manage");
     }
 
     @Test
@@ -280,7 +280,7 @@ public class KeycloakUserApiTest {
 
         assertGroups(result,
                 "recv_foo%2Fbar", "send_foo%2Fbar", "recv_bar%2Fbaz%2F%23", "send_bar%2Fbaz%2F%23",
-                "monitor", "monitor_#", "manage", "manage_#");
+                "monitor", "manage");
     }
 
     @Test
@@ -303,7 +303,7 @@ public class KeycloakUserApiTest {
 
         final Set<String> result = KeycloakUserApi.createDesiredGroupsSet(auth);
 
-        assertGroups(result, "manage", "manage_#");
+        assertGroups(result, "manage");
     }
 
     /**
diff --git a/systemtests/pom.xml b/systemtests/pom.xml
index de9f6e7f4..e4592689f 100644
--- a/systemtests/pom.xml
+++ b/systemtests/pom.xml
@@ -128,7 +128,7 @@
                     <dependency>
                         <groupId>org.junit.platform</groupId>
                         <artifactId>junit-platform-surefire-provider</artifactId>
-                        <version>${junit.platform.runner.version}</version>
+                        <version>${junit.platform.surefire.provider.version}</version>
                     </dependency>
                 </dependencies>
             </plugin>
diff --git a/systemtests/scripts/test_func.sh b/systemtests/scripts/test_func.sh
index 94ea6b43d..471fd79a9 100755
--- a/systemtests/scripts/test_func.sh
+++ b/systemtests/scripts/test_func.sh
@@ -42,7 +42,9 @@ function export_required_env {
     SANITIZED_NAMESPACE=${SANITIZED_NAMESPACE//\//-}
     KUBERNETES_NAMESPACE=${SANITIZED_NAMESPACE}
 
-    API_URL=$(oc config view -o jsonpath='{.clusters[0].cluster.server}')
+    if oc whoami --show-server=true > /dev/null 2>&1; then
+        API_URL=$(oc whoami --show-server=true)
+    fi
     export KUBERNETES_API_URL=${KUBERNETES_API_URL:-${API_URL}}
     export OPENSHIFT_USER=${OPENSHIFT_USER:-test}
     export OPENSHIFT_PASSWD=${OPENSHIFT_PASSWD:-test}
diff --git a/systemtests/src/main/java/io/enmasse/systemtest/Environment.java b/systemtests/src/main/java/io/enmasse/systemtest/Environment.java
index a8979cfde..076170fd2 100644
--- a/systemtests/src/main/java/io/enmasse/systemtest/Environment.java
+++ b/systemtests/src/main/java/io/enmasse/systemtest/Environment.java
@@ -21,6 +21,7 @@ public class Environment {
     public static final String tokenEnv = "KUBERNETES_API_TOKEN";
     public static final String upgradeEnv = "SYSTEMTESTS_UPGRADED";
     public static final String enmasseVersionProp = "enmasse.version";
+    public static final String domain = "KUBERNETES_DOMAIN";
 
     private final String token = System.getenv(tokenEnv);
     private final String url = System.getenv(urlEnv);
@@ -32,6 +33,7 @@ public class Environment {
     private final boolean upgrade = Boolean.parseBoolean(System.getenv().getOrDefault(upgradeEnv, "false"));
     private final String ocpVersion = System.getenv().getOrDefault(ocpVersionEnv, "3.11");
     private final String enmasseVersion = System.getProperty("enmasse.version");
+    private final String kubernetesDomain = System.getenv().getOrDefault(domain, ".nip.io");
 
     private Environment() {
         String debugFormat = "{}:{}";
@@ -120,4 +122,8 @@ public class Environment {
     public String enmasseVersion() {
         return enmasseVersion;
     }
+
+    public String kubernetesDomain() {
+        return kubernetesDomain;
+    }
 }
diff --git a/systemtests/src/main/java/io/enmasse/systemtest/SystemtestsKubernetesApps.java b/systemtests/src/main/java/io/enmasse/systemtest/SystemtestsKubernetesApps.java
index e256b01ae..9d7050619 100644
--- a/systemtests/src/main/java/io/enmasse/systemtest/SystemtestsKubernetesApps.java
+++ b/systemtests/src/main/java/io/enmasse/systemtest/SystemtestsKubernetesApps.java
@@ -197,6 +197,7 @@ public class SystemtestsKubernetesApps {
     }
 
     private static Ingress getSystemtestsIngressResource(String appName, int port) throws Exception {
+        Environment env = Environment.getInstance();
         IngressBackend backend = new IngressBackend();
         backend.setServiceName(appName);
         backend.setServicePort(new IntOrString(port));
@@ -211,7 +212,7 @@ public class SystemtestsKubernetesApps {
                 .endMetadata()
                 .withNewSpec()
                 .withRules(new IngressRuleBuilder()
-                        .withHost(appName + "." + new URL(Environment.getInstance().getApiUrl()).getHost() + ".nip.io")
+                        .withHost(appName + "." +  (env.kubernetesDomain().equals(".nip.io") ?  new URL(Environment.getInstance().getApiUrl()).getHost() + ".nip.io" : env.kubernetesDomain()))
                         .withNewHttp()
                         .withPaths(path)
                         .endHttp()
diff --git a/systemtests/src/test/java/io/enmasse/systemtest/brokered/infra/InfraTest.java b/systemtests/src/test/java/io/enmasse/systemtest/brokered/infra/InfraTest.java
index 463443078..9f97246c5 100644
--- a/systemtests/src/test/java/io/enmasse/systemtest/brokered/infra/InfraTest.java
+++ b/systemtests/src/test/java/io/enmasse/systemtest/brokered/infra/InfraTest.java
@@ -73,7 +73,7 @@ class InfraTest extends InfraTestBase implements ITestBaseBrokered{
 
     @Test
     void testDecrementInfra() throws Exception {
-        testReplaceInfra("512Mi", "512Mi", "256Mi");
+        testReplaceInfra("256Mi", "512Mi", "256Mi");
     }
 
     void testReplaceInfra(String brokerMemory, String brokerStorage, String adminMemory) throws Exception {
@@ -106,7 +106,14 @@ class InfraTest extends InfraTestBase implements ITestBaseBrokered{
 
     @Test
     void testReadInfra() throws Exception {
-        testCreateInfra();
+        testInfra = new InfraConfigDefinition("test-infra-1", AddressSpaceType.BROKERED, Arrays.asList(
+                new BrokerInfraSpec(Arrays.asList(
+                        new InfraResource("memory", "512Mi"),
+                        new InfraResource("storage", "1Gi"))),
+                new AdminInfraSpec(Collections.singletonList(
+                        new InfraResource("memory", "512Mi")))), environment.enmasseVersion());
+        plansProvider.createInfraConfig(testInfra);
+
         InfraConfigDefinition actualInfra = plansProvider.getBrokeredInfraConfig(testInfra.getName());
 
         assertEquals(testInfra.getName(), actualInfra.getName());
diff --git a/systemtests/src/test/java/io/enmasse/systemtest/standard/infra/InfraTest.java b/systemtests/src/test/java/io/enmasse/systemtest/standard/infra/InfraTest.java
index 7518590d2..1f46abf59 100644
--- a/systemtests/src/test/java/io/enmasse/systemtest/standard/infra/InfraTest.java
+++ b/systemtests/src/test/java/io/enmasse/systemtest/standard/infra/InfraTest.java
@@ -86,7 +86,7 @@ class InfraTest extends InfraTestBase implements ITestBaseStandard {
 
     @Test
     void testDecrementInfra() throws Exception {
-        testReplaceInfra("512Mi", "512Mi", 1, "128Mi", "256Mi");
+        testReplaceInfra("256Mi", "512Mi", 1, "128Mi", "256Mi");
     }
 
     void testReplaceInfra(String brokerMemory, String brokerStorage, int routerReplicas, String routerMemory, String adminMemory) throws Exception {
@@ -128,7 +128,16 @@ class InfraTest extends InfraTestBase implements ITestBaseStandard {
 
     @Test
     void testReadInfra() throws Exception {
-        testCreateInfra();
+        testInfra = new InfraConfigDefinition("test-infra-1", AddressSpaceType.STANDARD, Arrays.asList(
+                new BrokerInfraSpec(Arrays.asList(
+                        new InfraResource("memory", "512Mi"),
+                        new InfraResource("storage", "1Gi"))),
+                new RouterInfraSpec(Collections.singletonList(
+                        new InfraResource("memory", "256Mi")), 200, 2),
+                new AdminInfraSpec(Collections.singletonList(
+                        new InfraResource("memory", "512Mi")))), environment.enmasseVersion());
+        plansProvider.createInfraConfig(testInfra);
+
         InfraConfigDefinition actualInfra = plansProvider.getStandardInfraConfig(testInfra.getName());
 
         assertEquals(testInfra.getName(), actualInfra.getName());
@@ -150,6 +159,7 @@ class InfraTest extends InfraTestBase implements ITestBaseStandard {
         assertEquals(expectedRouter.getRequiredValueFromResource("memory"), actualRouter.getRequiredValueFromResource("memory"));
         assertEquals(expectedRouter.getLinkCapacity(), actualRouter.getLinkCapacity());
         assertEquals(expectedRouter.getMinReplicas(), actualRouter.getMinReplicas());
+
     }
 
     private boolean assertInfra(String brokerMemory, Optional<String> brokerStorage, int routerReplicas, String routermemory, String adminMemory) {