Require RIC instance key in controller methods 38/2038/2
authorLott, Christopher (cl778h) <cl778h@att.com>
Thu, 12 Dec 2019 18:36:30 +0000 (13:36 -0500)
committerLott, Christopher (cl778h) <cl778h@att.com>
Tue, 17 Dec 2019 20:01:57 +0000 (15:01 -0500)
Change-Id: Ibd0d1499a7391744904fabcce5f202eaa4e282d8
Signed-off-by: Lott, Christopher (cl778h) <cl778h@att.com>
39 files changed:
docs/developer-guide.rst
docs/release-notes.rst
pom.xml
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/DashboardApplication.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/DashboardConstants.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/A1MediatorApiBuilder.java [new file with mode: 0644]
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/A1MediatorConfiguration.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AppManagerApiBuilder.java [new file with mode: 0644]
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AppManagerConfiguration.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/CaasIngressConfiguration.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/E2ManagerApiBuilder.java [new file with mode: 0644]
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/E2ManagerConfiguration.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/RICInstanceConfiguration.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/SimpleKubernetesClientBuilder.java [new file with mode: 0644]
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/WebSecurityConfiguration.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/A1MediatorController.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/AdminController.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/AppManagerController.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/CaasIngressController.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/CustomResponseEntityExceptionHandler.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/controller/E2ManagerController.java
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/exception/UnknownInstanceException.java [new file with mode: 0644]
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/RicInstance.java [new file with mode: 0644]
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/RicInstanceKeyName.java [moved from webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/InstanceTransport.java with 62% similarity]
webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/RicInstanceList.java [new file with mode: 0644]
webapp-backend/src/main/resources/application.yaml
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/A1MediatorMockConfiguration.java
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/AppManagerMockConfiguration.java
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/CaasIngressMockConfiguration.java
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/E2ManagerMockConfiguration.java
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/RICInstanceMockConfiguration.java [new file with mode: 0644]
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/A1MediatorControllerTest.java
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/AbstractControllerTest.java
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/AdminController2.java
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/AdminControllerTest.java
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/AppManagerControllerTest.java
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/CaasIngressControllerTest.java
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/controller/E2ManagerControllerTest.java
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/model/ModelTest.java

index b0c71a7..e781294 100644 (file)
@@ -58,7 +58,7 @@ files.  These steps are required to launch:
 
 1. Install all project jar files locally
 2. Set an environment variable via JVM argument: ``-Dorg.oransc.ric.portal.dashboard=mock``
-3. Run the JUnit test case ``DashboardServerTest`` which is not exactly a "test" because it never finishes.
+3. Run the JUnit test case ``DashboardTestServer`` which is not exactly a "test" because it never finishes.
 
 These steps can be done with these commands::
 
index 8ef088e..ddcd11a 100644 (file)
@@ -11,6 +11,8 @@ Version 2.0.0, 22 Dec 2019
 * Add mock list of RIC instances to application properties
 * Add admin controller method to fetch list of RIC instances
 * Drop AUX cluster container list fetched via CAAS Ingress
+* Revise controller methods to require RIC instance key
+* Upgrade to Spring-Boot 2.1.11.RELEASE
 
 Version 1.3.0, 26 Nov 2019
 --------------------------
diff --git a/pom.xml b/pom.xml
index 8bee35b..9717883 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -26,7 +26,7 @@ limitations under the License.
                <!-- this group Id must match LF gerrit repository -->
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
-               <version>2.1.9.RELEASE</version>
+               <version>2.1.11.RELEASE</version>
                <relativePath /> <!-- lookup parent from repository -->
        </parent>
        <groupId>org.o-ran-sc.portal.ric-dashboard</groupId>
index 8cb774f..3a6d6a2 100644 (file)
 package org.oransc.ric.portal.dashboard;
 
 import java.lang.invoke.MethodHandles;
+import java.util.List;
 
-import org.oransc.ric.portal.dashboard.config.RICInstanceConfiguration;
-import org.oransc.ric.portal.dashboard.model.InstanceTransport;
+import org.oransc.ric.portal.dashboard.model.RicInstance;
+import org.oransc.ric.portal.dashboard.model.RicInstanceList;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -31,6 +32,7 @@ import org.springframework.boot.CommandLineRunner;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.context.annotation.ComponentScan;
+import org.springframework.util.Assert;
 
 @SpringBootApplication
 // Limit scan to dashboard classes; exclude generated API classes
