From: PatrikBuhr Date: Mon, 9 Dec 2019 15:39:11 +0000 (+0100) Subject: Added ServiceController and Service supervision X-Git-Tag: 1.0.1~81 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=7adad623a64bfbb96b3c73ed7c1d0d49aabff659;p=nonrtric.git Added ServiceController and Service supervision Checking application alive each minute. Change-Id: Ia562b349355f7c2bdded0595f348f0c96c9ccbda Issue-ID: NONRTRIC-84 Signed-off-by: PatrikBuhr --- diff --git a/policy-agent/src/main/java/org/oransc/policyagent/Beans.java b/policy-agent/src/main/java/org/oransc/policyagent/BeanFactory.java similarity index 91% rename from policy-agent/src/main/java/org/oransc/policyagent/Beans.java rename to policy-agent/src/main/java/org/oransc/policyagent/BeanFactory.java index c8f774c4..637eac1f 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/Beans.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/BeanFactory.java @@ -24,11 +24,12 @@ import org.oransc.policyagent.configuration.ApplicationConfig; import org.oransc.policyagent.repository.Policies; import org.oransc.policyagent.repository.PolicyTypes; import org.oransc.policyagent.repository.Rics; +import org.oransc.policyagent.repository.Services; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration -public class Beans { +class BeanFactory { @Bean public Policies getPolicies() { return new Policies(); @@ -49,4 +50,9 @@ public class Beans { return new ApplicationConfig(); } + @Bean + Services getServices() { + return new Services(); + } + } diff --git a/policy-agent/src/main/java/org/oransc/policyagent/configuration/ApplicationConfig.java b/policy-agent/src/main/java/org/oransc/policyagent/configuration/ApplicationConfig.java index 04471c88..c5cd44af 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/configuration/ApplicationConfig.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/configuration/ApplicationConfig.java @@ -54,6 +54,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; + import reactor.core.Disposable; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -108,9 +109,9 @@ public class ApplicationConfig { loadConfigurationFromFile(this.filepath); refreshConfigTask = createRefreshTask() // - .subscribe(e -> logger.info("Refreshed configuration data"), - throwable -> logger.error("Configuration refresh terminated due to exception", throwable), - () -> logger.error("Configuration refresh terminated")); + .subscribe(e -> logger.info("Refreshed configuration data"), + throwable -> logger.error("Configuration refresh terminated due to exception", throwable), + () -> logger.error("Configuration refresh terminated")); } Mono getEnvironment(Properties systemEnvironment) { @@ -119,10 +120,10 @@ public class ApplicationConfig { Flux createRefreshTask() { return getEnvironment(systemEnvironment) // - .flatMap(this::createCbsClient) // - .flatMapMany(this::periodicConfigurationUpdates) // - .map(this::parseRicConfigurationfromConsul) // - .onErrorResume(this::onErrorResume); + .flatMap(this::createCbsClient) // + .flatMapMany(this::periodicConfigurationUpdates) // + .map(this::parseRicConfigurationfromConsul) // + .onErrorResume(this::onErrorResume); } Mono createCbsClient(EnvProperties env) { @@ -153,7 +154,7 @@ public class ApplicationConfig { return this; } - private synchronized void setConfiguration(@NotNull Vector ricConfigs) { + private synchronized void setConfiguration(@NotNull Vector ricConfigs) { this.ricConfigs = ricConfigs; } diff --git a/policy-agent/src/main/java/org/oransc/policyagent/configuration/EnvironmentProcessor.java b/policy-agent/src/main/java/org/oransc/policyagent/configuration/EnvironmentProcessor.java index c2033f4e..5987c944 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/configuration/EnvironmentProcessor.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/configuration/EnvironmentProcessor.java @@ -19,8 +19,10 @@ */ package org.oransc.policyagent.configuration; + import java.util.Optional; import java.util.Properties; + import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.model.EnvProperties; import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.model.ImmutableEnvProperties; import org.oransc.policyagent.exceptions.EnvironmentLoaderException; @@ -41,11 +43,11 @@ class EnvironmentProcessor { EnvProperties envProperties; try { envProperties = ImmutableEnvProperties.builder() // - .consulHost(getConsulHost(systemEnvironment)) // - .consulPort(getConsultPort(systemEnvironment)) // - .cbsName(getConfigBindingService(systemEnvironment)) // - .appName(getService(systemEnvironment)) // - .build(); + .consulHost(getConsulHost(systemEnvironment)) // + .consulPort(getConsultPort(systemEnvironment)) // + .cbsName(getConfigBindingService(systemEnvironment)) // + .appName(getService(systemEnvironment)) // + .build(); } catch (EnvironmentLoaderException e) { return Mono.error(e); } @@ -55,27 +57,27 @@ class EnvironmentProcessor { private static String getConsulHost(Properties systemEnvironments) throws EnvironmentLoaderException { return Optional.ofNullable(systemEnvironments.getProperty("CONSUL_HOST")) - .orElseThrow(() -> new EnvironmentLoaderException("$CONSUL_HOST environment has not been defined")); + .orElseThrow(() -> new EnvironmentLoaderException("$CONSUL_HOST environment has not been defined")); } private static Integer getConsultPort(Properties systemEnvironments) { return Optional.ofNullable(systemEnvironments.getProperty("CONSUL_PORT")) // - .map(Integer::valueOf) // - .orElseGet(EnvironmentProcessor::getDefaultPortOfConsul); + .map(Integer::valueOf) // + .orElseGet(EnvironmentProcessor::getDefaultPortOfConsul); } private static String getConfigBindingService(Properties systemEnvironments) throws EnvironmentLoaderException { return Optional.ofNullable(systemEnvironments.getProperty("CONFIG_BINDING_SERVICE")) // - .orElseThrow( - () -> new EnvironmentLoaderException("$CONFIG_BINDING_SERVICE environment has not been defined")); + .orElseThrow( + () -> new EnvironmentLoaderException("$CONFIG_BINDING_SERVICE environment has not been defined")); } private static String getService(Properties systemEnvironments) throws EnvironmentLoaderException { return Optional - .ofNullable(Optional.ofNullable(systemEnvironments.getProperty("HOSTNAME")) - .orElse(systemEnvironments.getProperty("SERVICE_NAME"))) - .orElseThrow(() -> new EnvironmentLoaderException( - "Neither $HOSTNAME/$SERVICE_NAME have not been defined as system environment")); + .ofNullable(Optional.ofNullable(systemEnvironments.getProperty("HOSTNAME")) + .orElse(systemEnvironments.getProperty("SERVICE_NAME"))) + .orElseThrow(() -> new EnvironmentLoaderException( + "Neither $HOSTNAME/$SERVICE_NAME have not been defined as system environment")); } private static Integer getDefaultPortOfConsul() { diff --git a/policy-agent/src/main/java/org/oransc/policyagent/configuration/RicConfig.java b/policy-agent/src/main/java/org/oransc/policyagent/configuration/RicConfig.java index 8af3a9c7..aae9dee2 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/configuration/RicConfig.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/configuration/RicConfig.java @@ -21,6 +21,7 @@ package org.oransc.policyagent.configuration; import java.util.Vector; + import org.immutables.gson.Gson; import org.immutables.value.Value; diff --git a/policy-agent/src/main/java/org/oransc/policyagent/controllers/PolicyController.java b/policy-agent/src/main/java/org/oransc/policyagent/controllers/PolicyController.java index b2d0fab8..8e34aa9e 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/controllers/PolicyController.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/controllers/PolicyController.java @@ -21,9 +21,10 @@ package org.oransc.policyagent.controllers; import com.google.gson.Gson; import com.google.gson.GsonBuilder; + import java.util.Collection; import java.util.Vector; -import org.oransc.policyagent.Beans; + import org.oransc.policyagent.configuration.ApplicationConfig; import org.oransc.policyagent.exceptions.ServiceException; import org.oransc.policyagent.repository.ImmutablePolicy; @@ -32,6 +33,7 @@ import org.oransc.policyagent.repository.Policy; import org.oransc.policyagent.repository.PolicyTypes; import org.oransc.policyagent.repository.Ric; import org.oransc.policyagent.repository.Rics; +import org.oransc.policyagent.repository.Services; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -48,25 +50,26 @@ public class PolicyController { private final Rics rics; private final PolicyTypes types; private final Policies policies; + private final Services services; private static Gson gson = new GsonBuilder() // .serializeNulls() // .create(); // @Autowired - PolicyController(Beans beans) { - this.appConfig = beans.getApplicationConfig(); - this.rics = beans.getRics(); - this.types = beans.getPolicyTypes(); - this.policies = beans.getPolicies(); + PolicyController(ApplicationConfig config, PolicyTypes types, Policies policies, Rics rics, Services services) { + this.appConfig = config; + this.types = types; + this.policies = policies; + this.rics = rics; + this.services = services; } @GetMapping("/policy") public ResponseEntity getPolicy( // - @RequestParam(name = "instance", required = false, defaultValue = "new") String instance) { + @RequestParam(name = "instance", required = true) String instance) { try { Policy p = policies.get(instance); return new ResponseEntity(p.json(), HttpStatus.OK); - } catch (ServiceException e) { return new ResponseEntity(e.getMessage(), HttpStatus.NO_CONTENT); } @@ -136,6 +139,7 @@ public class PolicyController { @RequestBody String jsonBody) { try { + services.getService(service).ping(); Ric ricObj = rics.getRic(ric); Policy policy = ImmutablePolicy.builder() // .id(instanceId) // diff --git a/policy-agent/src/main/java/org/oransc/policyagent/controllers/PolicyInfo.java b/policy-agent/src/main/java/org/oransc/policyagent/controllers/PolicyInfo.java index 040ca3a6..f1268942 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/controllers/PolicyInfo.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/controllers/PolicyInfo.java @@ -26,7 +26,7 @@ import org.immutables.value.Value; @Value.Immutable @Gson.TypeAdapters -public interface PolicyInfo { +interface PolicyInfo { @SerializedName("id") public String name(); diff --git a/policy-agent/src/main/java/org/oransc/policyagent/controllers/RicInfo.java b/policy-agent/src/main/java/org/oransc/policyagent/controllers/RicInfo.java index 3d59e685..04e2cc56 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/controllers/RicInfo.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/controllers/RicInfo.java @@ -28,7 +28,7 @@ import org.immutables.value.Value; @Value.Immutable @Gson.TypeAdapters -public interface RicInfo { +interface RicInfo { @SerializedName("name") public String name(); diff --git a/policy-agent/src/main/java/org/oransc/policyagent/controllers/RicRepositoryController.java b/policy-agent/src/main/java/org/oransc/policyagent/controllers/RicRepositoryController.java index 7c63dcd8..5980fa40 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/controllers/RicRepositoryController.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/controllers/RicRepositoryController.java @@ -22,11 +22,14 @@ package org.oransc.policyagent.controllers; import com.google.gson.Gson; import com.google.gson.GsonBuilder; + import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; + import java.util.Optional; import java.util.Vector; + import org.oransc.policyagent.configuration.ApplicationConfig; import org.oransc.policyagent.configuration.RicConfig; import org.oransc.policyagent.repository.Ric; diff --git a/policy-agent/src/main/java/org/oransc/policyagent/controllers/ServiceController.java b/policy-agent/src/main/java/org/oransc/policyagent/controllers/ServiceController.java new file mode 100644 index 00000000..86335b66 --- /dev/null +++ b/policy-agent/src/main/java/org/oransc/policyagent/controllers/ServiceController.java @@ -0,0 +1,116 @@ +/*- + * ========================LICENSE_START================================= + * O-RAN-SC + * %% + * Copyright (C) 2019 Nordix Foundation + * %% + * 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.policyagent.controllers; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import java.time.Duration; +import java.util.Collection; +import java.util.Vector; + +import org.oransc.policyagent.configuration.ApplicationConfig; +import org.oransc.policyagent.exceptions.ServiceException; +import org.oransc.policyagent.repository.Service; +import org.oransc.policyagent.repository.Services; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class ServiceController { + + private final ApplicationConfig appConfig; + private final Services services; + private static Gson gson = new GsonBuilder() // + .serializeNulls() // + .create(); // + + @Autowired + ServiceController(ApplicationConfig config, Services services) { + this.appConfig = config; + this.services = services; + } + + @GetMapping("/service") + public ResponseEntity getService( // + @RequestParam(name = "name", required = true) String name) { + try { + Service s = services.getService(name); + String res = gson.toJson(toServiceStatus(s)); + return new ResponseEntity(res, HttpStatus.OK); + + } catch (ServiceException e) { + return new ResponseEntity(e.getMessage(), HttpStatus.NO_CONTENT); + } + } + + private ServiceStatus toServiceStatus(Service s) { + return ImmutableServiceStatus.builder() // + .name(s.getName()) // + .keepAliveInterval(s.getKeepAliveInterval().toSeconds()) // + .timeSincePing(s.timeSinceLastPing().toSeconds()) // + .build(); + } + + @PutMapping("/service") + public ResponseEntity putService( // + @RequestBody String jsonBody) { + try { + ServiceRegistrationInfo s = gson.fromJson(jsonBody, ImmutableServiceRegistrationInfo.class); + this.services.put(toService(s)); + return new ResponseEntity("OK", HttpStatus.OK); + } catch (Exception e) { + return new ResponseEntity(e.getMessage(), HttpStatus.NO_CONTENT); + } + } + + private Service toService(ServiceRegistrationInfo s) { + return new Service(s.name(), Duration.ofSeconds(s.keepAliveInterval())); + } + + @GetMapping("/services") + public ResponseEntity getServices() { + Collection allServices = this.services.getAll(); + Collection result = new Vector<>(allServices.size()); + for (Service s : allServices) { + result.add(toServiceStatus(s)); + } + return new ResponseEntity<>(gson.toJson(result), HttpStatus.OK); + } + + @PutMapping("/service/ping") + public ResponseEntity ping( // + @RequestBody String name) { + try { + Service s = services.getService(name); + s.ping(); + return new ResponseEntity("OK", HttpStatus.OK); + } catch (ServiceException e) { + return new ResponseEntity(e.getMessage(), HttpStatus.NO_CONTENT); + } + } + +} diff --git a/policy-agent/src/main/java/org/oransc/policyagent/controllers/ServiceRegistrationInfo.java b/policy-agent/src/main/java/org/oransc/policyagent/controllers/ServiceRegistrationInfo.java new file mode 100644 index 00000000..ede35dea --- /dev/null +++ b/policy-agent/src/main/java/org/oransc/policyagent/controllers/ServiceRegistrationInfo.java @@ -0,0 +1,37 @@ +/*- + * ========================LICENSE_START================================= + * O-RAN-SC + * %% + * Copyright (C) 2019 Nordix Foundation + * %% + * 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.policyagent.controllers; + +import com.google.gson.annotations.SerializedName; + +import org.immutables.gson.Gson; +import org.immutables.value.Value; + +@Value.Immutable +@Gson.TypeAdapters +public interface ServiceRegistrationInfo { + + @SerializedName("name") + public String name(); + + @SerializedName("keepAlive") + public long keepAliveInterval(); + +} diff --git a/policy-agent/src/main/java/org/oransc/policyagent/controllers/ServiceStatus.java b/policy-agent/src/main/java/org/oransc/policyagent/controllers/ServiceStatus.java new file mode 100644 index 00000000..64647b88 --- /dev/null +++ b/policy-agent/src/main/java/org/oransc/policyagent/controllers/ServiceStatus.java @@ -0,0 +1,40 @@ +/*- + * ========================LICENSE_START================================= + * O-RAN-SC + * %% + * Copyright (C) 2019 Nordix Foundation + * %% + * 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.policyagent.controllers; + +import com.google.gson.annotations.SerializedName; + +import org.immutables.gson.Gson; +import org.immutables.value.Value; + +@Value.Immutable +@Gson.TypeAdapters +public interface ServiceStatus { + + @SerializedName("name") + public String name(); + + @SerializedName("keepAlive") + public long keepAliveInterval(); + + @SerializedName("timeSincePing") + public long timeSincePing(); + +} diff --git a/policy-agent/src/main/java/org/oransc/policyagent/controllers/StartupService.java b/policy-agent/src/main/java/org/oransc/policyagent/controllers/StartupService.java index 12866ac0..40f01caa 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/controllers/StartupService.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/controllers/StartupService.java @@ -21,6 +21,7 @@ package org.oransc.policyagent.controllers; import java.util.Vector; + import org.oransc.policyagent.configuration.ApplicationConfig; import org.oransc.policyagent.configuration.RicConfig; import org.oransc.policyagent.repository.Ric; diff --git a/policy-agent/src/main/java/org/oransc/policyagent/repository/Policies.java b/policy-agent/src/main/java/org/oransc/policyagent/repository/Policies.java index 5f887889..cddd8a37 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/repository/Policies.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/repository/Policies.java @@ -24,6 +24,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Vector; + import org.oransc.policyagent.exceptions.ServiceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/policy-agent/src/main/java/org/oransc/policyagent/repository/PolicyTypes.java b/policy-agent/src/main/java/org/oransc/policyagent/repository/PolicyTypes.java index d3c2c4fc..6cf8ff41 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/repository/PolicyTypes.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/repository/PolicyTypes.java @@ -22,6 +22,7 @@ package org.oransc.policyagent.repository; import java.util.HashMap; import java.util.Map; + import org.oransc.policyagent.exceptions.ServiceException; public class PolicyTypes { diff --git a/policy-agent/src/main/java/org/oransc/policyagent/repository/Ric.java b/policy-agent/src/main/java/org/oransc/policyagent/repository/Ric.java index ffe493d2..066c0054 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/repository/Ric.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/repository/Ric.java @@ -21,6 +21,7 @@ package org.oransc.policyagent.repository; import java.util.Vector; + import org.oransc.policyagent.configuration.RicConfig; /** diff --git a/policy-agent/src/main/java/org/oransc/policyagent/repository/Service.java b/policy-agent/src/main/java/org/oransc/policyagent/repository/Service.java index 8efa5429..6a26b98e 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/repository/Service.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/repository/Service.java @@ -19,6 +19,39 @@ */ package org.oransc.policyagent.repository; -public interface Service { +import java.time.Duration; +import java.time.Instant; + +public class Service { + private final String name; + private final Duration keepAliveInterval; + private Instant lastPing; + // private final String callbackUrl1; // TBD + + public Service(String name, Duration keepAliveInterval) { + this.name = name; + this.keepAliveInterval = keepAliveInterval; + ping(); + } + + public String getName() { + return this.name; + } + + public Duration getKeepAliveInterval() { + return this.keepAliveInterval; + } + + public synchronized void ping() { + this.lastPing = Instant.now(); + } + + public synchronized boolean isExpired() { + return timeSinceLastPing().compareTo(this.keepAliveInterval) > 0; + } + + public synchronized Duration timeSinceLastPing() { + return Duration.between(this.lastPing, Instant.now()); + } } diff --git a/policy-agent/src/main/java/org/oransc/policyagent/repository/Services.java b/policy-agent/src/main/java/org/oransc/policyagent/repository/Services.java index 5b5b4a8a..789ea2e3 100644 --- a/policy-agent/src/main/java/org/oransc/policyagent/repository/Services.java +++ b/policy-agent/src/main/java/org/oransc/policyagent/repository/Services.java @@ -20,9 +20,11 @@ package org.oransc.policyagent.repository; +import java.util.Collection; import java.util.HashMap; import java.util.Map; +import org.oransc.policyagent.exceptions.ServiceException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,4 +36,24 @@ public class Services { public Services() { } + public synchronized Service getService(String name) throws ServiceException { + Service s = services.get(name); + if (s == null) { + throw new ServiceException("Could not find service: " + name); + } + return s; + } + + public synchronized Service get(String name) { + return services.get(name); + } + + public synchronized void put(Service service) { + services.put(service.getName(), service); + } + + public synchronized Collection getAll() { + return services.values(); + } + } diff --git a/policy-agent/src/main/java/org/oransc/policyagent/tasks/ServiceSupervision.java b/policy-agent/src/main/java/org/oransc/policyagent/tasks/ServiceSupervision.java new file mode 100644 index 00000000..03479dde --- /dev/null +++ b/policy-agent/src/main/java/org/oransc/policyagent/tasks/ServiceSupervision.java @@ -0,0 +1,83 @@ +/*- + * ========================LICENSE_START================================= + * O-RAN-SC + * %% + * Copyright (C) 2019 Nordix Foundation + * %% + * 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.policyagent.tasks; + +import org.oransc.policyagent.repository.Policies; +import org.oransc.policyagent.repository.Policy; +import org.oransc.policyagent.repository.Service; +import org.oransc.policyagent.repository.Services; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import reactor.core.publisher.Flux; + +@Component +@EnableScheduling +public class ServiceSupervision { + private static final Logger logger = LoggerFactory.getLogger(ServiceSupervision.class); + private final Services services; + private final Policies policies; + + @Autowired + public ServiceSupervision(Services services, Policies policies) { + this.services = services; + this.policies = policies; + } + + @Scheduled(fixedRate = 1000 * 60) + public void checkAllServices() { + logger.debug("Checking services starting"); + createTask().subscribe(this::onPolicyDeleted, this::onError, this::onComplete); + } + + private void onPolicyDeleted(Policy policy) { + logger.info("Policy deleted due to inactivity: " + policy.id() + ", service: " + policy.ownerServiceName()); + } + + private void onError(Throwable t) { + logger.error("Service supervision failed", t); + } + + private void onComplete() { + logger.debug("Checking services completed"); + } + + Flux createTask() { + return Flux.fromIterable(services.getAll()) // + .filter(service -> service.isExpired()) // + .doOnNext(service -> logger.info("Service is expired:" + service.getName())) + .flatMap(service -> getAllPolicies(service)) // + .flatMap(policy -> deletePolicy(policy)); + } + + Flux getAllPolicies(Service service) { + return Flux.fromIterable(policies.getForService(service.getName())); + } + + Flux deletePolicy(Policy policy) { + this.policies.remove(policy); + return Flux.just(policy); + } + +} diff --git a/policy-agent/src/test/java/org/oransc/policyagent/ApplicationTest.java b/policy-agent/src/test/java/org/oransc/policyagent/ApplicationTest.java index 18ea22bc..3b98ef56 100644 --- a/policy-agent/src/test/java/org/oransc/policyagent/ApplicationTest.java +++ b/policy-agent/src/test/java/org/oransc/policyagent/ApplicationTest.java @@ -21,10 +21,19 @@ package org.oransc.policyagent; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertFalse; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + import java.net.URL; + import org.junit.Test; import org.junit.runner.RunWith; import org.oransc.policyagent.configuration.ApplicationConfig; +import org.oransc.policyagent.controllers.ImmutableServiceRegistrationInfo; +import org.oransc.policyagent.controllers.ImmutableServiceStatus; +import org.oransc.policyagent.controllers.ServiceRegistrationInfo; +import org.oransc.policyagent.controllers.ServiceStatus; import org.oransc.policyagent.exceptions.ServiceException; import org.oransc.policyagent.repository.ImmutablePolicy; import org.oransc.policyagent.repository.ImmutablePolicyType; @@ -44,13 +53,22 @@ import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.web.client.RestTemplate; - @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) public class ApplicationTest { @Autowired - private Beans beans; + private Rics rics; + + @Autowired + private Policies policies; + + @Autowired + private PolicyTypes policyTypes; + + private static Gson gson = new GsonBuilder() // + .serializeNulls() // + .create(); // static class MockApplicationConfig extends ApplicationConfig { @Override @@ -60,28 +78,17 @@ public class ApplicationTest { } } - + /** + * overrides the BeanFactory + */ @TestConfiguration - static class Beans { - @Bean - public Rics getRics() { - return new Rics(); - } - - @Bean - public Policies getPolicies() { - return new Policies(); - } - - @Bean - public PolicyTypes getPolicyTypes() { - return new PolicyTypes(); - } + static class BeanFactory { @Bean public ApplicationConfig getApplicationConfig() { return new MockApplicationConfig(); } + } @LocalServerPort @@ -91,15 +98,15 @@ public class ApplicationTest { @Test public void getRics() throws Exception { - String cmd = "/rics"; - String rsp = this.restTemplate.getForObject("http://localhost:" + port + cmd, String.class); + String url = baseUrl() + "/rics"; + String rsp = this.restTemplate.getForObject(url, String.class); assertThat(rsp).contains("kista_1"); } @Test public void getRic() throws Exception { - String cmd = "/ric?managedElementId=kista_1"; - String rsp = this.restTemplate.getForObject("http://localhost:" + port + cmd, String.class); + String url = baseUrl() + "/ric?managedElementId=kista_1"; + String rsp = this.restTemplate.getForObject(url, String.class); assertThat(rsp).isEqualTo("ric1"); } @@ -107,13 +114,15 @@ public class ApplicationTest { @Test public void putPolicy() throws Exception { - String url = "http://localhost:" + port + "/policy?type=type1&instance=instance1&ric=ric1&service=service1"; + putService("service1"); + + String url = baseUrl() + "/policy?type=type1&instance=instance1&ric=ric1&service=service1"; String json = "{}"; addPolicyType("type1"); this.restTemplate.put(url, json); - Policy policy = beans.getPolicies().get("instance1"); + Policy policy = policies.get("instance1"); assertThat(policy).isNotNull(); assertThat(policy.id()).isEqualTo("instance1"); @@ -122,35 +131,39 @@ public class ApplicationTest { private PolicyType addPolicyType(String name) { PolicyType type = ImmutablePolicyType.builder() // - .jsonSchema("") // - .name(name) // - .build(); + .jsonSchema("") // + .name(name) // + .build(); - beans.getPolicyTypes().put(type); + policyTypes.put(type); return type; } private Policy addPolicy(String id, String typeName, String service) throws ServiceException { Policy p = ImmutablePolicy.builder().id(id) // - .json("{}") // - .ownerServiceName(service) // - .ric(beans.getRics().getRic("ric1")) // - .type(addPolicyType(typeName)) // - .build(); - beans.getPolicies().put(p); + .json("{}") // + .ownerServiceName(service) // + .ric(rics.getRic("ric1")) // + .type(addPolicyType(typeName)) // + .build(); + policies.put(p); return p; } + private String baseUrl() { + return "http://localhost:" + port; + } + @Test public void getPolicy() throws Exception { - String url = "http://localhost:" + port + "/policy?instance=id"; + String url = baseUrl() + "/policy?instance=id"; Policy policy = addPolicy("id", "typeName", "service1"); { String rsp = this.restTemplate.getForObject(url, String.class); assertThat(rsp).isEqualTo(policy.json()); } { - beans.getPolicies().remove(policy); + policies.remove(policy); ResponseEntity rsp = this.restTemplate.getForEntity(url, String.class); assertThat(rsp.getStatusCodeValue()).isEqualTo(HttpStatus.NO_CONTENT.value()); } @@ -158,7 +171,7 @@ public class ApplicationTest { @Test public void getPolicies() throws Exception { - String url = "http://localhost:" + port + "/policies"; + String url = baseUrl() + "/policies"; addPolicy("id1", "type1", "service1"); addPolicy("id2", "type2", "service2"); @@ -174,20 +187,49 @@ public class ApplicationTest { addPolicy("id2", "type1", "service2"); addPolicy("id3", "type2", "service1"); - String url = "http://localhost:" + port + "/policies?type=type1"; + String url = baseUrl() + "/policies?type=type1"; String rsp = this.restTemplate.getForObject(url, String.class); System.out.println(rsp); assertThat(rsp).contains("id1"); assertThat(rsp).contains("id2"); assertFalse(rsp.contains("id3")); - url = "http://localhost:" + port + "/policies?type=type1&service=service2"; + url = baseUrl() + "/policies?type=type1&service=service2"; rsp = this.restTemplate.getForObject(url, String.class); System.out.println(rsp); assertFalse(rsp.contains("id1")); assertThat(rsp).contains("id2"); assertFalse(rsp.contains("id3")); + } + + private void putService(String name) { + String url = baseUrl() + "/service"; + + ServiceRegistrationInfo service = ImmutableServiceRegistrationInfo.builder() // + .keepAliveInterval(1) // + .name(name) // + .build(); + String json = gson.toJson(service); + this.restTemplate.put(url, json); + } + + @Test + public void putAndGetService() throws Exception { + putService("name"); + + String url = baseUrl() + "/service?name=name"; + String rsp = this.restTemplate.getForObject(url, String.class); + ServiceStatus status = gson.fromJson(rsp, ImmutableServiceStatus.class); + assertThat(status.keepAliveInterval() == 1); + assertThat(status.name().equals("name")); + + url = baseUrl() + "/services"; + rsp = this.restTemplate.getForObject(url, String.class); + assertThat(rsp.contains("name")); + System.out.println(rsp); + url = baseUrl() + "/service/ping"; + this.restTemplate.put(url, "name"); } } diff --git a/policy-agent/src/test/java/org/oransc/policyagent/configuration/ApplicationConfigTest.java b/policy-agent/src/test/java/org/oransc/policyagent/configuration/ApplicationConfigTest.java index 0cbb3956..c8bbdfd2 100644 --- a/policy-agent/src/test/java/org/oransc/policyagent/configuration/ApplicationConfigTest.java +++ b/policy-agent/src/test/java/org/oransc/policyagent/configuration/ApplicationConfigTest.java @@ -21,30 +21,35 @@ package org.oransc.policyagent.configuration; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.doReturn; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.Properties; + import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.read.ListAppender; + import com.google.common.base.Charsets; import com.google.common.io.Resources; import com.google.gson.JsonIOException; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonSyntaxException; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Properties; + import org.junit.Test; import org.junit.jupiter.api.Assertions; import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.api.CbsClient; import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.model.EnvProperties; import org.onap.dcaegen2.services.sdk.rest.services.cbs.client.model.ImmutableEnvProperties; import org.oransc.policyagent.utils.LoggingUtils; + import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; @@ -54,14 +59,13 @@ public class ApplicationConfigTest { private ApplicationConfig appConfigUnderTest; CbsClient cbsClient = mock(CbsClient.class); - private static EnvProperties properties() { return ImmutableEnvProperties.builder() // - .consulHost("host") // - .consulPort(123) // - .cbsName("cbsName") // - .appName("appName") // - .build(); + .consulHost("host") // + .consulPort(123) // + .cbsName("cbsName") // + .appName("appName") // + .build(); } @Test @@ -73,9 +77,7 @@ public class ApplicationConfigTest { final ListAppender logAppender = LoggingUtils.getLogListAppender(ApplicationConfig.class); Flux task = appConfigUnderTest.createRefreshTask(); - StepVerifier.create(task) - .expectSubscription() - .verifyComplete(); + StepVerifier.create(task).expectSubscription().verifyComplete(); assertTrue(logAppender.list.toString().contains("$CONSUL_HOST environment has not been defined")); } @@ -96,12 +98,12 @@ public class ApplicationConfigTest { Flux task = appConfigUnderTest.createRefreshTask(); StepVerifier // - .create(task) // - .expectSubscription() // - .verifyComplete(); + .create(task) // + .expectSubscription() // + .verifyComplete(); assertTrue( - logAppender.list.toString().contains("Could not refresh application configuration java.io.IOException")); + logAppender.list.toString().contains("Could not refresh application configuration java.io.IOException")); } @Test @@ -119,10 +121,10 @@ public class ApplicationConfigTest { Flux task = appConfigUnderTest.createRefreshTask(); StepVerifier // - .create(task) // - .expectSubscription() // - .expectNext(appConfigUnderTest) // - .verifyComplete(); + .create(task) // + .expectSubscription() // + .expectNext(appConfigUnderTest) // + .verifyComplete(); Assertions.assertNotNull(appConfigUnderTest.getRicConfigs()); } diff --git a/policy-agent/src/test/java/org/oransc/policyagent/controllers/StartupServiceTest.java b/policy-agent/src/test/java/org/oransc/policyagent/controllers/StartupServiceTest.java index 5900f144..366524f6 100644 --- a/policy-agent/src/test/java/org/oransc/policyagent/controllers/StartupServiceTest.java +++ b/policy-agent/src/test/java/org/oransc/policyagent/controllers/StartupServiceTest.java @@ -25,6 +25,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.Vector; + import org.junit.Test; import org.oransc.policyagent.configuration.ApplicationConfig; import org.oransc.policyagent.configuration.ImmutableRicConfig;