@@ -40,7 +42,7 @@ public class DashboardApplication implements CommandLineRunner {
        private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
        @Autowired
-       private RICInstanceConfiguration instanceConfig;
+       private RicInstanceList instanceConfig;
 
        public static void main(String[] args) {
                SpringApplication.run(DashboardApplication.class, args);
@@ -50,8 +52,17 @@ public class DashboardApplication implements CommandLineRunner {
        public void run(String... args) throws Exception {
                // Ensure output appears on the console by using level WARN
                logger.warn("run: version '{}'", getImplementationVersion(MethodHandles.lookup().lookupClass()));
-               for (InstanceTransport it : instanceConfig.getInstances())
+               // Validate configuration
+               List<RicInstance> instances = instanceConfig.getInstances();
+               Assert.notEmpty(instances, "Instance list empty");
+               for (RicInstance it : instances) {
                        logger.warn("run: RIC instance {}", it);
+                       Assert.hasText(it.getKey(), "Instance key missing");
+                       Assert.hasText(it.getName(), "Name missing for instance " + it.getKey());
+                       Assert.hasText(it.getAppUrlPrefix(), "App URL prefix missing for instance " + it.getKey());
+                       Assert.hasText(it.getCaasUrlPrefix(), "Caas URL prefix missing for instance " + it.getKey());
+                       Assert.hasText(it.getPltUrlPrefix(), "Plt URL prefix missing for instance " + it.getKey());
+               }
        }
 
        /**
index 4225e88..6f02a22 100644 (file)
@@ -26,8 +26,11 @@ public abstract class DashboardConstants {
        }
 
        public static final String ENDPOINT_PREFIX = "/api";
+       // Spring path parameters
+       public static final String RIC_INSTANCE_KEY = "ric";
        // Factor out method names used in multiple controllers
        public static final String VERSION_METHOD = "version";
+       // Apps with metric panels
        public static final String APP_NAME_AC = "AC";
        public static final String APP_NAME_MC = "MC";
        // The role names are defined by ONAP Portal.
diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/A1MediatorApiBuilder.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/A1MediatorApiBuilder.java
new file mode 100644 (file)
index 0000000..0fbbcb3
--- /dev/null
@@ -0,0 +1,65 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+package org.oransc.ric.portal.dashboard.config;
+
+import java.lang.invoke.MethodHandles;
+
+import org.oransc.ric.a1med.client.api.A1MediatorApi;
+import org.oransc.ric.a1med.client.invoker.ApiClient;
+import org.oransc.ric.portal.dashboard.model.RicInstanceList;
+import org.oransc.ric.portal.dashboard.model.RicInstance;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.DefaultUriBuilderFactory;
+
+/**
+ * The OpenAPI generated API client code using Spring RestTemplate is not thread
+ * safe according to https://github.com/swagger-api/swagger-codegen/issues/9222
+ *
+ * As a workaround this builder creates a new client at every request. If this
+ * proves to be too slow then clients could be cached for each thread.
+ */
+public class A1MediatorApiBuilder {
+
+       private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+       private final String urlSuffix;
+       private final RicInstanceList instanceConfig;
+
+       public A1MediatorApiBuilder(final RicInstanceList instanceConfig, final String urlSuffix) {
+               logger.debug("ctor: suffix {}", urlSuffix);
+               this.instanceConfig = instanceConfig;
+               this.urlSuffix = urlSuffix;
+       }
+
+       private ApiClient apiClient(String instanceKey) {
+               RicInstance instance = instanceConfig.getInstance(instanceKey);
+               String url = new DefaultUriBuilderFactory(instance.getPltUrlPrefix().trim()).builder()
+                               .path(this.urlSuffix.trim()).build().normalize().toString();
+               logger.debug("apiClient URL {}", url);
+               return new ApiClient(new RestTemplate()).setBasePath(url);
+       }
+
+       public A1MediatorApi getA1MediatorApi(String instanceKey) {
+               return new A1MediatorApi(apiClient(instanceKey));
+       }
+
+}
index fd1bcbc..6853806 100644 (file)
@@ -21,8 +21,7 @@ package org.oransc.ric.portal.dashboard.config;
 
 import java.lang.invoke.MethodHandles;
 
-import org.oransc.ric.a1med.client.api.A1MediatorApi;
-import org.oransc.ric.a1med.client.invoker.ApiClient;
+import org.oransc.ric.portal.dashboard.model.RicInstanceList;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -30,11 +29,9 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Profile;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.DefaultUriBuilderFactory;
 
 /**
- * Creates an A1 mediator client as a bean to be managed by the Spring
+ * Creates an A1 mediator client builder as a bean to be managed by the Spring
  * container.
  */
 @Configuration
@@ -44,27 +41,21 @@ public class A1MediatorConfiguration {
        private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
        // Populated by the autowired constructor
-       private final String a1medUrl;
+       private final String urlSuffix;
+       private final RicInstanceList instanceConfig;
 
        @Autowired
-       public A1MediatorConfiguration(@Value("${a1med.url.prefix}") final String urlPrefix, //
-                       @Value("${a1med.url.suffix}") final String urlSuffix) {
-               logger.debug("ctor prefix '{}' suffix '{}'", urlPrefix, urlSuffix);
-               a1medUrl = new DefaultUriBuilderFactory(urlPrefix.trim()).builder().path(urlSuffix.trim()).build().normalize()
-                               .toString();
-               logger.info("Configuring A1 Mediator at URL {}", a1medUrl);
-       }
-
-       private ApiClient apiClient() {
-               ApiClient apiClient = new ApiClient(new RestTemplate());
-               apiClient.setBasePath(a1medUrl);
-               return apiClient;
+       public A1MediatorConfiguration(@Value("${a1med.url.suffix}") final String urlSuffix,
+                       final RicInstanceList instanceConfig) {
+               logger.info("ctor: URL suffix {}", urlSuffix);
+               this.urlSuffix = urlSuffix;
+               this.instanceConfig = instanceConfig;
        }
 
        @Bean
        // The bean (method) name must be globally unique
-       public A1MediatorApi a1MediatorApi() {
-               return new A1MediatorApi(apiClient());
+       public A1MediatorApiBuilder a1MediatorApiBuilder() {
+               return new A1MediatorApiBuilder(instanceConfig, urlSuffix);
        }
 
 }
diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AppManagerApiBuilder.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/AppManagerApiBuilder.java
new file mode 100644 (file)
index 0000000..aeb7559
--- /dev/null
@@ -0,0 +1,70 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+package org.oransc.ric.portal.dashboard.config;
+
+import java.lang.invoke.MethodHandles;
+
+import org.oransc.ric.plt.appmgr.client.api.HealthApi;
+import org.oransc.ric.plt.appmgr.client.api.XappApi;
+import org.oransc.ric.plt.appmgr.client.invoker.ApiClient;
+import org.oransc.ric.portal.dashboard.model.RicInstanceList;
+import org.oransc.ric.portal.dashboard.model.RicInstance;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.DefaultUriBuilderFactory;
+
+/**
+ * The OpenAPI generated API client code using Spring RestTemplate is not thread
+ * safe according to https://github.com/swagger-api/swagger-codegen/issues/9222
+ *
+ * As a workaround this builder creates a new client at every request. If this
+ * proves to be too slow then clients could be cached for each thread.
+ */
+public class AppManagerApiBuilder {
+
+       private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+       private final String urlSuffix;
+       private final RicInstanceList instanceConfig;
+
+       public AppManagerApiBuilder(final RicInstanceList instanceConfig, final String urlSuffix) {
+               logger.debug("ctor: suffix {}", urlSuffix);
+               this.instanceConfig = instanceConfig;
+               this.urlSuffix = urlSuffix;
+       }
+
+       private ApiClient apiClient(String instanceKey) {
+               RicInstance instance = instanceConfig.getInstance(instanceKey);
+               String url = new DefaultUriBuilderFactory(instance.getPltUrlPrefix().trim()).builder()
+                               .path(this.urlSuffix.trim()).build().normalize().toString();
+               logger.debug("apiClient URL {}", url);
+               return new ApiClient(new RestTemplate()).setBasePath(url);
+       }
+
+       public HealthApi getHealthApi(String instanceKey) {
+               return new HealthApi(apiClient(instanceKey));
+       }
+
+       public XappApi getXappApi(String instanceKey) {
+               return new XappApi(apiClient(instanceKey));
+       }
+
+}
index 94ba357..ffb5db6 100644 (file)
@@ -21,9 +21,7 @@ package org.oransc.ric.portal.dashboard.config;
 
 import java.lang.invoke.MethodHandles;
 
-import org.oransc.ric.plt.appmgr.client.api.HealthApi;
-import org.oransc.ric.plt.appmgr.client.api.XappApi;
-import org.oransc.ric.plt.appmgr.client.invoker.ApiClient;
+import org.oransc.ric.portal.dashboard.model.RicInstanceList;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -31,11 +29,9 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Profile;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.DefaultUriBuilderFactory;
 
 /**
- * Creates an xApp manager client as a bean to be managed by the Spring
+ * Creates an App manager client builder as a bean to be managed by the Spring
  * container.
  */
 @Configuration
@@ -45,38 +41,21 @@ public class AppManagerConfiguration {
        private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
        // Populated by the autowired constructor
-       private final String xappMgrUrl;
+       private final String urlSuffix;
+       private final RicInstanceList instanceConfig;
 
        @Autowired
-       public AppManagerConfiguration(@Value("${appmgr.url.prefix}") final String urlPrefix,
-                       @Value("${appmgr.url.suffix}") final String urlSuffix) {
-               logger.debug("ctor prefix '{}' suffix '{}'", urlPrefix, urlSuffix);
-               xappMgrUrl = new DefaultUriBuilderFactory(urlPrefix.trim()).builder().path(urlSuffix.trim()).build().normalize()
-                               .toString();
-               logger.info("Configuring App Manager at URL {}", xappMgrUrl);
+       public AppManagerConfiguration(@Value("${appmgr.url.suffix}") final String urlSuffix,
+                       final RicInstanceList instanceConfig) {
+               logger.info("ctor: URL suffix {}", urlSuffix);
+               this.urlSuffix = urlSuffix;
+               this.instanceConfig = instanceConfig;
        }
 
-       private ApiClient apiClient() {
-               ApiClient apiClient = new ApiClient(new RestTemplate());
-               apiClient.setBasePath(xappMgrUrl);
-               return apiClient;
-       }
-
-       /**
-        * @return A HealthApi with an ApiClient configured from properties
-        */
        @Bean
        // The bean (method) name must be globally unique
-       public HealthApi xappMgrHealthApi() {
-               return new HealthApi(apiClient());
+       public AppManagerApiBuilder appManagerApiBuilder() {
+               return new AppManagerApiBuilder(instanceConfig, urlSuffix);
        }
 
-       /**
-        * @return An XappApi with an ApiClient configured from properties
-        */
-       @Bean
-       // The bean (method) name must be globally unique
-       public XappApi xappMgrXappApi() {
-               return new XappApi(apiClient());
-       }
 }
index dd9449d..7bb3149 100644 (file)
@@ -23,7 +23,7 @@ import java.lang.invoke.MethodHandles;
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
 
-import org.oransc.ric.portal.dashboard.k8sapi.SimpleKubernetesClient;
+import org.oransc.ric.portal.dashboard.model.RicInstanceList;
 import org.oransc.ric.portal.dashboard.util.HttpsURLConnectionUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -32,7 +32,6 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Profile;
-import org.springframework.web.util.DefaultUriBuilderFactory;
 
 /**
  * Creates instances of CAAS-Ingres clients.
@@ -44,19 +43,18 @@ public class CaasIngressConfiguration {
        private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
        // Populated by the autowired constructor
-       private final String caasIngressPltUrl;
+       private final String urlSuffix;
+       private final RicInstanceList instanceConfig;
 
        @Autowired
        public CaasIngressConfiguration( //
-                       @Value("${caasingress.plt.url.prefix}") final String pltUrlPrefix,
-                       @Value("${caasingress.plt.url.suffix}") final String pltUrlSuffix,
-                       @Value("${caasingress.insecure}") final Boolean insecureFlag) //
-                       throws KeyManagementException, NoSuchAlgorithmException {
-               logger.debug("ctor caasingress plt prefix '{}' suffix '{}'", pltUrlPrefix, pltUrlSuffix);
-               logger.debug("ctor caasingress insecure flag {}", insecureFlag);
-               caasIngressPltUrl = new DefaultUriBuilderFactory(pltUrlPrefix.trim()).builder().path(pltUrlSuffix.trim())
-                               .build().normalize().toString();
-               logger.info("Configuring CAAS-Ingress URL: plt {}", caasIngressPltUrl);
+                       @Value("${caasingress.plt.url.suffix}") final String pltUrlSuffix, //
+                       @Value("${caasingress.insecure}") final Boolean insecureFlag, //
+                       final RicInstanceList instanceConfig) throws KeyManagementException, NoSuchAlgorithmException {
+               logger.debug("ctor: suffix {} insecure flag {}", pltUrlSuffix, insecureFlag);
+               this.urlSuffix = pltUrlSuffix;
+               this.instanceConfig = instanceConfig;
+               // This is a brutal hack:
                if (insecureFlag != null && insecureFlag) {
                        logger.warn("ctor: insecure flag set, disabling SSL checks");
                        HttpsURLConnectionUtils.turnOffSslChecking();
@@ -65,8 +63,8 @@ public class CaasIngressConfiguration {
 
        @Bean
        // The bean (method) name must be globally unique
-       public SimpleKubernetesClient ciPltApi() {
-               return new SimpleKubernetesClient(caasIngressPltUrl);
+       public SimpleKubernetesClientBuilder simpleKubernetesClientBuilder() {
+               return new SimpleKubernetesClientBuilder(instanceConfig, urlSuffix);
        }
 
 }
diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/E2ManagerApiBuilder.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/E2ManagerApiBuilder.java
new file mode 100644 (file)
index 0000000..6e64a54
--- /dev/null
@@ -0,0 +1,70 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+package org.oransc.ric.portal.dashboard.config;
+
+import java.lang.invoke.MethodHandles;
+
+import org.oransc.ric.e2mgr.client.api.HealthCheckApi;
+import org.oransc.ric.e2mgr.client.api.NodebApi;
+import org.oransc.ric.e2mgr.client.invoker.ApiClient;
+import org.oransc.ric.portal.dashboard.model.RicInstanceList;
+import org.oransc.ric.portal.dashboard.model.RicInstance;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.DefaultUriBuilderFactory;
+
+/**
+ * The OpenAPI generated API client code using Spring RestTemplate is not thread
+ * safe according to https://github.com/swagger-api/swagger-codegen/issues/9222
+ *
+ * As a workaround this builder creates a new client at every request. If this
+ * proves to be too slow then clients could be cached for each thread.
+ */
+public class E2ManagerApiBuilder {
+
+       private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+       private final String urlSuffix;
+       private final RicInstanceList instanceConfig;
+
+       public E2ManagerApiBuilder(final RicInstanceList instanceConfig, final String urlSuffix) {
+               logger.debug("ctor: suffix {}", urlSuffix);
+               this.instanceConfig = instanceConfig;
+               this.urlSuffix = urlSuffix;
+       }
+
+       private ApiClient apiClient(String instanceKey) {
+               RicInstance instance = instanceConfig.getInstance(instanceKey);
+               String url = new DefaultUriBuilderFactory(instance.getPltUrlPrefix().trim()).builder()
+                               .path(this.urlSuffix.trim()).build().normalize().toString();
+               logger.debug("apiClient URL {}", url);
+               return new ApiClient(new RestTemplate()).setBasePath(url);
+       }
+
+       public HealthCheckApi getHealthCheckApi(String instanceKey) {
+               return new HealthCheckApi(apiClient(instanceKey));
+       }
+
+       public NodebApi getNodebApi(String instanceKey) {
+               return new NodebApi(apiClient(instanceKey));
+       }
+
+}
index 21ca863..4b25622 100644 (file)
@@ -21,9 +21,7 @@ package org.oransc.ric.portal.dashboard.config;
 
 import java.lang.invoke.MethodHandles;
 
-import org.oransc.ric.e2mgr.client.api.HealthCheckApi;
-import org.oransc.ric.e2mgr.client.api.NodebApi;
-import org.oransc.ric.e2mgr.client.invoker.ApiClient;
+import org.oransc.ric.portal.dashboard.model.RicInstanceList;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -31,11 +29,10 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Profile;
-import org.springframework.web.client.RestTemplate;
-import org.springframework.web.util.DefaultUriBuilderFactory;
 
 /**
- * Creates an E2 manager client as a bean to be managed by the Spring container.
+ * Creates an E2 manager client builder as a bean to be managed by the Spring
+ * container.
  */
 @Configuration
 @Profile("!test")
@@ -44,33 +41,21 @@ public class E2ManagerConfiguration {
        private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
        // Populated by the autowired constructor
-       private final String e2mgrUrl;
+       private final String urlSuffix;
+       private final RicInstanceList instanceConfig;
 
        @Autowired
-       public E2ManagerConfiguration(@Value("${e2mgr.url.prefix}") final String urlPrefix,
-                       @Value("${e2mgr.url.suffix}") final String urlSuffix) {
-               logger.debug("ctor prefix '{}' suffix '{}'", urlPrefix, urlSuffix);
-               e2mgrUrl = new DefaultUriBuilderFactory(urlPrefix.trim()).builder().path(urlSuffix.trim()).build().normalize()
-                               .toString();
-               logger.info("Configuring E2 Manager at URL {}", e2mgrUrl);
-       }
-
-       private ApiClient apiClient() {
-               ApiClient apiClient = new ApiClient(new RestTemplate());
-               apiClient.setBasePath(e2mgrUrl);
-               return apiClient;
-       }
-
-       @Bean
-       // The bean (method) name must be globally unique
-       public HealthCheckApi e2MgrHealthCheckApi() {
-               return new HealthCheckApi(apiClient());
+       public E2ManagerConfiguration(@Value("${e2mgr.url.suffix}") final String urlSuffix,
+                       final RicInstanceList instanceConfig) {
+               logger.info("ctor: URL suffix {}", urlSuffix);
+               this.urlSuffix = urlSuffix;
+               this.instanceConfig = instanceConfig;
        }
 
        @Bean
        // The bean (method) name must be globally unique
-       public NodebApi e2MgrNodebApi() {
-               return new NodebApi(apiClient());
+       public E2ManagerApiBuilder e2ManagerApiBuilder() {
+               return new E2ManagerApiBuilder(instanceConfig, urlSuffix);
        }
 
 }
index f39f200..290331f 100644 (file)
@@ -23,14 +23,16 @@ package org.oransc.ric.portal.dashboard.config;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.oransc.ric.portal.dashboard.model.InstanceTransport;
+import org.oransc.ric.portal.dashboard.model.RicInstance;
+import org.oransc.ric.portal.dashboard.model.RicInstanceList;
 import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
 
 /**
- * Holds the list of RIC instances read from configuration data. This asserts no
- * Spring profile such as ("!test"). No mock version of this class is required.
- * Populated from a YAML list in the application properties like this:
+ * Publishes a list of RIC instances from configuration, written as a YAML list
+ * in application properties like this:
  * 
  * <pre>
  * ric-instance-list:
@@ -38,21 +40,28 @@ import org.springframework.context.annotation.Configuration;
         -
           key: key1
           name: Friendly Name One
+          urlPrefix: http://foo.bar.one/
         -
           key: key2
           name: Friendly Name Two
+          urlPrefix: http://foo.bar.two/
  * </pre>
  */
 @Configuration
 @ConfigurationProperties(prefix = "ric-instance-list")
+@Profile("!test")
 public class RICInstanceConfiguration {
-       private List<InstanceTransport> instances = new ArrayList<>();
 
-       public List<InstanceTransport> getInstances() {
-               return instances;
-       }
+       private List<RicInstance> instances = new ArrayList<>();
 
-       public void setInstances(List<InstanceTransport> instances) {
+       // Called by spring with config data
+       public void setInstances(List<RicInstance> instances) {
                this.instances = instances;
        }
+
+       @Bean
+       public RicInstanceList ricInstanceList() {
+               return new RicInstanceList(instances);
+       }
+
 }
diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/SimpleKubernetesClientBuilder.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/config/SimpleKubernetesClientBuilder.java
new file mode 100644 (file)
index 0000000..50af74f
--- /dev/null
@@ -0,0 +1,63 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+package org.oransc.ric.portal.dashboard.config;
+
+import java.lang.invoke.MethodHandles;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.oransc.ric.portal.dashboard.k8sapi.SimpleKubernetesClient;
+import org.oransc.ric.portal.dashboard.model.RicInstance;
+import org.oransc.ric.portal.dashboard.model.RicInstanceList;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.util.DefaultUriBuilderFactory;
+
+/**
+ * Creates, caches and serves out instances of SimpleKubernetesClient for a
+ * given instance. That class seems to be thread safe.
+ */
+public class SimpleKubernetesClientBuilder {
+
+       private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+       private Map<String, SimpleKubernetesClient> cache = new ConcurrentHashMap<>();
+
+       private final String urlSuffix;
+       private final RicInstanceList instanceConfig;
+
+       public SimpleKubernetesClientBuilder(final RicInstanceList instanceConfig, final String urlSuffix) {
+               logger.debug("ctor: suffix {}", urlSuffix);
+               this.instanceConfig = instanceConfig;
+               this.urlSuffix = urlSuffix;
+       }
+
+       public SimpleKubernetesClient getSimpleKubernetesClient(String instanceKey) {
+               logger.debug("getSimpleKubernetesClient instance {}", instanceKey);
+               if (cache.containsKey(instanceKey))
+                       return cache.get(instanceKey);
+               RicInstance instance = instanceConfig.getInstance(instanceKey);
+               String url = new DefaultUriBuilderFactory(instance.getCaasUrlPrefix().trim()).builder()
+                               .path(this.urlSuffix.trim()).build().normalize().toString();
+               SimpleKubernetesClient client = new SimpleKubernetesClient(url);
+               cache.put(instanceKey, client);
+               return client;
+       }
+
+}
index f4819d3..941dc46 100644 (file)
@@ -23,6 +23,7 @@ import java.lang.invoke.MethodHandles;
 import java.lang.reflect.InvocationTargetException;
 
 import org.onap.portalsdk.core.onboarding.util.PortalApiConstants;
+import org.oransc.ric.portal.dashboard.DashboardConstants;
 import org.oransc.ric.portal.dashboard.DashboardUserManager;
 import org.oransc.ric.portal.dashboard.controller.A1MediatorController;
 import org.oransc.ric.portal.dashboard.controller.AdminController;
@@ -83,7 +84,7 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
        }
 
        /**
-        * Resource paths that do not require authentication, especially including
+        * Resource paths that do not require authentication, including
         * Swagger-generated documentation.
         */
        protected static final String[] OPEN_PATHS = { //
@@ -92,14 +93,17 @@ public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
                        "/swagger-ui.html", //
                        "/webjars/**", //
                        PortalApiConstants.API_PREFIX + "/**", //
-                       A1MediatorController.CONTROLLER_PATH + "/" + A1MediatorController.VERSION_METHOD, //
+                       A1MediatorController.CONTROLLER_PATH + "/" + DashboardConstants.VERSION_METHOD, //
                        AdminController.CONTROLLER_PATH + "/" + AdminController.HEALTH_METHOD, //
                        AdminController.CONTROLLER_PATH + "/" + AdminController.VERSION_METHOD, //
-                       AppManagerController.CONTROLLER_PATH + "/" + AppManagerController.HEALTH_ALIVE_METHOD, //
-                       AppManagerController.CONTROLLER_PATH + "/" + AppManagerController.HEALTH_READY_METHOD, //
-                       AppManagerController.CONTROLLER_PATH + "/" + AppManagerController.VERSION_METHOD, //
-                       E2ManagerController.CONTROLLER_PATH + "/" + E2ManagerController.HEALTH_METHOD, //
-                       E2ManagerController.CONTROLLER_PATH + "/" + E2ManagerController.VERSION_METHOD, //
+                       AppManagerController.CONTROLLER_PATH + "/" + DashboardConstants.RIC_INSTANCE_KEY + "/*/"
+                                       + AppManagerController.HEALTH_ALIVE_METHOD, //
+                       AppManagerController.CONTROLLER_PATH + "/" + DashboardConstants.RIC_INSTANCE_KEY + "/*/"
+                                       + AppManagerController.HEALTH_READY_METHOD, //
+                       AppManagerController.CONTROLLER_PATH + "/" + DashboardConstants.VERSION_METHOD, //
+                       E2ManagerController.CONTROLLER_PATH + "/" + DashboardConstants.RIC_INSTANCE_KEY + "/*/"
+                                       + E2ManagerController.HEALTH_METHOD, //
+                       E2ManagerController.CONTROLLER_PATH + "/" + DashboardConstants.VERSION_METHOD, //
                        SimpleErrorController.ERROR_PATH };
 
        @Override
index 6fc8069..98a4855 100644 (file)
@@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletResponse;
 import org.oransc.ric.a1med.client.api.A1MediatorApi;
 import org.oransc.ric.portal.dashboard.DashboardApplication;
 import org.oransc.ric.portal.dashboard.DashboardConstants;
+import org.oransc.ric.portal.dashboard.config.A1MediatorApiBuilder;
 import org.oransc.ric.portal.dashboard.model.SuccessTransport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -45,7 +46,7 @@ import io.swagger.annotations.ApiParam;
 
 /**
  * Proxies calls from the front end to the A1 Mediator API to get and put
- * policies. The first application managed via this path is Admission Control.
+ * policies. All methods are deliberately kept ignorant of the data format.
  * 
  * If a method throws RestClientResponseException, it is handled by
  * {@link CustomResponseEntityExceptionHandler#handleProxyMethodException(Exception, org.springframework.web.context.request.WebRequest)}
@@ -58,54 +59,51 @@ public class A1MediatorController {
 
        private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
-       // Publish paths in constants so tests are easy to write
+       /** This path lacks the RIC instance pattern */
        public static final String CONTROLLER_PATH = DashboardConstants.ENDPOINT_PREFIX + "/a1-p";
-       // Endpoints
-       public static final String VERSION_METHOD = DashboardConstants.VERSION_METHOD;
        // Path parameters
        public static final String PP_POLICIES = "policies";
+       // The get and put methods use the same path
+       private static final String POLICY_METHOD_PATH = /* controller path + */ DashboardConstants.RIC_INSTANCE_KEY + "/{"
+                       + DashboardConstants.RIC_INSTANCE_KEY + "}/" + PP_POLICIES + "/{" + PP_POLICIES + "}";
 
        // Populated by the autowired constructor
-       private final A1MediatorApi a1MediatorApi;
+       private final A1MediatorApiBuilder a1MediatorClientBuilder;
 
        @Autowired
-       public A1MediatorController(final A1MediatorApi a1MediatorApi) {
-               Assert.notNull(a1MediatorApi, "API must not be null");
-               this.a1MediatorApi = a1MediatorApi;
+       public A1MediatorController(final A1MediatorApiBuilder a1MediatorApiBuilder) {
+               Assert.notNull(a1MediatorApiBuilder, "builder must not be null");
+               this.a1MediatorClientBuilder = a1MediatorApiBuilder;
                if (logger.isDebugEnabled())
-                       logger.debug("ctor: configured with client type {}", a1MediatorApi.getClass().getName());
+                       logger.debug("ctor: configured with builder type {}", a1MediatorApiBuilder.getClass().getName());
        }
 
        @ApiOperation(value = "Gets the A1 client library MANIFEST.MF property Implementation-Version.", response = SuccessTransport.class)
-       @GetMapping(VERSION_METHOD)
+       @GetMapping(DashboardConstants.VERSION_METHOD)
        // No role required
        public SuccessTransport getA1MediatorClientVersion() {
                return new SuccessTransport(200, DashboardApplication.getImplementationVersion(A1MediatorApi.class));
        }
 
-       /*
-        * This method is deliberately kept ignorant of the data passing thru.
-        */
        @ApiOperation(value = "Gets the specified policy from the A1 Mediator")
-       @GetMapping(PP_POLICIES + "/{" + PP_POLICIES + "}")
+       @GetMapping(POLICY_METHOD_PATH)
        @Secured({ DashboardConstants.ROLE_ADMIN, DashboardConstants.ROLE_STANDARD })
-       public Object getPolicy(@PathVariable(PP_POLICIES) String policyName) {
-               logger.debug("getPolicy {}", policyName);
-               return a1MediatorApi.a1ControllerGetHandler(policyName);
+       public Object getPolicy(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
+                       @PathVariable(PP_POLICIES) String policyName) {
+               logger.debug("getPolicy instance {} policy {}", instanceKey, policyName);
+               return a1MediatorClientBuilder.getA1MediatorApi(instanceKey).a1ControllerGetHandler(policyName);
        }
 
-       /*
-        * This method is deliberately kept ignorant of the data passing thru.
-        */
        @ApiOperation(value = "Puts the specified policy to the A1 Mediator")
-       @PutMapping(PP_POLICIES + "/{" + PP_POLICIES + "}")
+       @PutMapping(POLICY_METHOD_PATH)
        @Secured({ DashboardConstants.ROLE_ADMIN })
-       public void putPolicy(@PathVariable(PP_POLICIES) String policyName,
-                       @ApiParam(value = "Policy body") @RequestBody String policy, //
+       public void putPolicy(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
+                       @PathVariable(PP_POLICIES) String policyName, @ApiParam(value = "Policy body") @RequestBody String policy, //
                        HttpServletResponse response) {
-               logger.debug("putPolicy name {} value {}", policyName, policy);
-               a1MediatorApi.a1ControllerPutHandler(policyName, policy);
-               response.setStatus(a1MediatorApi.getApiClient().getStatusCode().value());
+               logger.debug("putPolicy instance {} name {} value {}", instanceKey, policyName, policy);
+               A1MediatorApi api = a1MediatorClientBuilder.getA1MediatorApi(instanceKey);
+               api.a1ControllerPutHandler(policyName, policy);
+               response.setStatus(api.getApiClient().getStatusCode().value());
        }
 
 }
index 39488bd..17d9843 100644 (file)
@@ -28,10 +28,10 @@ import org.onap.portalsdk.core.restful.domain.EcompUser;
 import org.oransc.ric.portal.dashboard.DashboardApplication;
 import org.oransc.ric.portal.dashboard.DashboardConstants;
 import org.oransc.ric.portal.dashboard.DashboardUserManager;
-import org.oransc.ric.portal.dashboard.config.RICInstanceConfiguration;
 import org.oransc.ric.portal.dashboard.model.ErrorTransport;
 import org.oransc.ric.portal.dashboard.model.IDashboardResponse;
-import org.oransc.ric.portal.dashboard.model.InstanceTransport;
+import org.oransc.ric.portal.dashboard.model.RicInstanceList;
+import org.oransc.ric.portal.dashboard.model.RicInstanceKeyName;
 import org.oransc.ric.portal.dashboard.model.SuccessTransport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -73,7 +73,7 @@ public class AdminController {
        private DashboardUserManager dashboardUserManager;
 
        @Autowired
-       private RICInstanceConfiguration instanceConfig;
+       private RicInstanceList instanceConfig;
 
        @ApiOperation(value = "Gets the Dashboard MANIFEST.MF property Implementation-Version.", response = SuccessTransport.class)
        @GetMapping(VERSION_METHOD)
@@ -102,12 +102,12 @@ public class AdminController {
                return dashboardUserManager.getUsers();
        }
 
-       @ApiOperation(value = "Gets the list of RIC instances.", response = InstanceTransport.class, responseContainer = "List")
+       @ApiOperation(value = "Gets the list of RIC instances.", response = RicInstanceKeyName.class, responseContainer = "List")
        @GetMapping(INSTANCE_METHOD)
        @Secured({ DashboardConstants.ROLE_ADMIN, DashboardConstants.ROLE_STANDARD })
-       public List<InstanceTransport> getInstances() {
+       public List<RicInstanceKeyName> getInstances() {
                logger.debug("getInstances");
-               return instanceConfig.getInstances();
+               return instanceConfig.getKeyNameList();
        }
 
        @ApiOperation(value = "Gets the kibana metrics URL for the specified app.", response = SuccessTransport.class)
index cf267da..2dcc7d5 100644 (file)
@@ -34,6 +34,7 @@ import org.oransc.ric.plt.appmgr.client.model.XAppInfo;
 import org.oransc.ric.plt.appmgr.client.model.Xapp;
 import org.oransc.ric.portal.dashboard.DashboardApplication;
 import org.oransc.ric.portal.dashboard.DashboardConstants;
+import org.oransc.ric.portal.dashboard.config.AppManagerApiBuilder;
 import org.oransc.ric.portal.dashboard.model.AppTransport;
 import org.oransc.ric.portal.dashboard.model.DashboardDeployableXapps;
 import org.oransc.ric.portal.dashboard.model.SuccessTransport;
@@ -72,95 +73,106 @@ public class AppManagerController {
 
        // Publish paths in constants so tests are easy to write
        public static final String CONTROLLER_PATH = DashboardConstants.ENDPOINT_PREFIX + "/appmgr";
-       // Endpoints
-       public static final String HEALTH_ALIVE_METHOD = "/health/alive";
-       public static final String HEALTH_READY_METHOD = "/health/ready";
-       public static final String CONFIG_METHOD = "/config";
-       public static final String XAPPS_METHOD = "/xapps";
+       public static final String HEALTH_ALIVE_METHOD = "health/alive";
+       public static final String HEALTH_READY_METHOD = "health/ready";
+       public static final String CONFIG_METHOD = "config";
+       public static final String XAPPS_METHOD = "xapps";
        public static final String XAPPS_LIST_METHOD = XAPPS_METHOD + "/list";
-       public static final String VERSION_METHOD = DashboardConstants.VERSION_METHOD;
        // Path parameters
        public static final String PP_XAPP_NAME = "xAppName";
+       // minimize repeats
+       private static final String CONFIG_METHOD_PATH = DashboardConstants.RIC_INSTANCE_KEY + "/{"
+                       + DashboardConstants.RIC_INSTANCE_KEY + "}/" + CONFIG_METHOD;
+       private static final String XAPPS_METHOD_PATH = DashboardConstants.RIC_INSTANCE_KEY + "/{"
+                       + DashboardConstants.RIC_INSTANCE_KEY + "}/" + XAPPS_METHOD;
 
        // Populated by the autowired constructor
-       private final HealthApi healthApi;
-       private final XappApi xappApi;
+       private final AppManagerApiBuilder appManagerApiBuilder;
 
        @Autowired
-       public AppManagerController(final HealthApi healthApi, final XappApi xappApi) {
-               Assert.notNull(healthApi, "health API must not be null");
-               Assert.notNull(xappApi, "xapp API must not be null");
-               this.healthApi = healthApi;
-               this.xappApi = xappApi;
+       public AppManagerController(final AppManagerApiBuilder appManagerApiBuilder) {
+               Assert.notNull(appManagerApiBuilder, "builder must not be null");
+               this.appManagerApiBuilder = appManagerApiBuilder;
                if (logger.isDebugEnabled())
-                       logger.debug("ctor: configured with client types {} and {}", healthApi.getClass().getName(),
-                                       xappApi.getClass().getName());
+                       logger.debug("ctor: configured with builder type {}", appManagerApiBuilder.getClass().getName());
        }
 
-       @ApiOperation(value = "Gets the XApp manager client library MANIFEST.MF property Implementation-Version.", response = SuccessTransport.class)
-       @GetMapping(VERSION_METHOD)
+       @ApiOperation(value = "Gets the App manager client library MANIFEST.MF property Implementation-Version.", response = SuccessTransport.class)
+       @GetMapping(DashboardConstants.VERSION_METHOD)
        // No role required
        public SuccessTransport getClientVersion() {
                return new SuccessTransport(200, DashboardApplication.getImplementationVersion(HealthApi.class));
        }
 
-       @ApiOperation(value = "Health check of xApp Manager - Liveness probe.")
-       @GetMapping(HEALTH_ALIVE_METHOD)
+       @ApiOperation(value = "Health check of App Manager - Liveness probe.")
+       @GetMapping(DashboardConstants.RIC_INSTANCE_KEY + "/{" + DashboardConstants.RIC_INSTANCE_KEY + "}/"
+                       + HEALTH_ALIVE_METHOD)
        // No role required
-       public void getHealth(HttpServletResponse response) {
-               logger.debug("getHealthAlive");
-               healthApi.getHealthAlive();
-               response.setStatus(healthApi.getApiClient().getStatusCode().value());
+       public void getHealth(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
+                       HttpServletResponse response) {
+               logger.debug("getHealthAlive instance {}", instanceKey);
+               HealthApi api = appManagerApiBuilder.getHealthApi(instanceKey);
+               api.getHealthAlive();
+               response.setStatus(api.getApiClient().getStatusCode().value());
        }
 
-       @ApiOperation(value = "Readiness check of xApp Manager - Readiness probe.")
-       @GetMapping(HEALTH_READY_METHOD)
+       @ApiOperation(value = "Readiness check of App Manager - Readiness probe.")
+       @GetMapping(DashboardConstants.RIC_INSTANCE_KEY + "/{" + DashboardConstants.RIC_INSTANCE_KEY + "}/"
+                       + HEALTH_READY_METHOD)
        // No role required
-       public void getHealthReady(HttpServletResponse response) {
-               logger.debug("getHealthReady");
-               healthApi.getHealthReady();
-               response.setStatus(healthApi.getApiClient().getStatusCode().value());
+       public void getHealthReady(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
+                       HttpServletResponse response) {
+               logger.debug("getHealthReady instance {}", instanceKey);
+               HealthApi api = appManagerApiBuilder.getHealthApi(instanceKey);
+               api.getHealthReady();
+               response.setStatus(api.getApiClient().getStatusCode().value());
        }
 
-       @ApiOperation(value = "Returns the configuration of all xapps.", response = AllXappConfig.class)
-       @GetMapping(CONFIG_METHOD)
+       @ApiOperation(value = "Returns the configuration of all Xapps.", response = AllXappConfig.class)
+       @GetMapping(CONFIG_METHOD_PATH)
        @Secured({ DashboardConstants.ROLE_ADMIN, DashboardConstants.ROLE_STANDARD })
-       public AllXappConfig getAllXappConfig() {
-               logger.debug("getAllXappConfig");
-               return xappApi.getAllXappConfig();
+       public AllXappConfig getAllXappConfig(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey) {
+               logger.debug("getAllXappConfig instance {}", instanceKey);
+               return appManagerApiBuilder.getXappApi(instanceKey).getAllXappConfig();
        }
 
-       @ApiOperation(value = "Create xApp config.", response = XAppConfig.class)
-       @PostMapping(CONFIG_METHOD)
+       @ApiOperation(value = "Create XApp config.", response = XAppConfig.class)
+       @PostMapping(CONFIG_METHOD_PATH)
        @Secured({ DashboardConstants.ROLE_ADMIN })
-       public XAppConfig createXappConfig(@RequestBody XAppConfig xAppConfig) {
-               logger.debug("createXappConfig {}", xAppConfig);
-               return xappApi.createXappConfig(xAppConfig);
+       public XAppConfig createXappConfig(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
+                       @RequestBody XAppConfig xAppConfig) {
+               logger.debug("createXappConfig instance {} config {}", instanceKey, xAppConfig);
+               return appManagerApiBuilder.getXappApi(instanceKey).createXappConfig(xAppConfig);
        }
 
-       @ApiOperation(value = "Modify xApp config.", response = XAppConfig.class)
-       @PutMapping(CONFIG_METHOD)
+       @ApiOperation(value = "Modify XApp config.", response = XAppConfig.class)
+       @PutMapping(CONFIG_METHOD_PATH)
        @Secured({ DashboardConstants.ROLE_ADMIN })
-       public XAppConfig modifyXappConfig(@RequestBody XAppConfig xAppConfig) {
-               logger.debug("modifyXappConfig {}", xAppConfig);
-               return xappApi.modifyXappConfig(xAppConfig);
+       public XAppConfig modifyXappConfig(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
+                       @RequestBody XAppConfig xAppConfig) {
+               logger.debug("modifyXappConfig instance {} config {}", instanceKey, xAppConfig);
+               return appManagerApiBuilder.getXappApi(instanceKey).modifyXappConfig(xAppConfig);
        }
 
-       @ApiOperation(value = "Delete xApp configuration.")
-       @DeleteMapping(CONFIG_METHOD + "/{" + PP_XAPP_NAME + "}")
+       @ApiOperation(value = "Delete XApp configuration.")
+       @DeleteMapping(CONFIG_METHOD_PATH + "/{" + PP_XAPP_NAME + "}")
        @Secured({ DashboardConstants.ROLE_ADMIN })
-       public void deleteXappConfig(@RequestBody ConfigMetadata configMetadata, HttpServletResponse response) {
-               logger.debug("deleteXappConfig {}", configMetadata);
-               xappApi.deleteXappConfig(configMetadata);
-               response.setStatus(healthApi.getApiClient().getStatusCode().value());
+       public void deleteXappConfig(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
+                       @RequestBody ConfigMetadata configMetadata, HttpServletResponse response) {
+               logger.debug("deleteXappConfig instance {} config {}", instanceKey, configMetadata);
+               XappApi api = appManagerApiBuilder.getXappApi(instanceKey);
+               api.deleteXappConfig(configMetadata);
+               response.setStatus(api.getApiClient().getStatusCode().value());
        }
 
        @ApiOperation(value = "Returns a list of deployable xapps.", response = DashboardDeployableXapps.class)
-       @GetMapping(XAPPS_LIST_METHOD)
+       @GetMapping(DashboardConstants.RIC_INSTANCE_KEY + "/{" + DashboardConstants.RIC_INSTANCE_KEY + "}/"
+                       + XAPPS_LIST_METHOD)
        @Secured({ DashboardConstants.ROLE_ADMIN, DashboardConstants.ROLE_STANDARD })
-       public DashboardDeployableXapps getAvailableXapps() {
-               logger.debug("getAvailableXapps");
-               AllDeployableXapps appNames = xappApi.listAllDeployableXapps();
+       public DashboardDeployableXapps getAvailableXapps(
+                       @PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey) {
+               logger.debug("getAvailableXapps instance {}", instanceKey);
+               AllDeployableXapps appNames = appManagerApiBuilder.getXappApi(instanceKey).listAllDeployableXapps();
                // Answer a collection of structure instead of string
                // because I expect the AppMgr to be extended with
                // additional properties for each one.
@@ -171,36 +183,40 @@ public class AppManagerController {
        }
 
        @ApiOperation(value = "Returns the status of all deployed xapps.", response = AllDeployedXapps.class)
-       @GetMapping(XAPPS_METHOD)
+       @GetMapping(XAPPS_METHOD_PATH)
        @Secured({ DashboardConstants.ROLE_ADMIN, DashboardConstants.ROLE_STANDARD })
-       public AllDeployedXapps getDeployedXapps() {
-               logger.debug("getDeployedXapps");
-               return xappApi.getAllXapps();
+       public AllDeployedXapps getDeployedXapps(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey) {
+               logger.debug("getDeployedXapps instance {}", instanceKey);
+               return appManagerApiBuilder.getXappApi(instanceKey).getAllXapps();
        }
 
        @ApiOperation(value = "Returns the status of a given xapp.", response = Xapp.class)
-       @GetMapping(XAPPS_METHOD + "/{" + PP_XAPP_NAME + "}")
+       @GetMapping(XAPPS_METHOD_PATH + "/{" + PP_XAPP_NAME + "}")
        @Secured({ DashboardConstants.ROLE_ADMIN, DashboardConstants.ROLE_STANDARD })
-       public Xapp getXapp(@PathVariable("xAppName") String xAppName) {
-               logger.debug("getXapp {}", xAppName);
-               return xappApi.getXappByName(xAppName);
+       public Xapp getXapp(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
+                       @PathVariable(PP_XAPP_NAME) String appName) {
+               logger.debug("getXapp instance {} name {}", instanceKey, appName);
+               return appManagerApiBuilder.getXappApi(instanceKey).getXappByName(appName);
        }
 
        @ApiOperation(value = "Deploy a xapp.", response = Xapp.class)
-       @PostMapping(XAPPS_METHOD)
+       @PostMapping(XAPPS_METHOD_PATH)
        @Secured({ DashboardConstants.ROLE_ADMIN })
-       public Xapp deployXapp(@RequestBody XAppInfo xAppInfo) {
-               logger.debug("deployXapp {}", xAppInfo);
-               return xappApi.deployXapp(xAppInfo);
+       public Xapp deployXapp(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
+                       @RequestBody XAppInfo appInfo) {
+               logger.debug("deployXapp instance {} info {}", instanceKey, appInfo);
+               return appManagerApiBuilder.getXappApi(instanceKey).deployXapp(appInfo);
        }
 
        @ApiOperation(value = "Undeploy an existing xapp.")
-       @DeleteMapping(XAPPS_METHOD + "/{" + PP_XAPP_NAME + "}")
+       @DeleteMapping(XAPPS_METHOD_PATH + "/{" + PP_XAPP_NAME + "}")
        @Secured({ DashboardConstants.ROLE_ADMIN })
-       public void undeployXapp(@PathVariable("xAppName") String xAppName, HttpServletResponse response) {
-               logger.debug("undeployXapp {}", xAppName);
-               xappApi.undeployXapp(xAppName);
-               response.setStatus(xappApi.getApiClient().getStatusCode().value());
+       public void undeployXapp(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
+                       @PathVariable(PP_XAPP_NAME) String appName, HttpServletResponse response) {
+               logger.debug("undeployXapp instance {} name {}", instanceKey, appName);
+               XappApi api = appManagerApiBuilder.getXappApi(instanceKey);
+               api.undeployXapp(appName);
+               response.setStatus(api.getApiClient().getStatusCode().value());
        }
 
 }
index f8272b3..7d91f17 100644 (file)
@@ -24,6 +24,7 @@ import java.lang.invoke.MethodHandles;
 import javax.servlet.http.HttpServletResponse;
 
 import org.oransc.ric.portal.dashboard.DashboardConstants;
+import org.oransc.ric.portal.dashboard.config.SimpleKubernetesClientBuilder;
 import org.oransc.ric.portal.dashboard.k8sapi.SimpleKubernetesClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -59,7 +60,7 @@ public class CaasIngressController {
        // Publish constants so tests are easy to write
        public static final String CONTROLLER_PATH = DashboardConstants.ENDPOINT_PREFIX + "/caas-ingress";
        // Endpoints
-       public static final String PODS_METHOD = "/pods";
+       public static final String PODS_METHOD = "pods";
        // Path parameters
        public static final String PP_CLUSTER = "cluster";
        public static final String PP_NAMESPACE = "namespace";
@@ -67,28 +68,31 @@ public class CaasIngressController {
        public static final String CLUSTER_PLT = "plt";
        public static final String CLUSTER_RIC = "ric"; // alternate for PLT
 
-       private final SimpleKubernetesClient ciPltClient;
+       // Populated by the autowired constructor
+       private final SimpleKubernetesClientBuilder simpleKubernetesClientBuilder;
 
        @Autowired
-       public CaasIngressController(final SimpleKubernetesClient ciPltApi) {
-               Assert.notNull(ciPltApi, "pltApi must not be null");
-               this.ciPltClient = ciPltApi;
+       public CaasIngressController(final SimpleKubernetesClientBuilder simpleKubernetesClientBuilder) {
+               Assert.notNull(simpleKubernetesClientBuilder, "builder must not be null");
+               this.simpleKubernetesClientBuilder = simpleKubernetesClientBuilder;
                if (logger.isDebugEnabled())
-                       logger.debug("ctor: configured with plt api {}", ciPltClient.getClass().getName());
+                       logger.debug("ctor: configured with builder type {}", simpleKubernetesClientBuilder.getClass().getName());
        }
 
        /*
         * No need to parse the V1PodList, just pass thru as a string.
         */
        @ApiOperation(value = "Gets list of pods in the specified cluster for the specified namespace", response = String.class)
-       @GetMapping(PODS_METHOD + "/" + PP_CLUSTER + "/{" + PP_CLUSTER + "}" + "/" + PP_NAMESPACE + "/{" + PP_NAMESPACE
-                       + "}")
+       @GetMapping(DashboardConstants.RIC_INSTANCE_KEY + "/{" + DashboardConstants.RIC_INSTANCE_KEY + "}/" + PODS_METHOD
+                       + "/" + PP_CLUSTER + "/{" + PP_CLUSTER + "}" + "/" + PP_NAMESPACE + "/{" + PP_NAMESPACE + "}")
        @Secured({ DashboardConstants.ROLE_ADMIN, DashboardConstants.ROLE_STANDARD })
-       public String listPods(@PathVariable(PP_CLUSTER) String cluster, @PathVariable(PP_NAMESPACE) String namespace,
-                       HttpServletResponse response) {
-               logger.debug("listPods: cluster {}, namespace {}", cluster, namespace);
+       public String listPods(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey, //
+                       @PathVariable(PP_CLUSTER) String cluster, //
+                       @PathVariable(PP_NAMESPACE) String namespace, HttpServletResponse response) {
+               logger.debug("listPods: instance {} cluster {} namespace {}", instanceKey, cluster, namespace);
+               SimpleKubernetesClient client = simpleKubernetesClientBuilder.getSimpleKubernetesClient(instanceKey);
                if (CLUSTER_PLT.equalsIgnoreCase(cluster) || CLUSTER_RIC.equalsIgnoreCase(cluster)) {
-                       return ciPltClient.listPods(namespace);
+                       return client.listPods(namespace);
                } else {
                        logger.warn("listPods: unknown cluster {}", cluster);
                        response.setStatus(HttpStatus.BAD_REQUEST.value());
index f5ecd10..a881616 100644 (file)
@@ -21,6 +21,7 @@ package org.oransc.ric.portal.dashboard.controller;
 
 import java.lang.invoke.MethodHandles;
 
+import org.oransc.ric.portal.dashboard.exception.UnknownInstanceException;
 import org.oransc.ric.portal.dashboard.model.ErrorTransport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -79,4 +80,20 @@ public class CustomResponseEntityExceptionHandler extends ResponseEntityExceptio
                }
        }
 
+       /**
+        * Logs a warning if an invalid RIC instance key is used.
+        * 
+        * @param ex
+        *                    The exception
+        * @param request
+        *                    The original request
+        * @return A response entity with status code 400
+        */
+       @ExceptionHandler({ UnknownInstanceException.class })
+       public final ResponseEntity<ErrorTransport> handleUnknownInstanceException(Exception ex, WebRequest request) {
+               log.warn("handleUnknownInstanceException: request {}, exception {}", request.getDescription(false),
+                               ex.toString());
+               return new ResponseEntity<>(new ErrorTransport(400, ex), HttpStatus.BAD_REQUEST);
+       }
+
 }
index 17e68fd..749ecae 100644 (file)
@@ -33,6 +33,7 @@ import org.oransc.ric.e2mgr.client.model.ResetRequest;
 import org.oransc.ric.e2mgr.client.model.SetupRequest;
 import org.oransc.ric.portal.dashboard.DashboardApplication;
 import org.oransc.ric.portal.dashboard.DashboardConstants;
+import org.oransc.ric.portal.dashboard.config.E2ManagerApiBuilder;
 import org.oransc.ric.portal.dashboard.model.RanDetailsTransport;
 import org.oransc.ric.portal.dashboard.model.SuccessTransport;
 import org.slf4j.Logger;
@@ -68,65 +69,67 @@ public class E2ManagerController {
 
        private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
-       // Publish paths in constants so tests are easy to write
+       // Publish paths in constants for tests
        public static final String CONTROLLER_PATH = DashboardConstants.ENDPOINT_PREFIX + "/e2mgr";
        // Dashboard only
        public static final String HEALTH_METHOD = "health";
-       public static final String VERSION_METHOD = DashboardConstants.VERSION_METHOD;
        // Keep these consistent with the E2M implementation
-       /* package */ static final String NODEB_PREFIX = "/nodeb";
+       /* package */ static final String NODEB_PREFIX = "nodeb";
        public static final String RAN_METHOD = NODEB_PREFIX + "/ran";
        public static final String NODEB_SHUTDOWN_METHOD = NODEB_PREFIX + "/shutdown";
        public static final String NODEB_LIST_METHOD = NODEB_PREFIX + "/ids";
        public static final String ENDC_SETUP_METHOD = NODEB_PREFIX + "/endc-setup";
        public static final String X2_SETUP_METHOD = NODEB_PREFIX + "/x2-setup";
        // Reset uses prefix, adds a path parameter below
-       public static final String RESET_METHOD = "/reset";
+       public static final String RESET_METHOD = "reset";
        // Path parameters
        private static final String PP_RANNAME = "ranName";
 
        // Populated by the autowired constructor
-       private final HealthCheckApi e2HealthCheckApi;
-       private final NodebApi e2NodebApi;
+       private final E2ManagerApiBuilder e2ManagerApiBuilder;
 
        @Autowired
-       public E2ManagerController(final HealthCheckApi e2HealthCheckApi, final NodebApi e2NodebApi) {
-               Assert.notNull(e2HealthCheckApi, "API must not be null");
-               Assert.notNull(e2NodebApi, "API must not be null");
-               this.e2HealthCheckApi = e2HealthCheckApi;
-               this.e2NodebApi = e2NodebApi;
+       public E2ManagerController(final E2ManagerApiBuilder e2ManagerApiBuilder) {
+               Assert.notNull(e2ManagerApiBuilder, "builder must not be null");
+               this.e2ManagerApiBuilder = e2ManagerApiBuilder;
+               if (logger.isDebugEnabled())
+                       logger.debug("ctor: configured with builder type {}", e2ManagerApiBuilder.getClass().getName());
        }
 
        @ApiOperation(value = "Gets the E2 manager client library MANIFEST.MF property Implementation-Version.", response = SuccessTransport.class)
-       @GetMapping(VERSION_METHOD)
+       @GetMapping(DashboardConstants.VERSION_METHOD)
        // No role required
        public SuccessTransport getClientVersion() {
                return new SuccessTransport(200, DashboardApplication.getImplementationVersion(HealthCheckApi.class));
        }
 
        @ApiOperation(value = "Gets the health from the E2 manager, expressed as the response code.")
-       @GetMapping(HEALTH_METHOD)
+       @GetMapping(DashboardConstants.RIC_INSTANCE_KEY + "/{" + DashboardConstants.RIC_INSTANCE_KEY + "}/" + HEALTH_METHOD)
        // No role required
-       public void healthGet(HttpServletResponse response) {
-               logger.debug("healthGet");
-               e2HealthCheckApi.healthGet();
-               response.setStatus(e2HealthCheckApi.getApiClient().getStatusCode().value());
+       public void healthGet(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
+                       HttpServletResponse response) {
+               logger.debug("healthGet instance {}", instanceKey);
+               HealthCheckApi api = e2ManagerApiBuilder.getHealthCheckApi(instanceKey);
+               api.healthGet();
+               response.setStatus(api.getApiClient().getStatusCode().value());
        }
 
        // This calls other methods to simplify the task of the front-end.
        @ApiOperation(value = "Gets all RAN identities and statuses from the E2 manager.", response = RanDetailsTransport.class, responseContainer = "List")
-       @GetMapping(RAN_METHOD)
+       @GetMapping(DashboardConstants.RIC_INSTANCE_KEY + "/{" + DashboardConstants.RIC_INSTANCE_KEY + "}/" + RAN_METHOD)
        @Secured({ DashboardConstants.ROLE_ADMIN, DashboardConstants.ROLE_STANDARD })
-       public List<RanDetailsTransport> getRanDetails() {
-               logger.debug("getRanDetails");
-               List<NodebIdentity> nodebIdList = e2NodebApi.getNodebIdList();
+       public List<RanDetailsTransport> getRanDetails(
+                       @PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey) {
+               logger.debug("getRanDetails instance {}", instanceKey);
+               NodebApi api = e2ManagerApiBuilder.getNodebApi(instanceKey);
+               List<NodebIdentity> nodebIdList = api.getNodebIdList();
                logger.debug("getRanDetails: nodebIdList {}", nodebIdList);
                List<RanDetailsTransport> details = new ArrayList<>();
                for (NodebIdentity nbid : nodebIdList) {
                        GetNodebResponse nbResp = null;
                        try {
                                // Catch exceptions to keep looping despite failures
-                               nbResp = e2NodebApi.getNb(nbid.getInventoryName());
+                               nbResp = api.getNb(nbid.getInventoryName());
                        } catch (HttpStatusCodeException ex) {
                                logger.warn("E2 getNb failed for name {}: {}", nbid.getInventoryName(), ex.toString());
                                nbResp = new GetNodebResponse().connectionStatus("UNKNOWN").ip("UNKNOWN").port(-1)
@@ -138,56 +141,71 @@ public class E2ManagerController {
        }
 
        @ApiOperation(value = "Get RAN identities list.", response = NodebIdentity.class, responseContainer = "List")
-       @GetMapping(NODEB_LIST_METHOD)
+       @GetMapping(DashboardConstants.RIC_INSTANCE_KEY + "/{" + DashboardConstants.RIC_INSTANCE_KEY + "}/"
+                       + NODEB_LIST_METHOD)
        @Secured({ DashboardConstants.ROLE_ADMIN, DashboardConstants.ROLE_STANDARD })
-       public List<NodebIdentity> getNodebIdList() {
-               logger.debug("getNodebIdList");
-               return e2NodebApi.getNodebIdList();
+       public List<NodebIdentity> getNodebIdList(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey) {
+               logger.debug("getNodebIdList instance {}", instanceKey);
+               return e2ManagerApiBuilder.getNodebApi(instanceKey).getNodebIdList();
        }
 
        @ApiOperation(value = "Get RAN by name.", response = GetNodebResponse.class)
-       @GetMapping(NODEB_SHUTDOWN_METHOD + "/{" + PP_RANNAME + "}")
+       @GetMapping(DashboardConstants.RIC_INSTANCE_KEY + "/{" + DashboardConstants.RIC_INSTANCE_KEY + "}/" + NODEB_PREFIX
+                       + "/{" + PP_RANNAME + "}")
        @Secured({ DashboardConstants.ROLE_ADMIN, DashboardConstants.ROLE_STANDARD })
-       public GetNodebResponse getNb(@PathVariable(PP_RANNAME) String ranName) {
-               logger.debug("getNb {}", ranName);
-               return e2NodebApi.getNb(ranName);
+       public GetNodebResponse getNb(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
+                       @PathVariable(PP_RANNAME) String ranName) {
+               logger.debug("getNb instance {} name {}", instanceKey, ranName);
+               return e2ManagerApiBuilder.getNodebApi(instanceKey).getNb(ranName);
        }
 
        @ApiOperation(value = "Sets up an EN-DC RAN connection via the E2 manager.")
-       @PostMapping(ENDC_SETUP_METHOD)
+       @PostMapping(DashboardConstants.RIC_INSTANCE_KEY + "/{" + DashboardConstants.RIC_INSTANCE_KEY + "}/"
+                       + ENDC_SETUP_METHOD)
        @Secured({ DashboardConstants.ROLE_ADMIN })
-       public void endcSetup(@RequestBody SetupRequest setupRequest, HttpServletResponse response) {
-               logger.debug("endcSetup {}", setupRequest);
-               e2NodebApi.endcSetup(setupRequest);
-               response.setStatus(e2NodebApi.getApiClient().getStatusCode().value());
+       public void endcSetup(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
+                       @RequestBody SetupRequest setupRequest, HttpServletResponse response) {
+               logger.debug("endcSetup instance {} request {}", instanceKey, setupRequest);
+               NodebApi api = e2ManagerApiBuilder.getNodebApi(instanceKey);
+               api.endcSetup(setupRequest);
+               response.setStatus(api.getApiClient().getStatusCode().value());
        }
 
        @ApiOperation(value = "Sets up an X2 RAN connection via the E2 manager.")
-       @PostMapping(X2_SETUP_METHOD)
+       @PostMapping(DashboardConstants.RIC_INSTANCE_KEY + "/{" + DashboardConstants.RIC_INSTANCE_KEY + "}/"
+                       + X2_SETUP_METHOD)
        @Secured({ DashboardConstants.ROLE_ADMIN })
-       public void x2Setup(@RequestBody SetupRequest setupRequest, HttpServletResponse response) {
-               logger.debug("x2Setup {}", setupRequest);
-               e2NodebApi.x2Setup(setupRequest);
-               response.setStatus(e2NodebApi.getApiClient().getStatusCode().value());
+       public void x2Setup(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
+                       @RequestBody SetupRequest setupRequest, HttpServletResponse response) {
+               logger.debug("x2Setup instance {} request {}", instanceKey, setupRequest);
+               NodebApi api = e2ManagerApiBuilder.getNodebApi(instanceKey);
+               api.x2Setup(setupRequest);
+               response.setStatus(api.getApiClient().getStatusCode().value());
        }
 
        @ApiOperation(value = "Close all connections to the RANs and delete the data from the nodeb-rnib DB.")
-       @PutMapping(NODEB_SHUTDOWN_METHOD)
+       @PutMapping(DashboardConstants.RIC_INSTANCE_KEY + "/{" + DashboardConstants.RIC_INSTANCE_KEY + "}/"
+                       + NODEB_SHUTDOWN_METHOD)
        @Secured({ DashboardConstants.ROLE_ADMIN })
-       public void nodebShutdownPut(HttpServletResponse response) {
-               logger.debug("nodebShutdownPut");
-               e2NodebApi.nodebShutdownPut();
-               response.setStatus(e2NodebApi.getApiClient().getStatusCode().value());
+       public void nodebShutdownPut(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
+                       HttpServletResponse response) {
+               logger.debug("nodebShutdownPut instance {}", instanceKey);
+               NodebApi api = e2ManagerApiBuilder.getNodebApi(instanceKey);
+               api.nodebShutdownPut();
+               response.setStatus(api.getApiClient().getStatusCode().value());
        }
 
        @ApiOperation(value = "Abort any other ongoing procedures over X2 between the RIC and the RAN.")
-       @PutMapping(NODEB_PREFIX + "/{" + PP_RANNAME + "}" + RESET_METHOD)
+       @PutMapping(DashboardConstants.RIC_INSTANCE_KEY + "/{" + DashboardConstants.RIC_INSTANCE_KEY + "}/" + NODEB_PREFIX
+                       + "/{" + PP_RANNAME + "}/" + RESET_METHOD)
        @Secured({ DashboardConstants.ROLE_ADMIN })
-       public void reset(@PathVariable(PP_RANNAME) String ranName, @RequestBody ResetRequest resetRequest,
+       public void reset(@PathVariable(DashboardConstants.RIC_INSTANCE_KEY) String instanceKey,
+                       @PathVariable(PP_RANNAME) String ranName, @RequestBody ResetRequest resetRequest,
                        HttpServletResponse response) {
-               logger.debug("reset");
-               e2NodebApi.reset(ranName, resetRequest);
-               response.setStatus(e2NodebApi.getApiClient().getStatusCode().value());
+               logger.debug("reset instance {} name {}", instanceKey, ranName);
+               NodebApi api = e2ManagerApiBuilder.getNodebApi(instanceKey);
+               api.reset(ranName, resetRequest);
+               response.setStatus(api.getApiClient().getStatusCode().value());
        }
 
 }
diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/exception/UnknownInstanceException.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/exception/UnknownInstanceException.java
new file mode 100644 (file)
index 0000000..f0fb074
--- /dev/null
@@ -0,0 +1,33 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+package org.oransc.ric.portal.dashboard.exception;
+
+public class UnknownInstanceException extends IllegalArgumentException {
+
+       private static final long serialVersionUID = -3887065423512216019L;
+
+       public UnknownInstanceException() {
+               super();
+       }
+
+       public UnknownInstanceException(String s) {
+               super(s);
+       }
+}
diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/RicInstance.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/RicInstance.java
new file mode 100644 (file)
index 0000000..ad3b3f2
--- /dev/null
@@ -0,0 +1,111 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.oransc.ric.portal.dashboard.model;
+
+/**
+ * POJO for RIC instance details.
+ */
+public class RicInstance extends RicInstanceKeyName {
+
+       /* Application entry point */
+       private String appUrlPrefix;
+       /* Platform entry point */
+       private String pltUrlPrefix;
+       /* CAAS-Ingress */
+       private String caasUrlPrefix;
+
+       /**
+        * Builds an empty object.
+        */
+       public RicInstance() {
+               super();
+       }
+
+       public RicInstance key(String key) {
+               super.key(key);
+               return this;
+       }
+
+       public RicInstance name(String name) {
+               super.name(name);
+               return this;
+       }
+
+       public RicInstanceKeyName toKeyName() {
+               return new RicInstanceKeyName(getKey(), getName());
+       }
+
+       public String getAppUrlPrefix() {
+               return appUrlPrefix;
+       }
+
+       public void setAppUrlPrefix(String urlPrefix) {
+               this.appUrlPrefix = urlPrefix;
+       }
+
+       public RicInstance appUrlPrefix(String prefix) {
+               this.appUrlPrefix = prefix;
+               return this;
+       }
+
+       public String getPltUrlPrefix() {
+               return pltUrlPrefix;
+       }
+
+       public void setPltUrlPrefix(String pltUrlPrefix) {
+               this.pltUrlPrefix = pltUrlPrefix;
+       }
+
+       public RicInstance pltUrlPrefix(String prefix) {
+               this.pltUrlPrefix = prefix;
+               return this;
+       }
+
+       public String getCaasUrlPrefix() {
+               return caasUrlPrefix;
+       }
+
+       public void setCaasUrlPrefix(String caasUrlPrefix) {
+               this.caasUrlPrefix = caasUrlPrefix;
+       }
+
+       public RicInstance caasUrlPrefix(String prefix) {
+               this.caasUrlPrefix = prefix;
+               return this;
+       }
+
+       @Override
+       public String toString() {
+               return this.getClass().getName() + "[key=" + getKey() + ", name=" + getName() + ", appUrlPrefix=" + appUrlPrefix
+                               + ", pltUrlPrefix=" + pltUrlPrefix + ", caasUrlPrefix=" + caasUrlPrefix + "]";
+       }
+
+       @Override
+       public int hashCode() {
+               final int prime = 31;
+               int result = super.hashCode();
+               result = prime * result + ((appUrlPrefix == null) ? 0 : appUrlPrefix.hashCode());
+               result = prime * result + ((caasUrlPrefix == null) ? 0 : caasUrlPrefix.hashCode());
+               result = prime * result + ((pltUrlPrefix == null) ? 0 : pltUrlPrefix.hashCode());
+               return result;
+       }
+
+}
 
 package org.oransc.ric.portal.dashboard.model;
 
+import java.util.Objects;
+
 /**
- * Trivial model to transport key-name pairs that represent RIC instances.
+ * Transport model for RIC instance key-name pairs.
  */
-public class InstanceTransport implements IDashboardResponse {
+public class RicInstanceKeyName implements IDashboardResponse {
 
        private String key;
        private String name;
@@ -31,7 +33,7 @@ public class InstanceTransport implements IDashboardResponse {
        /**
         * Builds an empty object.
         */
-       public InstanceTransport() {
+       public RicInstanceKeyName() {
                // no-arg constructor
        }
 
@@ -43,7 +45,7 @@ public class InstanceTransport implements IDashboardResponse {
         * @param name
         *                 Name
         */
-       public InstanceTransport(String key, String name) {
+       public RicInstanceKeyName(String key, String name) {
                this.key = key;
                this.name = name;
        }
@@ -56,6 +58,11 @@ public class InstanceTransport implements IDashboardResponse {
                this.key = key;
        }
 
+       public RicInstanceKeyName key(String key) {
+               this.key = key;
+               return this;
+       }
+
        public String getName() {
                return name;
        }
@@ -64,9 +71,35 @@ public class InstanceTransport implements IDashboardResponse {
                this.name = s;
        }
 
+       public RicInstanceKeyName name(String name) {
+               this.name = name;
+               return this;
+       }
+
        @Override
        public String toString() {
                return this.getClass().getName() + "[key=" + getKey() + ", name=" + getName() + "]";
        }
 
+       @Override
+       public int hashCode() {
+               final int prime = 31;
+               int result = 1;
+               result = prime * result + ((key == null) ? 0 : key.hashCode());
+               result = prime * result + ((name == null) ? 0 : name.hashCode());
+               return result;
+       }
+
+       @Override
+       public boolean equals(Object obj) {
+               if (this == obj)
+                       return true;
+               if (obj == null)
+                       return false;
+               if (getClass() != obj.getClass())
+                       return false;
+               RicInstanceKeyName other = (RicInstanceKeyName) obj;
+               return Objects.equals(key, other.key);
+       }
+
 }
diff --git a/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/RicInstanceList.java b/webapp-backend/src/main/java/org/oransc/ric/portal/dashboard/model/RicInstanceList.java
new file mode 100644 (file)
index 0000000..4f8d34e
--- /dev/null
@@ -0,0 +1,71 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.oransc.ric.portal.dashboard.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.oransc.ric.portal.dashboard.exception.UnknownInstanceException;
+
+public class RicInstanceList {
+
+       private final List<RicInstance> instances;
+
+       public RicInstanceList() {
+               this.instances = new ArrayList<>();
+       }
+
+       public RicInstanceList(List<RicInstance> list) {
+               this.instances = list;
+       }
+
+       public List<RicInstance> getInstances() {
+               return instances;
+       }
+
+       /**
+        * Gets a list of key-name pairs.
+        * 
+        * @return List of RicInstanceKeyName objects.
+        */
+       public List<RicInstanceKeyName> getKeyNameList() {
+               List<RicInstanceKeyName> list = new ArrayList<>();
+               for (RicInstance i : instances)
+                       list.add(i.toKeyName());
+               return list;
+       }
+
+       /**
+        * Gets the instance with the specified key
+        * 
+        * @param instanceKey
+        *                        Key to fetch
+        * @return Instance
+        * @throws UnknownInstanceException
+        *                                      If the key is not known
+        */
+       public RicInstance getInstance(String instanceKey) {
+               for (RicInstance i : instances)
+                       if (i.getKey().equals(instanceKey))
+                               return i;
+               throw new UnknownInstanceException(instanceKey);
+       }
+}
index ab7ff6f..9b8f5d0 100644 (file)
@@ -45,24 +45,21 @@ portalapi:
     username:
     password:
 
-# endpoint URLs must be supplied at deployment time
+# Instance-specific URL prefixes must be supplied at deployment time
 
 # A1 Mediator
 a1med:
     url:
-        prefix: http://jar-app-props-default-A1-URL-prefix
         suffix:
 
 # App Manager
 appmgr:
     url:
-        prefix: http://jar-app-props-default-Xapp-Mgr-URL
         suffix: /ric/v1
 
 # E2 Manager
 e2mgr:
     url:
-        prefix: http://jar-app-props-default-E2-URL
         suffix: /v1
 
 # Kubernetes API via https://github.com/nokia/caas-ingress
@@ -71,7 +68,6 @@ caasingress:
     insecure: true
     plt:
         url:
-            prefix: https://jar-app-props-default-caas-ingress-plt-URL
             suffix: /api
 
 # Mimic slow endpoints by defining sleep period, in milliseconds
@@ -91,6 +87,12 @@ ric-instance-list:
         -
           key: i1
           name: Primary RIC Instance
+          appUrlPrefix: App prefix 1
+          caasUrlPrefix: Caas prefix 1
+          pltUrlPrefix: Plt prefix 1
         -
           key: i2
           name: RIC Instance Nr Two
+          appUrlPrefix: App prefix 2
+          caasUrlPrefix: Caas prefix 2
+          pltUrlPrefix: Plt prefix 2
index 877f097..d3ac7a7 100644 (file)
@@ -42,7 +42,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 
 /**
- * Creates a mock implementation of the A1 mediator client API.
+ * Creates a mock implementation of the A1 mediator client builder.
  */
 @Configuration
 @Profile("test")
@@ -54,13 +54,14 @@ public class A1MediatorMockConfiguration {
        public static final String AC_CONTROL_NAME = "admission_control_policy";
 
        // Simulate remote method delay for UI testing
-       @Value("${mock.config.delay:0}")
-       private int delayMs;
+       private final int delayMs;
 
+       // Mock values
        private final Map<String, String> appPolicyMap;
 
-       public A1MediatorMockConfiguration() {
-               logger.info("Configuring mock A1 Mediator");
+       public A1MediatorMockConfiguration(@Value("${mock.config.delay:0}") int delayMs) {
+               logger.info("ctor: mock A1 Mediator configured with delay {}", delayMs);
+               this.delayMs = delayMs;
                appPolicyMap = new HashMap<>();
                // Define a mock AC policy
                ObjectMapper mapper = new ObjectMapper();
@@ -80,9 +81,7 @@ public class A1MediatorMockConfiguration {
                return mockClient;
        }
 
-       @Bean
-       // Use the same name as regular configuration
-       public A1MediatorApi a1MediatorApi() {
+       private A1MediatorApi a1MediatorApi() {
                ApiClient apiClient = apiClient();
                A1MediatorApi mockApi = mock(A1MediatorApi.class);
                when(mockApi.getApiClient()).thenReturn(apiClient);
@@ -107,4 +106,13 @@ public class A1MediatorMockConfiguration {
                return mockApi;
        }
 
+       @Bean
+       // Must use the same name as the non-mock configuration
+       public A1MediatorApiBuilder a1MediatorApiBuilder() {
+               final A1MediatorApi mockApi = a1MediatorApi();
+               final A1MediatorApiBuilder mockBuilder = mock(A1MediatorApiBuilder.class);
+               when(mockBuilder.getA1MediatorApi(any(String.class))).thenReturn(mockApi);
+               return mockBuilder;
+       }
+
 }
index ba84fd4..6b0517e 100644 (file)
@@ -88,9 +88,7 @@ public class AppManagerMockConfiguration {
                subRes = new SubscriptionResponse().eventType(SubscriptionResponse.EventTypeEnum.ALL).id("subid").version(1);
        }
 
-       @Bean
-       // Use the same name as regular configuration
-       public HealthApi xappMgrHealthApi() {
+       private HealthApi healthApi() {
                ApiClient mockClient = mock(ApiClient.class);
                when(mockClient.getStatusCode()).thenReturn(HttpStatus.OK);
                HealthApi mockApi = mock(HealthApi.class);
@@ -100,9 +98,7 @@ public class AppManagerMockConfiguration {
                return mockApi;
        }
 
-       @Bean
-       // Use the same name as regular configuration
-       public XappApi xappMgrXappApi() {
+       private XappApi xappApi() {
                ApiClient mockClient = mock(ApiClient.class);
                when(mockClient.getStatusCode()).thenReturn(HttpStatus.OK);
                XappApi mockApi = mock(XappApi.class);
@@ -187,4 +183,15 @@ public class AppManagerMockConfiguration {
                return mockApi;
        }
 
+       @Bean
+       // Must use the same name as the non-mock configuration
+       public AppManagerApiBuilder appManagerApiBuilder() {
+               final AppManagerApiBuilder mockBuilder = mock(AppManagerApiBuilder.class);
+               final HealthApi mockHealthApi = healthApi();
+               when(mockBuilder.getHealthApi(any(String.class))).thenReturn(mockHealthApi);
+               final XappApi mockXappApi = xappApi();
+               when(mockBuilder.getXappApi(any(String.class))).thenReturn(mockXappApi);
+               return mockBuilder;
+       }
+
 }
index 56a01ab..1420086 100644 (file)
@@ -22,6 +22,7 @@ package org.oransc.ric.portal.dashboard.config;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -76,9 +77,7 @@ public class CaasIngressMockConfiguration {
                return sb.toString();
        }
 
-       @Bean
-       // Use the same name as regular configuration
-       public SimpleKubernetesClient ciPltApi() throws IOException {
+       private SimpleKubernetesClient simpleKubernetesClient() {
                SimpleKubernetesClient mockClient = mock(SimpleKubernetesClient.class);
                doAnswer(inv -> {
                        String ns = inv.<String>getArgument(0);
@@ -86,9 +85,18 @@ public class CaasIngressMockConfiguration {
                        if ("ricplt".equals(ns))
                                return pltPods;
                        else
-                               throw new Exception("Fake server failure");
+                               throw new IllegalArgumentException("Fake server failure");
                }).when(mockClient).listPods(any(String.class));
                return mockClient;
        }
 
+       @Bean
+       // The bean (method) name must be globally unique
+       public SimpleKubernetesClientBuilder simpleKubernetesClientBuilder() {
+               final SimpleKubernetesClientBuilder mockBuilder = mock(SimpleKubernetesClientBuilder.class);
+               SimpleKubernetesClient client = simpleKubernetesClient();
+               when(mockBuilder.getSimpleKubernetesClient(any(String.class))).thenReturn(client);
+               return mockBuilder;
+       }
+
 }
index b3b4c9c..3f33f40 100644 (file)
@@ -59,8 +59,8 @@ public class E2ManagerMockConfiguration {
        @Value("${mock.config.delay:0}")
        private int delayMs;
 
-       public static final String RAN_NAME_1 = "Connected RAN";
-       public static final String RAN_NAME_2 = "Unknown RAN";
+       public static final String RAN_NAME_1 = "Connected-RAN";
+       public static final String RAN_NAME_2 = "Unknown-RAN";
 
        private final List<NodebIdentity> nodebIdList;
        private final Map<String, GetNodebResponse> nodebResponseMap;
@@ -91,9 +91,7 @@ public class E2ManagerMockConfiguration {
                return mockClient;
        }
 
-       @Bean
-       // Use the same name as regular configuration
-       public HealthCheckApi e2MgrHealthCheckApi() {
+       private HealthCheckApi healthCheckApi() {
                ApiClient apiClient = apiClient();
                HealthCheckApi mockApi = mock(HealthCheckApi.class);
                when(mockApi.getApiClient()).thenReturn(apiClient);
@@ -101,9 +99,7 @@ public class E2ManagerMockConfiguration {
                return mockApi;
        }
 
-       @Bean
-       // Use the same name as regular configuration
-       public NodebApi e2MgrNodebApi() {
+       private NodebApi nodebApi() {
                ApiClient apiClient = apiClient();
                NodebApi mockApi = mock(NodebApi.class);
                when(mockApi.getApiClient()).thenReturn(apiClient);
@@ -164,4 +160,15 @@ public class E2ManagerMockConfiguration {
                return mockApi;
        }
 
+       @Bean
+       // Must use the same name as the non-mock configuration
+       public E2ManagerApiBuilder e2ManagerApiBuilder() {
+               final E2ManagerApiBuilder mockBuilder = mock(E2ManagerApiBuilder.class);
+               final HealthCheckApi mockHealthCheckApi = healthCheckApi();
+               when(mockBuilder.getHealthCheckApi(any(String.class))).thenReturn(mockHealthCheckApi);
+               final NodebApi mockNodebApi = nodebApi();
+               when(mockBuilder.getNodebApi(any(String.class))).thenReturn(mockNodebApi);
+               return mockBuilder;
+       }
+
 }
diff --git a/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/RICInstanceMockConfiguration.java b/webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/RICInstanceMockConfiguration.java
new file mode 100644 (file)
index 0000000..2f9e82c
--- /dev/null
@@ -0,0 +1,57 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+package org.oransc.ric.portal.dashboard.config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.oransc.ric.portal.dashboard.model.RicInstance;
+import org.oransc.ric.portal.dashboard.model.RicInstanceList;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Component;
+
+/**
+ * Publishes a mock list of RIC instances.
+ */
+@Component
+@Profile("test")
+public class RICInstanceMockConfiguration {
+
+       // Publish constants for use in tests
+       public static final String INSTANCE_KEY_1 = "i1";
+       public static final String INSTANCE_KEY_2 = "i2";
+
+       @Bean
+       public RicInstanceList ricInstanceList() {
+               List<RicInstance> instances = new ArrayList<>();
+               RicInstance i1 = new RicInstance().key(INSTANCE_KEY_1).name("Friendly Name One")
+                               .appUrlPrefix("http://foo.bar/app").pltUrlPrefix("http://foo.bar/plt")
+                               .caasUrlPrefix("http://foo.bar/caas");
+               instances.add(i1);
+               RicInstance i2 = new RicInstance().key(INSTANCE_KEY_2).name("Friendly Name Two")
+                               .appUrlPrefix("http://foo.bar/2/app").pltUrlPrefix("http://foo.bar/2/plt")
+                               .caasUrlPrefix("http://foo.bar/2/caas");
+               instances.add(i2);
+               return new RicInstanceList(instances);
+       }
+
+}
index 77e23b8..325d869 100644 (file)
@@ -26,7 +26,9 @@ import java.net.URI;
 import org.junit.Assert;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
+import org.oransc.ric.portal.dashboard.DashboardConstants;
 import org.oransc.ric.portal.dashboard.config.A1MediatorMockConfiguration;
+import org.oransc.ric.portal.dashboard.config.RICInstanceMockConfiguration;
 import org.oransc.ric.portal.dashboard.model.SuccessTransport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -43,7 +45,7 @@ public class A1MediatorControllerTest extends AbstractControllerTest {
 
        @Test
        public void versionTest() {
-               URI uri = buildUri(null, A1MediatorController.CONTROLLER_PATH, A1MediatorController.VERSION_METHOD);
+               URI uri = buildUri(null, A1MediatorController.CONTROLLER_PATH, DashboardConstants.VERSION_METHOD);
                logger.info("Invoking {}", uri);
                SuccessTransport st = restTemplate.getForObject(uri, SuccessTransport.class);
                Assertions.assertFalse(st.getData().toString().isEmpty());
@@ -51,7 +53,8 @@ public class A1MediatorControllerTest extends AbstractControllerTest {
 
        @Test
        public void getTest() throws IOException {
-               URI uri = buildUri(null, A1MediatorController.CONTROLLER_PATH, A1MediatorController.PP_POLICIES,
+               URI uri = buildUri(null, A1MediatorController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, A1MediatorController.PP_POLICIES,
                                A1MediatorMockConfiguration.AC_CONTROL_NAME);
                logger.info("Invoking {}", uri);
                ResponseEntity<String> response = testRestTemplateStandardRole().exchange(uri, HttpMethod.GET, null,
@@ -62,12 +65,13 @@ public class A1MediatorControllerTest extends AbstractControllerTest {
 
        @Test
        public void putTest() throws IOException {
+               URI uri = buildUri(null, A1MediatorController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, A1MediatorController.PP_POLICIES,
+                               A1MediatorMockConfiguration.AC_CONTROL_NAME);
                ObjectMapper mapper = new ObjectMapper();
                JsonNode body = mapper.readTree("{ \"policy\" : true }");
-               URI uri = buildUri(null, A1MediatorController.CONTROLLER_PATH, A1MediatorController.PP_POLICIES,
-                               A1MediatorMockConfiguration.AC_CONTROL_NAME);
                HttpEntity<JsonNode> entity = new HttpEntity<>(body);
-               logger.info("Invoking {}", uri);
+               logger.info("Invoking {} with body {}", uri, body);
                ResponseEntity<Void> voidResponse = testRestTemplateAdminRole().exchange(uri, HttpMethod.PUT, entity,
                                Void.class);
                Assertions.assertTrue(voidResponse.getStatusCode().is2xxSuccessful());
index d4163f0..e9aedc4 100644 (file)
@@ -55,13 +55,13 @@ public class AbstractControllerTest {
        protected TestRestTemplate restTemplate;
 
        /**
-        * Flexible URI builder.
+        * Builds URI from path components and query parameters.
         * 
         * @param queryParams
         *                        Map of string-string query parameters
         * @param path
         *                        Array of path components. If a component has an
-        *                        embedded slash, the string is split and each
+        *                        embedded slash, that string is split and each
         *                        subcomponent is added individually.
         * @return URI
         */
index 4383752..c40c285 100644 (file)
@@ -21,7 +21,6 @@ package org.oransc.ric.portal.dashboard.controller;
 
 import java.lang.invoke.MethodHandles;
 
-import org.oransc.ric.portal.dashboard.DashboardConstants;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.http.MediaType;
@@ -39,9 +38,6 @@ public class AdminController2 {
 
        private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
-       // Publish paths in constants so tests are easy to write
-       public static final String CONTROLLER_PATH = DashboardConstants.ENDPOINT_PREFIX + "/admin";
-
        @GetMapping("throw1")
        public void throw1() {
                logger.warn("throwing RestClientResponseException");
index f1c2680..d6f206e 100644 (file)
@@ -30,7 +30,7 @@ import org.junit.jupiter.api.Test;
 import org.onap.portalsdk.core.restful.domain.EcompUser;
 import org.oransc.ric.portal.dashboard.DashboardConstants;
 import org.oransc.ric.portal.dashboard.model.ErrorTransport;
-import org.oransc.ric.portal.dashboard.model.InstanceTransport;
+import org.oransc.ric.portal.dashboard.model.RicInstanceKeyName;
 import org.oransc.ric.portal.dashboard.model.SuccessTransport;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -62,8 +62,8 @@ public class AdminControllerTest extends AbstractControllerTest {
        public void getInstancesTest() {
                URI uri = buildUri(null, AdminController.CONTROLLER_PATH, AdminController.INSTANCE_METHOD);
                logger.info("Invoking {}", uri);
-               ResponseEntity<List<InstanceTransport>> response = testRestTemplateStandardRole().exchange(uri, HttpMethod.GET,
-                               null, new ParameterizedTypeReference<List<InstanceTransport>>() {
+               ResponseEntity<List<RicInstanceKeyName>> response = testRestTemplateStandardRole().exchange(uri, HttpMethod.GET,
+                               null, new ParameterizedTypeReference<List<RicInstanceKeyName>>() {
                                });
                Assertions.assertFalse(response.getBody().isEmpty());
        }
index c9ec4b0..961e693 100644 (file)
@@ -30,6 +30,8 @@ import org.oransc.ric.plt.appmgr.client.model.ConfigMetadata;
 import org.oransc.ric.plt.appmgr.client.model.XAppConfig;
 import org.oransc.ric.plt.appmgr.client.model.XAppInfo;
 import org.oransc.ric.plt.appmgr.client.model.Xapp;
+import org.oransc.ric.portal.dashboard.DashboardConstants;
+import org.oransc.ric.portal.dashboard.config.RICInstanceMockConfiguration;
 import org.oransc.ric.portal.dashboard.model.DashboardDeployableXapps;
 import org.oransc.ric.portal.dashboard.model.SuccessTransport;
 import org.slf4j.Logger;
@@ -44,7 +46,7 @@ public class AppManagerControllerTest extends AbstractControllerTest {
 
        @Test
        public void versionTest() {
-               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, AppManagerController.VERSION_METHOD);
+               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, DashboardConstants.VERSION_METHOD);
                logger.info("Invoking {}", uri);
                SuccessTransport st = restTemplate.getForObject(uri, SuccessTransport.class);
                Assertions.assertFalse(st.getData().toString().isEmpty());
@@ -52,7 +54,8 @@ public class AppManagerControllerTest extends AbstractControllerTest {
 
        @Test
        public void healthAliveTest() {
-               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, AppManagerController.HEALTH_ALIVE_METHOD);
+               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, AppManagerController.HEALTH_ALIVE_METHOD);
                logger.info("Invoking {}", uri);
                ResponseEntity<Void> voidResponse = restTemplate.getForEntity(uri, Void.class);
                Assertions.assertTrue(voidResponse.getStatusCode().is2xxSuccessful());
@@ -60,7 +63,8 @@ public class AppManagerControllerTest extends AbstractControllerTest {
 
        @Test
        public void healthReadyTest() {
-               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, AppManagerController.HEALTH_READY_METHOD);
+               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, AppManagerController.HEALTH_READY_METHOD);
                logger.info("Invoking {}", uri);
                ResponseEntity<Void> voidResponse = restTemplate.getForEntity(uri, Void.class);
                Assertions.assertTrue(voidResponse.getStatusCode().is2xxSuccessful());
@@ -68,7 +72,8 @@ public class AppManagerControllerTest extends AbstractControllerTest {
 
        @Test
        public void appListTest() {
-               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, AppManagerController.XAPPS_LIST_METHOD);
+               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, AppManagerController.XAPPS_LIST_METHOD);
                logger.info("Invoking {}", uri);
                DashboardDeployableXapps apps = testRestTemplateStandardRole().getForObject(uri,
                                DashboardDeployableXapps.class);
@@ -77,7 +82,8 @@ public class AppManagerControllerTest extends AbstractControllerTest {
 
        @Test
        public void appStatusesTest() {
-               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, AppManagerController.XAPPS_METHOD);
+               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, AppManagerController.XAPPS_METHOD);
                logger.info("Invoking {}", uri);
                AllDeployedXapps apps = testRestTemplateStandardRole().getForObject(uri, AllDeployedXapps.class);
                Assertions.assertFalse(apps.isEmpty());
@@ -85,7 +91,8 @@ public class AppManagerControllerTest extends AbstractControllerTest {
 
        @Test
        public void appStatusTest() {
-               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, AppManagerController.XAPPS_METHOD, "app");
+               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, AppManagerController.XAPPS_METHOD, "app");
                logger.info("Invoking {}", uri);
                Xapp app = testRestTemplateStandardRole().getForObject(uri, Xapp.class);
                Assertions.assertFalse(app.getName().isEmpty());
@@ -93,7 +100,8 @@ public class AppManagerControllerTest extends AbstractControllerTest {
 
        @Test
        public void deployAppTest() {
-               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, AppManagerController.XAPPS_METHOD);
+               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, AppManagerController.XAPPS_METHOD);
                logger.info("Invoking {}", uri);
                XAppInfo info = new XAppInfo();
                Xapp app = testRestTemplateAdminRole().postForObject(uri, info, Xapp.class);
@@ -102,7 +110,8 @@ public class AppManagerControllerTest extends AbstractControllerTest {
 
        @Test
        public void undeployAppTest() {
-               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, AppManagerController.XAPPS_METHOD, "app");
+               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, AppManagerController.XAPPS_METHOD, "app");
                logger.info("Invoking {}", uri);
                ResponseEntity<Void> voidResponse = testRestTemplateAdminRole().exchange(uri, HttpMethod.DELETE, null,
                                Void.class);
@@ -111,7 +120,8 @@ public class AppManagerControllerTest extends AbstractControllerTest {
 
        @Test
        public void getConfigTest() {
-               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, AppManagerController.CONFIG_METHOD);
+               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, AppManagerController.CONFIG_METHOD);
                logger.info("Invoking {}", uri);
                AllXappConfig config = testRestTemplateStandardRole().getForObject(uri, AllXappConfig.class);
                Assertions.assertFalse(config.isEmpty());
@@ -119,7 +129,8 @@ public class AppManagerControllerTest extends AbstractControllerTest {
 
        @Test
        public void createConfigTest() {
-               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, AppManagerController.CONFIG_METHOD);
+               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, AppManagerController.CONFIG_METHOD);
                logger.info("Invoking {}", uri);
                XAppConfig newConfig = new XAppConfig();
                XAppConfig response = testRestTemplateAdminRole().postForObject(uri, newConfig, XAppConfig.class);
@@ -128,7 +139,8 @@ public class AppManagerControllerTest extends AbstractControllerTest {
 
        @Test
        public void deleteConfigTest() {
-               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, AppManagerController.CONFIG_METHOD, "app");
+               URI uri = buildUri(null, AppManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, AppManagerController.CONFIG_METHOD, "app");
                logger.info("Invoking {}", uri);
                ConfigMetadata delConfig = new ConfigMetadata();
                HttpEntity<ConfigMetadata> entity = new HttpEntity<>(delConfig);
index 41dfcaf..b91c44c 100644 (file)
@@ -25,6 +25,8 @@ import java.net.URI;
 import org.junit.Assert;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
+import org.oransc.ric.portal.dashboard.DashboardConstants;
+import org.oransc.ric.portal.dashboard.config.RICInstanceMockConfiguration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -35,7 +37,8 @@ public class CaasIngressControllerTest extends AbstractControllerTest {
        @Test
        public void pltTest() {
                final String nsPlt = "ricplt";
-               URI uri = buildUri(null, CaasIngressController.CONTROLLER_PATH, CaasIngressController.PODS_METHOD,
+               URI uri = buildUri(null, CaasIngressController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, CaasIngressController.PODS_METHOD,
                                CaasIngressController.PP_CLUSTER, CaasIngressController.CLUSTER_PLT, CaasIngressController.PP_NAMESPACE,
                                nsPlt);
                logger.info("Invoking {}", uri);
@@ -47,7 +50,8 @@ public class CaasIngressControllerTest extends AbstractControllerTest {
        @Test
        public void unknownClusterTest() {
                final String nsPlt = "ricplt";
-               URI uri = buildUri(null, CaasIngressController.CONTROLLER_PATH, CaasIngressController.PODS_METHOD,
+               URI uri = buildUri(null, CaasIngressController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, CaasIngressController.PODS_METHOD,
                                CaasIngressController.PP_CLUSTER, "cluster", CaasIngressController.PP_NAMESPACE, nsPlt);
                logger.info("Invoking {}", uri);
                String s = testRestTemplateStandardRole().getForObject(uri, String.class);
@@ -58,7 +62,8 @@ public class CaasIngressControllerTest extends AbstractControllerTest {
        @Test
        public void bogusNsTest() {
                final String ns = "unknown";
-               URI uri = buildUri(null, CaasIngressController.CONTROLLER_PATH, CaasIngressController.PODS_METHOD,
+               URI uri = buildUri(null, CaasIngressController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, CaasIngressController.PODS_METHOD,
                                CaasIngressController.PP_CLUSTER, CaasIngressController.CLUSTER_PLT, CaasIngressController.PP_NAMESPACE,
                                ns);
                logger.info("Invoking {}", uri);
index ddd2b09..e6744fe 100644 (file)
@@ -29,7 +29,9 @@ import org.oransc.ric.e2mgr.client.model.GetNodebResponse;
 import org.oransc.ric.e2mgr.client.model.NodebIdentity;
 import org.oransc.ric.e2mgr.client.model.ResetRequest;
 import org.oransc.ric.e2mgr.client.model.SetupRequest;
+import org.oransc.ric.portal.dashboard.DashboardConstants;
 import org.oransc.ric.portal.dashboard.config.E2ManagerMockConfiguration;
+import org.oransc.ric.portal.dashboard.config.RICInstanceMockConfiguration;
 import org.oransc.ric.portal.dashboard.model.RanDetailsTransport;
 import org.oransc.ric.portal.dashboard.model.SuccessTransport;
 import org.slf4j.Logger;
@@ -44,7 +46,8 @@ public class E2ManagerControllerTest extends AbstractControllerTest {
        private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
        private ResponseEntity<Void> endcSetup() {
-               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, E2ManagerController.ENDC_SETUP_METHOD);
+               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, E2ManagerController.ENDC_SETUP_METHOD);
                logger.info("Invoking {}", uri);
                SetupRequest setup = new SetupRequest().ranName(E2ManagerMockConfiguration.RAN_NAME_1);
                HttpEntity<SetupRequest> entity = new HttpEntity<>(setup);
@@ -52,7 +55,8 @@ public class E2ManagerControllerTest extends AbstractControllerTest {
        }
 
        private ResponseEntity<Void> reset() {
-               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, E2ManagerController.NODEB_PREFIX, "ignored",
+               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, E2ManagerController.NODEB_PREFIX, "ignored",
                                E2ManagerController.RESET_METHOD);
                logger.info("Invoking {}", uri);
                ResetRequest reset = new ResetRequest();
@@ -60,9 +64,23 @@ public class E2ManagerControllerTest extends AbstractControllerTest {
                return testRestTemplateAdminRole().exchange(uri, HttpMethod.PUT, entity, Void.class);
        }
 
+       @Test
+       public void endcSetupTest() {
+               ResponseEntity<Void> voidResponse = endcSetup();
+               Assertions.assertTrue(voidResponse.getStatusCode().is2xxSuccessful());
+               reset();
+       }
+
+       @Test
+       public void resetTest() {
+               ResponseEntity<Void> voidResponse = reset();
+               logger.debug("resetTest: response {}", voidResponse);
+               Assertions.assertTrue(voidResponse.getStatusCode().is2xxSuccessful());
+       }
+
        @Test
        public void versionTest() {
-               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, E2ManagerController.VERSION_METHOD);
+               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, DashboardConstants.VERSION_METHOD);
                logger.info("Invoking {}", uri);
                SuccessTransport st = restTemplate.getForObject(uri, SuccessTransport.class);
                Assertions.assertFalse(st.getData().toString().isEmpty());
@@ -70,7 +88,8 @@ public class E2ManagerControllerTest extends AbstractControllerTest {
 
        @Test
        public void healthTest() {
-               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, E2ManagerController.HEALTH_METHOD);
+               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, E2ManagerController.HEALTH_METHOD);
                logger.info("Invoking {}", uri);
                ResponseEntity<Void> voidResponse = restTemplate.getForEntity(uri, Void.class);
                Assertions.assertTrue(voidResponse.getStatusCode().is2xxSuccessful());
@@ -79,7 +98,8 @@ public class E2ManagerControllerTest extends AbstractControllerTest {
        @Test
        public void ranDetailsTest() {
                endcSetup();
-               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, E2ManagerController.RAN_METHOD);
+               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, E2ManagerController.RAN_METHOD);
                logger.info("Invoking {}", uri);
                ResponseEntity<List<RanDetailsTransport>> response = testRestTemplateStandardRole().exchange(uri,
                                HttpMethod.GET, null, new ParameterizedTypeReference<List<RanDetailsTransport>>() {
@@ -91,7 +111,8 @@ public class E2ManagerControllerTest extends AbstractControllerTest {
        @Test
        public void nodebListTest() {
                endcSetup();
-               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, E2ManagerController.NODEB_LIST_METHOD);
+               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, E2ManagerController.NODEB_LIST_METHOD);
                logger.info("Invoking {}", uri);
                ResponseEntity<List<NodebIdentity>> response = testRestTemplateStandardRole().exchange(uri, HttpMethod.GET,
                                null, new ParameterizedTypeReference<List<NodebIdentity>>() {
@@ -103,7 +124,8 @@ public class E2ManagerControllerTest extends AbstractControllerTest {
        @Test
        public void nodebStatusTest() {
                endcSetup();
-               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, E2ManagerController.NODEB_SHUTDOWN_METHOD,
+               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, E2ManagerController.NODEB_PREFIX,
                                E2ManagerMockConfiguration.RAN_NAME_1);
                logger.info("Invoking {}", uri);
                GetNodebResponse response = testRestTemplateStandardRole().getForObject(uri, GetNodebResponse.class);
@@ -111,16 +133,10 @@ public class E2ManagerControllerTest extends AbstractControllerTest {
                reset();
        }
 
-       @Test
-       public void endcSetupTest() {
-               ResponseEntity<Void> voidResponse = endcSetup();
-               Assertions.assertTrue(voidResponse.getStatusCode().is2xxSuccessful());
-               reset();
-       }
-
        @Test
        public void x2SetupTest() {
-               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, E2ManagerController.X2_SETUP_METHOD);
+               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, E2ManagerController.X2_SETUP_METHOD);
                logger.info("Invoking {}", uri);
                SetupRequest setup = new SetupRequest().ranName(E2ManagerMockConfiguration.RAN_NAME_1);
                HttpEntity<SetupRequest> entity = new HttpEntity<>(setup);
@@ -133,18 +149,12 @@ public class E2ManagerControllerTest extends AbstractControllerTest {
        // Aka big--button test
        @Test
        public void nodebShutdownPutTest() {
-               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, E2ManagerController.NODEB_SHUTDOWN_METHOD);
+               URI uri = buildUri(null, E2ManagerController.CONTROLLER_PATH, DashboardConstants.RIC_INSTANCE_KEY,
+                               RICInstanceMockConfiguration.INSTANCE_KEY_1, E2ManagerController.NODEB_SHUTDOWN_METHOD);
                logger.info("Invoking {}", uri);
                ResponseEntity<Void> voidResponse = testRestTemplateAdminRole().exchange(uri, HttpMethod.PUT, null, Void.class);
                logger.debug("nodebPutTest: response {}", voidResponse);
                Assertions.assertTrue(voidResponse.getStatusCode().is2xxSuccessful());
        }
 
-       @Test
-       public void resetTest() {
-               ResponseEntity<Void> voidResponse = reset();
-               logger.debug("resetTest: response {}", voidResponse);
-               Assertions.assertTrue(voidResponse.getStatusCode().is2xxSuccessful());
-       }
-
 }
index 8aab066..71225aa 100644 (file)
@@ -84,15 +84,15 @@ public class ModelTest extends AbstractModelTest {
                logger.info(m.toString());
        }
 
-       private void checkInstanceTransport(InstanceTransport m) {
+       private void checkInstanceTransport(RicInstanceKeyName m) {
                Assert.assertEquals(s1, m.getKey());
                Assert.assertEquals(s2, m.getName());
        }
 
        @Test
        public void testInstanceTransport() {
-               InstanceTransport m = new InstanceTransport(s1, s1);
-               m = new InstanceTransport();
+               RicInstanceKeyName m = new RicInstanceKeyName(s1, s1);
+               m = new RicInstanceKeyName();
                m.setKey(s1);
                m.setName(s2);
                checkInstanceTransport(m);